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.
- 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 +2 -10
- 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 -20
- data/app/controllers/decidim/action_delegator/admin/manage_participants_controller.rb +11 -19
- 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/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 +15 -14
- data/app/models/decidim/action_delegator/participant.rb +7 -10
- 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/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 -36
- data/config/i18n-tasks.yml +27 -5
- data/config/locales/ca.yml +103 -146
- data/config/locales/cs.yml +161 -145
- data/config/locales/en.yml +110 -75
- data/config/locales/es.yml +108 -154
- 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 +48 -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 -122
- 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/controllers/decidim/action_delegator/questions_summary_controller.rb +0 -14
- 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 -36
- 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/_question/replace_vote_info.html.erb.deface +0 -4
- 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/_results/replace_results.html.erb.deface +0 -3
- 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 -3
- 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/_consultation_header/add_consultation_callout.html.erb.deface +0 -9
- data/app/overrides/layouts/decidim/_question_header/add_consultation_callout.html.erb.deface +0 -9
- 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/entrypoints/decidim_action_delegator_questions_summary.js +0 -1
- data/app/packs/src/decidim/action_delegator/questions.js +0 -33
- data/app/packs/src/decidim/action_delegator/summary.js +0 -24
- 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/_link_with_results.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 -15
- 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/action_delegator/consultations/questions/_weight_results.html.erb +0 -8
- data/app/views/decidim/consultations/question_votes/_callout.html.erb +0 -47
- data/app/views/decidim/consultations/question_votes/update_vote_button.js.erb +0 -82
- data/lib/tasks/import_direct_verification.rake +0 -30
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
67
|
+
Decidim::ActionDelegator::AdminEngine,
|
86
68
|
at: "/admin/action_delegator"
|
87
69
|
)
|
@@ -0,0 +1,382 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :action_delegator do
|
4
|
+
desc "Migrate old decidim-consultations data to decidim-elections component"
|
5
|
+
task :migrate_consultations, [:component_id, :consultation_id] => :environment do |_task, args|
|
6
|
+
component_id = args[:component_id]
|
7
|
+
consultation_id = args[:consultation_id]
|
8
|
+
|
9
|
+
if component_id.blank?
|
10
|
+
puts "ERROR: component_id is required"
|
11
|
+
puts "Usage: rake action_delegator:migrate_consultations[COMPONENT_ID] or rake action_delegator:migrate_consultations[COMPONENT_ID,CONSULTATION_ID]"
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
component = Decidim::Component.find_by(id: component_id)
|
16
|
+
unless component&.manifest_name == "elections"
|
17
|
+
puts "ERROR: Component ##{component_id} not found or is not an elections component"
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
|
21
|
+
# Define inline models for old consultation tables (module no longer exists in Decidim)
|
22
|
+
module Legacy
|
23
|
+
class Consultation < ApplicationRecord
|
24
|
+
self.table_name = "decidim_consultations"
|
25
|
+
has_many :questions, class_name: "Legacy::Question", foreign_key: :decidim_consultation_id
|
26
|
+
end
|
27
|
+
|
28
|
+
class Question < ApplicationRecord
|
29
|
+
self.table_name = "decidim_consultations_questions"
|
30
|
+
belongs_to :consultation, class_name: "Legacy::Consultation", foreign_key: :decidim_consultation_id
|
31
|
+
has_many :responses, class_name: "Legacy::Response", foreign_key: :decidim_consultations_questions_id
|
32
|
+
has_many :votes, class_name: "Legacy::Vote", foreign_key: :decidim_consultation_question_id
|
33
|
+
end
|
34
|
+
|
35
|
+
class Response < ApplicationRecord
|
36
|
+
self.table_name = "decidim_consultations_responses"
|
37
|
+
belongs_to :question, class_name: "Legacy::Question", foreign_key: :decidim_consultations_questions_id
|
38
|
+
belongs_to :response_group, class_name: "Legacy::ResponseGroup", foreign_key: :decidim_consultations_response_group_id, optional: true
|
39
|
+
end
|
40
|
+
|
41
|
+
class ResponseGroup < ApplicationRecord
|
42
|
+
self.table_name = "decidim_consultations_response_groups"
|
43
|
+
belongs_to :question, class_name: "Legacy::Question", foreign_key: :decidim_consultations_questions_id
|
44
|
+
has_many :responses, class_name: "Legacy::Response", foreign_key: :decidim_consultations_response_group_id
|
45
|
+
end
|
46
|
+
|
47
|
+
class Vote < ApplicationRecord
|
48
|
+
self.table_name = "decidim_consultations_votes"
|
49
|
+
belongs_to :question, class_name: "Legacy::Question", foreign_key: :decidim_consultation_question_id
|
50
|
+
belongs_to :response, class_name: "Legacy::Response", foreign_key: :decidim_consultations_response_id
|
51
|
+
belongs_to :author, class_name: "Decidim::User", foreign_key: :decidim_author_id
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Check if consultations table exists
|
56
|
+
unless ActiveRecord::Base.connection.table_exists?("decidim_consultations")
|
57
|
+
puts "ERROR: decidim_consultations table not found. Make sure you have legacy data to migrate."
|
58
|
+
exit 1
|
59
|
+
end
|
60
|
+
|
61
|
+
# Fetch consultations to migrate
|
62
|
+
consultations = if consultation_id.present?
|
63
|
+
Legacy::Consultation.where(id: consultation_id)
|
64
|
+
else
|
65
|
+
Legacy::Consultation.where(decidim_organization_id: component.organization.id)
|
66
|
+
end
|
67
|
+
|
68
|
+
if consultations.empty?
|
69
|
+
puts "No consultations found"
|
70
|
+
exit 0
|
71
|
+
end
|
72
|
+
|
73
|
+
# Calculate source data statistics
|
74
|
+
source_stats = {
|
75
|
+
consultations: consultations.count,
|
76
|
+
questions: 0,
|
77
|
+
responses: 0,
|
78
|
+
votes: 0
|
79
|
+
}
|
80
|
+
|
81
|
+
consultations.each do |c|
|
82
|
+
source_stats[:questions] += c.questions.count
|
83
|
+
c.questions.each do |q|
|
84
|
+
source_stats[:responses] += q.responses.count
|
85
|
+
source_stats[:votes] += q.votes.count
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
migrated_stats = {
|
90
|
+
elections: 0,
|
91
|
+
questions: 0,
|
92
|
+
responses: 0,
|
93
|
+
votes: 0,
|
94
|
+
skipped_votes: 0,
|
95
|
+
skipped_consultations: 0,
|
96
|
+
errors: []
|
97
|
+
}
|
98
|
+
|
99
|
+
puts "\nStarting migration of #{source_stats[:consultations]} consultations from decidim-consultations to decidim-elections"
|
100
|
+
puts "Component: ##{component.id} - #{component.name}"
|
101
|
+
puts "Consultations:"
|
102
|
+
consultations.each do |c|
|
103
|
+
puts " • ##{c.id} - #{c.title}"
|
104
|
+
end
|
105
|
+
puts "\nSource data summary:"
|
106
|
+
puts "-" * 70
|
107
|
+
puts "TYPE Elections Questions Responses Votes"
|
108
|
+
puts "-" * 70
|
109
|
+
puts format("%-12s %12d %12d %12d %12d", "SOURCE", source_stats[:consultations], source_stats[:questions], source_stats[:responses], source_stats[:votes])
|
110
|
+
puts "-" * 70
|
111
|
+
puts ""
|
112
|
+
unless ENV["CI"].present? || ENV["FORCE_MIGRATION"].to_s.downcase == "true"
|
113
|
+
print "Continue migration? (y/N): "
|
114
|
+
answer = $stdin.gets.chomp.downcase
|
115
|
+
unless answer == "y"
|
116
|
+
puts "Aborted by user."
|
117
|
+
exit 0
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def determine_census_config(consultation, setting)
|
122
|
+
resource_handlers = extract_authorization_handlers(consultation)
|
123
|
+
census_manifest = determine_census_manifest(setting, resource_handlers)
|
124
|
+
authorization_handlers = determine_authorization_handlers(setting, resource_handlers, census_manifest)
|
125
|
+
census_settings = build_census_settings(census_manifest, setting, authorization_handlers)
|
126
|
+
|
127
|
+
[census_manifest, census_settings]
|
128
|
+
end
|
129
|
+
|
130
|
+
def extract_authorization_handlers(consultation)
|
131
|
+
question_ids = consultation.questions.pluck(:id)
|
132
|
+
return [] unless ActiveRecord::Base.connection.table_exists?("decidim_resource_permissions") && question_ids.any?
|
133
|
+
|
134
|
+
handlers = []
|
135
|
+
perms = ActiveRecord::Base.connection.execute(<<-SQL.squish)
|
136
|
+
SELECT permissions FROM decidim_resource_permissions
|
137
|
+
WHERE resource_type = 'Decidim::Consultations::Question'
|
138
|
+
AND resource_id IN (#{question_ids.join(",")})
|
139
|
+
AND permissions::jsonb -> 'vote' -> 'authorization_handlers' IS NOT NULL
|
140
|
+
SQL
|
141
|
+
|
142
|
+
perms.each do |perm|
|
143
|
+
perm_handlers = begin
|
144
|
+
JSON.parse(perm["permissions"])["vote"]["authorization_handlers"].keys
|
145
|
+
rescue StandardError
|
146
|
+
[]
|
147
|
+
end
|
148
|
+
handlers.concat(perm_handlers)
|
149
|
+
end
|
150
|
+
handlers.uniq
|
151
|
+
end
|
152
|
+
|
153
|
+
def determine_census_manifest(setting, resource_handlers)
|
154
|
+
return "action_delegator_census" if setting&.delegations&.any?
|
155
|
+
return "internal_users" if setting&.authorization_method.present? || resource_handlers.any?
|
156
|
+
|
157
|
+
"internal_users"
|
158
|
+
end
|
159
|
+
|
160
|
+
def determine_authorization_handlers(setting, resource_handlers, census_manifest)
|
161
|
+
return [] if census_manifest == "action_delegator_census"
|
162
|
+
return ["delegations_verifier"] if setting&.authorization_method.present?
|
163
|
+
|
164
|
+
resource_handlers
|
165
|
+
end
|
166
|
+
|
167
|
+
def build_census_settings(census_manifest, setting, authorization_handlers)
|
168
|
+
return { "setting_id" => setting.id } if census_manifest == "action_delegator_census" && setting
|
169
|
+
|
170
|
+
return {} if authorization_handlers.empty?
|
171
|
+
|
172
|
+
{
|
173
|
+
authorization_handlers: authorization_handlers.index_with do |handler|
|
174
|
+
handler == "delegations_verifier" && setting ? { "options" => { "setting" => setting.id.to_s } } : { "options" => {} }
|
175
|
+
end
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
def build_question_description(old_question)
|
180
|
+
parts = [old_question.subtitle, old_question.what_is_decided].compact.compact_blank
|
181
|
+
return {} if parts.empty?
|
182
|
+
|
183
|
+
parts_by_locale = parts.each_with_object({}) do |part, result|
|
184
|
+
part.each do |locale, text|
|
185
|
+
result[locale] ||= []
|
186
|
+
result[locale] << text if text.present?
|
187
|
+
end
|
188
|
+
end
|
189
|
+
parts_by_locale.transform_values { |arr| arr.join("\n\n") }
|
190
|
+
end
|
191
|
+
|
192
|
+
def migrate_question_votes(old_question, new_question, response_mapping, migrated_stats)
|
193
|
+
votes_migrated = 0
|
194
|
+
votes_skipped = 0
|
195
|
+
|
196
|
+
old_question.votes.find_each do |old_vote|
|
197
|
+
user = old_vote.author
|
198
|
+
unless user
|
199
|
+
votes_skipped += 1
|
200
|
+
migrated_stats[:skipped_votes] += 1
|
201
|
+
next
|
202
|
+
end
|
203
|
+
|
204
|
+
new_response_id = response_mapping[old_vote.decidim_consultations_response_id]
|
205
|
+
unless new_response_id
|
206
|
+
votes_skipped += 1
|
207
|
+
migrated_stats[:skipped_votes] += 1
|
208
|
+
next
|
209
|
+
end
|
210
|
+
|
211
|
+
new_vote = Decidim::Elections::Vote.new(
|
212
|
+
question: new_question,
|
213
|
+
response_option_id: new_response_id,
|
214
|
+
voter_uid: user.to_global_id.to_s,
|
215
|
+
created_at: old_vote.created_at,
|
216
|
+
updated_at: old_vote.updated_at
|
217
|
+
)
|
218
|
+
|
219
|
+
if new_vote.save
|
220
|
+
votes_migrated += 1
|
221
|
+
migrated_stats[:votes] += 1
|
222
|
+
else
|
223
|
+
votes_skipped += 1
|
224
|
+
migrated_stats[:skipped_votes] += 1
|
225
|
+
puts " ✗ Failed to migrate Vote ##{old_vote.id}: #{new_vote.errors.full_messages.join(", ")}"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
puts " ✓ Migrated #{votes_migrated} votes, skipped #{votes_skipped} votes"
|
230
|
+
|
231
|
+
[votes_migrated, votes_skipped]
|
232
|
+
end
|
233
|
+
|
234
|
+
consultations.find_each do |consultation|
|
235
|
+
ActiveRecord::Base.transaction do
|
236
|
+
setting = Decidim::ActionDelegator::Setting.find_by(decidim_consultation_id: consultation.id)
|
237
|
+
|
238
|
+
# Check if already migrated (idempotency check by matching title)
|
239
|
+
existing_election = Decidim::Elections::Election.joins(:component)
|
240
|
+
.where(component: component, title: consultation.title)
|
241
|
+
.first
|
242
|
+
|
243
|
+
if existing_election
|
244
|
+
cons_title = consultation.title["en"] || consultation.title.values.first
|
245
|
+
puts " ✓ Consultation ##{consultation.id} (#{cons_title}) already migrated to Election ##{existing_election.id}"
|
246
|
+
migrated_stats[:skipped_consultations] += 1
|
247
|
+
next
|
248
|
+
end
|
249
|
+
|
250
|
+
census_manifest, census_settings = determine_census_config(consultation, setting)
|
251
|
+
|
252
|
+
# Create Election from Consultation
|
253
|
+
election = Decidim::Elections::Election.new(
|
254
|
+
component: component,
|
255
|
+
title: consultation.title,
|
256
|
+
description: consultation.description,
|
257
|
+
start_at: consultation.start_voting_date&.to_time&.beginning_of_day,
|
258
|
+
end_at: consultation.end_voting_date&.to_time&.end_of_day,
|
259
|
+
published_at: consultation.published_at,
|
260
|
+
published_results_at: consultation.results_published_at,
|
261
|
+
results_availability: "after_end",
|
262
|
+
census_manifest: census_manifest,
|
263
|
+
census_settings: census_settings,
|
264
|
+
created_at: consultation.created_at,
|
265
|
+
updated_at: consultation.updated_at
|
266
|
+
)
|
267
|
+
|
268
|
+
if election.save
|
269
|
+
migrated_stats[:elections] += 1
|
270
|
+
puts " ✓ Created Election ##{election.id} from Consultation ##{consultation.id}"
|
271
|
+
|
272
|
+
consultation.questions.order(:order).each_with_index do |old_question, index|
|
273
|
+
new_question = Decidim::Elections::Question.new(
|
274
|
+
election: election,
|
275
|
+
body: old_question.title.transform_values { |t| ActionController::Base.helpers.strip_tags(t) },
|
276
|
+
description: build_question_description(old_question),
|
277
|
+
position: old_question.order || index,
|
278
|
+
question_type: (old_question.max_votes.to_i > 1 ? "multiple_option" : "single_option"),
|
279
|
+
created_at: old_question.created_at,
|
280
|
+
updated_at: old_question.updated_at
|
281
|
+
)
|
282
|
+
|
283
|
+
unless new_question.save
|
284
|
+
migrated_stats[:errors] << "Question creation failed: #{new_question.errors.full_messages.join(", ")}"
|
285
|
+
puts " ✗ Failed to create Question from Old Question ##{old_question.id}: #{new_question.errors.full_messages.join(", ")}"
|
286
|
+
next
|
287
|
+
end
|
288
|
+
|
289
|
+
migrated_stats[:questions] += 1
|
290
|
+
|
291
|
+
response_mapping = {}
|
292
|
+
old_question.responses.each do |old_response|
|
293
|
+
title = old_response.title
|
294
|
+
if old_response.response_group
|
295
|
+
title = title.to_h do |locale, text|
|
296
|
+
group_text = old_response.response_group.title[locale]
|
297
|
+
combined_text = [group_text, text].compact.join(" - ")
|
298
|
+
[locale, combined_text]
|
299
|
+
end
|
300
|
+
end
|
301
|
+
new_response = Decidim::Elections::ResponseOption.new(
|
302
|
+
question: new_question,
|
303
|
+
body: title,
|
304
|
+
created_at: old_response.created_at,
|
305
|
+
updated_at: old_response.updated_at
|
306
|
+
)
|
307
|
+
|
308
|
+
if new_response.save
|
309
|
+
response_mapping[old_response.id] = new_response.id
|
310
|
+
migrated_stats[:responses] += 1
|
311
|
+
else
|
312
|
+
migrated_stats[:errors] << "Response failed: #{new_response.errors.full_messages.join(", ")}"
|
313
|
+
puts " ✗ Failed to create Response from Old Response ##{old_response.id}: #{new_response.errors.full_messages.join(", ")}"
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
puts " ✓ Created Question ##{new_question.id} with #{response_mapping.size} Responses"
|
318
|
+
|
319
|
+
migrate_question_votes(old_question, new_question, response_mapping, migrated_stats)
|
320
|
+
|
321
|
+
new_question.response_options.each { |ro| Decidim::Elections::ResponseOption.reset_counters(ro.id, :votes) }
|
322
|
+
Decidim::Elections::Question.reset_counters(new_question.id, :votes)
|
323
|
+
end
|
324
|
+
|
325
|
+
# Update election votes count
|
326
|
+
election.update_votes_count!
|
327
|
+
else
|
328
|
+
cons_title = consultation.title["en"] || consultation.title.values.first
|
329
|
+
migrated_stats[:errors] << "Consultation ##{consultation.id} (#{cons_title}): #{election.errors.full_messages.join(", ")}"
|
330
|
+
puts " ✗ Failed to create Election from Consultation ##{consultation.id}: #{election.errors.full_messages.join(", ")}"
|
331
|
+
raise ActiveRecord::Rollback
|
332
|
+
end
|
333
|
+
rescue StandardError => e
|
334
|
+
cons_title = begin
|
335
|
+
consultation.title["en"] || consultation.title.values.first
|
336
|
+
rescue StandardError
|
337
|
+
"ID #{consultation.id}"
|
338
|
+
end
|
339
|
+
migrated_stats[:errors] << "Consultation ##{consultation.id} (#{cons_title}): #{e.message}"
|
340
|
+
puts " ✗ Exception migrating Consultation ##{consultation.id} (#{cons_title}): #{e.message}"
|
341
|
+
Rails.logger.error e.backtrace.join("\n")
|
342
|
+
raise ActiveRecord::Rollback
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
puts "\n#{"-" * 70}"
|
347
|
+
puts "Migration results: Consultations → Elections"
|
348
|
+
puts "-" * 70
|
349
|
+
puts " Elections Questions Responses Votes"
|
350
|
+
puts "-" * 70
|
351
|
+
puts format("%-12s %12d %12d %12d %12d", "SOURCE", source_stats[:consultations], source_stats[:questions], source_stats[:responses], source_stats[:votes])
|
352
|
+
puts format("%-12s %12d %12d %12d %12d", "MIGRATED", migrated_stats[:elections], migrated_stats[:questions], migrated_stats[:responses], migrated_stats[:votes])
|
353
|
+
|
354
|
+
puts format("%-12s %12d %12s %12s %12s", "EXISTED", migrated_stats[:skipped_consultations], "-", "-", "-") if migrated_stats[:skipped_consultations].positive?
|
355
|
+
|
356
|
+
puts format("%-12s %12s %12s %12s %12d", "SKIPPED", "-", "-", "-", migrated_stats[:skipped_votes]) if migrated_stats[:skipped_votes].positive?
|
357
|
+
|
358
|
+
if migrated_stats[:errors].any?
|
359
|
+
puts "\nErrors (#{migrated_stats[:errors].size}):"
|
360
|
+
migrated_stats[:errors].each { |err| puts " • #{err}" }
|
361
|
+
end
|
362
|
+
|
363
|
+
puts ""
|
364
|
+
total_processed = migrated_stats[:elections] + migrated_stats[:skipped_consultations]
|
365
|
+
success = total_processed == source_stats[:consultations] &&
|
366
|
+
migrated_stats[:questions] == source_stats[:questions] &&
|
367
|
+
migrated_stats[:responses] == source_stats[:responses] &&
|
368
|
+
migrated_stats[:votes] == source_stats[:votes] &&
|
369
|
+
migrated_stats[:errors].empty? &&
|
370
|
+
(migrated_stats[:skipped_votes]).zero?
|
371
|
+
|
372
|
+
if success
|
373
|
+
if migrated_stats[:skipped_consultations].positive?
|
374
|
+
puts "✓ All data processed (#{migrated_stats[:elections]} migrated, #{migrated_stats[:skipped_consultations]} already existed)"
|
375
|
+
else
|
376
|
+
puts "✓ All data migrated successfully"
|
377
|
+
end
|
378
|
+
else
|
379
|
+
puts "⚠ Some data was not migrated (see details above)"
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "decidim-action_delegator",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.9.0",
|
4
4
|
"description": "Delgation actions (votes) for Decidim",
|
5
5
|
"main": "index.js",
|
6
6
|
"directories": {
|
@@ -16,7 +16,7 @@
|
|
16
16
|
},
|
17
17
|
"repository": {
|
18
18
|
"type": "git",
|
19
|
-
"url": "git+https://github.com/
|
19
|
+
"url": "git+https://github.com/Openpoke/decidim-module-action_delegator.git"
|
20
20
|
},
|
21
21
|
"keywords": [
|
22
22
|
"decidim"
|
@@ -24,34 +24,17 @@
|
|
24
24
|
"author": "ivan@pokecode.net",
|
25
25
|
"license": "AGPL-3.0-or-later",
|
26
26
|
"bugs": {
|
27
|
-
"url": "https://github.com/
|
27
|
+
"url": "https://github.com/Openpoke/decidim-module-action_delegator/issues"
|
28
28
|
},
|
29
|
-
"homepage": "https://github.com/
|
29
|
+
"homepage": "https://github.com/Openpoke/decidim-module-action_delegator#readme",
|
30
30
|
"stylelint": {
|
31
|
-
"extends": "@decidim/stylelint-config"
|
32
|
-
"rules" : {
|
33
|
-
"block-opening-brace-space-before": "always"
|
34
|
-
}
|
31
|
+
"extends": "@decidim/stylelint-config"
|
35
32
|
},
|
36
33
|
"devDependencies": {
|
37
|
-
"@
|
38
|
-
"@
|
39
|
-
"@
|
40
|
-
"@
|
41
|
-
"
|
42
|
-
"@babel/plugin-transform-regenerator": "^7.20.5",
|
43
|
-
"@babel/plugin-transform-runtime": "^7.19.6",
|
44
|
-
"@babel/preset-env": "^7.20.2",
|
45
|
-
"@babel/preset-react": "^7.18.6",
|
46
|
-
"@decidim/dev": "0.27.1",
|
47
|
-
"@decidim/eslint-config": "0.27.1",
|
48
|
-
"@decidim/stylelint-config": "0.27.1",
|
49
|
-
"eslint-config-prettier": "^8.2.0",
|
50
|
-
"eslint-config-standard": "^11.0.0",
|
51
|
-
"eslint-plugin-import": "^2.22.0",
|
52
|
-
"eslint-plugin-standard": "^3.1.0",
|
53
|
-
"sass-embedded": "~1.57.1"
|
54
|
-
},
|
55
|
-
"dependencies": {
|
34
|
+
"@decidim/dev": "0.30",
|
35
|
+
"@decidim/eslint-config": "0.30",
|
36
|
+
"@decidim/prettier-config": "0.30",
|
37
|
+
"@decidim/stylelint-config": "0.30",
|
38
|
+
"postcss-scss": "^4.0.9"
|
56
39
|
}
|
57
40
|
}
|