decidim-demographics 0.31.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +26 -0
  3. data/Rakefile +3 -0
  4. data/app/commands/decidim/demographics/admin/update_demographics_settings.rb +44 -0
  5. data/app/commands/decidim/demographics/delete_demographic_data.rb +24 -0
  6. data/app/controllers/decidim/demographics/admin/application_controller.rb +42 -0
  7. data/app/controllers/decidim/demographics/admin/publish_responses_controller.rb +24 -0
  8. data/app/controllers/decidim/demographics/admin/questions_controller.rb +33 -0
  9. data/app/controllers/decidim/demographics/admin/responses_controller.rb +36 -0
  10. data/app/controllers/decidim/demographics/admin/settings_controller.rb +33 -0
  11. data/app/controllers/decidim/demographics/application_controller.rb +17 -0
  12. data/app/controllers/decidim/demographics/demographics_controller.rb +70 -0
  13. data/app/forms/decidim/demographics/admin/demographics_settings_form.rb +11 -0
  14. data/app/helpers/decidim/demographics/publish_responses_helper.rb +104 -0
  15. data/app/models/decidim/demographics/application_record.rb +10 -0
  16. data/app/models/decidim/demographics/demographic.rb +9 -0
  17. data/app/packs/entrypoints/decidim_demographics.js +1 -0
  18. data/app/packs/stylesheets/decidim/demographics/demographics.scss +37 -0
  19. data/app/permissions/decidim/demographics/admin/permissions.rb +22 -0
  20. data/app/permissions/decidim/demographics/permissions.rb +23 -0
  21. data/app/views/decidim/demographics/admin/demographics/_tabs_menu.html.erb +15 -0
  22. data/app/views/decidim/demographics/admin/publish_responses/index.html.erb +36 -0
  23. data/app/views/decidim/demographics/admin/questions/_questions_form.html.erb +74 -0
  24. data/app/views/decidim/demographics/admin/questions/edit.html.erb +13 -0
  25. data/app/views/decidim/demographics/admin/responses/index.html.erb +98 -0
  26. data/app/views/decidim/demographics/admin/settings/show.html.erb +23 -0
  27. data/app/views/decidim/demographics/demographics/_questionnaire.html.erb +88 -0
  28. data/app/views/decidim/demographics/demographics/_response.html.erb +41 -0
  29. data/app/views/decidim/demographics/demographics/responses/_single_option.html.erb +19 -0
  30. data/app/views/decidim/demographics/demographics/show.html.erb +25 -0
  31. data/config/assets.rb +8 -0
  32. data/config/locales/am-ET.yml +1 -0
  33. data/config/locales/ar.yml +1 -0
  34. data/config/locales/bg.yml +1 -0
  35. data/config/locales/bn-BD.yml +1 -0
  36. data/config/locales/bs-BA.yml +1 -0
  37. data/config/locales/ca-IT.yml +79 -0
  38. data/config/locales/ca.yml +79 -0
  39. data/config/locales/cs.yml +55 -0
  40. data/config/locales/da.yml +1 -0
  41. data/config/locales/de.yml +79 -0
  42. data/config/locales/el.yml +1 -0
  43. data/config/locales/en.yml +79 -0
  44. data/config/locales/eo.yml +1 -0
  45. data/config/locales/es-MX.yml +79 -0
  46. data/config/locales/es-PY.yml +79 -0
  47. data/config/locales/es.yml +79 -0
  48. data/config/locales/et.yml +1 -0
  49. data/config/locales/eu.yml +79 -0
  50. data/config/locales/fa-IR.yml +1 -0
  51. data/config/locales/fi-plain.yml +79 -0
  52. data/config/locales/fi.yml +79 -0
  53. data/config/locales/fr-CA.yml +79 -0
  54. data/config/locales/fr.yml +79 -0
  55. data/config/locales/ga-IE.yml +1 -0
  56. data/config/locales/gl.yml +1 -0
  57. data/config/locales/gn-PY.yml +1 -0
  58. data/config/locales/he-IL.yml +1 -0
  59. data/config/locales/hr.yml +1 -0
  60. data/config/locales/hu.yml +1 -0
  61. data/config/locales/id-ID.yml +1 -0
  62. data/config/locales/is-IS.yml +1 -0
  63. data/config/locales/it.yml +1 -0
  64. data/config/locales/ja.yml +79 -0
  65. data/config/locales/ka-GE.yml +1 -0
  66. data/config/locales/kaa.yml +1 -0
  67. data/config/locales/ko.yml +1 -0
  68. data/config/locales/lb.yml +1 -0
  69. data/config/locales/lo-LA.yml +1 -0
  70. data/config/locales/lt.yml +1 -0
  71. data/config/locales/lv.yml +1 -0
  72. data/config/locales/mt.yml +1 -0
  73. data/config/locales/nl.yml +1 -0
  74. data/config/locales/no.yml +8 -0
  75. data/config/locales/oc-FR.yml +1 -0
  76. data/config/locales/om-ET.yml +1 -0
  77. data/config/locales/pl.yml +1 -0
  78. data/config/locales/pt-BR.yml +1 -0
  79. data/config/locales/pt.yml +1 -0
  80. data/config/locales/ro-RO.yml +1 -0
  81. data/config/locales/ru.yml +1 -0
  82. data/config/locales/si-LK.yml +1 -0
  83. data/config/locales/sk.yml +1 -0
  84. data/config/locales/sl.yml +1 -0
  85. data/config/locales/so-SO.yml +1 -0
  86. data/config/locales/sq-AL.yml +1 -0
  87. data/config/locales/sr-CS.yml +1 -0
  88. data/config/locales/sv.yml +79 -0
  89. data/config/locales/sw-KE.yml +1 -0
  90. data/config/locales/th-TH.yml +1 -0
  91. data/config/locales/ti-ER.yml +1 -0
  92. data/config/locales/tr-TR.yml +1 -0
  93. data/config/locales/uk.yml +1 -0
  94. data/config/locales/val-ES.yml +1 -0
  95. data/config/locales/vi.yml +1 -0
  96. data/config/locales/zh-CN.yml +1 -0
  97. data/config/locales/zh-TW.yml +1 -0
  98. data/db/migrate/20250305200253_create_decidim_demographics_demographics.rb +12 -0
  99. data/decidim-demographics.gemspec +37 -0
  100. data/lib/decidim/demographics/admin.rb +10 -0
  101. data/lib/decidim/demographics/admin_engine.rb +83 -0
  102. data/lib/decidim/demographics/engine.rb +41 -0
  103. data/lib/decidim/demographics/test/factories.rb +16 -0
  104. data/lib/decidim/demographics/version.rb +10 -0
  105. data/lib/decidim/demographics.rb +52 -0
  106. data/lib/tasks/decidim_demographics.rake +14 -0
  107. metadata +195 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2572bda270734d954964af2fc083221aa83af70d7455b5527a865a969b71f7e7
4
+ data.tar.gz: 604ec62cd5b07aa7ac8539f9a9d21e988eb3e7e4d49a194c0decae258038a93f
5
+ SHA512:
6
+ metadata.gz: 917f79eef27f12df2f0962e76d1dc8d54ac9fce118279b276dbf287f505da9172c560e0ae245360715055be6e7eccaf5a58cb05b089bae601811e51063be400a
7
+ data.tar.gz: 83f708b0437594f145095e68a8bbffc2c5b31a17f307953661f197e5ab97351c152b6d48ca70122ed21ab7099deda62030a11012cbd8a2000adc0451c0533dea
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # Decidim::Demographics
2
+
3
+ The demographic data module allows participants to voluntarily donate their demographic information for statistical purposes. The collected data will be anonymized, aggregated, and visualized in compliance with GDPR regulations. This feature aims to enhance the understanding of participant demographics while ensuring transparency and data privacy.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "decidim-demographics"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle
17
+ bin/rails decidim_demographics:install:migrations
18
+ ```
19
+
20
+ ## Contributing
21
+
22
+ See [Decidim](https://github.com/decidim/decidim).
23
+
24
+ ## License
25
+
26
+ This engine is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/dev/common_rake"
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module Admin
6
+ class UpdateDemographicsSettings < Decidim::Command
7
+ # Initializes an UpdateDemographicsSettings Command.
8
+ #
9
+ # @param form - The form from which to get the data.
10
+ def initialize(form)
11
+ @form = form
12
+ end
13
+
14
+ attr_reader :form
15
+
16
+ delegate :current_organization, to: :form
17
+ delegate :current_user, to: :form
18
+
19
+ # Updates the demographic data if valid.
20
+ #
21
+ # Broadcasts :ok if successful, :invalid otherwise.
22
+ def call
23
+ Decidim.traceability.perform_action!("update", demographic, current_user) do
24
+ update_demographic_settings
25
+ end
26
+
27
+ broadcast(:ok)
28
+ rescue ActiveRecord::RecordInvalid
29
+ broadcast(:invalid)
30
+ end
31
+
32
+ private
33
+
34
+ def demographic
35
+ @demographic ||= Decidim::Demographics::Demographic.where(organization: current_organization).first_or_create!
36
+ end
37
+
38
+ def update_demographic_settings
39
+ demographic.update!(collect_data: form.collect_data)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ class DeleteDemographicData < Decidim::Command
6
+ # Initializes a DeleteDemographicData Command.
7
+ #
8
+ # @param questionnaire [Decidim::Forms::Questionnaire] The questionnaire containing demographic data
9
+ # @param user [Decidim::User] The user whose demographic data should be deleted
10
+ def initialize(questionnaire, user)
11
+ @questionnaire = questionnaire
12
+ @user = user
13
+ end
14
+
15
+ def call
16
+ @questionnaire.responses.where(user: @user).destroy_all
17
+
18
+ broadcast(:ok)
19
+ rescue ActiveRecord::RecordInvalid
20
+ broadcast(:invalid)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module Admin
6
+ # This controller is the abstract class from which all other controllers of
7
+ # this engine inherit.
8
+ #
9
+ # Note that it inherits from `Decidim::Admin::ApplicationController`, which
10
+ # overrides its layout and provides all kinds of useful methods.
11
+ class ApplicationController < Decidim::Admin::ApplicationController
12
+ register_permissions(::Decidim::Demographics::Admin::ApplicationController,
13
+ ::Decidim::Demographics::Admin::Permissions,
14
+ ::Decidim::Admin::Permissions)
15
+
16
+ layout "decidim/admin/insights"
17
+
18
+ add_breadcrumb_item_from_menu :admin_settings_menu
19
+
20
+ private
21
+
22
+ def questionnaire
23
+ @questionnaire ||= Decidim::Forms::Questionnaire.where(questionnaire_for:).first_or_create
24
+ @questionnaire.override_edit!
25
+ @questionnaire
26
+ end
27
+
28
+ def questionnaire_for
29
+ demographic
30
+ end
31
+
32
+ def permission_class_chain
33
+ ::Decidim.permissions_registry.chain_for(::Decidim::Demographics::Admin::ApplicationController)
34
+ end
35
+
36
+ def demographic
37
+ @demographic ||= Decidim::Demographics::Demographic.where(organization: current_organization).first_or_create!
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module Admin
6
+ # Mind that even though the name of the controller, currently we do not allow the publication.
7
+ # This is only for showing to the admin the visualization of the responses
8
+ class PublishResponsesController < Admin::ApplicationController
9
+ include Decidim::Forms::Admin::Concerns::HasQuestionnaireResponsesUrlHelper
10
+
11
+ helper PublishResponsesHelper
12
+ helper_method :questionnaire_for, :questionnaire
13
+
14
+ def index
15
+ enforce_permission_to(:index, :demographics)
16
+ end
17
+
18
+ def questionnaire_url
19
+ responses_path
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module Admin
6
+ class QuestionsController < Admin::ApplicationController
7
+ include Decidim::Forms::Admin::Concerns::HasQuestionnaire
8
+ include Decidim::Forms::Admin::Concerns::HasQuestionnaireResponsesUrlHelper
9
+
10
+ def edit_questions_template = "decidim/demographics/admin/questions/edit"
11
+
12
+ def after_update_url = edit_questions_questions_path
13
+
14
+ def questionnaire_participants_url = decidim_admin_demographics.responses_path
15
+
16
+ def update_url = update_questions_questions_path
17
+
18
+ def response_options_url(_params) = decidim_admin_demographics.responses_path
19
+
20
+ def questionnaire
21
+ @questionnaire ||= Decidim::Forms::Questionnaire.where(questionnaire_for:).first_or_initialize
22
+ @questionnaire.override_edit!
23
+ Decidim::Demographics.create_default_questionnaire!(@questionnaire)
24
+ @questionnaire
25
+ end
26
+
27
+ def questionnaire_for = demographic
28
+
29
+ def edit_questionnaire_title = t(:title, scope: "decidim.demographics.admin.questions.edit")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module Admin
6
+ class ResponsesController < Admin::ApplicationController
7
+ include Decidim::Forms::Admin::Concerns::HasQuestionnaireResponses
8
+ helper_method :questionnaire_for, :questionnaire
9
+
10
+ def index
11
+ enforce_permission_to :index, permission_subject
12
+
13
+ @query = paginate(collection)
14
+ @participants = participants(@query)
15
+ @total = questionnaire.count_participants
16
+ @survey = questionnaire_for
17
+
18
+ render template: "decidim/demographics/admin/responses/index"
19
+ end
20
+
21
+ def permission_subject = :demographics_responses
22
+
23
+ def questionnaire_for = demographic
24
+
25
+ def questionnaire_export_response_url(id) = export_response_response_path(id:)
26
+
27
+ def questionnaire_url = edit_questions_questions_path
28
+
29
+ # Specify where to redirect after exporting a user response
30
+ def questionnaire_participant_responses_url(id) = response_path(id:)
31
+
32
+ def questionnaire_participants_url = decidim_admin_demographics.responses_path
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module Admin
6
+ class SettingsController < Decidim::Demographics::Admin::ApplicationController
7
+ def show
8
+ enforce_permission_to(:update, :demographics)
9
+
10
+ @form = form(Admin::DemographicsSettingsForm).from_model(demographic)
11
+ end
12
+
13
+ def update
14
+ enforce_permission_to(:update, :demographics)
15
+
16
+ @form = form(Admin::DemographicsSettingsForm).from_params(params)
17
+
18
+ Admin::UpdateDemographicsSettings.call(@form) do
19
+ on(:ok) do
20
+ flash[:notice] = I18n.t("update.success", scope: "decidim.demographics.admin.settings")
21
+ redirect_to decidim_admin_demographics.settings_path
22
+ end
23
+
24
+ on(:invalid) do
25
+ flash.now[:alert] = I18n.t("update.invalid", scope: "decidim.demographics.admin.settings")
26
+ render action: "edit", status: :unprocessable_entity
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ class ApplicationController < Decidim::ApplicationController
6
+ include FormFactory
7
+ register_permissions(::Decidim::Demographics::ApplicationController,
8
+ ::Decidim::Demographics::Permissions,
9
+ ::Decidim::Admin::Permissions,
10
+ ::Decidim::Permissions)
11
+
12
+ def permission_class_chain
13
+ ::Decidim.permissions_registry.chain_for(::Decidim::Demographics::ApplicationController)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ class DemographicsController < Decidim::Demographics::ApplicationController
6
+ include Decidim::Forms::Concerns::HasQuestionnaire
7
+ include Decidim::UserProfile
8
+
9
+ helper_method :allow_editing_responses?, :demographic
10
+
11
+ def show
12
+ @form = form(Decidim::Forms::QuestionnaireForm).from_model(questionnaire)
13
+ @form.add_responses!(questionnaire:, session_token:, ip_hash:)
14
+ @form.allow_editing_responses = true
15
+
16
+ render template:
17
+ end
18
+
19
+ def destroy
20
+ DeleteDemographicData.call(questionnaire, current_user) do
21
+ on(:ok) do
22
+ flash[:notice] = I18n.t("destroy.success", scope: "decidim.demographics")
23
+ redirect_to demographics_engine.demographics_path
24
+ end
25
+
26
+ on(:invalid) do
27
+ flash.now[:alert] = I18n.t("destroy.error", scope: "decidim.demographics")
28
+ redirect_to demographics_engine.demographics_path
29
+ end
30
+ end
31
+ end
32
+
33
+ def template
34
+ "decidim/demographics/demographics/show"
35
+ end
36
+
37
+ private
38
+
39
+ def after_response_path = demographics_path
40
+
41
+ def form_path = demographics_path
42
+
43
+ def update_url = respond_demographics_path
44
+
45
+ def allow_responses?
46
+ demographic.collect_data?
47
+ end
48
+
49
+ def allow_editing_responses?
50
+ demographic.collect_data?
51
+ end
52
+
53
+ def questionnaire_for = demographic
54
+
55
+ def demographic
56
+ @demographic ||= Decidim::Demographics::Demographic.where(organization: current_organization).first_or_create!
57
+ end
58
+
59
+ def enforce_permission_to_respond_questionnaire
60
+ enforce_permission_to :respond, :demographics
61
+ end
62
+
63
+ def questionnaire
64
+ @questionnaire ||= Decidim::Forms::Questionnaire.where(questionnaire_for:).first_or_initialize
65
+ Decidim::Demographics.create_default_questionnaire!(@questionnaire)
66
+ @questionnaire
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module Admin
6
+ class DemographicsSettingsForm < Decidim::Form
7
+ attribute :collect_data, Boolean
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module PublishResponsesHelper
6
+ def question_response_is_publicable(question_type)
7
+ ignored_question_types = %w(short_response long_response 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(responses: { choices: [:response_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
+ def options_column_chart_wrapper(question)
37
+ tally = question.responses.map { |response| response.choices.map { |choice| translated_attribute(choice.response_option.body) } }.tally
38
+
39
+ column_chart(tally, download: true)
40
+ end
41
+
42
+ def colors_list
43
+ %w(
44
+ #3366CC
45
+ #DC3912
46
+ #FF9900
47
+ #109618
48
+ #3B3EAC
49
+ #0099C6
50
+ #DD4477
51
+ #66AA00
52
+ #B82E2E
53
+ #316395
54
+ )
55
+ end
56
+
57
+ private
58
+
59
+ def matrix_stack_chart_wrapper(question)
60
+ counts = Hash.new { |hash, key| hash[key] = Hash.new(0) }
61
+
62
+ question.responses.each do |response|
63
+ response.choices.each do |choice|
64
+ name = translated_attribute(choice.response_option.body)
65
+ row = translated_attribute(choice.matrix_row.body)
66
+
67
+ counts[name][row] += 1
68
+ end
69
+ end
70
+
71
+ tally = counts.map do |name, row_data|
72
+ {
73
+ name:,
74
+ data: row_data.map { |row, count| [row, count] }
75
+ }
76
+ end
77
+
78
+ column_chart(tally, stacked: true, legend: :right, download: true)
79
+ end
80
+
81
+ def sorting_stack_chart_wrapper(question)
82
+ counts = Hash.new { |hash, key| hash[key] = Hash.new(0) }
83
+
84
+ question.responses.each do |response|
85
+ response.choices.each do |choice|
86
+ name = translated_attribute(choice.response_option.body)
87
+ row = choice.position + 1
88
+
89
+ counts[row][name] += 1
90
+ end
91
+ end
92
+
93
+ tally = counts.map do |name, row_data|
94
+ {
95
+ name:,
96
+ data: row_data.map { |row, count| [row, count] }
97
+ }
98
+ end
99
+
100
+ bar_chart(tally.sort_by { |data| data[:name] }, stacked: true, download: true)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ # Abstract class from which all models in this engine inherit.
6
+ class ApplicationRecord < ActiveRecord::Base
7
+ self.abstract_class = true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ class Demographic < ApplicationRecord
6
+ belongs_to :organization, foreign_key: :decidim_organization_id, class_name: "Decidim::Organization"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ import "stylesheets/decidim/demographics/demographics.scss"
@@ -0,0 +1,37 @@
1
+ .demographic {
2
+ .response-questionnaire {
3
+ @apply border-t-0 border-background pt-8;
4
+
5
+ &__question-label {
6
+ @apply before:hidden;
7
+ }
8
+
9
+ &__step {
10
+ @apply space-y-6;
11
+ }
12
+
13
+ &__footer {
14
+ @apply flex flex-col gap-6 pt-6 border-t-2 border-background text-gray-2 only:border-t-0;
15
+ }
16
+
17
+ /* text-like inputs */
18
+ input[type="date"],
19
+ input[type="datetime-local"],
20
+ input[type="email"],
21
+ input[type="month"],
22
+ input[type="number"],
23
+ input[type="password"],
24
+ input[type="search"],
25
+ input[type="tel"],
26
+ input[type="text"],
27
+ input[type="time"],
28
+ input[type="url"],
29
+ input[type="week"],
30
+ select,
31
+ textarea {
32
+ &:not(.reset-defaults) {
33
+ @apply border border-gray;
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ module Admin
6
+ class Permissions < Decidim::DefaultPermissions
7
+ def permissions
8
+ return permission_action unless user
9
+ return permission_action unless permission_action.scope == :admin
10
+
11
+ toggle_allow(user.admin?) if permission_action.subject == :demographics && permission_action.action == :index
12
+ toggle_allow(user.admin?) if permission_action.subject == :demographics && permission_action.action == :update
13
+ toggle_allow(user.admin?) if permission_action.subject == :demographics_responses && permission_action.action == :index
14
+ toggle_allow(user.admin?) if permission_action.subject == :demographics_responses && permission_action.action == :show
15
+ toggle_allow(user.admin?) if permission_action.subject == :demographics_responses && permission_action.action == :export_response
16
+
17
+ permission_action
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Demographics
5
+ class Permissions < Decidim::DefaultPermissions
6
+ def permissions
7
+ return permission_action unless user
8
+ return permission_action unless permission_action.scope == :public
9
+ return permission_action unless permission_action.subject == :demographics
10
+
11
+ toggle_allow(demographic.collect_data?) if permission_action.action == :respond
12
+
13
+ permission_action
14
+ end
15
+
16
+ private
17
+
18
+ def demographic
19
+ @demographic ||= Decidim::Demographics::Demographic.where(organization: user.organization).first_or_initialize
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ <% add_decidim_page_title(t("decidim.demographics.admin.demographics.tabs_menu.title")) %>
2
+
3
+ <div class="item_show__header">
4
+ <h1 class="item_show__header-title">
5
+ <%= t(".title") %>
6
+ </h1>
7
+ </div>
8
+
9
+ <div class="flex justify-between">
10
+ <div class="w-2/3">
11
+ <%= admin_tabs(:admin_demographics_menu).render %>
12
+ </div>
13
+
14
+ <%= yield if block_given? %>
15
+ </div>
@@ -0,0 +1,36 @@
1
+ <% add_decidim_page_title(t(".title")) %>
2
+
3
+ <%= render "decidim/demographics/admin/demographics/tabs_menu" do %>
4
+ <%= link_to t("actions.back", scope: "decidim.forms.admin.questionnaires"), questionnaire_url, class: "main-tabs-menu__cta-button" %>
5
+ <% end %>
6
+
7
+ <h1 class="item_show__header-title">
8
+ <%= t(".description") %>
9
+ </h1>
10
+
11
+ <hr class="border-b border-t-0 border-gray mb-8 pb-4">
12
+
13
+ <div class="item__edit item__edit-1col">
14
+ <div class="item__edit-form">
15
+ <ol class="list-decimal list-inside">
16
+ <% questionnaire.questions.each do |question| %>
17
+ <% next if question.question_type == "separator" %>
18
+ <% next if question.question_type == "title_and_description" %>
19
+
20
+ <li class="<%= "text-gray" unless question_response_is_publicable(question.question_type) %> mb-6">
21
+ <div class="inline">
22
+ <span><%= translated_attribute question.body %> (<%= I18n.t("decidim.surveys.admin.publish_responses.index.responses", count: question.responses.count) %>)</span>
23
+ </div>
24
+
25
+ <% if question_response_is_publicable(question.question_type) %>
26
+ <div class="m-4">
27
+ <%= chart_for_question(question.id) %>
28
+ </div>
29
+ <% end %>
30
+ </li>
31
+ <% end %>
32
+ </ol>
33
+ </div>
34
+ </div>
35
+
36
+ <%= append_javascript_pack_tag "decidim_forms_admin" %>