decidim-action_delegator 0.8.2 → 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 (194) 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 +2 -10
  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 -20
  15. data/app/controllers/decidim/action_delegator/admin/manage_participants_controller.rb +11 -19
  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/ponderation_form.rb +2 -1
  28. data/app/forms/decidim/action_delegator/admin/setting_form.rb +16 -10
  29. data/app/forms/decidim/action_delegator/censuses/internal_users_form.rb +32 -0
  30. data/app/forms/decidim/action_delegator/verifications/delegations_verifier_form.rb +41 -25
  31. data/app/helpers/decidim/action_delegator/admin/{delegation_helper.rb → settings_helper.rb} +3 -16
  32. data/app/helpers/decidim/action_delegator/settings_helper.rb +124 -0
  33. data/app/jobs/decidim/action_delegator/admin/invite_participants_job.rb +1 -1
  34. data/app/jobs/decidim/action_delegator/send_sms_job.rb +2 -2
  35. data/app/jobs/decidim/action_delegator/twilio_send_sms_job.rb +2 -2
  36. data/app/models/decidim/action_delegator/delegation.rb +15 -14
  37. data/app/models/decidim/action_delegator/participant.rb +7 -10
  38. data/app/models/decidim/action_delegator/ponderation.rb +0 -2
  39. data/app/models/decidim/action_delegator/setting.rb +14 -32
  40. data/app/overrides/decidim/elections/admin/dashboard/_results/_add_results_contents.html.erb.deface +10 -0
  41. data/app/overrides/decidim/elections/admin/dashboard/_results/_add_results_tabs.html.erb.deface +3 -0
  42. data/app/overrides/decidim/elections/elections/_election_aside/add_delegation_buttons.html.erb.deface +3 -0
  43. data/app/overrides/decidim/elections/elections/_vote_results/replace_results_div.html.erb.deface +8 -0
  44. data/app/overrides/decidim/elections/per_question_votes/show/add_delegation_hidden_input.html.erb.deface +3 -0
  45. data/app/overrides/decidim/elections/per_question_votes/show/add_delegation_id_to_links.html.erb.deface +3 -0
  46. data/app/overrides/decidim/elections/per_question_votes/waiting/add_delegation_buttons.html.erb.deface +3 -0
  47. data/app/overrides/decidim/elections/votes/receipt/add_delegation_buttons.html.erb.deface +3 -0
  48. data/app/packs/entrypoints/decidim_action_delegator_elections.js +1 -0
  49. data/app/packs/src/decidim/action_delegator/elections_live_results.js +160 -0
  50. data/app/permissions/decidim/action_delegator/admin/permissions.rb +29 -0
  51. data/app/permissions/decidim/action_delegator/permissions.rb +6 -30
  52. data/app/presenters/decidim/action_delegator/setting_presenter.rb +33 -0
  53. data/app/queries/decidim/action_delegator/action_delegator_census_users.rb +51 -0
  54. data/app/queries/decidim/action_delegator/authorized_resources.rb +28 -0
  55. data/app/queries/decidim/action_delegator/election_settings.rb +23 -0
  56. data/app/queries/decidim/action_delegator/{delegated_votes_versions.rb → elections_delegated_votes_versions.rb} +8 -8
  57. data/app/queries/decidim/action_delegator/elections_question_responses_by_type.rb +33 -0
  58. data/app/queries/decidim/action_delegator/elections_question_weighted_responses.rb +28 -0
  59. data/app/queries/decidim/action_delegator/elections_votes_with_ponderations.rb +62 -0
  60. data/app/services/decidim/action_delegator/participants_csv_importer.rb +1 -1
  61. data/app/services/decidim/action_delegator/sms_gateway.rb +2 -2
  62. data/app/views/decidim/action_delegator/admin/censuses/_action_delegator_census_form.html.erb +44 -0
  63. data/app/views/decidim/action_delegator/admin/censuses/_action_delegator_census_options_form.html.erb +25 -0
  64. data/app/views/decidim/action_delegator/admin/delegations/index.html.erb +12 -13
  65. data/app/views/decidim/action_delegator/admin/delegations/new.html.erb +29 -27
  66. data/app/views/decidim/action_delegator/admin/manage_delegations/new.html.erb +36 -24
  67. data/app/views/decidim/action_delegator/admin/manage_participants/new.html.erb +47 -33
  68. data/app/views/decidim/action_delegator/admin/participants/_form.html.erb +14 -8
  69. data/app/views/decidim/action_delegator/admin/participants/edit.html.erb +11 -13
  70. data/app/views/decidim/action_delegator/admin/participants/index.html.erb +20 -25
  71. data/app/views/decidim/action_delegator/admin/participants/new.html.erb +11 -13
  72. data/app/views/decidim/action_delegator/admin/ponderations/_form.html.erb +13 -7
  73. data/app/views/decidim/action_delegator/admin/ponderations/edit.html.erb +11 -13
  74. data/app/views/decidim/action_delegator/admin/ponderations/index.html.erb +8 -11
  75. data/app/views/decidim/action_delegator/admin/ponderations/new.html.erb +11 -13
  76. data/app/views/decidim/action_delegator/admin/settings/_form.html.erb +26 -12
  77. data/app/views/decidim/action_delegator/admin/settings/_participants_sync_check.html.erb +1 -1
  78. data/app/views/decidim/action_delegator/admin/settings/_setting_checks.html.erb +11 -16
  79. data/app/views/decidim/action_delegator/admin/settings/edit.html.erb +11 -12
  80. data/app/views/decidim/action_delegator/admin/settings/index.html.erb +22 -19
  81. data/app/views/decidim/action_delegator/admin/settings/new.html.erb +11 -12
  82. data/app/views/decidim/action_delegator/admin/shared/_tabs_menu.html.erb +15 -0
  83. data/app/views/decidim/action_delegator/censuses/_internal_users_form.html.erb +61 -0
  84. data/app/views/decidim/action_delegator/elections/_delegation_buttons.html.erb +10 -0
  85. data/app/views/decidim/action_delegator/elections/_normal_election_buttons.html.erb +13 -0
  86. data/app/views/decidim/action_delegator/elections/_per_question_buttons.html.erb +9 -0
  87. data/app/views/decidim/action_delegator/elections/_per_question_waiting_buttons.html.erb +19 -0
  88. data/app/views/decidim/action_delegator/elections/_vote_results.html.erb +10 -0
  89. data/app/views/decidim/action_delegator/elections/_vote_results_question.html.erb +13 -0
  90. data/app/views/decidim/action_delegator/elections/admin/dashboard/_by_type_and_weight.html.erb +45 -0
  91. data/app/views/decidim/action_delegator/elections/admin/dashboard/_results_tabs.html.erb +5 -0
  92. data/app/views/decidim/action_delegator/elections/admin/dashboard/_results_type_info.html.erb +4 -0
  93. data/app/views/decidim/action_delegator/elections/admin/dashboard/_sum_of_weights.html.erb +43 -0
  94. data/app/views/decidim/action_delegator/elections/admin/dashboard/_totals.html.erb +27 -0
  95. data/app/views/decidim/action_delegator/user_delegations/index.html.erb +13 -14
  96. data/app/views/decidim/action_delegator/verifications/delegations_verifier/authorizations/edit.html.erb +19 -29
  97. data/app/views/decidim/action_delegator/verifications/delegations_verifier/authorizations/new.html.erb +42 -40
  98. data/config/assets.rb +3 -36
  99. data/config/i18n-tasks.yml +27 -5
  100. data/config/locales/ca.yml +103 -146
  101. data/config/locales/cs.yml +161 -145
  102. data/config/locales/en.yml +110 -75
  103. data/config/locales/es.yml +108 -154
  104. data/db/migrate/20200824113801_create_settings.rb +1 -1
  105. data/db/migrate/20250729104037_add_title_to_action_delegator_settings.rb +31 -0
  106. data/lib/decidim/action_delegator/admin_engine.rb +72 -45
  107. data/lib/decidim/action_delegator/common_rake.rb +13 -0
  108. data/lib/decidim/action_delegator/engine.rb +48 -19
  109. data/lib/decidim/action_delegator/test/delegation_examples.rb +144 -0
  110. data/lib/decidim/action_delegator/test/factories.rb +11 -6
  111. data/lib/decidim/action_delegator/verifications/delegations_authorizer.rb +80 -47
  112. data/lib/decidim/action_delegator/version.rb +3 -3
  113. data/lib/decidim/action_delegator.rb +8 -26
  114. data/lib/tasks/migrate_consultations.rake +382 -0
  115. data/lib/tasks/upgrade_tasks.rake +5 -0
  116. data/package.json +10 -27
  117. metadata +72 -122
  118. data/app/commands/concerns/decidim/action_delegator/consultations/multiple_vote_question_override.rb +0 -31
  119. data/app/commands/concerns/decidim/action_delegator/consultations/vote_question_override.rb +0 -44
  120. data/app/commands/decidim/action_delegator/admin/fix_resource_permissions.rb +0 -46
  121. data/app/commands/decidim/action_delegator/vote_delegation.rb +0 -28
  122. data/app/controllers/concerns/decidim/action_delegator/consultations/consultations_controller_override.rb +0 -16
  123. data/app/controllers/concerns/decidim/action_delegator/consultations/question_multiple_votes_controller_override.rb +0 -29
  124. data/app/controllers/concerns/decidim/action_delegator/consultations/question_votes_controller_override.rb +0 -57
  125. data/app/controllers/concerns/decidim/action_delegator/consultations/questions_controller_override.rb +0 -16
  126. data/app/controllers/concerns/decidim/action_delegator/needs_consultation_styles.rb +0 -24
  127. data/app/controllers/decidim/action_delegator/admin/consultations/exports_controller.rb +0 -27
  128. data/app/controllers/decidim/action_delegator/admin/consultations_controller.rb +0 -47
  129. data/app/controllers/decidim/action_delegator/admin/exports/_sum_of_weights_controller.rb +0 -15
  130. data/app/controllers/decidim/action_delegator/questions_summary_controller.rb +0 -14
  131. data/app/forms/concerns/decidim/action_delegator/consultations/vote_form_override.rb +0 -15
  132. data/app/helpers/decidim/action_delegator/delegation_helper.rb +0 -13
  133. data/app/jobs/decidim/action_delegator/export_consultation_results_job.rb +0 -51
  134. data/app/models/concerns/decidim/action_delegator/consultations/question_override.rb +0 -36
  135. data/app/models/concerns/decidim/action_delegator/consultations/vote_override.rb +0 -15
  136. data/app/models/decidim/action_delegator/unversioned_vote.rb +0 -19
  137. data/app/models/decidim/action_delegator/whodunnit_vote.rb +0 -28
  138. data/app/overrides/decidim/consultations/admin/consultations/results/add_ongoing_warning.html.erb.deface +0 -3
  139. data/app/overrides/decidim/consultations/consultations/_question/add_delegation_link.html.erb.deface +0 -3
  140. data/app/overrides/decidim/consultations/consultations/_question/replace_vote_info.html.erb.deface +0 -4
  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/_results/replace_results.html.erb.deface +0 -3
  145. data/app/overrides/decidim/consultations/questions/_vote_button/add_delegations_link.html.erb.deface +0 -3
  146. data/app/overrides/decidim/consultations/questions/_vote_button/add_modal.html.erb.deface +0 -3
  147. data/app/overrides/decidim/consultations/questions/_vote_button/add_modal_javascript.html.erb.deface +0 -3
  148. data/app/overrides/decidim/consultations/questions/_vote_button/replace_delegation_to_multivote_link.html.erb.deface +0 -8
  149. data/app/overrides/decidim/consultations/questions/_vote_modal/add_delegation_callout.html.erb.deface +0 -3
  150. data/app/overrides/decidim/consultations/questions/_vote_modal_confirm/add_delegation_callout.html.erb.deface +0 -3
  151. data/app/overrides/decidim/consultations/questions/_vote_modal_confirm/add_hidden_field.html.erb.deface +0 -3
  152. data/app/overrides/layouts/decidim/_consultation_header/add_consultation_callout.html.erb.deface +0 -9
  153. data/app/overrides/layouts/decidim/_question_header/add_consultation_callout.html.erb.deface +0 -9
  154. data/app/overrides/layouts/decidim/admin/remove_deprecation.rb +0 -10
  155. data/app/packs/entrypoints/decidim_action_delegator.scss +0 -1
  156. data/app/packs/entrypoints/decidim_action_delegator_questions.js +0 -5
  157. data/app/packs/entrypoints/decidim_action_delegator_questions_summary.js +0 -1
  158. data/app/packs/src/decidim/action_delegator/questions.js +0 -33
  159. data/app/packs/src/decidim/action_delegator/summary.js +0 -24
  160. data/app/packs/stylesheets/decidim/action_delegator/questions.scss +0 -26
  161. data/app/permissions/concerns/decidim/action_delegator/consultations/permissions_override.rb +0 -35
  162. data/app/presenters/decidim/action_delegator/question_with_totals.rb +0 -24
  163. data/app/queries/decidim/action_delegator/consultation_delegations.rb +0 -25
  164. data/app/queries/decidim/action_delegator/delegates_votes_by_consultation.rb +0 -24
  165. data/app/queries/decidim/action_delegator/delegates_votes_by_question.rb +0 -26
  166. data/app/queries/decidim/action_delegator/delegation_votes.rb +0 -30
  167. data/app/queries/decidim/action_delegator/grantee_delegations.rb +0 -24
  168. data/app/queries/decidim/action_delegator/organization_delegations.rb +0 -26
  169. data/app/queries/decidim/action_delegator/organization_settings.rb +0 -31
  170. data/app/queries/decidim/action_delegator/responses.rb +0 -24
  171. data/app/queries/decidim/action_delegator/responses_by_membership.rb +0 -58
  172. data/app/queries/decidim/action_delegator/scrutiny.rb +0 -87
  173. data/app/queries/decidim/action_delegator/setting_delegations.rb +0 -19
  174. data/app/queries/decidim/action_delegator/sum_of_membership_weight.rb +0 -44
  175. data/app/queries/decidim/action_delegator/sum_of_weights.rb +0 -25
  176. data/app/queries/decidim/action_delegator/type_and_weight.rb +0 -26
  177. data/app/queries/decidim/action_delegator/voted_with_ponderations.rb +0 -30
  178. data/app/queries/decidim/action_delegator/votes_count_aggregation.rb +0 -34
  179. data/app/serializers/decidim/action_delegator/consultation_results_serializer.rb +0 -19
  180. data/app/views/decidim/action_delegator/admin/consultations/_ongoing_consultation_warning.html.erb +0 -3
  181. data/app/views/decidim/action_delegator/admin/consultations/results.html.erb +0 -65
  182. data/app/views/decidim/action_delegator/admin/consultations/weighted_results.html.erb +0 -66
  183. data/app/views/decidim/action_delegator/consultations/_link_to_question.html.erb +0 -11
  184. data/app/views/decidim/action_delegator/consultations/_link_with_results.html.erb +0 -11
  185. data/app/views/decidim/action_delegator/consultations/questions/_callout.html.erb +0 -5
  186. data/app/views/decidim/action_delegator/consultations/questions/_delegations_modal.html.erb +0 -34
  187. data/app/views/decidim/action_delegator/consultations/questions/_link_to_delegations.html.erb +0 -15
  188. data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_active.html.erb +0 -32
  189. data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_finished.html.erb +0 -9
  190. data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_upcoming.html.erb +0 -8
  191. data/app/views/decidim/action_delegator/consultations/questions/_weight_results.html.erb +0 -8
  192. data/app/views/decidim/consultations/question_votes/_callout.html.erb +0 -47
  193. data/app/views/decidim/consultations/question_votes/update_vote_button.js.erb +0 -82
  194. data/lib/tasks/import_direct_verification.rake +0 -30
@@ -23,53 +23,75 @@ module Decidim
23
23
  delete :destroy_all, on: :collection
24
24
  end
25
25
  resources :manage_delegations, only: [:new, :create]
26
- resources :permissions, only: [:create] do
26
+ resources :permissions do
27
27
  post :sync, on: :collection
28
28
  end
29
29
  end
30
30
 
31
- resources :consultations, param: :slug, only: [] do
31
+ # TODO: replace with real implementation once results pages for elections are ready
32
+ resources :elections, param: :slug, only: [] do
32
33
  get :results, on: :member
33
- get :weighted_results, on: :member
34
- resources :exports, only: :create, module: :consultations
34
+ # get :weighted_results, on: :member
35
+ # resources :exports, only: :create, module: :elections
35
36
 
36
- namespace :exports do
37
- resources :sum_of_weights, only: :create
38
- end
37
+ # namespace :exports do
38
+ # resources :sum_of_weights, only: :create
39
+ # end
39
40
  end
40
41
 
41
42
  root to: "delegations#index"
42
43
  end
43
44
 
44
- # marks the main "Users" menu in the admin always active when we are in the action_delegator admin space
45
- initializer "decidim_admin_action_delegator.main_menu" do
46
- Decidim.menu :admin_menu do |menu|
47
- if (item = menu.items.find { |it| it.identifier == :impersonatable_users })
48
- item.active.first << "decidim/action_delegator/admin/settings"
49
- item.active.first << "decidim/action_delegator/admin/ponderations"
50
- item.active.first << "decidim/action_delegator/admin/participants"
51
- item.active.first << "decidim/action_delegator/admin/manage_participants"
52
- item.active.first << "decidim/action_delegator/admin/delegations"
53
- item.active.first << "decidim/action_delegator/admin/manage_delegations"
54
- end
55
- end
56
- end
57
-
58
45
  initializer "decidim_admin_action_delegator.admin_user_menu" do
59
46
  Decidim.menu :admin_user_menu do |menu|
60
47
  menu.add_item :action_delegator,
61
48
  I18n.t("menu.delegations", scope: "decidim.action_delegator.admin"), decidim_admin_action_delegator.settings_path,
62
49
  active: is_active_link?(decidim_admin_action_delegator.settings_path),
50
+ icon_name: "government-line",
63
51
  if: allowed_to?(:index, :impersonatable_user)
64
52
  end
65
53
  end
66
54
 
67
- initializer "decidim_admin_action_delegator.admin_consultation_menu" do
68
- Decidim.menu :admin_consultation_menu do |menu|
69
- menu.remove_item :results_consultation
70
- is_results = is_active_link?(decidim_admin_consultations.results_consultation_path(current_consultation)) ||
71
- is_active_link?(decidim_admin_action_delegator.results_consultation_path(current_consultation)) ||
72
- is_active_link?(decidim_admin_action_delegator.weighted_results_consultation_path(current_consultation))
55
+ initializer "decidim_elections_admin.menu" do
56
+ Decidim.menu :admin_action_delegator_menu do |menu|
57
+ menu.add_item :setting_main,
58
+ I18n.t("main", scope: "decidim.action_delegator.admin.menu.action_delegator_menu"),
59
+ current_setting ? decidim_admin_action_delegator.edit_setting_path(current_setting) : decidim_admin_action_delegator.new_setting_path,
60
+ icon_name: "bill-line",
61
+ active: is_active_link?(decidim_admin_action_delegator.new_setting_path) ||
62
+ (current_setting && is_active_link?(decidim_admin_action_delegator.edit_setting_path(current_setting)))
63
+
64
+ menu.add_item :setting_ponderations,
65
+ I18n.t("ponderations", scope: "decidim.action_delegator.admin.menu.action_delegator_menu"),
66
+ current_setting ? decidim_admin_action_delegator.setting_ponderations_path(current_setting) : "#",
67
+ icon_name: "scales-line",
68
+ active: current_setting && is_active_link?(decidim_admin_action_delegator.setting_ponderations_path(current_setting))
69
+
70
+ menu.add_item :setting_participants,
71
+ I18n.t("participants", scope: "decidim.action_delegator.admin.menu.action_delegator_menu"),
72
+ current_setting ? decidim_admin_action_delegator.setting_participants_path(current_setting) : "#",
73
+ icon_name: "group-line",
74
+ active: current_setting && (is_active_link?(decidim_admin_action_delegator.setting_participants_path(current_setting)) ||
75
+ is_active_link?(decidim_admin_action_delegator.new_setting_participant_path(current_setting)) ||
76
+ is_active_link?(decidim_admin_action_delegator.new_setting_manage_participant_path(current_setting)) ||
77
+ (@participant && is_active_link?(decidim_admin_action_delegator.edit_setting_participant_path(current_setting, @participant))))
78
+
79
+ menu.add_item :setting_delegations,
80
+ I18n.t("delegations", scope: "decidim.action_delegator.admin.menu.action_delegator_menu"),
81
+ current_setting ? decidim_admin_action_delegator.setting_delegations_path(current_setting) : "#",
82
+ icon_name: "user-shared-line",
83
+ active: current_setting && (is_active_link?(decidim_admin_action_delegator.setting_delegations_path(current_setting)) ||
84
+ is_active_link?(decidim_admin_action_delegator.new_setting_delegation_path(current_setting)) ||
85
+ is_active_link?(decidim_admin_action_delegator.new_setting_manage_delegation_path(current_setting)))
86
+ end
87
+ end
88
+
89
+ initializer "decidim_admin_action_delegator.admin_election_menu" do
90
+ Decidim.menu :admin_election_menu do |menu|
91
+ menu.remove_item :results_election
92
+ is_results = is_active_link?(decidim_admin_elections.results_election_path(current_election)) ||
93
+ is_active_link?(decidim_admin_action_delegator.results_election_path(current_election)) ||
94
+ is_active_link?(decidim_admin_action_delegator.weighted_results_election_path(current_election))
73
95
  params = {
74
96
  position: 1.2,
75
97
  active: is_results,
@@ -77,32 +99,37 @@ module Decidim
77
99
  }
78
100
  params[:submenu] = { target_menu: :admin_delegation_results_submenu } if is_results
79
101
  menu.add_item :delegated_results,
80
- I18n.t("results", scope: "decidim.admin.menu.consultations_submenu"),
81
- decidim_admin_consultations.results_consultation_path(current_consultation),
102
+ I18n.t("results", scope: "decidim.admin.menu.elections_submenu"),
103
+ decidim_admin_elections.results_election_path(current_election),
82
104
  params
83
105
  end
84
106
  end
85
107
 
86
- initializer "decidim_admin_action_delegator.admin_consultation_menu" do
108
+ initializer "decidim_admin_action_delegator.admin_election_menu" do
87
109
  Decidim.menu :admin_delegation_results_submenu do |menu|
110
+ election = @election
111
+ current_component_admin_proxy = election ? Decidim::EngineRouter.admin_proxy(election.component) : nil
112
+
88
113
  menu.add_item :by_answer,
89
- I18n.t("by_answer", scope: "decidim.action_delegator.admin.menu.consultations_submenu"),
90
- decidim_admin_consultations.results_consultation_path(current_consultation),
91
- position: 1.0,
92
- active: is_active_link?(decidim_admin_consultations.results_consultation_path(current_consultation)),
93
- if: allowed_to?(:read, :question)
114
+ I18n.t("by_answer", scope: "decidim.action_delegator.admin.menu.elections_submenu"),
115
+ @election.present? && @election.census_ready? ? current_component_admin_proxy&.dashboard_election_path(@election) : "#",
116
+ icon_name: "list-check",
117
+ active: :exact
94
118
  menu.add_item :by_type_and_weight,
95
- I18n.t("by_type_and_weight", scope: "decidim.action_delegator.admin.menu.consultations_submenu"),
96
- decidim_admin_action_delegator.results_consultation_path(current_consultation),
97
- position: 1.1,
98
- active: is_active_link?(decidim_admin_action_delegator.results_consultation_path(current_consultation), :exact),
99
- if: allowed_to?(:read, :question)
119
+ I18n.t("by_type_and_weight", scope: "decidim.action_delegator.admin.menu.elections_submenu"),
120
+ @election.present? && @election.census_ready? ? current_component_admin_proxy&.dashboard_election_path(@election, results: :by_type_and_weight) : "#",
121
+ icon_name: "list-check-2",
122
+ active: :exact
100
123
  menu.add_item :sum_of_weights,
101
- I18n.t("sum_of_weights", scope: "decidim.action_delegator.admin.menu.consultations_submenu"),
102
- decidim_admin_action_delegator.weighted_results_consultation_path(current_consultation),
103
- position: 1.2,
104
- active: is_active_link?(decidim_admin_action_delegator.weighted_results_consultation_path(current_consultation)),
105
- if: allowed_to?(:read, :question)
124
+ I18n.t("sum_of_weights", scope: "decidim.action_delegator.admin.menu.elections_submenu"),
125
+ @election.present? && @election.census_ready? ? current_component_admin_proxy&.dashboard_election_path(@election, results: :sum_of_weights) : "#",
126
+ icon_name: "bar-chart-2-line",
127
+ active: :exact
128
+ menu.add_item :totals,
129
+ I18n.t("totals", scope: "decidim.action_delegator.admin.menu.elections_submenu"),
130
+ @election.present? && @election.census_ready? ? current_component_admin_proxy&.dashboard_election_path(@election, results: :totals) : "#",
131
+ icon_name: "scales-line",
132
+ active: :exact
106
133
  end
107
134
  end
108
135
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "decidim/dev"
6
+ # require "parallel_tests/tasks"
7
+
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.rspec_opts = "--format progress --format RspecJunitFormatter -o ~/rspec/rspec.xml" if ENV["CI"]
10
+ end
11
+ task default: [:spec]
12
+
13
+ Decidim::Dev.install_tasks
@@ -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,34 +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
28
  resources :user_delegations, controller: :user_delegations, only: [:index]
20
29
  root to: "user_delegations#index"
21
30
  end
22
- resources :questions_summary, param: :slug, only: [:show]
23
- end
24
-
25
- config.to_prepare do
26
- # override votes questions
27
- Decidim::Consultations::Question.include(Decidim::ActionDelegator::Consultations::QuestionOverride)
28
- Decidim::Consultations::VoteQuestion.include(Decidim::ActionDelegator::Consultations::VoteQuestionOverride)
29
- Decidim::Consultations::MultipleVoteQuestion.include(Decidim::ActionDelegator::Consultations::MultipleVoteQuestionOverride)
30
- Decidim::Consultations::VoteForm.include(Decidim::ActionDelegator::Consultations::VoteFormOverride)
31
- Decidim::Consultations::MultiVoteForm.include(Decidim::ActionDelegator::Consultations::VoteFormOverride)
32
- Decidim::Consultations::Vote.include(Decidim::ActionDelegator::Consultations::VoteOverride)
33
- Decidim::Consultations::Permissions.include(Decidim::ActionDelegator::Consultations::PermissionsOverride)
34
31
  end
35
32
 
36
33
  initializer "decidim_action_delegator.overrides", after: "decidim.action_controller" do
37
34
  config.to_prepare do
38
35
  Decidim::Devise::SessionsController.include(Decidim::ActionDelegator::Devise::SessionsControllerOverride)
39
- Decidim::Consultations::QuestionVotesController.include(Decidim::ActionDelegator::Consultations::QuestionVotesControllerOverride)
40
- Decidim::Consultations::QuestionsController.include(Decidim::ActionDelegator::Consultations::QuestionsControllerOverride)
41
- Decidim::Consultations::ConsultationsController.include(Decidim::ActionDelegator::Consultations::ConsultationsControllerOverride)
42
- 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
43
42
  end
44
43
  end
45
44
 
@@ -51,6 +50,13 @@ module Decidim
51
50
  workflow.engine = Decidim::ActionDelegator::Verifications::DelegationsVerifier::Engine
52
51
  workflow.expires_in = Decidim::ActionDelegator.authorization_expiration_time
53
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
54
60
  end
55
61
  end
56
62
 
@@ -58,7 +64,7 @@ module Decidim
58
64
  Decidim.register_assets_path File.expand_path("app/packs", root)
59
65
  end
60
66
 
61
- initializer "decidim.user_menu" do
67
+ initializer "decidim_action_delegator.user_menu" do
62
68
  Decidim.menu :user_menu do |menu|
63
69
  menu.add_item :vote_delegations,
64
70
  t("vote_delegations", scope: "layouts.decidim.user_profile"),
@@ -67,6 +73,29 @@ module Decidim
67
73
  active: :exact
68
74
  end
69
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
70
99
  end
71
100
  end
72
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.2"
7
- DECIDIM_VERSION = "0.27.6"
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