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.
- checksums.yaml +4 -4
- data/README.md +104 -58
- data/Rakefile +2 -2
- data/app/commands/decidim/action_delegator/admin/create_delegation.rb +1 -3
- data/app/commands/decidim/action_delegator/admin/create_setting.rb +5 -2
- data/app/commands/decidim/action_delegator/admin/update_setting.rb +4 -2
- data/app/controllers/concerns/decidim/action_delegator/devise/sessions_controller_override.rb +1 -1
- data/app/controllers/concerns/decidim/action_delegator/election_per_question_votes_controller_override.rb +65 -0
- data/app/controllers/concerns/decidim/action_delegator/election_votes_controller_override.rb +38 -0
- data/app/controllers/concerns/decidim/action_delegator/votes_controller_methods.rb +46 -0
- data/app/controllers/decidim/action_delegator/admin/application_controller.rb +11 -5
- data/app/controllers/decidim/action_delegator/admin/delegations_controller.rb +3 -11
- data/app/controllers/decidim/action_delegator/admin/invite_participants_controller.rb +0 -8
- data/app/controllers/decidim/action_delegator/admin/manage_delegations_controller.rb +13 -21
- data/app/controllers/decidim/action_delegator/admin/manage_participants_controller.rb +11 -20
- data/app/controllers/decidim/action_delegator/admin/participants_controller.rb +1 -9
- data/app/controllers/decidim/action_delegator/admin/permissions_controller.rb +1 -24
- data/app/controllers/decidim/action_delegator/admin/ponderations_controller.rb +0 -8
- data/app/controllers/decidim/action_delegator/admin/settings_controller.rb +12 -12
- data/app/controllers/decidim/action_delegator/application_controller.rb +3 -3
- data/app/controllers/decidim/action_delegator/elections/admin/results_controller.rb +58 -0
- data/app/controllers/decidim/action_delegator/elections/results_controller.rb +36 -0
- data/app/controllers/decidim/action_delegator/user_delegations_controller.rb +1 -1
- data/app/controllers/decidim/action_delegator/verifications/delegations_verifier/authorizations_controller.rb +14 -18
- data/app/forms/decidim/action_delegator/admin/action_delegator_census_form.rb +44 -0
- data/app/forms/decidim/action_delegator/admin/csv_import_form.rb +17 -0
- data/app/forms/decidim/action_delegator/admin/delegation_form.rb +6 -2
- data/app/forms/decidim/action_delegator/admin/ponderation_form.rb +2 -1
- data/app/forms/decidim/action_delegator/admin/setting_form.rb +16 -10
- data/app/forms/decidim/action_delegator/censuses/internal_users_form.rb +32 -0
- data/app/forms/decidim/action_delegator/verifications/delegations_verifier_form.rb +41 -25
- data/app/helpers/decidim/action_delegator/admin/{delegation_helper.rb → settings_helper.rb} +3 -16
- data/app/helpers/decidim/action_delegator/settings_helper.rb +124 -0
- data/app/jobs/decidim/action_delegator/admin/invite_participants_job.rb +1 -1
- data/app/jobs/decidim/action_delegator/send_sms_job.rb +2 -2
- data/app/jobs/decidim/action_delegator/twilio_send_sms_job.rb +2 -2
- data/app/models/decidim/action_delegator/delegation.rb +35 -9
- data/app/models/decidim/action_delegator/participant.rb +15 -9
- data/app/models/decidim/action_delegator/ponderation.rb +0 -2
- data/app/models/decidim/action_delegator/setting.rb +14 -32
- data/app/overrides/decidim/elections/admin/dashboard/_results/_add_results_contents.html.erb.deface +10 -0
- data/app/overrides/decidim/elections/admin/dashboard/_results/_add_results_tabs.html.erb.deface +3 -0
- data/app/overrides/decidim/elections/elections/_election_aside/add_delegation_buttons.html.erb.deface +3 -0
- data/app/overrides/decidim/elections/elections/_vote_results/replace_results_div.html.erb.deface +8 -0
- data/app/overrides/decidim/elections/per_question_votes/show/add_delegation_hidden_input.html.erb.deface +3 -0
- data/app/overrides/decidim/elections/per_question_votes/show/add_delegation_id_to_links.html.erb.deface +3 -0
- data/app/overrides/decidim/elections/per_question_votes/waiting/add_delegation_buttons.html.erb.deface +3 -0
- data/app/overrides/decidim/elections/votes/receipt/add_delegation_buttons.html.erb.deface +3 -0
- data/app/packs/entrypoints/decidim_action_delegator_elections.js +1 -0
- data/app/packs/src/decidim/action_delegator/elections_live_results.js +160 -0
- data/app/permissions/decidim/action_delegator/admin/permissions.rb +29 -0
- data/app/permissions/decidim/action_delegator/permissions.rb +6 -30
- data/app/presenters/decidim/action_delegator/setting_presenter.rb +33 -0
- data/app/queries/decidim/action_delegator/action_delegator_census_users.rb +51 -0
- data/app/queries/decidim/action_delegator/authorized_resources.rb +28 -0
- data/app/queries/decidim/action_delegator/election_settings.rb +23 -0
- data/app/queries/decidim/action_delegator/{delegated_votes_versions.rb → elections_delegated_votes_versions.rb} +8 -8
- data/app/queries/decidim/action_delegator/elections_question_responses_by_type.rb +33 -0
- data/app/queries/decidim/action_delegator/elections_question_weighted_responses.rb +28 -0
- data/app/queries/decidim/action_delegator/elections_votes_with_ponderations.rb +62 -0
- data/app/services/decidim/action_delegator/delegations_csv_importer.rb +3 -3
- data/app/services/decidim/action_delegator/participants_csv_importer.rb +1 -1
- data/app/services/decidim/action_delegator/sms_gateway.rb +2 -2
- data/app/views/decidim/action_delegator/admin/censuses/_action_delegator_census_form.html.erb +44 -0
- data/app/views/decidim/action_delegator/admin/censuses/_action_delegator_census_options_form.html.erb +25 -0
- data/app/views/decidim/action_delegator/admin/delegations/index.html.erb +12 -13
- data/app/views/decidim/action_delegator/admin/delegations/new.html.erb +29 -27
- data/app/views/decidim/action_delegator/admin/manage_delegations/new.html.erb +36 -24
- data/app/views/decidim/action_delegator/admin/manage_participants/new.html.erb +47 -33
- data/app/views/decidim/action_delegator/admin/participants/_form.html.erb +14 -8
- data/app/views/decidim/action_delegator/admin/participants/edit.html.erb +11 -13
- data/app/views/decidim/action_delegator/admin/participants/index.html.erb +20 -25
- data/app/views/decidim/action_delegator/admin/participants/new.html.erb +11 -13
- data/app/views/decidim/action_delegator/admin/ponderations/_form.html.erb +13 -7
- data/app/views/decidim/action_delegator/admin/ponderations/edit.html.erb +11 -13
- data/app/views/decidim/action_delegator/admin/ponderations/index.html.erb +8 -11
- data/app/views/decidim/action_delegator/admin/ponderations/new.html.erb +11 -13
- data/app/views/decidim/action_delegator/admin/settings/_form.html.erb +26 -12
- data/app/views/decidim/action_delegator/admin/settings/_participants_sync_check.html.erb +1 -1
- data/app/views/decidim/action_delegator/admin/settings/_setting_checks.html.erb +11 -16
- data/app/views/decidim/action_delegator/admin/settings/edit.html.erb +11 -12
- data/app/views/decidim/action_delegator/admin/settings/index.html.erb +22 -19
- data/app/views/decidim/action_delegator/admin/settings/new.html.erb +11 -12
- data/app/views/decidim/action_delegator/admin/shared/_tabs_menu.html.erb +15 -0
- data/app/views/decidim/action_delegator/censuses/_internal_users_form.html.erb +61 -0
- data/app/views/decidim/action_delegator/elections/_delegation_buttons.html.erb +10 -0
- data/app/views/decidim/action_delegator/elections/_normal_election_buttons.html.erb +13 -0
- data/app/views/decidim/action_delegator/elections/_per_question_buttons.html.erb +9 -0
- data/app/views/decidim/action_delegator/elections/_per_question_waiting_buttons.html.erb +19 -0
- data/app/views/decidim/action_delegator/elections/_vote_results.html.erb +10 -0
- data/app/views/decidim/action_delegator/elections/_vote_results_question.html.erb +13 -0
- data/app/views/decidim/action_delegator/elections/admin/dashboard/_by_type_and_weight.html.erb +45 -0
- data/app/views/decidim/action_delegator/elections/admin/dashboard/_results_tabs.html.erb +5 -0
- data/app/views/decidim/action_delegator/elections/admin/dashboard/_results_type_info.html.erb +4 -0
- data/app/views/decidim/action_delegator/elections/admin/dashboard/_sum_of_weights.html.erb +43 -0
- data/app/views/decidim/action_delegator/elections/admin/dashboard/_totals.html.erb +27 -0
- data/app/views/decidim/action_delegator/user_delegations/index.html.erb +13 -14
- data/app/views/decidim/action_delegator/verifications/delegations_verifier/authorizations/edit.html.erb +19 -29
- data/app/views/decidim/action_delegator/verifications/delegations_verifier/authorizations/new.html.erb +42 -40
- data/config/assets.rb +3 -35
- data/config/i18n-tasks.yml +27 -5
- data/config/locales/ca.yml +70 -56
- data/config/locales/cs.yml +161 -145
- data/config/locales/en.yml +110 -67
- data/config/locales/es.yml +70 -56
- data/db/migrate/20200824113801_create_settings.rb +1 -1
- data/db/migrate/20250729104037_add_title_to_action_delegator_settings.rb +31 -0
- data/lib/decidim/action_delegator/admin_engine.rb +72 -45
- data/lib/decidim/action_delegator/common_rake.rb +13 -0
- data/lib/decidim/action_delegator/engine.rb +49 -19
- data/lib/decidim/action_delegator/test/delegation_examples.rb +144 -0
- data/lib/decidim/action_delegator/test/factories.rb +11 -6
- data/lib/decidim/action_delegator/verifications/delegations_authorizer.rb +80 -47
- data/lib/decidim/action_delegator/version.rb +3 -3
- data/lib/decidim/action_delegator.rb +8 -26
- data/lib/tasks/migrate_consultations.rake +382 -0
- data/lib/tasks/upgrade_tasks.rake +5 -0
- data/package.json +10 -27
- metadata +72 -112
- data/app/commands/concerns/decidim/action_delegator/consultations/multiple_vote_question_override.rb +0 -31
- data/app/commands/concerns/decidim/action_delegator/consultations/vote_question_override.rb +0 -44
- data/app/commands/decidim/action_delegator/admin/fix_resource_permissions.rb +0 -46
- data/app/commands/decidim/action_delegator/vote_delegation.rb +0 -28
- data/app/controllers/concerns/decidim/action_delegator/consultations/consultations_controller_override.rb +0 -16
- data/app/controllers/concerns/decidim/action_delegator/consultations/question_multiple_votes_controller_override.rb +0 -29
- data/app/controllers/concerns/decidim/action_delegator/consultations/question_votes_controller_override.rb +0 -57
- data/app/controllers/concerns/decidim/action_delegator/consultations/questions_controller_override.rb +0 -16
- data/app/controllers/concerns/decidim/action_delegator/needs_consultation_styles.rb +0 -24
- data/app/controllers/decidim/action_delegator/admin/consultations/exports_controller.rb +0 -27
- data/app/controllers/decidim/action_delegator/admin/consultations_controller.rb +0 -47
- data/app/controllers/decidim/action_delegator/admin/exports/_sum_of_weights_controller.rb +0 -15
- data/app/forms/concerns/decidim/action_delegator/consultations/vote_form_override.rb +0 -15
- data/app/helpers/decidim/action_delegator/delegation_helper.rb +0 -13
- data/app/jobs/decidim/action_delegator/export_consultation_results_job.rb +0 -51
- data/app/models/concerns/decidim/action_delegator/consultations/question_override.rb +0 -18
- data/app/models/concerns/decidim/action_delegator/consultations/vote_override.rb +0 -15
- data/app/models/decidim/action_delegator/unversioned_vote.rb +0 -19
- data/app/models/decidim/action_delegator/whodunnit_vote.rb +0 -28
- data/app/overrides/decidim/consultations/admin/consultations/results/add_ongoing_warning.html.erb.deface +0 -3
- data/app/overrides/decidim/consultations/consultations/_question/add_delegation_link.html.erb.deface +0 -3
- data/app/overrides/decidim/consultations/consultations/_regular_questions/prevent_empty_questions.html.erb.deface +0 -10
- data/app/overrides/decidim/consultations/consultations/_regular_questions/remove_highlighted_scopes.html.erb.deface +0 -5
- data/app/overrides/decidim/consultations/question_multiple_votes/_form/add_delegation_notice.html.erb.deface +0 -8
- data/app/overrides/decidim/consultations/questions/_vote_button/add_delegations_link.html.erb.deface +0 -3
- data/app/overrides/decidim/consultations/questions/_vote_button/add_modal.html.erb.deface +0 -3
- data/app/overrides/decidim/consultations/questions/_vote_button/add_modal_javascript.html.erb.deface +0 -4
- data/app/overrides/decidim/consultations/questions/_vote_button/replace_delegation_to_multivote_link.html.erb.deface +0 -8
- data/app/overrides/decidim/consultations/questions/_vote_modal/add_delegation_callout.html.erb.deface +0 -3
- data/app/overrides/decidim/consultations/questions/_vote_modal_confirm/add_delegation_callout.html.erb.deface +0 -3
- data/app/overrides/decidim/consultations/questions/_vote_modal_confirm/add_hidden_field.html.erb.deface +0 -3
- data/app/overrides/layouts/decidim/admin/remove_deprecation.rb +0 -10
- data/app/packs/entrypoints/decidim_action_delegator.scss +0 -1
- data/app/packs/entrypoints/decidim_action_delegator_questions.js +0 -5
- data/app/packs/src/decidim/action_delegator/questions.js +0 -33
- data/app/packs/stylesheets/decidim/action_delegator/questions.scss +0 -26
- data/app/permissions/concerns/decidim/action_delegator/consultations/permissions_override.rb +0 -35
- data/app/presenters/decidim/action_delegator/question_with_totals.rb +0 -24
- data/app/queries/decidim/action_delegator/consultation_delegations.rb +0 -25
- data/app/queries/decidim/action_delegator/delegates_votes_by_consultation.rb +0 -24
- data/app/queries/decidim/action_delegator/delegates_votes_by_question.rb +0 -26
- data/app/queries/decidim/action_delegator/delegation_votes.rb +0 -30
- data/app/queries/decidim/action_delegator/grantee_delegations.rb +0 -24
- data/app/queries/decidim/action_delegator/organization_delegations.rb +0 -26
- data/app/queries/decidim/action_delegator/organization_settings.rb +0 -31
- data/app/queries/decidim/action_delegator/responses.rb +0 -24
- data/app/queries/decidim/action_delegator/responses_by_membership.rb +0 -58
- data/app/queries/decidim/action_delegator/scrutiny.rb +0 -87
- data/app/queries/decidim/action_delegator/setting_delegations.rb +0 -19
- data/app/queries/decidim/action_delegator/sum_of_membership_weight.rb +0 -44
- data/app/queries/decidim/action_delegator/sum_of_weights.rb +0 -25
- data/app/queries/decidim/action_delegator/type_and_weight.rb +0 -26
- data/app/queries/decidim/action_delegator/voted_with_ponderations.rb +0 -30
- data/app/queries/decidim/action_delegator/votes_count_aggregation.rb +0 -34
- data/app/serializers/decidim/action_delegator/consultation_results_serializer.rb +0 -19
- data/app/views/decidim/action_delegator/admin/consultations/_ongoing_consultation_warning.html.erb +0 -3
- data/app/views/decidim/action_delegator/admin/consultations/results.html.erb +0 -65
- data/app/views/decidim/action_delegator/admin/consultations/weighted_results.html.erb +0 -66
- data/app/views/decidim/action_delegator/consultations/_link_to_question.html.erb +0 -11
- data/app/views/decidim/action_delegator/consultations/questions/_callout.html.erb +0 -5
- data/app/views/decidim/action_delegator/consultations/questions/_delegations_modal.html.erb +0 -34
- data/app/views/decidim/action_delegator/consultations/questions/_link_to_delegations.html.erb +0 -11
- data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_active.html.erb +0 -32
- data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_finished.html.erb +0 -9
- data/app/views/decidim/action_delegator/consultations/questions/_vote_delegated_upcoming.html.erb +0 -8
- data/app/views/decidim/consultations/question_votes/update_vote_button.js.erb +0 -82
- data/lib/tasks/import_direct_verification.rake +0 -30
@@ -5,15 +5,23 @@ require "securerandom"
|
|
5
5
|
module Decidim
|
6
6
|
module ActionDelegator
|
7
7
|
module Verifications
|
8
|
-
#
|
8
|
+
# This verifier checks if there is some setting in which the participant is required
|
9
|
+
# to verify it's phone (the first active setting will be used for that).
|
10
|
+
# If no setting requires phone verification, it will check if there is some setting
|
11
|
+
# in which the participant is required to verify it's email.
|
12
|
+
# If no setting requires email verification, the user won't be able to proceed.
|
13
|
+
# If there are multiple active settings, the user will be verified for the first one
|
14
|
+
#
|
15
|
+
# Note that the ActionAuthorizer associated with this handler will check the current status
|
16
|
+
# of the settings and delegations regardless of this verification metadata
|
9
17
|
class DelegationsVerifierForm < AuthorizationHandler
|
10
18
|
attribute :email, String
|
11
19
|
attribute :phone, String
|
12
20
|
|
13
|
-
validates :verification_code, :sms_gateway, presence: true
|
21
|
+
validates :verification_code, :sms_gateway, presence: true, if: ->(form) { form.setting&.phone_required? }
|
14
22
|
validates :phone, presence: true, if: ->(form) { form.setting&.phone_required? }
|
15
23
|
validates :email, presence: true, if: ->(form) { form.setting&.email_required? }
|
16
|
-
|
24
|
+
|
17
25
|
validate :user_in_census
|
18
26
|
|
19
27
|
alias user current_user
|
@@ -24,7 +32,7 @@ module Decidim
|
|
24
32
|
|
25
33
|
def unique_id
|
26
34
|
Digest::MD5.hexdigest(
|
27
|
-
"#{setting&.phone_required? ? phone : email}-#{setting&.organization&.id}-#{Digest::MD5.hexdigest(Rails.application.
|
35
|
+
"#{setting&.phone_required? ? phone : email}-#{setting&.organization&.id}-#{Digest::MD5.hexdigest(Rails.application.secret_key_base)}"
|
28
36
|
)
|
29
37
|
end
|
30
38
|
|
@@ -41,10 +49,17 @@ module Decidim
|
|
41
49
|
|
42
50
|
def metadata
|
43
51
|
{
|
44
|
-
phone
|
52
|
+
phone:,
|
53
|
+
setting_ids:
|
45
54
|
}
|
46
55
|
end
|
47
56
|
|
57
|
+
def setting_ids
|
58
|
+
return [] unless current_user
|
59
|
+
|
60
|
+
valid_participants&.map(&:decidim_action_delegator_setting_id)&.uniq || []
|
61
|
+
end
|
62
|
+
|
48
63
|
# The verification metadata to validate in the next step.
|
49
64
|
def verification_metadata
|
50
65
|
{
|
@@ -55,34 +70,43 @@ module Decidim
|
|
55
70
|
|
56
71
|
# currently, we rely on the last setting.
|
57
72
|
# This could be improved by allowing the user to select the setting (or related phone).
|
58
|
-
def
|
59
|
-
@
|
73
|
+
def active_settings
|
74
|
+
@active_settings ||= context[:active_settings]
|
60
75
|
end
|
61
76
|
|
62
|
-
|
63
|
-
|
77
|
+
# find the participant in any of the active settings
|
78
|
+
# If phone is required, just find the first participant and validate the phone
|
79
|
+
# if not, find by email in any of the active settings
|
80
|
+
def participant
|
81
|
+
valid_participants&.first
|
64
82
|
end
|
65
83
|
|
66
|
-
def
|
67
|
-
return unless setting
|
84
|
+
def valid_participants
|
85
|
+
return [] unless setting
|
68
86
|
|
69
|
-
@
|
87
|
+
@valid_participants ||= begin
|
70
88
|
params = {}
|
71
89
|
params[:email] = email if setting.email_required?
|
72
90
|
if setting.phone_required?
|
73
91
|
if phone.blank?
|
74
|
-
@
|
92
|
+
@valid_participants = setting.participants.none
|
75
93
|
else
|
76
|
-
params[:phone] = phone
|
77
94
|
params[:phone] = phone_prefixes.map { |prefix| "#{prefix}#{phone}" }
|
78
95
|
params[:phone] += phone_prefixes.map { |prefix| phone.delete_prefix(prefix).to_s }
|
79
96
|
end
|
80
97
|
end
|
81
98
|
|
82
|
-
setting.participants.
|
99
|
+
setting.participants.where(params)
|
83
100
|
end
|
84
101
|
end
|
85
102
|
|
103
|
+
# find the first setting where phone is required or, if not, the first setting where email is required
|
104
|
+
# This works because the email is unique per user so it does not matter which setting we use to find the participant
|
105
|
+
# If the setting requires phone, only one active setting with phone verification is allowed to exist at a time
|
106
|
+
def setting
|
107
|
+
@setting ||= active_settings&.phone_required&.first || active_settings&.email_required&.first
|
108
|
+
end
|
109
|
+
|
86
110
|
private
|
87
111
|
|
88
112
|
def phone_prefixes
|
@@ -95,16 +119,8 @@ module Decidim
|
|
95
119
|
return if errors.any?
|
96
120
|
return if participant
|
97
121
|
|
98
|
-
errors.add(:phone, :phone_not_found) if setting
|
99
|
-
errors.add(:email, :email_not_found) if setting
|
100
|
-
end
|
101
|
-
|
102
|
-
def setting_exists
|
103
|
-
return if errors.any?
|
104
|
-
return if setting
|
105
|
-
|
106
|
-
errors.add(:phone, :invalid)
|
107
|
-
errors.add(:email, :invalid)
|
122
|
+
errors.add(:phone, :phone_not_found) if setting&.phone_required?
|
123
|
+
errors.add(:email, :email_not_found) if setting&.email_required?
|
108
124
|
end
|
109
125
|
|
110
126
|
def verification_code
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Decidim
|
4
4
|
module ActionDelegator
|
5
5
|
module Admin
|
6
|
-
module
|
6
|
+
module SettingsHelper
|
7
7
|
def granters_for_select
|
8
8
|
current_organization.users
|
9
9
|
end
|
@@ -12,31 +12,18 @@ module Decidim
|
|
12
12
|
current_organization.users
|
13
13
|
end
|
14
14
|
|
15
|
-
def consultations_for_select
|
16
|
-
organization_consultations.map { |consultation| [translated_attribute(consultation.title), consultation.id] }
|
17
|
-
end
|
18
|
-
|
19
15
|
def ponderations_for_select(setting)
|
20
16
|
setting.ponderations.map { |ponderation| [ponderation.title, ponderation.id] }
|
21
17
|
end
|
22
18
|
|
23
|
-
def organization_consultations
|
24
|
-
Decidim::Consultations::OrganizationConsultations.new(current_organization).query
|
25
|
-
end
|
26
|
-
|
27
|
-
def missing_verifications_for(resources, action)
|
28
|
-
resources.where.not(id: Decidim::ResourcePermission.select(:resource_id)
|
29
|
-
.where(resource: resources)
|
30
|
-
.where(Arel.sql("permissions->'#{action}'->'authorization_handlers'->>'delegations_verifier' IS NOT NULL")))
|
31
|
-
end
|
32
|
-
|
33
19
|
def missing_decidim_users(participants)
|
34
20
|
participants.where(decidim_user: nil).or(participants.where.not(decidim_user: current_organization.users)).where.not(id: missing_registered_users(participants))
|
35
21
|
end
|
36
22
|
|
23
|
+
# TODO: need to check
|
37
24
|
def missing_registered_users(participants)
|
38
25
|
participants.where.not(email: current_organization.users.select(:email))
|
39
|
-
.where.not("MD5(CONCAT(phone,'-'
|
26
|
+
.where.not("MD5(CONCAT(phone, '-', CAST(? AS text), '-', CAST(? AS text))) IN (?)",
|
40
27
|
current_organization.id,
|
41
28
|
Digest::MD5.hexdigest(Rails.application.secret_key_base),
|
42
29
|
Authorization.select(:unique_id).where.not(unique_id: nil))
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ActionDelegator
|
5
|
+
module SettingsHelper
|
6
|
+
include ActionView::Helpers::NumberHelper
|
7
|
+
|
8
|
+
def current_resource_settings
|
9
|
+
@current_resource_settings ||= if defined?(election) && election.present?
|
10
|
+
settings_for(election)
|
11
|
+
elsif @election.present?
|
12
|
+
settings_for(@election)
|
13
|
+
else
|
14
|
+
Decidim::ActionDelegator::Setting.none
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def settings_for(resource)
|
19
|
+
case resource
|
20
|
+
when Decidim::Elections::Election
|
21
|
+
Decidim::ActionDelegator::ElectionSettings.new(resource).query
|
22
|
+
else
|
23
|
+
Decidim::ActionDelegator::Setting.none
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def delegations_for(resource, user)
|
28
|
+
case resource
|
29
|
+
when Decidim::Elections::Election
|
30
|
+
Decidim::ActionDelegator::Delegation.where(
|
31
|
+
setting: settings_for(resource),
|
32
|
+
grantee: user
|
33
|
+
)
|
34
|
+
else
|
35
|
+
Decidim::ActionDelegator::Delegation.none
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def participant_voted?(resource, user)
|
40
|
+
case resource
|
41
|
+
when Decidim::Elections::Election
|
42
|
+
resource.votes.exists?(voter_uid: user.to_global_id.to_s)
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def elections_question_responses_by_type(question)
|
49
|
+
# Use size instead of count since votes are preloaded
|
50
|
+
total_votes = question.votes.size
|
51
|
+
|
52
|
+
ElectionsQuestionResponsesByType.new(question, current_resource_settings).query.map do |option|
|
53
|
+
ponderation ||= Decidim::ActionDelegator::Ponderation.find_by(id: option.ponderation_id)
|
54
|
+
votes_count = option.votes_total || 0
|
55
|
+
votes_count_text = I18n.t("votes_count", scope: "decidim.elections.admin.dashboard.questions_table", count: votes_count)
|
56
|
+
votes_percent = total_votes.positive? ? (option.votes_total.to_f / total_votes) * 100 : 0
|
57
|
+
{
|
58
|
+
id: option.id,
|
59
|
+
body: translated_attribute(option.body),
|
60
|
+
votes_count: votes_count,
|
61
|
+
votes_count_text: votes_count_text,
|
62
|
+
votes_percent: votes_percent,
|
63
|
+
votes_percent_text: number_to_percentage(votes_percent, precision: 1),
|
64
|
+
ponderation_id: ponderation&.id,
|
65
|
+
ponderation_title: ponderation&.title || "-"
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def elections_question_weighted_responses(question)
|
71
|
+
# Use size instead of count since votes are preloaded
|
72
|
+
total_votes = question.votes.size
|
73
|
+
|
74
|
+
question_totals = {}
|
75
|
+
responses = ElectionsQuestionWeightedResponses.new(question, current_resource_settings).query.map do |option|
|
76
|
+
question_totals[question.id] ||= 0.0
|
77
|
+
question_totals[question.id] += option.weighted_votes_total.to_f
|
78
|
+
option
|
79
|
+
end
|
80
|
+
|
81
|
+
responses.map do |option|
|
82
|
+
votes_count = option.weighted_votes_total || 0
|
83
|
+
votes_percent = total_votes.positive? ? (option.weighted_votes_total.to_f / question_totals[question.id]) * 100 : 0
|
84
|
+
{
|
85
|
+
id: option.id,
|
86
|
+
question_id: question.id,
|
87
|
+
body: translated_attribute(option.body),
|
88
|
+
votes_count: votes_count,
|
89
|
+
votes_count_text: I18n.t("votes_count", scope: "decidim.elections.admin.dashboard.questions_table", count: votes_count),
|
90
|
+
votes_percent: votes_percent,
|
91
|
+
votes_percent_text: number_to_percentage(votes_percent, precision: 1)
|
92
|
+
}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def elections_question_stats(question)
|
97
|
+
question_totals = {}
|
98
|
+
ElectionsQuestionWeightedResponses.new(question, current_resource_settings).query.each do |option|
|
99
|
+
question_totals[question.id] ||= 0.0
|
100
|
+
question_totals[question.id] += option.weighted_votes_total.to_f
|
101
|
+
end
|
102
|
+
|
103
|
+
# Use preloaded votes association
|
104
|
+
votes = question.votes
|
105
|
+
unweighted_votes = votes.size
|
106
|
+
weighted_votes = question_totals[question.id].to_f.round
|
107
|
+
# Note that this works because votes cannot be edited, only created or destroyed. So only one version will exist per vote (the creation event)
|
108
|
+
delegated_votes = votes.select { |vote| vote.versions.any? { |v| v.decidim_action_delegator_delegation_id.present? } }.size
|
109
|
+
participants = votes.map(&:voter_uid).uniq.size
|
110
|
+
|
111
|
+
{
|
112
|
+
participants: participants,
|
113
|
+
participants_text: I18n.t("participants_count", scope: "decidim.action_delegator.elections.admin.dashboard.questions_table", count: participants),
|
114
|
+
unweighted_votes: unweighted_votes,
|
115
|
+
unweighted_votes_text: I18n.t("votes_count", scope: "decidim.elections.admin.dashboard.questions_table", count: unweighted_votes),
|
116
|
+
weighted_votes: weighted_votes,
|
117
|
+
weighted_votes_text: I18n.t("votes_count", scope: "decidim.elections.admin.dashboard.questions_table", count: weighted_votes),
|
118
|
+
delegated_votes: delegated_votes,
|
119
|
+
delegated_votes_text: I18n.t("votes_count", scope: "decidim.elections.admin.dashboard.questions_table", count: delegated_votes)
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -27,7 +27,7 @@ module Decidim
|
|
27
27
|
def users_list_to_invite
|
28
28
|
@users_list_to_invite ||= @current_setting.participants.where(decidim_user: nil)
|
29
29
|
.where.not(email: @organization.users.select(:email))
|
30
|
-
.where.not("MD5(CONCAT(phone,'-'
|
30
|
+
.where.not("MD5(CONCAT(phone::text, '-', CAST(? AS text), '-', CAST(? AS text))) IN (?)",
|
31
31
|
@organization.id,
|
32
32
|
Digest::MD5.hexdigest(Rails.application.secret_key_base),
|
33
33
|
Authorization.select(:unique_id)
|
@@ -28,8 +28,8 @@ module Decidim
|
|
28
28
|
def send_sms!
|
29
29
|
@response = client.call(:send_sms,
|
30
30
|
message: {
|
31
|
-
user: ENV
|
32
|
-
pass: ENV
|
31
|
+
user: ENV.fetch("SMS_USER", nil),
|
32
|
+
pass: ENV.fetch("SMS_PASS", nil),
|
33
33
|
src: sender,
|
34
34
|
dst: mobile_phone_number,
|
35
35
|
msg: message
|
@@ -16,21 +16,47 @@ module Decidim
|
|
16
16
|
message: I18n.t("delegations.create.error_granter_unique", scope: "decidim.action_delegator.admin")
|
17
17
|
}
|
18
18
|
|
19
|
-
|
19
|
+
validate :grantee_is_not_granter
|
20
|
+
validate :granter_and_grantee_belongs_to_same_organization
|
21
|
+
validate :granter_is_same_organization_as_context
|
22
|
+
|
23
|
+
delegate :resource, to: :setting
|
20
24
|
|
21
25
|
before_destroy { |record| throw(:abort) if record.grantee_voted? }
|
22
26
|
|
23
|
-
def
|
24
|
-
|
27
|
+
def grantee_voted?
|
28
|
+
return false unless grantee && setting
|
29
|
+
|
30
|
+
@grantee_voted ||= PaperTrail::Version.exists?(
|
31
|
+
whodunnit: grantee.id,
|
32
|
+
object_changes: { decidim_action_delegator_delegation_id: id }
|
33
|
+
)
|
25
34
|
end
|
26
35
|
|
27
|
-
|
28
|
-
|
36
|
+
# a safe way to get the user that represents the granter in this setting
|
37
|
+
# it might not exist if the granter is not in the census
|
38
|
+
def user
|
39
|
+
@user ||= setting.participants.find_by(decidim_user: granter)&.decidim_user
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def grantee_is_not_granter
|
45
|
+
return unless granter == grantee
|
46
|
+
|
47
|
+
errors.add(:grantee, :invalid)
|
48
|
+
end
|
49
|
+
|
50
|
+
def granter_and_grantee_belongs_to_same_organization
|
51
|
+
return unless granter.organization != grantee.organization
|
52
|
+
|
53
|
+
errors.add(:grantee, :invalid)
|
54
|
+
end
|
55
|
+
|
56
|
+
def granter_is_same_organization_as_context
|
57
|
+
return unless setting && granter.organization != setting.organization
|
29
58
|
|
30
|
-
|
31
|
-
granter_votes = Decidim::Consultations::Vote.where(author: granter, question: consultation.questions)
|
32
|
-
granter_votes&.detect { |vote| vote.versions.exists?(whodunnit: grantee&.id) } ? true : false
|
33
|
-
end
|
59
|
+
errors.add(:granter, :invalid)
|
34
60
|
end
|
35
61
|
end
|
36
62
|
end
|
@@ -18,13 +18,14 @@ module Decidim
|
|
18
18
|
class_name: "Decidim::User",
|
19
19
|
optional: true
|
20
20
|
|
21
|
-
delegate :consultation, to: :setting
|
22
21
|
delegate :organization, to: :setting
|
23
22
|
|
24
23
|
validates :decidim_user, uniqueness: { scope: :setting }, if: -> { decidim_user.present? }
|
25
24
|
validates :email, uniqueness: { scope: :setting }, if: -> { email.present? }
|
26
25
|
validates :phone, uniqueness: { scope: :setting }, if: -> { phone.present? }
|
27
26
|
|
27
|
+
validate :user_belongs_to_organization
|
28
|
+
|
28
29
|
# sets the decidim user if found
|
29
30
|
before_save :set_decidim_user
|
30
31
|
|
@@ -36,7 +37,7 @@ module Decidim
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def user_from_metadata
|
39
|
-
@user_from_metadata ||= if setting
|
40
|
+
@user_from_metadata ||= if setting&.email_required?
|
40
41
|
Decidim::User.find_by(email: email, organization: setting.organization)
|
41
42
|
else
|
42
43
|
Decidim::Authorization.find_by(unique_id: uniq_ids)&.user
|
@@ -48,7 +49,7 @@ module Decidim
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def self.verifier_ids(seeds)
|
51
|
-
seeds.map { |seed| Digest::MD5.hexdigest("#{seed}-#{Digest::MD5.hexdigest(Rails.application.
|
52
|
+
seeds.map { |seed| Digest::MD5.hexdigest("#{seed}-#{Digest::MD5.hexdigest(Rails.application.secret_key_base)}") }
|
52
53
|
end
|
53
54
|
|
54
55
|
def self.phone_combinations(phones)
|
@@ -80,15 +81,12 @@ module Decidim
|
|
80
81
|
ponderation&.title
|
81
82
|
end
|
82
83
|
|
83
|
-
# checks if the user has voted
|
84
|
+
# checks if the user has voted
|
84
85
|
def voted?
|
85
86
|
return false if user.blank?
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
.where(decidim_consultations_questions: {
|
90
|
-
decidim_consultation_id: setting.consultation.id
|
91
|
-
}, author: user).any?
|
88
|
+
# TODO: Replace vote check once new context is defined
|
89
|
+
false
|
92
90
|
end
|
93
91
|
|
94
92
|
private
|
@@ -96,6 +94,14 @@ module Decidim
|
|
96
94
|
def set_decidim_user
|
97
95
|
self.decidim_user = user_from_metadata if decidim_user.blank?
|
98
96
|
end
|
97
|
+
|
98
|
+
def user_belongs_to_organization
|
99
|
+
return if decidim_user.blank? || setting.blank?
|
100
|
+
|
101
|
+
return if decidim_user.organization == setting.organization
|
102
|
+
|
103
|
+
errors.add(:decidim_user, :invalid)
|
104
|
+
end
|
99
105
|
end
|
100
106
|
end
|
101
107
|
end
|
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module ActionDelegator
|
5
|
-
# Contains the delegation settings of
|
5
|
+
# Contains the delegation settings of an election. Rather than a single attribute here
|
6
6
|
# a setting is the record itself: a bunch of configuration values.
|
7
7
|
class Setting < ApplicationRecord
|
8
8
|
self.table_name = "decidim_action_delegator_settings"
|
9
9
|
|
10
|
-
belongs_to :
|
11
|
-
foreign_key: "
|
12
|
-
class_name: "Decidim::
|
10
|
+
belongs_to :organization,
|
11
|
+
foreign_key: "decidim_organization_id",
|
12
|
+
class_name: "Decidim::Organization"
|
13
13
|
has_many :delegations,
|
14
14
|
inverse_of: :setting,
|
15
15
|
foreign_key: "decidim_action_delegator_setting_id",
|
@@ -28,43 +28,25 @@ module Decidim
|
|
28
28
|
|
29
29
|
validates :max_grants, presence: true
|
30
30
|
validates :max_grants, numericality: { greater_than: 0 }
|
31
|
-
validates :consultation, uniqueness: true
|
32
31
|
|
33
|
-
enum authorization_method:
|
32
|
+
enum :authorization_method, [:phone, :email, :both], prefix: :verify_with
|
34
33
|
|
35
|
-
|
36
|
-
|
34
|
+
scope :active, -> { where(active: true) }
|
35
|
+
scope :phone_required, -> { where(authorization_method: [:phone, :both]) }
|
36
|
+
scope :email_required, -> { where(authorization_method: [:email, :both]) }
|
37
37
|
|
38
38
|
default_scope { order(created_at: :desc) }
|
39
39
|
|
40
|
-
def
|
41
|
-
@state ||= if consultation.end_voting_date < Time.zone.now
|
42
|
-
:closed
|
43
|
-
elsif consultation.start_voting_date <= Time.zone.now
|
44
|
-
:ongoing
|
45
|
-
else
|
46
|
-
:pending
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def ongoing?
|
51
|
-
state == :ongoing
|
52
|
-
end
|
40
|
+
def editable? = active?
|
53
41
|
|
54
|
-
def
|
55
|
-
state != :closed
|
56
|
-
end
|
42
|
+
def destroyable? = participants.empty? && ponderations.empty? && delegations.empty?
|
57
43
|
|
58
|
-
def
|
59
|
-
participants.empty? && ponderations.empty? && delegations.empty?
|
60
|
-
end
|
44
|
+
def phone_required? = verify_with_phone? || verify_with_both?
|
61
45
|
|
62
|
-
def
|
63
|
-
verify_with_phone? || verify_with_both?
|
64
|
-
end
|
46
|
+
def email_required? = verify_with_email? || verify_with_both?
|
65
47
|
|
66
|
-
def
|
67
|
-
|
48
|
+
def presenter
|
49
|
+
Decidim::ActionDelegator::SettingPresenter.new(self)
|
68
50
|
end
|
69
51
|
end
|
70
52
|
end
|
data/app/overrides/decidim/elections/admin/dashboard/_results/_add_results_contents.html.erb.deface
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
<!-- replace "erb[loud]:contains('decidim/elections/admin/dashboard/questions_with_results')" -->
|
2
|
+
|
3
|
+
<%= render "decidim/action_delegator/elections/admin/dashboard/results_type_info" if current_resource_settings.present? %>
|
4
|
+
|
5
|
+
<% if current_resource_settings.present? && lookup_context.exists?("decidim/action_delegator/elections/admin/dashboard/#{params[:results]}", [], true) %>
|
6
|
+
<%= render "decidim/action_delegator/elections/admin/dashboard/#{params[:results]}" %>
|
7
|
+
<% append_javascript_pack_tag("decidim_action_delegator_elections") %>
|
8
|
+
<% else %>
|
9
|
+
<%= render "decidim/elections/admin/dashboard/questions_with_results" %>
|
10
|
+
<% end %>
|
data/app/overrides/decidim/elections/elections/_vote_results/replace_results_div.html.erb.deface
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
<!-- surround "div[data-erb-data-results-live-update]" -->
|
2
|
+
|
3
|
+
<% if current_resource_settings.present? %>
|
4
|
+
<%= render "decidim/action_delegator/elections/vote_results", questions: %>
|
5
|
+
<% append_javascript_pack_tag("decidim_action_delegator_elections") %>
|
6
|
+
<% else %>
|
7
|
+
<%= render_original %>
|
8
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
import "src/decidim/action_delegator/elections_live_results.js";
|