decidim-surveys 0.29.1 → 0.30.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/surveys/survey_card_metadata_cell.rb +43 -0
  3. data/app/cells/decidim/surveys/survey_cell.rb +26 -0
  4. data/app/cells/decidim/surveys/survey_l_cell.rb +34 -0
  5. data/app/cells/decidim/surveys/survey_s_cell.rb +21 -0
  6. data/app/commands/decidim/surveys/admin/create_survey.rb +21 -0
  7. data/app/commands/decidim/surveys/admin/publish_survey.rb +58 -0
  8. data/app/commands/decidim/surveys/admin/unpublish_survey.rb +44 -0
  9. data/app/commands/decidim/surveys/admin/update_survey.rb +62 -0
  10. data/app/commands/decidim/surveys/publish_answers.rb +55 -0
  11. data/app/commands/decidim/surveys/unpublish_answers.rb +55 -0
  12. data/app/controllers/concerns/decidim/surveys/admin/filterable.rb +23 -0
  13. data/app/controllers/decidim/surveys/admin/answers_controller.rb +73 -0
  14. data/app/controllers/decidim/surveys/admin/publish_answers_controller.rb +66 -0
  15. data/app/controllers/decidim/surveys/admin/surveys_controller.rb +99 -11
  16. data/app/controllers/decidim/surveys/surveys_controller.rb +50 -5
  17. data/app/forms/decidim/surveys/admin/survey_form.rb +18 -0
  18. data/app/helpers/decidim/surveys/application_helper.rb +34 -0
  19. data/app/helpers/decidim/surveys/publish_answers_helper.rb +104 -0
  20. data/app/helpers/decidim/surveys/survey_helper.rb +4 -0
  21. data/app/models/decidim/surveys/survey.rb +67 -12
  22. data/app/permissions/decidim/surveys/admin/permissions.rb +10 -1
  23. data/app/permissions/decidim/surveys/permissions.rb +0 -2
  24. data/app/presenters/decidim/surveys/admin_log/survey_presenter.rb +34 -0
  25. data/app/queries/decidim/surveys/metrics/answers_metric_manage.rb +3 -3
  26. data/app/queries/decidim/surveys/metrics/survey_participants_metric_measure.rb +2 -2
  27. data/app/views/decidim/surveys/admin/answers/index.html.erb +49 -0
  28. data/app/views/decidim/surveys/admin/answers/show.html.erb +43 -0
  29. data/app/views/decidim/surveys/admin/publish_answers/_toggle_button.html.erb +22 -0
  30. data/app/views/decidim/surveys/admin/publish_answers/index.html.erb +44 -0
  31. data/app/views/decidim/surveys/admin/surveys/_form.html.erb +28 -0
  32. data/app/views/decidim/surveys/admin/surveys/edit.html.erb +4 -21
  33. data/app/views/decidim/surveys/admin/surveys/edit_questions.html.erb +47 -0
  34. data/app/views/decidim/surveys/admin/surveys/index.html.erb +51 -0
  35. data/app/views/decidim/surveys/surveys/_published_questions_answers.html.erb +13 -0
  36. data/app/views/decidim/surveys/surveys/_surveys.html.erb +13 -0
  37. data/app/views/decidim/surveys/surveys/index.html.erb +27 -0
  38. data/app/views/decidim/surveys/surveys/index.js.erb +4 -0
  39. data/app/views/decidim/surveys/surveys/not_allowed.html.erb +22 -0
  40. data/config/locales/ar.yml +4 -3
  41. data/config/locales/bg.yml +0 -14
  42. data/config/locales/bn-BD.yml +1 -0
  43. data/config/locales/bs-BA.yml +1 -0
  44. data/config/locales/ca.yml +83 -14
  45. data/config/locales/cs.yml +87 -14
  46. data/config/locales/de.yml +83 -14
  47. data/config/locales/el.yml +0 -11
  48. data/config/locales/en.yml +83 -14
  49. data/config/locales/es-MX.yml +83 -14
  50. data/config/locales/es-PY.yml +83 -14
  51. data/config/locales/es.yml +83 -14
  52. data/config/locales/eu.yml +85 -16
  53. data/config/locales/fi-plain.yml +83 -14
  54. data/config/locales/fi.yml +83 -14
  55. data/config/locales/fr-CA.yml +74 -14
  56. data/config/locales/fr.yml +74 -14
  57. data/config/locales/ga-IE.yml +0 -4
  58. data/config/locales/gl.yml +0 -10
  59. data/config/locales/hu.yml +0 -3
  60. data/config/locales/id-ID.yml +0 -2
  61. data/config/locales/is-IS.yml +0 -2
  62. data/config/locales/it.yml +3 -10
  63. data/config/locales/ja.yml +80 -13
  64. data/config/locales/lb.yml +0 -10
  65. data/config/locales/lt.yml +0 -11
  66. data/config/locales/lv.yml +0 -3
  67. data/config/locales/nl.yml +0 -10
  68. data/config/locales/no.yml +0 -10
  69. data/config/locales/pl.yml +0 -14
  70. data/config/locales/pt-BR.yml +0 -14
  71. data/config/locales/pt.yml +0 -10
  72. data/config/locales/ro-RO.yml +0 -11
  73. data/config/locales/ru.yml +0 -2
  74. data/config/locales/sk.yml +0 -3
  75. data/config/locales/sv.yml +0 -14
  76. data/config/locales/tr-TR.yml +0 -10
  77. data/config/locales/uk.yml +0 -2
  78. data/config/locales/zh-CN.yml +0 -6
  79. data/config/locales/zh-TW.yml +0 -11
  80. data/db/migrate/20240828103030_add_deleted_at_to_decidim_surveys_surveys.rb +8 -0
  81. data/db/migrate/20240925124312_add_settings_to_decidim_surveys_surveys.rb +42 -0
  82. data/db/migrate/20250115193836_add_allow_survey_editing.rb +7 -0
  83. data/decidim-surveys.gemspec +2 -2
  84. data/lib/decidim/api/survey_type.rb +11 -2
  85. data/lib/decidim/api/surveys_type.rb +5 -8
  86. data/lib/decidim/surveys/admin_engine.rb +15 -5
  87. data/lib/decidim/surveys/component.rb +7 -24
  88. data/lib/decidim/surveys/engine.rb +2 -2
  89. data/lib/decidim/surveys/seeds.rb +115 -10
  90. data/lib/decidim/surveys/test/factories.rb +24 -0
  91. data/lib/decidim/surveys/version.rb +1 -1
  92. metadata +51 -19
  93. data/app/commands/decidim/surveys/create_survey.rb +0 -19
  94. 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 to update a Page.
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::HasQuestionnaireAnswers
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
- @form = form(Decidim::Forms::Admin::QuestionnaireForm).from_model(questionnaire)
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 i18n_flashes_scope
38
- "decidim.surveys.admin.surveys"
121
+ def surveys
122
+ @surveys ||= filtered_collection
39
123
  end
40
124
 
41
125
  def survey
42
- @survey ||= Survey.find_by(component: current_component)
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
- helper_method :authorizations
13
+ helper PublishAnswersHelper
14
+ helper_method :authorizations, :surveys, :show_published_questions_answers?
12
15
 
13
- delegate :allow_unregistered?, to: :current_settings
16
+ before_action :check_permissions, except: [:index]
17
+ before_action :check_editable, only: [:edit]
14
18
 
15
- before_action :check_permissions
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? || (current_settings.allow_answers? && survey.open?)
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 ||= Survey.find_by(component: current_component)
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
- def clean_after_publish?
18
- component.settings.clean_after_publish?
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 starts_at
22
- component.settings.starts_at
51
+ def closed?
52
+ !open?
23
53
  end
24
54
 
25
- def ends_at
26
- component.settings.ends_at
55
+ def self.ransackable_scopes(_auth_object = nil)
56
+ [:with_any_state]
27
57
  end
28
58
 
29
- def open?
30
- return true if starts_at.blank? && ends_at.blank?
31
- return true if ends_at.blank? && starts_at.past?
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
- return Time.zone.now.between?(starts_at, ends_at) if starts_at.present? && ends_at.present?
63
+ def self.log_presenter_class_for(_log)
64
+ Decidim::Surveys::AdminLog::SurveyPresenter
65
+ end
35
66
 
36
- false
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, decidim_category_id: nil,
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("decidim_forms_answers.created_at <= ?", end_time)
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("decidim_forms_answers.created_at >= ?", start_time).count
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("decidim_forms_answers.created_at <= ?", end_time)
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("decidim_forms_answers.created_at >= ?", start_time).pluck(:decidim_user_id).uniq
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 %>