decidim-surveys 0.29.2 → 0.30.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/surveys/survey_card_metadata_cell.rb +43 -0
- data/app/cells/decidim/surveys/survey_cell.rb +26 -0
- data/app/cells/decidim/surveys/survey_l_cell.rb +34 -0
- data/app/cells/decidim/surveys/survey_s_cell.rb +21 -0
- data/app/commands/decidim/surveys/admin/create_survey.rb +21 -0
- data/app/commands/decidim/surveys/admin/publish_survey.rb +58 -0
- data/app/commands/decidim/surveys/admin/unpublish_survey.rb +44 -0
- data/app/commands/decidim/surveys/admin/update_survey.rb +62 -0
- data/app/commands/decidim/surveys/publish_answers.rb +55 -0
- data/app/commands/decidim/surveys/unpublish_answers.rb +55 -0
- data/app/controllers/concerns/decidim/surveys/admin/filterable.rb +23 -0
- data/app/controllers/decidim/surveys/admin/answers_controller.rb +73 -0
- data/app/controllers/decidim/surveys/admin/publish_answers_controller.rb +66 -0
- data/app/controllers/decidim/surveys/admin/surveys_controller.rb +99 -11
- data/app/controllers/decidim/surveys/surveys_controller.rb +50 -5
- data/app/forms/decidim/surveys/admin/survey_form.rb +18 -0
- data/app/helpers/decidim/surveys/application_helper.rb +34 -0
- data/app/helpers/decidim/surveys/publish_answers_helper.rb +104 -0
- data/app/helpers/decidim/surveys/survey_helper.rb +4 -0
- data/app/models/decidim/surveys/survey.rb +67 -12
- data/app/permissions/decidim/surveys/admin/permissions.rb +10 -1
- data/app/permissions/decidim/surveys/permissions.rb +0 -2
- data/app/presenters/decidim/surveys/admin_log/survey_presenter.rb +34 -0
- data/app/queries/decidim/surveys/metrics/answers_metric_manage.rb +3 -3
- data/app/queries/decidim/surveys/metrics/survey_participants_metric_measure.rb +2 -2
- data/app/views/decidim/surveys/admin/answers/index.html.erb +49 -0
- data/app/views/decidim/surveys/admin/answers/show.html.erb +43 -0
- data/app/views/decidim/surveys/admin/publish_answers/_toggle_button.html.erb +22 -0
- data/app/views/decidim/surveys/admin/publish_answers/index.html.erb +44 -0
- data/app/views/decidim/surveys/admin/surveys/_form.html.erb +28 -0
- data/app/views/decidim/surveys/admin/surveys/edit.html.erb +4 -21
- data/app/views/decidim/surveys/admin/surveys/edit_questions.html.erb +47 -0
- data/app/views/decidim/surveys/admin/surveys/index.html.erb +51 -0
- data/app/views/decidim/surveys/surveys/_published_questions_answers.html.erb +13 -0
- data/app/views/decidim/surveys/surveys/_surveys.html.erb +13 -0
- data/app/views/decidim/surveys/surveys/index.html.erb +27 -0
- data/app/views/decidim/surveys/surveys/index.js.erb +4 -0
- data/app/views/decidim/surveys/surveys/not_allowed.html.erb +22 -0
- data/config/locales/ar.yml +4 -3
- data/config/locales/bg.yml +0 -14
- data/config/locales/ca.yml +83 -14
- data/config/locales/cs.yml +87 -14
- data/config/locales/de.yml +83 -14
- data/config/locales/el.yml +0 -11
- data/config/locales/en.yml +83 -14
- data/config/locales/es-MX.yml +83 -14
- data/config/locales/es-PY.yml +83 -14
- data/config/locales/es.yml +83 -14
- data/config/locales/eu.yml +83 -14
- data/config/locales/fi-plain.yml +83 -14
- data/config/locales/fi.yml +83 -14
- data/config/locales/fr-CA.yml +74 -14
- data/config/locales/fr.yml +74 -14
- data/config/locales/ga-IE.yml +0 -4
- data/config/locales/gl.yml +0 -10
- data/config/locales/hu.yml +0 -3
- data/config/locales/id-ID.yml +0 -2
- data/config/locales/is-IS.yml +0 -2
- data/config/locales/it.yml +3 -10
- data/config/locales/ja.yml +80 -13
- data/config/locales/lb.yml +0 -10
- data/config/locales/lt.yml +0 -11
- data/config/locales/lv.yml +0 -3
- data/config/locales/nl.yml +0 -10
- data/config/locales/no.yml +0 -10
- data/config/locales/pl.yml +0 -14
- data/config/locales/pt-BR.yml +0 -14
- data/config/locales/pt.yml +0 -10
- data/config/locales/ro-RO.yml +0 -11
- data/config/locales/ru.yml +0 -2
- data/config/locales/sk.yml +0 -3
- data/config/locales/sv.yml +0 -14
- data/config/locales/tr-TR.yml +0 -10
- data/config/locales/uk.yml +0 -2
- data/config/locales/zh-CN.yml +0 -6
- data/config/locales/zh-TW.yml +0 -11
- data/db/migrate/20240828103030_add_deleted_at_to_decidim_surveys_surveys.rb +8 -0
- data/db/migrate/20240925124312_add_settings_to_decidim_surveys_surveys.rb +42 -0
- data/db/migrate/20250115193836_add_allow_survey_editing.rb +7 -0
- data/decidim-surveys.gemspec +1 -1
- data/lib/decidim/api/survey_type.rb +2 -2
- data/lib/decidim/api/surveys_type.rb +4 -5
- data/lib/decidim/surveys/admin_engine.rb +15 -5
- data/lib/decidim/surveys/component.rb +7 -24
- data/lib/decidim/surveys/engine.rb +2 -2
- data/lib/decidim/surveys/seeds.rb +115 -10
- data/lib/decidim/surveys/test/factories.rb +24 -0
- data/lib/decidim/surveys/version.rb +1 -1
- metadata +48 -18
- data/app/commands/decidim/surveys/create_survey.rb +0 -19
- data/app/views/decidim/surveys/admin/component/_actions.html.erb +0 -44
@@ -3,43 +3,131 @@
|
|
3
3
|
module Decidim
|
4
4
|
module Surveys
|
5
5
|
module Admin
|
6
|
-
# This controller allows the user
|
6
|
+
# This controller allows the user create and edit questionnaires for Surveys.
|
7
7
|
class SurveysController < Admin::ApplicationController
|
8
8
|
include Decidim::Forms::Admin::Concerns::HasQuestionnaire
|
9
|
-
include Decidim::Forms::Admin::Concerns::
|
9
|
+
include Decidim::Forms::Admin::Concerns::HasQuestionnaireAnswersUrlHelper
|
10
|
+
include Decidim::Surveys::Admin::Filterable
|
11
|
+
|
12
|
+
helper_method :surveys
|
13
|
+
|
14
|
+
def index; end
|
15
|
+
|
16
|
+
def create
|
17
|
+
enforce_permission_to(:create, :questionnaire)
|
18
|
+
Decidim::Surveys::Admin::CreateSurvey.call(current_component) do
|
19
|
+
on(:ok) do |survey|
|
20
|
+
flash[:notice] = I18n.t("create.success", scope: "decidim.surveys.admin.surveys")
|
21
|
+
redirect_to edit_survey_path(survey)
|
22
|
+
end
|
23
|
+
|
24
|
+
on(:invalid) do
|
25
|
+
flash.now[:alert] = I18n.t("create.invalid", scope: "decidim.surveys.admin.surveys")
|
26
|
+
render action: "index"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
10
30
|
|
11
31
|
def edit
|
12
32
|
enforce_permission_to(:update, :questionnaire, questionnaire:)
|
33
|
+
@form = form(Admin::SurveyForm).from_model(survey)
|
34
|
+
end
|
35
|
+
|
36
|
+
def update
|
37
|
+
enforce_permission_to(:update, :questionnaire, questionnaire:)
|
38
|
+
@form = form(Admin::SurveyForm).from_params(params)
|
39
|
+
|
40
|
+
Admin::UpdateSurvey.call(@form, survey, current_user) do
|
41
|
+
on(:ok) do
|
42
|
+
flash[:notice] = I18n.t("update.success", scope: "decidim.surveys.admin.surveys")
|
43
|
+
redirect_to(surveys_path) && return
|
44
|
+
end
|
45
|
+
|
46
|
+
on(:invalid) do
|
47
|
+
flash.now[:alert] = I18n.t("update.invalid", scope: "decidim.surveys.admin.surveys")
|
48
|
+
render action: "edit"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def publish
|
54
|
+
enforce_permission_to(:update, :questionnaire, questionnaire:)
|
55
|
+
Decidim::Surveys::Admin::PublishSurvey.call(survey, current_user) do
|
56
|
+
on(:ok) do
|
57
|
+
flash[:notice] = I18n.t("publish.success", scope: "decidim.surveys.admin.surveys")
|
58
|
+
redirect_to surveys_path
|
59
|
+
end
|
60
|
+
|
61
|
+
on(:invalid) do
|
62
|
+
flash.now[:alert] = I18n.t("publish.invalid", scope: "decidim.surveys.admin.surveys")
|
63
|
+
render action: "index"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def unpublish
|
69
|
+
enforce_permission_to(:update, :questionnaire, questionnaire:)
|
70
|
+
Decidim::Surveys::Admin::UnpublishSurvey.call(survey, current_user) do
|
71
|
+
on(:ok) do
|
72
|
+
flash[:notice] = I18n.t("unpublish.success", scope: "decidim.surveys.admin.surveys")
|
73
|
+
redirect_to surveys_path
|
74
|
+
end
|
75
|
+
|
76
|
+
on(:invalid) do
|
77
|
+
flash.now[:alert] = I18n.t("unpublish.invalid", scope: "decidim.surveys.admin.surveys")
|
78
|
+
render action: "index"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
13
82
|
|
14
|
-
|
83
|
+
def destroy
|
84
|
+
enforce_permission_to(:destroy, :questionnaire, questionnaire:)
|
85
|
+
Decidim::Commands::DestroyResource.call(survey, current_user) do
|
86
|
+
on(:ok) do
|
87
|
+
flash[:notice] = I18n.t("destroy.success", scope: "decidim.surveys.admin.surveys")
|
88
|
+
|
89
|
+
redirect_to surveys_path
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def edit_questions_template
|
95
|
+
"decidim/surveys/admin/surveys/edit_questions"
|
15
96
|
end
|
16
97
|
|
17
98
|
def questionnaire_for
|
18
99
|
survey
|
19
100
|
end
|
20
101
|
|
102
|
+
def after_update_url
|
103
|
+
surveys_path
|
104
|
+
end
|
105
|
+
|
106
|
+
def questionnaire_participants_url
|
107
|
+
Decidim::EngineRouter.admin_proxy(survey.component).survey_answers_path(survey)
|
108
|
+
end
|
109
|
+
|
21
110
|
# Specify the public url from which the survey can be viewed and answered
|
22
111
|
def public_url
|
23
112
|
Decidim::EngineRouter.main_proxy(current_component).survey_path(survey)
|
24
113
|
end
|
25
114
|
|
26
|
-
# Specify where to redirect after exporting a user response
|
27
|
-
def questionnaire_participant_answers_url(session_token)
|
28
|
-
Decidim::EngineRouter.admin_proxy(survey.component).show_survey_path(session_token:)
|
29
|
-
end
|
30
|
-
|
31
115
|
def edit_questionnaire_title
|
32
116
|
t(:title, scope: "decidim.forms.admin.questionnaires.form", questionnaire_for: translated_attribute(current_component.name))
|
33
117
|
end
|
34
118
|
|
35
119
|
private
|
36
120
|
|
37
|
-
def
|
38
|
-
|
121
|
+
def surveys
|
122
|
+
@surveys ||= filtered_collection
|
39
123
|
end
|
40
124
|
|
41
125
|
def survey
|
42
|
-
@survey ||=
|
126
|
+
@survey ||= collection.find(params[:id])
|
127
|
+
end
|
128
|
+
|
129
|
+
def collection
|
130
|
+
@collection ||= Decidim::Surveys::Survey.where(component: current_component)
|
43
131
|
end
|
44
132
|
end
|
45
133
|
end
|
@@ -7,12 +7,24 @@ module Decidim
|
|
7
7
|
include Decidim::Forms::Concerns::HasQuestionnaire
|
8
8
|
include Decidim::ComponentPathHelper
|
9
9
|
include Decidim::Surveys::SurveyHelper
|
10
|
+
include FilterResource
|
11
|
+
include Paginable
|
10
12
|
|
11
|
-
|
13
|
+
helper PublishAnswersHelper
|
14
|
+
helper_method :authorizations, :surveys, :show_published_questions_answers?
|
12
15
|
|
13
|
-
|
16
|
+
before_action :check_permissions, except: [:index]
|
17
|
+
before_action :check_editable, only: [:edit]
|
14
18
|
|
15
|
-
|
19
|
+
def index; end
|
20
|
+
|
21
|
+
def edit
|
22
|
+
@form = form(Decidim::Forms::QuestionnaireForm).from_model(questionnaire)
|
23
|
+
@form.add_answers!(questionnaire:, session_token:, ip_hash:)
|
24
|
+
@form.allow_editing_answers = questionnaire.questionnaire_for&.allow_editing_answers?
|
25
|
+
|
26
|
+
render template: "decidim/forms/questionnaires/edit"
|
27
|
+
end
|
16
28
|
|
17
29
|
def check_permissions
|
18
30
|
render :no_permission unless action_authorized_to(:answer, resource: survey).ok?
|
@@ -24,8 +36,27 @@ module Decidim
|
|
24
36
|
|
25
37
|
protected
|
26
38
|
|
39
|
+
def check_editable
|
40
|
+
return if allow_editing_answers?
|
41
|
+
|
42
|
+
flash.now[:error] = t("decidim.forms.step_navigation.show.disallowed")
|
43
|
+
render :not_allowed
|
44
|
+
end
|
45
|
+
|
46
|
+
def allow_editing_answers?
|
47
|
+
visitor_can_edit_answers? && survey.open?
|
48
|
+
end
|
49
|
+
|
50
|
+
def show_published_questions_answers?
|
51
|
+
survey.closed? && survey.questionnaire.questions.pluck(:survey_answers_published_at).any?
|
52
|
+
end
|
53
|
+
|
27
54
|
def allow_answers?
|
28
|
-
!current_component.published? ||
|
55
|
+
!current_component.published? || survey.open?
|
56
|
+
end
|
57
|
+
|
58
|
+
def allow_unregistered?
|
59
|
+
survey.allow_unregistered
|
29
60
|
end
|
30
61
|
|
31
62
|
def form_path
|
@@ -38,8 +69,22 @@ module Decidim
|
|
38
69
|
"decidim.surveys.surveys"
|
39
70
|
end
|
40
71
|
|
72
|
+
def surveys
|
73
|
+
paginate(search.result).published
|
74
|
+
end
|
75
|
+
|
41
76
|
def survey
|
42
|
-
@survey ||=
|
77
|
+
@survey ||= search_collection.find_by(id: params[:id])
|
78
|
+
end
|
79
|
+
|
80
|
+
def search_collection
|
81
|
+
@search_collection ||= Decidim::Surveys::Survey.where(component: current_component)
|
82
|
+
end
|
83
|
+
|
84
|
+
def default_filter_params
|
85
|
+
{
|
86
|
+
with_any_state: %w(open)
|
87
|
+
}
|
43
88
|
end
|
44
89
|
end
|
45
90
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
module Admin
|
6
|
+
class SurveyForm < Decidim::Forms::Admin::QuestionnaireForm
|
7
|
+
translatable_attribute :announcement, String
|
8
|
+
|
9
|
+
attribute :allow_answers, Boolean
|
10
|
+
attribute :allow_unregistered, Boolean
|
11
|
+
attribute :clean_after_publish, Boolean
|
12
|
+
attribute :allow_editing_answers, Boolean
|
13
|
+
attribute :starts_at, Decidim::Attributes::TimeWithZone
|
14
|
+
attribute :ends_at, Decidim::Attributes::TimeWithZone
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
# Custom helpers, scoped to the surveys engine.
|
6
|
+
#
|
7
|
+
module ApplicationHelper
|
8
|
+
include PaginateHelper
|
9
|
+
include Decidim::SanitizeHelper
|
10
|
+
include Decidim::CheckBoxesTreeHelper
|
11
|
+
include Decidim::RichTextEditorHelper
|
12
|
+
|
13
|
+
# Returns a TreeNode to be used in the list filters to filter surveys by
|
14
|
+
# its state.
|
15
|
+
def filter_surveys_date_values
|
16
|
+
[
|
17
|
+
["all", t("all", scope: "decidim.surveys.surveys.filters")],
|
18
|
+
["open", { checked: true }, t("open", scope: "decidim.surveys.surveys.filters.state_values")],
|
19
|
+
["closed", t("closed", scope: "decidim.surveys.surveys.filters.state_values")]
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
def filter_sections
|
24
|
+
@filter_sections ||= [{
|
25
|
+
method: :with_any_state,
|
26
|
+
collection: filter_surveys_date_values,
|
27
|
+
label: t("decidim.proposals.proposals.filters.state"),
|
28
|
+
id: "state",
|
29
|
+
type: :radio_buttons
|
30
|
+
}]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
module PublishAnswersHelper
|
6
|
+
def question_answer_is_publicable(question_type)
|
7
|
+
ignored_question_types = %w(short_answer long_answer separator files).freeze
|
8
|
+
|
9
|
+
ignored_question_types.exclude?(question_type)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Renders the chart for the given question.
|
13
|
+
# Uses chartkick to render the chart.
|
14
|
+
#
|
15
|
+
# @param question_id [Integer] the question id for Decidim:
|
16
|
+
def chart_for_question(question_id)
|
17
|
+
question = Decidim::Forms::Question.includes(answers: { choices: [:answer_option, :matrix_row] }).find(question_id)
|
18
|
+
|
19
|
+
Chartkick.options = {
|
20
|
+
library: { animation: { easing: "easeOutQuart" } },
|
21
|
+
colors: colors_list
|
22
|
+
}
|
23
|
+
|
24
|
+
case question.question_type
|
25
|
+
when "single_option", "multiple_option"
|
26
|
+
options_column_chart_wrapper(question)
|
27
|
+
when "matrix_single", "matrix_multiple"
|
28
|
+
matrix_stack_chart_wrapper(question)
|
29
|
+
when "sorting"
|
30
|
+
sorting_stack_chart_wrapper(question)
|
31
|
+
else
|
32
|
+
"Unknown question type"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def sorting_stack_chart_wrapper(question)
|
39
|
+
counts = Hash.new { |hash, key| hash[key] = Hash.new(0) }
|
40
|
+
|
41
|
+
question.answers.each do |answer|
|
42
|
+
answer.choices.each do |choice|
|
43
|
+
name = translated_attribute(choice.answer_option.body)
|
44
|
+
row = choice.position + 1
|
45
|
+
|
46
|
+
counts[row][name] += 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
tally = counts.map do |name, row_data|
|
51
|
+
{
|
52
|
+
name:,
|
53
|
+
data: row_data.map { |row, count| [row, count] }
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
bar_chart(tally.sort_by { |data| data[:name] }, stacked: true, download: true)
|
58
|
+
end
|
59
|
+
|
60
|
+
def matrix_stack_chart_wrapper(question)
|
61
|
+
counts = Hash.new { |hash, key| hash[key] = Hash.new(0) }
|
62
|
+
|
63
|
+
question.answers.each do |answer|
|
64
|
+
answer.choices.each do |choice|
|
65
|
+
name = translated_attribute(choice.answer_option.body)
|
66
|
+
row = translated_attribute(choice.matrix_row.body)
|
67
|
+
|
68
|
+
counts[name][row] += 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
tally = counts.map do |name, row_data|
|
73
|
+
{
|
74
|
+
name:,
|
75
|
+
data: row_data.map { |row, count| [row, count] }
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
column_chart(tally, stacked: true, legend: :right, download: true)
|
80
|
+
end
|
81
|
+
|
82
|
+
def options_column_chart_wrapper(question)
|
83
|
+
tally = question.answers.map { |answer| answer.choices.map { |choice| translated_attribute(choice.answer_option.body) } }.tally
|
84
|
+
|
85
|
+
column_chart(tally, download: true)
|
86
|
+
end
|
87
|
+
|
88
|
+
def colors_list
|
89
|
+
%w(
|
90
|
+
#3366CC
|
91
|
+
#DC3912
|
92
|
+
#FF9900
|
93
|
+
#109618
|
94
|
+
#3B3EAC
|
95
|
+
#0099C6
|
96
|
+
#DD4477
|
97
|
+
#66AA00
|
98
|
+
#B82E2E
|
99
|
+
#316395
|
100
|
+
)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -26,6 +26,10 @@ module Decidim
|
|
26
26
|
def authorizations
|
27
27
|
@authorizations ||= action_authorized_to(:answer, resource: questionnaire_for)
|
28
28
|
end
|
29
|
+
|
30
|
+
def filter_date_values
|
31
|
+
flat_filter_values(:all, :open, :closed, scope: "decidim.surveys.surveys.filters.date_values")
|
32
|
+
end
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -7,33 +7,88 @@ module Decidim
|
|
7
7
|
include Decidim::Resourceable
|
8
8
|
include Decidim::Forms::HasQuestionnaire
|
9
9
|
include Decidim::HasComponent
|
10
|
+
include Decidim::FilterableResource
|
11
|
+
include Decidim::Publicable
|
10
12
|
|
11
13
|
component_manifest_name "surveys"
|
12
14
|
|
13
15
|
delegate :title, to: :questionnaire
|
16
|
+
delegate :description, to: :questionnaire
|
17
|
+
delegate :tos, to: :questionnaire
|
14
18
|
|
15
19
|
validates :questionnaire, presence: true
|
16
20
|
|
17
|
-
|
18
|
-
|
21
|
+
scope :open, lambda {
|
22
|
+
where(allow_answers: true)
|
23
|
+
.where(starts_at: nil, ends_at: nil).or(
|
24
|
+
where("starts_at <= ? AND (ends_at IS NULL OR ends_at > ?)", Time.current, Time.current)
|
25
|
+
).or(
|
26
|
+
where("ends_at > ? AND (starts_at IS NULL OR starts_at <= ?)", Time.current, Time.current)
|
27
|
+
)
|
28
|
+
}
|
29
|
+
scope :closed, lambda {
|
30
|
+
where(allow_answers: false).or(
|
31
|
+
where("starts_at > ?", Time.current).or(
|
32
|
+
where(ends_at: ...Time.current)
|
33
|
+
)
|
34
|
+
)
|
35
|
+
}
|
36
|
+
scope :published, -> { where.not(published_at: nil) }
|
37
|
+
|
38
|
+
scope_search_multi :with_any_state, [:open, :closed]
|
39
|
+
|
40
|
+
def open?
|
41
|
+
return false if allow_answers.blank?
|
42
|
+
return true if time_indefinite?
|
43
|
+
return true if started_but_no_end?
|
44
|
+
return true if no_start_but_ends_later?
|
45
|
+
|
46
|
+
return within_time_range? if time_range_defined?
|
47
|
+
|
48
|
+
false
|
19
49
|
end
|
20
50
|
|
21
|
-
def
|
22
|
-
|
51
|
+
def closed?
|
52
|
+
!open?
|
23
53
|
end
|
24
54
|
|
25
|
-
def
|
26
|
-
|
55
|
+
def self.ransackable_scopes(_auth_object = nil)
|
56
|
+
[:with_any_state]
|
27
57
|
end
|
28
58
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
return true if starts_at.blank? && ends_at.future?
|
59
|
+
def self.ransackable_attributes(_auth_object = nil)
|
60
|
+
%w(ends_at starts_at allow_answers)
|
61
|
+
end
|
33
62
|
|
34
|
-
|
63
|
+
def self.log_presenter_class_for(_log)
|
64
|
+
Decidim::Surveys::AdminLog::SurveyPresenter
|
65
|
+
end
|
35
66
|
|
36
|
-
|
67
|
+
# Public: Overrides the `allow_resource_permissions?` Resourceable concern method.
|
68
|
+
def allow_resource_permissions?
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def time_indefinite?
|
75
|
+
starts_at.blank? && ends_at.blank?
|
76
|
+
end
|
77
|
+
|
78
|
+
def started_but_no_end?
|
79
|
+
ends_at.blank? && starts_at.past?
|
80
|
+
end
|
81
|
+
|
82
|
+
def no_start_but_ends_later?
|
83
|
+
starts_at.blank? && ends_at.future?
|
84
|
+
end
|
85
|
+
|
86
|
+
def time_range_defined?
|
87
|
+
starts_at.present? && ends_at.present?
|
88
|
+
end
|
89
|
+
|
90
|
+
def within_time_range?
|
91
|
+
Time.zone.now.between?(starts_at, ends_at)
|
37
92
|
end
|
38
93
|
end
|
39
94
|
end
|
@@ -12,7 +12,7 @@ module Decidim
|
|
12
12
|
case permission_action.subject
|
13
13
|
when :questionnaire
|
14
14
|
case permission_action.action
|
15
|
-
when :export_answers, :update
|
15
|
+
when :export_answers, :update, :create, :destroy
|
16
16
|
permission_action.allow!
|
17
17
|
end
|
18
18
|
when :questionnaire_answers
|
@@ -20,6 +20,15 @@ module Decidim
|
|
20
20
|
when :index, :show, :export_response
|
21
21
|
permission_action.allow!
|
22
22
|
end
|
23
|
+
when :questionnaire_publish_answers
|
24
|
+
case permission_action.action
|
25
|
+
when :index, :update, :destroy
|
26
|
+
if context.fetch(:survey).allow_answers
|
27
|
+
permission_action.disallow!
|
28
|
+
else
|
29
|
+
permission_action.allow!
|
30
|
+
end
|
31
|
+
end
|
23
32
|
end
|
24
33
|
|
25
34
|
permission_action
|
@@ -4,8 +4,6 @@ module Decidim
|
|
4
4
|
module Surveys
|
5
5
|
class Permissions < Decidim::DefaultPermissions
|
6
6
|
def permissions
|
7
|
-
return permission_action unless user || context[:current_settings].allow_unregistered?
|
8
|
-
|
9
7
|
return Decidim::Surveys::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
|
10
8
|
return permission_action if permission_action.scope != :public
|
11
9
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
module AdminLog
|
6
|
+
# This class holds the logic to present a `Decidim::Surveys::Survey`
|
7
|
+
# for the `AdminLog` log.
|
8
|
+
#
|
9
|
+
# Usage should be automatic and you should not need to call this class
|
10
|
+
# directly, but here is an example:
|
11
|
+
#
|
12
|
+
# action_log = Decidim::ActionLog.last
|
13
|
+
# view_helpers # => this comes from the views
|
14
|
+
# SurveyPresenter.new(action_log, view_helpers).present
|
15
|
+
class SurveyPresenter < Decidim::Log::BasePresenter
|
16
|
+
private
|
17
|
+
|
18
|
+
# i18n-tasks-use t("decidim.surveys.admin_log.survey.create")
|
19
|
+
# i18n-tasks-use t("decidim.surveys.admin_log.survey.delete")
|
20
|
+
# i18n-tasks-use t("decidim.surveys.admin_log.survey.publish")
|
21
|
+
# i18n-tasks-use t("decidim.surveys.admin_log.survey.unpublish")
|
22
|
+
# i18n-tasks-use t("decidim.surveys.admin_log.survey.update")
|
23
|
+
def action_string
|
24
|
+
case action
|
25
|
+
when "delete", "create", "update", "publish", "unpublish"
|
26
|
+
"decidim.surveys.admin_log.survey.#{action}"
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -16,7 +16,7 @@ module Decidim
|
|
16
16
|
quantity_value = results[:quantity] || 0
|
17
17
|
space_type, space_id, survey_id = key
|
18
18
|
record = Decidim::Metric.find_or_initialize_by(day: @day.to_s, metric_type: @metric_name,
|
19
|
-
organization: @organization,
|
19
|
+
organization: @organization, decidim_taxonomy_id: nil,
|
20
20
|
participatory_space_type: space_type, participatory_space_id: space_id,
|
21
21
|
related_object_type: Decidim::Surveys::Survey.name, related_object_id: survey_id)
|
22
22
|
record.assign_attributes(cumulative: cumulative_value, quantity: quantity_value)
|
@@ -32,13 +32,13 @@ module Decidim
|
|
32
32
|
@query = retrieve_surveys.each_with_object({}) do |survey, grouped_answers|
|
33
33
|
answers = Decidim::Forms::Answer.joins(:questionnaire)
|
34
34
|
.where(questionnaire: retrieve_questionnaires(survey))
|
35
|
-
.where(
|
35
|
+
.where(decidim_forms_answers: { created_at: ..end_time })
|
36
36
|
next grouped_answers unless answers
|
37
37
|
|
38
38
|
group_key = generate_group_key(survey)
|
39
39
|
grouped_answers[group_key] ||= { cumulative: 0, quantity: 0 }
|
40
40
|
grouped_answers[group_key][:cumulative] += answers.count
|
41
|
-
grouped_answers[group_key][:quantity] += answers.where(
|
41
|
+
grouped_answers[group_key][:quantity] += answers.where(decidim_forms_answers: { created_at: start_time.. }).count
|
42
42
|
end
|
43
43
|
@query
|
44
44
|
end
|
@@ -17,11 +17,11 @@ module Decidim
|
|
17
17
|
|
18
18
|
answers = Decidim::Forms::Answer.joins(:questionnaire)
|
19
19
|
.where(questionnaire: questionnaires)
|
20
|
-
.where(
|
20
|
+
.where(decidim_forms_answers: { created_at: ..end_time })
|
21
21
|
|
22
22
|
{
|
23
23
|
cumulative_users: answers.pluck(:decidim_user_id).uniq,
|
24
|
-
quantity_users: answers.where(
|
24
|
+
quantity_users: answers.where(decidim_forms_answers: { created_at: start_time.. }).pluck(:decidim_user_id).uniq
|
25
25
|
}
|
26
26
|
end
|
27
27
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<div class="card" id="answers">
|
2
|
+
<div class="item_show__header">
|
3
|
+
<h1 class="item_show__header-title">
|
4
|
+
<%= t ".title", total: @total %>
|
5
|
+
<%= link_to t("actions.back", scope: "decidim.forms.admin.questionnaires"), questionnaire_url, class: "button button__sm button__secondary new" %>
|
6
|
+
</h1>
|
7
|
+
</div>
|
8
|
+
<div class="table-scroll">
|
9
|
+
<table class="table-list">
|
10
|
+
<thead>
|
11
|
+
<tr>
|
12
|
+
<th>#</th>
|
13
|
+
<th><%= first_table_th(@participants.first) %></th>
|
14
|
+
<th><%= t("user_status", scope: "decidim.forms.user_answers_serializer") %></th>
|
15
|
+
<th><%= t("ip_hash", scope: "decidim.forms.user_answers_serializer") %></th>
|
16
|
+
<th><%= t("completion", scope: "decidim.forms.user_answers_serializer") %></th>
|
17
|
+
<th><%= t("created_at", scope: "decidim.forms.user_answers_serializer") %></th>
|
18
|
+
<th></th>
|
19
|
+
</tr>
|
20
|
+
</thead>
|
21
|
+
<tbody>
|
22
|
+
<% @participants.each_with_index do |participant, idx| %>
|
23
|
+
<tr>
|
24
|
+
<td><%= idx + 1 + page_offset %></td>
|
25
|
+
<td>
|
26
|
+
<% if allowed_to? :show, :questionnaire_answers %>
|
27
|
+
<%= link_to first_table_td(participant), questionnaire_participant_answers_url(participant.session_token) %>
|
28
|
+
<% else %>
|
29
|
+
<%= first_table_td(participant) %></td>
|
30
|
+
<% end %>
|
31
|
+
<td><%= participant.status %></td>
|
32
|
+
<td><%= participant.ip_hash %></td>
|
33
|
+
<td><%= display_percentage(participant.completion) %></td>
|
34
|
+
<td><%= l participant.answered_at, format: :short %></td>
|
35
|
+
<td class="table-list__actions">
|
36
|
+
<% if allowed_to? :show, :questionnaire_answers %>
|
37
|
+
<%= icon_link_to "eye-line", questionnaire_participant_answers_url(participant.session_token), t("actions.show", scope: "decidim.forms.admin.questionnaires.answers"), class: "action-icon--eye", target: "_blank", data: { "external-link": false } %>
|
38
|
+
<% end %>
|
39
|
+
<% if allowed_to? :export_response, :questionnaire_answers %>
|
40
|
+
<%= icon_link_to "download-line", questionnaire_export_response_url(participant.session_token), t("actions.export", scope: "decidim.forms.admin.questionnaires.answers"), class: "action-icon--data-transfer-download" %>
|
41
|
+
<% end %>
|
42
|
+
</td>
|
43
|
+
</tr>
|
44
|
+
<% end %>
|
45
|
+
</tbody>
|
46
|
+
</table>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
<%= decidim_paginate @query %>
|