decidim-action_delegator 0.8.1 → 0.9.0

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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +104 -58
  3. data/Rakefile +2 -2
  4. data/app/commands/decidim/action_delegator/admin/create_delegation.rb +1 -3
  5. data/app/commands/decidim/action_delegator/admin/create_setting.rb +5 -2
  6. data/app/commands/decidim/action_delegator/admin/update_setting.rb +4 -2
  7. data/app/controllers/concerns/decidim/action_delegator/devise/sessions_controller_override.rb +1 -1
  8. data/app/controllers/concerns/decidim/action_delegator/election_per_question_votes_controller_override.rb +65 -0
  9. data/app/controllers/concerns/decidim/action_delegator/election_votes_controller_override.rb +38 -0
  10. data/app/controllers/concerns/decidim/action_delegator/votes_controller_methods.rb +46 -0
  11. data/app/controllers/decidim/action_delegator/admin/application_controller.rb +11 -5
  12. data/app/controllers/decidim/action_delegator/admin/delegations_controller.rb +3 -11
  13. data/app/controllers/decidim/action_delegator/admin/invite_participants_controller.rb +0 -8
  14. data/app/controllers/decidim/action_delegator/admin/manage_delegations_controller.rb +13 -21
  15. data/app/controllers/decidim/action_delegator/admin/manage_participants_controller.rb +11 -20
  16. data/app/controllers/decidim/action_delegator/admin/participants_controller.rb +1 -9
  17. data/app/controllers/decidim/action_delegator/admin/permissions_controller.rb +1 -24
  18. data/app/controllers/decidim/action_delegator/admin/ponderations_controller.rb +0 -8
  19. data/app/controllers/decidim/action_delegator/admin/settings_controller.rb +12 -12
  20. data/app/controllers/decidim/action_delegator/application_controller.rb +3 -3
  21. data/app/controllers/decidim/action_delegator/elections/admin/results_controller.rb +58 -0
  22. data/app/controllers/decidim/action_delegator/elections/results_controller.rb +36 -0
  23. data/app/controllers/decidim/action_delegator/user_delegations_controller.rb +1 -1
  24. data/app/controllers/decidim/action_delegator/verifications/delegations_verifier/authorizations_controller.rb +14 -18
  25. data/app/forms/decidim/action_delegator/admin/action_delegator_census_form.rb +44 -0
  26. data/app/forms/decidim/action_delegator/admin/csv_import_form.rb +17 -0
  27. data/app/forms/decidim/action_delegator/admin/delegation_form.rb +6 -2
  28. data/app/forms/decidim/action_delegator/admin/ponderation_form.rb +2 -1
  29. data/app/forms/decidim/action_delegator/admin/setting_form.rb +16 -10
  30. data/app/forms/decidim/action_delegator/censuses/internal_users_form.rb +32 -0
  31. data/app/forms/decidim/action_delegator/verifications/delegations_verifier_form.rb +41 -25
  32. data/app/helpers/decidim/action_delegator/admin/{delegation_helper.rb → settings_helper.rb} +3 -16
  33. data/app/helpers/decidim/action_delegator/settings_helper.rb +124 -0
  34. data/app/jobs/decidim/action_delegator/admin/invite_participants_job.rb +1 -1
  35. data/app/jobs/decidim/action_delegator/send_sms_job.rb +2 -2
  36. data/app/jobs/decidim/action_delegator/twilio_send_sms_job.rb +2 -2
  37. data/app/models/decidim/action_delegator/delegation.rb +35 -9
  38. data/app/models/decidim/action_delegator/participant.rb +15 -9
  39. data/app/models/decidim/action_delegator/ponderation.rb +0 -2
  40. data/app/models/decidim/action_delegator/setting.rb +14 -32
  41. data/app/overrides/decidim/elections/admin/dashboard/_results/_add_results_contents.html.erb.deface +10 -0
  42. data/app/overrides/decidim/elections/admin/dashboard/_results/_add_results_tabs.html.erb.deface +3 -0
  43. data/app/overrides/decidim/elections/elections/_election_aside/add_delegation_buttons.html.erb.deface +3 -0
  44. data/app/overrides/decidim/elections/elections/_vote_results/replace_results_div.html.erb.deface +8 -0
  45. data/app/overrides/decidim/elections/per_question_votes/show/add_delegation_hidden_input.html.erb.deface +3 -0
  46. data/app/overrides/decidim/elections/per_question_votes/show/add_delegation_id_to_links.html.erb.deface +3 -0
  47. data/app/overrides/decidim/elections/per_question_votes/waiting/add_delegation_buttons.html.erb.deface +3 -0
  48. data/app/overrides/decidim/elections/votes/receipt/add_delegation_buttons.html.erb.deface +3 -0
  49. data/app/packs/entrypoints/decidim_action_delegator_elections.js +1 -0
  50. data/app/packs/src/decidim/action_delegator/elections_live_results.js +160 -0
  51. data/app/permissions/decidim/action_delegator/admin/permissions.rb +29 -0
  52. data/app/permissions/decidim/action_delegator/permissions.rb +6 -30
  53. data/app/presenters/decidim/action_delegator/setting_presenter.rb +33 -0
  54. data/app/queries/decidim/action_delegator/action_delegator_census_users.rb +51 -0
  55. data/app/queries/decidim/action_delegator/authorized_resources.rb +28 -0
  56. data/app/queries/decidim/action_delegator/election_settings.rb +23 -0
  57. data/app/queries/decidim/action_delegator/{delegated_votes_versions.rb → elections_delegated_votes_versions.rb} +8 -8
  58. data/app/queries/decidim/action_delegator/elections_question_responses_by_type.rb +33 -0
  59. data/app/queries/decidim/action_delegator/elections_question_weighted_responses.rb +28 -0
  60. data/app/queries/decidim/action_delegator/elections_votes_with_ponderations.rb +62 -0
  61. data/app/services/decidim/action_delegator/delegations_csv_importer.rb +3 -3
  62. data/app/services/decidim/action_delegator/participants_csv_importer.rb +1 -1
  63. data/app/services/decidim/action_delegator/sms_gateway.rb +2 -2
  64. data/app/views/decidim/action_delegator/admin/censuses/_action_delegator_census_form.html.erb +44 -0
  65. data/app/views/decidim/action_delegator/admin/censuses/_action_delegator_census_options_form.html.erb +25 -0
  66. data/app/views/decidim/action_delegator/admin/delegations/index.html.erb +12 -13
  67. data/app/views/decidim/action_delegator/admin/delegations/new.html.erb +29 -27
  68. data/app/views/decidim/action_delegator/admin/manage_delegations/new.html.erb +36 -24
  69. data/app/views/decidim/action_delegator/admin/manage_participants/new.html.erb +47 -33
  70. data/app/views/decidim/action_delegator/admin/participants/_form.html.erb +14 -8
  71. data/app/views/decidim/action_delegator/admin/participants/edit.html.erb +11 -13
  72. data/app/views/decidim/action_delegator/admin/participants/index.html.erb +20 -25
  73. data/app/views/decidim/action_delegator/admin/participants/new.html.erb +11 -13
  74. data/app/views/decidim/action_delegator/admin/ponderations/_form.html.erb +13 -7
  75. data/app/views/decidim/action_delegator/admin/ponderations/edit.html.erb +11 -13
  76. data/app/views/decidim/action_delegator/admin/ponderations/index.html.erb +8 -11
  77. data/app/views/decidim/action_delegator/admin/ponderations/new.html.erb +11 -13
  78. data/app/views/decidim/action_delegator/admin/settings/_form.html.erb +26 -12
  79. data/app/views/decidim/action_delegator/admin/settings/_participants_sync_check.html.erb +1 -1
  80. data/app/views/decidim/action_delegator/admin/settings/_setting_checks.html.erb +11 -16
  81. data/app/views/decidim/action_delegator/admin/settings/edit.html.erb +11 -12
  82. data/app/views/decidim/action_delegator/admin/settings/index.html.erb +22 -19
  83. data/app/views/decidim/action_delegator/admin/settings/new.html.erb +11 -12
  84. data/app/views/decidim/action_delegator/admin/shared/_tabs_menu.html.erb +15 -0
  85. data/app/views/decidim/action_delegator/censuses/_internal_users_form.html.erb +61 -0
  86. data/app/views/decidim/action_delegator/elections/_delegation_buttons.html.erb +10 -0
  87. data/app/views/decidim/action_delegator/elections/_normal_election_buttons.html.erb +13 -0
  88. data/app/views/decidim/action_delegator/elections/_per_question_buttons.html.erb +9 -0
  89. data/app/views/decidim/action_delegator/elections/_per_question_waiting_buttons.html.erb +19 -0
  90. data/app/views/decidim/action_delegator/elections/_vote_results.html.erb +10 -0
  91. data/app/views/decidim/action_delegator/elections/_vote_results_question.html.erb +13 -0
  92. data/app/views/decidim/action_delegator/elections/admin/dashboard/_by_type_and_weight.html.erb +45 -0
  93. data/app/views/decidim/action_delegator/elections/admin/dashboard/_results_tabs.html.erb +5 -0
  94. data/app/views/decidim/action_delegator/elections/admin/dashboard/_results_type_info.html.erb +4 -0
  95. data/app/views/decidim/action_delegator/elections/admin/dashboard/_sum_of_weights.html.erb +43 -0
  96. data/app/views/decidim/action_delegator/elections/admin/dashboard/_totals.html.erb +27 -0
  97. data/app/views/decidim/action_delegator/user_delegations/index.html.erb +13 -14
  98. data/app/views/decidim/action_delegator/verifications/delegations_verifier/authorizations/edit.html.erb +19 -29
  99. data/app/views/decidim/action_delegator/verifications/delegations_verifier/authorizations/new.html.erb +42 -40
  100. data/config/assets.rb +3 -35
  101. data/config/i18n-tasks.yml +27 -5
  102. data/config/locales/ca.yml +70 -56
  103. data/config/locales/cs.yml +161 -145
  104. data/config/locales/en.yml +110 -67
  105. data/config/locales/es.yml +70 -56
  106. data/db/migrate/20200824113801_create_settings.rb +1 -1
  107. data/db/migrate/20250729104037_add_title_to_action_delegator_settings.rb +31 -0
  108. data/lib/decidim/action_delegator/admin_engine.rb +72 -45
  109. data/lib/decidim/action_delegator/common_rake.rb +13 -0
  110. data/lib/decidim/action_delegator/engine.rb +49 -19
  111. data/lib/decidim/action_delegator/test/delegation_examples.rb +144 -0
  112. data/lib/decidim/action_delegator/test/factories.rb +11 -6
  113. data/lib/decidim/action_delegator/verifications/delegations_authorizer.rb +80 -47
  114. data/lib/decidim/action_delegator/version.rb +3 -3
  115. data/lib/decidim/action_delegator.rb +8 -26
  116. data/lib/tasks/migrate_consultations.rake +382 -0
  117. data/lib/tasks/upgrade_tasks.rake +5 -0
  118. data/package.json +10 -27
  119. metadata +72 -112
  120. data/app/commands/concerns/decidim/action_delegator/consultations/multiple_vote_question_override.rb +0 -31
  121. data/app/commands/concerns/decidim/action_delegator/consultations/vote_question_override.rb +0 -44
  122. data/app/commands/decidim/action_delegator/admin/fix_resource_permissions.rb +0 -46
  123. data/app/commands/decidim/action_delegator/vote_delegation.rb +0 -28
  124. data/app/controllers/concerns/decidim/action_delegator/consultations/consultations_controller_override.rb +0 -16
  125. data/app/controllers/concerns/decidim/action_delegator/consultations/question_multiple_votes_controller_override.rb +0 -29
  126. data/app/controllers/concerns/decidim/action_delegator/consultations/question_votes_controller_override.rb +0 -57
  127. data/app/controllers/concerns/decidim/action_delegator/consultations/questions_controller_override.rb +0 -16
  128. data/app/controllers/concerns/decidim/action_delegator/needs_consultation_styles.rb +0 -24
  129. data/app/controllers/decidim/action_delegator/admin/consultations/exports_controller.rb +0 -27
  130. data/app/controllers/decidim/action_delegator/admin/consultations_controller.rb +0 -47
  131. data/app/controllers/decidim/action_delegator/admin/exports/_sum_of_weights_controller.rb +0 -15
  132. data/app/forms/concerns/decidim/action_delegator/consultations/vote_form_override.rb +0 -15
  133. data/app/helpers/decidim/action_delegator/delegation_helper.rb +0 -13
  134. data/app/jobs/decidim/action_delegator/export_consultation_results_job.rb +0 -51
  135. data/app/models/concerns/decidim/action_delegator/consultations/question_override.rb +0 -18
  136. data/app/models/concerns/decidim/action_delegator/consultations/vote_override.rb +0 -15
  137. data/app/models/decidim/action_delegator/unversioned_vote.rb +0 -19
  138. data/app/models/decidim/action_delegator/whodunnit_vote.rb +0 -28
  139. data/app/overrides/decidim/consultations/admin/consultations/results/add_ongoing_warning.html.erb.deface +0 -3
  140. data/app/overrides/decidim/consultations/consultations/_question/add_delegation_link.html.erb.deface +0 -3
  141. data/app/overrides/decidim/consultations/consultations/_regular_questions/prevent_empty_questions.html.erb.deface +0 -10
  142. data/app/overrides/decidim/consultations/consultations/_regular_questions/remove_highlighted_scopes.html.erb.deface +0 -5
  143. data/app/overrides/decidim/consultations/question_multiple_votes/_form/add_delegation_notice.html.erb.deface +0 -8
  144. data/app/overrides/decidim/consultations/questions/_vote_button/add_delegations_link.html.erb.deface +0 -3
  145. data/app/overrides/decidim/consultations/questions/_vote_button/add_modal.html.erb.deface +0 -3
  146. data/app/overrides/decidim/consultations/questions/_vote_button/add_modal_javascript.html.erb.deface +0 -4
  147. data/app/overrides/decidim/consultations/questions/_vote_button/replace_delegation_to_multivote_link.html.erb.deface +0 -8
  148. data/app/overrides/decidim/consultations/questions/_vote_modal/add_delegation_callout.html.erb.deface +0 -3
  149. data/app/overrides/decidim/consultations/questions/_vote_modal_confirm/add_delegation_callout.html.erb.deface +0 -3
  150. data/app/overrides/decidim/consultations/questions/_vote_modal_confirm/add_hidden_field.html.erb.deface +0 -3
  151. data/app/overrides/layouts/decidim/admin/remove_deprecation.rb +0 -10
  152. data/app/packs/entrypoints/decidim_action_delegator.scss +0 -1
  153. data/app/packs/entrypoints/decidim_action_delegator_questions.js +0 -5
  154. data/app/packs/src/decidim/action_delegator/questions.js +0 -33
  155. data/app/packs/stylesheets/decidim/action_delegator/questions.scss +0 -26
  156. data/app/permissions/concerns/decidim/action_delegator/consultations/permissions_override.rb +0 -35
  157. data/app/presenters/decidim/action_delegator/question_with_totals.rb +0 -24
  158. data/app/queries/decidim/action_delegator/consultation_delegations.rb +0 -25
  159. data/app/queries/decidim/action_delegator/delegates_votes_by_consultation.rb +0 -24
  160. data/app/queries/decidim/action_delegator/delegates_votes_by_question.rb +0 -26
  161. data/app/queries/decidim/action_delegator/delegation_votes.rb +0 -30
  162. data/app/queries/decidim/action_delegator/grantee_delegations.rb +0 -24
  163. data/app/queries/decidim/action_delegator/organization_delegations.rb +0 -26
  164. data/app/queries/decidim/action_delegator/organization_settings.rb +0 -31
  165. data/app/queries/decidim/action_delegator/responses.rb +0 -24
  166. data/app/queries/decidim/action_delegator/responses_by_membership.rb +0 -58
  167. data/app/queries/decidim/action_delegator/scrutiny.rb +0 -87
  168. data/app/queries/decidim/action_delegator/setting_delegations.rb +0 -19
  169. data/app/queries/decidim/action_delegator/sum_of_membership_weight.rb +0 -44
  170. data/app/queries/decidim/action_delegator/sum_of_weights.rb +0 -25
  171. data/app/queries/decidim/action_delegator/type_and_weight.rb +0 -26
  172. data/app/queries/decidim/action_delegator/voted_with_ponderations.rb +0 -30
  173. data/app/queries/decidim/action_delegator/votes_count_aggregation.rb +0 -34
  174. data/app/serializers/decidim/action_delegator/consultation_results_serializer.rb +0 -19
  175. data/app/views/decidim/action_delegator/admin/consultations/_ongoing_consultation_warning.html.erb +0 -3
  176. data/app/views/decidim/action_delegator/admin/consultations/results.html.erb +0 -65
  177. data/app/views/decidim/action_delegator/admin/consultations/weighted_results.html.erb +0 -66
  178. data/app/views/decidim/action_delegator/consultations/_link_to_question.html.erb +0 -11
  179. data/app/views/decidim/action_delegator/consultations/questions/_callout.html.erb +0 -5
  180. data/app/views/decidim/action_delegator/consultations/questions/_delegations_modal.html.erb +0 -34
  181. data/app/views/decidim/action_delegator/consultations/questions/_link_to_delegations.html.erb +0 -11
  182. data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_active.html.erb +0 -32
  183. data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_finished.html.erb +0 -9
  184. data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_upcoming.html.erb +0 -8
  185. data/app/views/decidim/consultations/question_votes/update_vote_button.js.erb +0 -82
  186. data/lib/tasks/import_direct_verification.rake +0 -30
@@ -3,7 +3,7 @@
3
3
  require "savon"
4
4
  require "rails"
5
5
  require "decidim/core"
6
- require "decidim/consultations"
6
+ require "decidim/elections"
7
7
  require "deface"
8
8
 
9
9
  module Decidim
@@ -12,33 +12,33 @@ module Decidim
12
12
  # Handles all the logic related to delegation except verifications
13
13
  class Engine < ::Rails::Engine
14
14
  isolate_namespace Decidim::ActionDelegator
15
+ include Decidim::TranslatableAttributes
15
16
 
16
17
  routes do
17
- # Add engine routes here
18
+ namespace :elections do
19
+ get ":id/sum_of_weights", to: "results#sum_of_weights", as: :results_sum_of_weights
20
+ namespace :admin do
21
+ get ":id/by_type_and_weight", to: "results#by_type_and_weight", as: :results_by_type_and_weight
22
+ get ":id/sum_of_weights", to: "results#sum_of_weights", as: :results_sum_of_weights
23
+ get ":id/totals", to: "results#totals", as: :results_totals
24
+ end
25
+ end
26
+
18
27
  authenticate(:user) do
19
- resources :user_delegations, controller: :user_delegations
28
+ resources :user_delegations, controller: :user_delegations, only: [:index]
20
29
  root to: "user_delegations#index"
21
30
  end
22
31
  end
23
32
 
24
- config.to_prepare do
25
- # override votes questions
26
- Decidim::Consultations::Question.include(Decidim::ActionDelegator::Consultations::QuestionOverride)
27
- Decidim::Consultations::VoteQuestion.include(Decidim::ActionDelegator::Consultations::VoteQuestionOverride)
28
- Decidim::Consultations::MultipleVoteQuestion.include(Decidim::ActionDelegator::Consultations::MultipleVoteQuestionOverride)
29
- Decidim::Consultations::VoteForm.include(Decidim::ActionDelegator::Consultations::VoteFormOverride)
30
- Decidim::Consultations::MultiVoteForm.include(Decidim::ActionDelegator::Consultations::VoteFormOverride)
31
- Decidim::Consultations::Vote.include(Decidim::ActionDelegator::Consultations::VoteOverride)
32
- Decidim::Consultations::Permissions.include(Decidim::ActionDelegator::Consultations::PermissionsOverride)
33
- end
34
-
35
33
  initializer "decidim_action_delegator.overrides", after: "decidim.action_controller" do
36
34
  config.to_prepare do
37
35
  Decidim::Devise::SessionsController.include(Decidim::ActionDelegator::Devise::SessionsControllerOverride)
38
- Decidim::Consultations::QuestionVotesController.include(Decidim::ActionDelegator::Consultations::QuestionVotesControllerOverride)
39
- Decidim::Consultations::QuestionsController.include(Decidim::ActionDelegator::Consultations::QuestionsControllerOverride)
40
- Decidim::Consultations::ConsultationsController.include(Decidim::ActionDelegator::Consultations::ConsultationsControllerOverride)
41
- Decidim::Consultations::QuestionMultipleVotesController.include(Decidim::ActionDelegator::Consultations::QuestionMultipleVotesControllerOverride)
36
+ if Decidim.module_installed?(:elections)
37
+ Decidim::Elections::VotesController.include(Decidim::ActionDelegator::ElectionVotesControllerOverride)
38
+ Decidim::Elections::PerQuestionVotesController.include(Decidim::ActionDelegator::ElectionPerQuestionVotesControllerOverride)
39
+ Decidim::Elections::ElectionsController.helper(SettingsHelper)
40
+ Decidim::Elections::Admin::ElectionsController.helper(SettingsHelper)
41
+ end
42
42
  end
43
43
  end
44
44
 
@@ -50,6 +50,13 @@ module Decidim
50
50
  workflow.engine = Decidim::ActionDelegator::Verifications::DelegationsVerifier::Engine
51
51
  workflow.expires_in = Decidim::ActionDelegator.authorization_expiration_time
52
52
  workflow.time_between_renewals = 1.minute
53
+ workflow.options do |options|
54
+ options.attribute :setting, type: :select, raw_choices: true, choices: lambda { |context|
55
+ Decidim::ActionDelegator::Setting.where(organization: context[:component]&.organization).active.map do |setting|
56
+ [translated_attribute(setting.title), setting.id]
57
+ end
58
+ }
59
+ end
53
60
  end
54
61
  end
55
62
 
@@ -57,7 +64,7 @@ module Decidim
57
64
  Decidim.register_assets_path File.expand_path("app/packs", root)
58
65
  end
59
66
 
60
- initializer "decidim.user_menu" do
67
+ initializer "decidim_action_delegator.user_menu" do
61
68
  Decidim.menu :user_menu do |menu|
62
69
  menu.add_item :vote_delegations,
63
70
  t("vote_delegations", scope: "layouts.decidim.user_profile"),
@@ -66,6 +73,29 @@ module Decidim
66
73
  active: :exact
67
74
  end
68
75
  end
76
+
77
+ initializer "decidim_action_delegator.census_registry" do
78
+ next unless Decidim.module_installed?(:elections)
79
+
80
+ Decidim::Elections.census_registry.register(:action_delegator_census) do |manifest|
81
+ manifest.admin_form = "Decidim::ActionDelegator::Admin::ActionDelegatorCensusForm"
82
+ manifest.admin_form_partial = "decidim/action_delegator/admin/censuses/action_delegator_census_form"
83
+ manifest.voter_form = "Decidim::ActionDelegator::Censuses::InternalUsersForm"
84
+ manifest.voter_form_partial = "decidim/action_delegator/censuses/internal_users_form"
85
+
86
+ manifest.user_query do |election|
87
+ Decidim::ActionDelegator::ActionDelegatorCensusUsers.new(election).query
88
+ end
89
+
90
+ manifest.census_ready_validator { |election| election.census_settings["setting_id"].present? }
91
+ end
92
+ end
93
+
94
+ initializer "decidim_action_delegator.icons" do
95
+ Decidim.icons.register(name: "weight-line", icon: "weight-line", category: "system", description: "", engine: :action_delegator)
96
+ Decidim.icons.register(name: "user-shared-line", icon: "user-shared-line", category: "system", description: "", engine: :action_delegator)
97
+ Decidim.icons.register(name: "arrow-go-forward-line", icon: "arrow-go-forward-line", category: "system", description: "", engine: :action_delegator)
98
+ end
69
99
  end
70
100
  end
71
101
  end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples "voting in a per question election" do
4
+ it "shows delegation and allows the user vote for himself and the granter" do
5
+ expect(page).to have_css(".election__aside-voted")
6
+ expect(page).to have_content("You have delegated votes.")
7
+ expect(page).to have_content("You can vote on behalf of the following participants in this election:")
8
+
9
+ within ".election__aside-voted" do
10
+ expect(page).to have_content(user.name.to_s)
11
+ end
12
+
13
+ click_on "Vote"
14
+ expect(page).to have_content("You are voting for yourself (#{delegate_user.name})")
15
+
16
+ first("input[value=\"#{response_option1.id}\"]").click
17
+ click_on "Cast vote"
18
+
19
+ expect(page).to have_content("Waiting for the next question")
20
+
21
+ expect(page).to have_css(".waiting-buttons")
22
+ expect(page).to have_content("You have delegated votes.")
23
+ expect(page).to have_link(
24
+ "Continue voting on behalf of #{user.name}",
25
+ href: election_per_question_vote_path(current_question.id, delegation.id)
26
+ )
27
+ click_on "Continue voting on behalf of #{user.name}"
28
+ expect(page).to have_content("You are voting on behalf of #{user.name}")
29
+
30
+ first("input[value=\"#{response_option2.id}\"]").click
31
+ click_on "Cast vote"
32
+
33
+ expect(page).to have_content("Your vote has been successfully cast")
34
+ expect(page).to have_link("Edit your vote", href: election_per_question_vote_path(current_question))
35
+ expect(page).to have_link("Edit vote for #{user.name}", href: election_per_question_vote_path(current_question) + "?delegation=#{delegation.id}")
36
+
37
+ expect(last_vote(delegate_user).response_option).to eq(response_option1)
38
+ expect(last_vote(user).response_option).to eq(response_option2)
39
+
40
+ click_on "Edit vote for #{user.name}"
41
+ first("input[value=\"#{response_option1.id}\"]").click
42
+ click_on "Cast vote"
43
+
44
+ expect(page).to have_content("Your vote has been successfully cast")
45
+ expect(last_vote(user).response_option.reload).to eq(response_option1)
46
+
47
+ click_on "Edit your vote"
48
+ first("input[value=\"#{response_option2.id}\"]").click
49
+ click_on "Cast vote"
50
+
51
+ sleep 0.1 # Wait for the versioning to be saved
52
+ expect(last_vote(delegate_user).response_option.reload).to eq(response_option2)
53
+ expect(last_vote(delegate_user).versions.first.whodunnit).to eq(delegate_user.id.to_s)
54
+ expect(last_vote(delegate_user).versions.first.decidim_action_delegator_delegation_id).to be_blank
55
+ expect(last_vote(user).versions.first.whodunnit).to eq(delegate_user.id.to_s)
56
+ expect(last_vote(user).versions.first.decidim_action_delegator_delegation_id).to eq(delegation.id)
57
+ end
58
+
59
+ context "when delegate has voted for delegated user" do
60
+ let!(:next_question) { create(:election_question, :voting_enabled, :with_response_options, election:) }
61
+ let!(:vote1) { create(:election_vote, question: current_question, response_option: current_question.response_options.first, voter_uid: user.to_global_id.to_s) }
62
+ let!(:vote2) { create(:election_vote, question: next_question, response_option: next_question.response_options.first, voter_uid: user.to_global_id.to_s) }
63
+
64
+ it "shows voted status on election page" do
65
+ visit election_path
66
+ expect(page).to have_content("You have delegated votes.")
67
+ expect(page).to have_content("You can vote on behalf of the following participants in this election:")
68
+
69
+ within all(".election__aside-voted").last do
70
+ expect(page).to have_content("✔ #{user.name}")
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ shared_examples "voting in a normal election" do
77
+ it "shows delegation and allows the user vote for himself and the granter" do
78
+ expect(page).to have_css(".election__aside-voted")
79
+ expect(page).to have_content("You have delegated votes.")
80
+ expect(page).to have_content("Vote on behalf of #{user.name}")
81
+
82
+ click_on "Vote"
83
+
84
+ first("input[value=\"#{response_option1.id}\"]").click
85
+ click_on "Next"
86
+ sleep 0.1
87
+ first('input[type="radio"], input[type="checkbox"]').click
88
+ click_on "Next"
89
+ click_on "Cast vote"
90
+
91
+ expect(page).to have_content("Your vote has been successfully cast")
92
+ click_on "Exit the voting booth"
93
+
94
+ expect(page).to have_content("You have already voted.")
95
+ expect(last_vote(delegate_user).response_option).to eq(response_option1)
96
+
97
+ click_on "Vote on behalf of #{user.name}"
98
+ expect(page).to have_content("You are voting on behalf of #{user.name}")
99
+
100
+ first("input[value=\"#{response_option2.id}\"]").click
101
+ click_on "Next"
102
+ sleep 0.1
103
+ first('input[type="radio"], input[type="checkbox"]').click
104
+ click_on "Next"
105
+ click_on "Cast vote"
106
+
107
+ expect(page).to have_content("Your vote has been successfully cast")
108
+ click_on "Exit the voting booth"
109
+ expect(page).to have_content("You have already voted.")
110
+
111
+ expect(last_vote(user).response_option.reload).to eq(response_option2)
112
+
113
+ click_on "Vote"
114
+ first("input[value=\"#{response_option2.id}\"]").click
115
+ click_on "Next"
116
+ sleep 0.1
117
+ click_on "Next"
118
+ click_on "Cast vote"
119
+ click_on "Exit the voting booth"
120
+
121
+ expect(last_vote(delegate_user).reload.response_option).to eq(response_option2)
122
+
123
+ click_on "Vote on behalf of #{user.name}"
124
+ first("input[value=\"#{response_option1.id}\"]").click
125
+ click_on "Next"
126
+ sleep 0.1
127
+ click_on "Next"
128
+ click_on "Cast vote"
129
+ click_on "Exit the voting booth"
130
+
131
+ expect(last_vote(user).reload.response_option).to eq(response_option1)
132
+ expect(last_vote(delegate_user).versions.first.whodunnit).to eq(delegate_user.id.to_s)
133
+ expect(last_vote(delegate_user).versions.first.decidim_action_delegator_delegation_id).to be_blank
134
+ expect(last_vote(user).versions.first.whodunnit).to eq(delegate_user.id.to_s)
135
+ expect(last_vote(user).versions.first.decidim_action_delegator_delegation_id).to eq(delegation.id)
136
+ end
137
+ end
138
+
139
+ shared_examples "no delegations available" do
140
+ it "does not show delegation buttons" do
141
+ expect(page).to have_no_css(".election__aside-voted")
142
+ expect(page).to have_no_content("You have delegated votes.")
143
+ end
144
+ end
@@ -1,13 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "decidim/core/test/factories"
4
- require "decidim/consultations/test/factories"
5
-
6
3
  FactoryBot.define do
7
4
  factory :delegation, class: "Decidim::ActionDelegator::Delegation" do
8
5
  setting
9
- granter { association :user, organization: setting.consultation.organization }
10
- grantee { association :user, organization: setting.consultation.organization }
6
+ granter { association :user, organization: setting.organization }
7
+ grantee { association :user, organization: setting.organization }
11
8
  end
12
9
 
13
10
  factory :ponderation, class: "Decidim::ActionDelegator::Ponderation" do
@@ -24,13 +21,21 @@ FactoryBot.define do
24
21
  end
25
22
 
26
23
  factory :setting, class: "Decidim::ActionDelegator::Setting" do
24
+ organization { create(:organization) }
25
+ transient do
26
+ skip_injection { false }
27
+ end
28
+
29
+ title { generate_localized_title(:title, skip_injection:) }
30
+ description { generate_localized_description(:description, skip_injection:) }
27
31
  max_grants { 3 }
28
- consultation
32
+
29
33
  trait :with_ponderations do
30
34
  after(:create) do |setting|
31
35
  create_list(:ponderation, 3, setting: setting)
32
36
  end
33
37
  end
38
+
34
39
  trait :with_participants do
35
40
  after(:create) do |setting|
36
41
  create_list(:participant, 3, setting: setting)
@@ -5,77 +5,110 @@ module Decidim
5
5
  module Verifications
6
6
  class DelegationsAuthorizer < Decidim::Verifications::DefaultActionAuthorizer
7
7
  def authorize
8
- status = super
9
- return status unless status == [:ok, {}]
8
+ if !authorization
9
+ [:missing, { action: :authorize }]
10
+ elsif authorization_expired?
11
+ [:expired, { action: :authorize }]
12
+ elsif !authorization.granted?
13
+ [:pending, { action: :resume }]
14
+ elsif invalid_setting?
15
+ return [:unauthorized, { extra_explanation: extra_explanations }]
16
+ else
17
+ [:ok, {}]
18
+ end
19
+ end
10
20
 
11
- # if used outside a consultation, allow all
12
- return [:ok, {}] if consultation.blank?
13
- return [:ok, {}] if belongs_to_consultation? && user_in_census?
21
+ def invalid_setting?
22
+ return true unless setting
23
+ return true unless user_is_a_participant?
14
24
 
15
- [:unauthorized, { extra_explanation: extra_explanations }]
25
+ false
16
26
  end
17
27
 
18
28
  private
19
29
 
20
- def belongs_to_consultation?
21
- return unless setting&.consultation
30
+ def user_is_a_participant?
31
+ return false unless setting && setting.active?
22
32
 
23
- setting.consultation == consultation
33
+ setting.participants.exists?(participant_params(setting))
24
34
  end
25
35
 
26
- def user_in_census?
27
- return unless setting&.participants
28
-
29
- setting.participants.exists?(decidim_user: authorization.user) || setting.participants.exists?(census_params)
36
+ def participant_params(setting)
37
+ params = {}
38
+ params[:email] = authorization.user.email if setting.email_required?
39
+ params[:phone] = authorization.metadata["phone"] if setting.phone_required?
40
+ params
30
41
  end
31
42
 
32
- def census_params
33
- return @census_params if @census_params
34
-
35
- @census_params = { email: authorization.user.email }
36
- @census_params[:phone] = authorization.metadata["phone"] if setting.phone_required?
37
- @census_params
43
+ def authorizations_path
44
+ Decidim::Verifications::Engine.routes.url_helpers.authorizations_path
38
45
  end
39
46
 
40
47
  def extra_explanations
41
48
  return @extra_explanations if @extra_explanations
42
49
 
43
- unless setting
44
- return [{
45
- key: "no_setting",
46
- params: { scope: "decidim.action_delegator.delegations_authorizer" }
47
- }]
48
- end
49
-
50
- @extra_explanations = [{
51
- key: "not_in_census",
52
- params: { scope: "decidim.action_delegator.delegations_authorizer" }
53
- }]
54
-
55
- @extra_explanations << {
56
- key: "email",
57
- params: { scope: "decidim.action_delegator.delegations_authorizer", email: authorization.user.email }
58
- }
59
-
60
- if setting.phone_required?
50
+ @extra_explanations = []
51
+
52
+ if setting
53
+ if setting.active?
54
+ @extra_explanations << {
55
+ key: "not_in_census_html",
56
+ params: {
57
+ scope: "decidim.action_delegator.delegations_authorizer",
58
+ census: translated_attribute(setting.title),
59
+ renew_path: authorizations_path
60
+ }
61
+ }
62
+ if setting.email_required?
63
+ @extra_explanations << {
64
+ key: "email",
65
+ params: { scope: "decidim.action_delegator.delegations_authorizer", email: authorization.user.email }
66
+ }
67
+ end
68
+ if setting.phone_required?
69
+ @extra_explanations << {
70
+ key: "phone",
71
+ params: { scope: "decidim.action_delegator.delegations_authorizer", phone: authorization.metadata["phone"] || "---" }
72
+ }
73
+ end
74
+ else
75
+ @extra_explanations << {
76
+ key: "inactive_setting_html",
77
+ params: {
78
+ scope: "decidim.action_delegator.delegations_authorizer",
79
+ census: translated_attribute(setting.title),
80
+ renew_path: authorizations_path
81
+ }
82
+ }
83
+ end
84
+ else
61
85
  @extra_explanations << {
62
- key: "phone",
63
- params: { scope: "decidim.action_delegator.delegations_authorizer", phone: authorization.metadata["phone"] || "---" }
86
+ key: "no_setting_html",
87
+ params: {
88
+ scope: "decidim.action_delegator.delegations_authorizer",
89
+ renew_path: authorizations_path
90
+ }
64
91
  }
65
92
  end
66
- @extra_explanations
67
- end
68
93
 
69
- def setting
70
- @setting ||= Decidim::ActionDelegator::Setting.find_by(consultation: consultation)
94
+ @extra_explanations
71
95
  end
72
96
 
73
- def consultation
74
- @consultation ||= (component.participatory_space if component&.participatory_space.is_a?(Decidim::Consultation))
97
+ # Obtain the setting from the resource (in case is an election) or from the standard options (coming from the component/resource permissions hash) otherwise
98
+ def setting_id
99
+ @setting_id ||= if resource && resource.respond_to?(:census_settings) && resource.respond_to?(:census_manifest)
100
+ if resource.census_manifest == "action_delegator_census"
101
+ resource.census_settings["setting_id"]
102
+ else
103
+ resource.census_settings.dig("authorization_handlers", "delegations_verifier", "options", "setting")
104
+ end
105
+ else
106
+ options["setting"]
107
+ end
75
108
  end
76
109
 
77
- def manifest
78
- @manifest ||= Decidim::Verifications.find_workflow_manifest(authorization&.name)
110
+ def setting
111
+ @setting ||= Decidim::ActionDelegator::Setting.find_by(id: setting_id)
79
112
  end
80
113
  end
81
114
  end
@@ -3,8 +3,8 @@
3
3
  module Decidim
4
4
  # This holds the decidim-action_delegator version.
5
5
  module ActionDelegator
6
- VERSION = "0.8.1"
7
- DECIDIM_VERSION = "0.27.4"
8
- COMPAT_DECIDIM_VERSION = [">= 0.27.0", "< 0.28"].freeze
6
+ VERSION = "0.9.0"
7
+ DECIDIM_VERSION = { github: "decidim/decidim", branch: "develop" }.freeze
8
+ COMPAT_DECIDIM_VERSION = [">= 0.31.0.dev", "< 0.32"].freeze
9
9
  end
10
10
  end
@@ -14,25 +14,25 @@ module Decidim
14
14
  # this is the SmsGateway provided by this module
15
15
  # Note that it will be ignored if you provide your own SmsGateway in Decidim.sms_gateway_service
16
16
  config_accessor :sms_gateway_service do
17
- "Decidim::ActionDelegator::SmsGateway"
17
+ Decidim::Env.new("AD_SMS_GATEWAY_SERVICE", "Decidim::ActionDelegator::SmsGateway").to_s
18
18
  end
19
19
 
20
20
  # The default expiration time for the integrated authorization
21
21
  # if zero, the authorization won't be registered
22
22
  config_accessor :authorization_expiration_time do
23
- 3.months
23
+ Decidim::Env.new("AD_AUTHORIZATION_EXPIRATION_TIME").presence&.to_i || 3.months
24
24
  end
25
25
 
26
26
  # Put this to false if you don't want to allow administrators to invite users not registered
27
27
  # in the platform when uploading a census (inviting users without permission can be a GDPR offense).
28
28
  config_accessor :allow_to_invite_users do
29
- true
29
+ Decidim::Env.new("AD_ALLOW_TO_INVITE_USERS", true).present?
30
30
  end
31
31
 
32
32
  # If true, tries to automatically authorize users when they log in with the "Corporate Governance Verifier"
33
33
  # Note that this is only possible when the verifier is configured to use only the email (if SMS is required, the user will have to do the standard verification process)
34
34
  config_accessor :authorize_on_login do
35
- true
35
+ Decidim::Env.new("AD_AUTHORIZE_ON_LOGIN", true).present?
36
36
  end
37
37
 
38
38
  # used for comparing phone numbers from a census list and the ones introduced by the user
@@ -40,30 +40,12 @@ module Decidim
40
40
  # if you have a census list with +34 666 666 666 and the user introduces 0034666666666 or 666666666, they will be considered the same
41
41
  # can be empty or null if yo don't want to check different combinations of prefixes
42
42
  config_accessor :phone_prefixes do
43
- %w(+34 0034 34)
43
+ Decidim::Env.new("AD_PHONE_PREFIXES", "+34,0034,34").to_array
44
44
  end
45
45
 
46
46
  # The regex for validating phone numbers
47
47
  config_accessor :phone_regex do
48
- /^\d{6,15}$/ # 6 to 15 digits
49
- end
50
-
51
- # Consultations has an annoying and totally useless deprecation warning
52
- # This plugin removes it by default.
53
- # If you want to keep it, you can set this config to false
54
- config_accessor :remove_consultation_deprecation_warning do
55
- true
56
- end
57
-
58
- # In a consultation the highlighted questions are duplicated in the list of regular questions
59
- # this maintains the highlighted questions in the highlighted list and removes them from the regular list
60
- config_accessor :remove_duplicated_highlighted_questions do
61
- true
62
- end
63
-
64
- # If true, admins can view the result of a consultation even if the consultation is ongoing
65
- config_accessor :admin_preview_results do
66
- true
48
+ Decidim::Env.new("AD_PHONE_REGEX", '^\d{6,15}$').to_s # 6 to 15 digits
67
49
  end
68
50
  end
69
51
  end
@@ -74,7 +56,7 @@ end
74
56
  # manage their delegations
75
57
  Decidim.register_global_engine(
76
58
  :decidim_action_delegator, # this is the name of the global method to access engine routes
77
- ::Decidim::ActionDelegator::Engine,
59
+ Decidim::ActionDelegator::Engine,
78
60
  at: "/action_delegator"
79
61
  )
80
62
 
@@ -82,6 +64,6 @@ Decidim.register_global_engine(
82
64
  # create their own
83
65
  Decidim.register_global_engine(
84
66
  :decidim_admin_action_delegator,
85
- ::Decidim::ActionDelegator::AdminEngine,
67
+ Decidim::ActionDelegator::AdminEngine,
86
68
  at: "/admin/action_delegator"
87
69
  )