decidim-elections 0.25.2 → 0.26.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/elections/election_m_cell.rb +1 -1
  3. data/app/cells/decidim/votings/content_blocks/highlighted_votings_cell.rb +12 -0
  4. data/app/cells/decidim/votings/content_blocks/landing_page/description_cell.rb +1 -1
  5. data/app/cells/decidim/votings/voting_m_cell.rb +1 -1
  6. data/app/commands/decidim/elections/admin/add_user_as_trustee.rb +1 -1
  7. data/app/commands/decidim/elections/admin/report_missing_trustee.rb +68 -0
  8. data/app/commands/decidim/elections/admin/setup_election.rb +1 -1
  9. data/app/commands/decidim/elections/admin/start_tally.rb +1 -1
  10. data/app/commands/decidim/votings/admin/create_ballot_style.rb +8 -5
  11. data/app/commands/decidim/votings/admin/destroy_ballot_style.rb +11 -3
  12. data/app/commands/decidim/votings/admin/update_ballot_style.rb +6 -1
  13. data/app/commands/decidim/votings/census/admin/create_dataset.rb +13 -5
  14. data/app/controllers/concerns/decidim/monitoring_committee_polling_station_closures/admin/filterable.rb +1 -1
  15. data/app/controllers/concerns/decidim/polling_stations/admin/filterable.rb +1 -1
  16. data/app/controllers/decidim/elections/admin/steps_controller.rb +26 -7
  17. data/app/controllers/decidim/votings/admin/ballot_styles_controller.rb +1 -1
  18. data/app/forms/decidim/elections/admin/action_form.rb +4 -0
  19. data/app/forms/decidim/elections/admin/report_missing_trustee_form.rb +22 -0
  20. data/app/forms/decidim/elections/admin/setup_form.rb +4 -0
  21. data/app/models/decidim/elections/action.rb +1 -1
  22. data/app/models/decidim/elections/trustee.rb +4 -0
  23. data/app/models/decidim/votings/ballot_style.rb +6 -0
  24. data/app/models/decidim/votings/census/dataset.rb +2 -0
  25. data/app/models/decidim/votings/monitoring_committee_member.rb +6 -0
  26. data/app/models/decidim/votings/polling_officer.rb +5 -0
  27. data/app/models/decidim/votings/polling_station.rb +6 -0
  28. data/app/packs/entrypoints/decidim_elections_admin_trustees_process.js +1 -0
  29. data/app/packs/src/decidim/elections/admin/pending_action.js +1 -1
  30. data/app/packs/src/decidim/elections/admin/trustees_process.js +125 -0
  31. data/app/packs/src/decidim/elections/election_log.js +89 -73
  32. data/app/packs/src/decidim/elections/trustee/key_ceremony.js +3 -3
  33. data/app/packs/src/decidim/elections/trustee/tally.js +3 -3
  34. data/app/packs/src/decidim/elections/trustee/trustee_zone.js +29 -18
  35. data/app/packs/src/decidim/elections/voter/casting-vote.js +1 -1
  36. data/app/packs/src/decidim/elections/voter/setup-vote.js +5 -5
  37. data/app/packs/src/decidim/elections/voter/verify-vote.js +1 -1
  38. data/app/packs/src/decidim/votings/in-person-vote.js +1 -1
  39. data/app/presenters/decidim/elections/admin_log/election_presenter.rb +34 -9
  40. data/app/presenters/decidim/elections/admin_log/trustee_presenter.rb +50 -0
  41. data/app/presenters/decidim/elections/trustee_presenter.rb +5 -1
  42. data/app/presenters/decidim/votings/admin_log/ballot_style_presenter.rb +35 -0
  43. data/app/presenters/decidim/votings/admin_log/monitoring_committee_member_presenter.rb +50 -0
  44. data/app/presenters/decidim/votings/admin_log/polling_officer_presenter.rb +50 -0
  45. data/app/presenters/decidim/votings/admin_log/polling_station_presenter.rb +29 -0
  46. data/app/presenters/decidim/votings/admin_log/voting_presenter.rb +1 -1
  47. data/app/presenters/decidim/votings/census/admin_log/dataset_presenter.rb +7 -6
  48. data/app/services/decidim/votings/voting_search.rb +2 -2
  49. data/app/views/decidim/elections/admin/steps/_create_election.html.erb +3 -3
  50. data/app/views/decidim/elections/admin/steps/_key_ceremony.html.erb +44 -9
  51. data/app/views/decidim/elections/admin/steps/_tally.html.erb +60 -10
  52. data/app/views/decidim/elections/admin/steps/index.html.erb +17 -15
  53. data/app/views/decidim/elections/elections/_filters_small_view.html.erb +3 -3
  54. data/app/views/decidim/elections/elections/election_log.html.erb +1 -1
  55. data/app/views/decidim/elections/elections/show.html.erb +1 -1
  56. data/app/views/decidim/elections/trustee_zone/elections/show.html.erb +1 -1
  57. data/app/views/decidim/elections/trustee_zone/trustees/show.html.erb +1 -1
  58. data/app/views/decidim/elections/votes/_onboarding_modal.html.erb +1 -1
  59. data/app/views/decidim/elections/votes/_show_casted.html.erb +1 -1
  60. data/app/views/decidim/elections/votes/_show_casting.html.erb +1 -1
  61. data/app/views/decidim/elections/votes/new.html.erb +3 -3
  62. data/app/views/decidim/elections/votes/verify.html.erb +1 -1
  63. data/app/views/decidim/votings/admin/votings/index.html.erb +1 -1
  64. data/app/views/decidim/votings/polling_officer_zone/closures/_modal_ballots_count_error.html.erb +3 -2
  65. data/app/views/decidim/votings/polling_officer_zone/closures/_modal_ballots_results_count_error.html.erb +3 -2
  66. data/app/views/decidim/votings/polling_officer_zone/closures/_sign_form.html.erb +4 -3
  67. data/app/views/decidim/votings/polling_officer_zone/closures/edit.html.erb +1 -1
  68. data/app/views/decidim/votings/polling_officer_zone/closures/new.html.erb +1 -1
  69. data/app/views/decidim/votings/polling_officer_zone/in_person_votes/new.html.erb +1 -1
  70. data/app/views/decidim/votings/polling_officer_zone/in_person_votes/show.html.erb +1 -1
  71. data/app/views/decidim/votings/votings/_filters_small_view.html.erb +3 -3
  72. data/app/views/decidim/votings/votings/_promoted_voting.html.erb +1 -1
  73. data/config/assets.rb +1 -0
  74. data/config/locales/ca.yml +2 -17
  75. data/config/locales/cs.yml +45 -13
  76. data/config/locales/de.yml +0 -15
  77. data/config/locales/en.yml +41 -11
  78. data/config/locales/es-MX.yml +2 -17
  79. data/config/locales/es-PY.yml +2 -17
  80. data/config/locales/es.yml +43 -15
  81. data/config/locales/eu.yml +24 -17
  82. data/config/locales/fi-plain.yml +41 -13
  83. data/config/locales/fi.yml +41 -13
  84. data/config/locales/fr-CA.yml +32 -14
  85. data/config/locales/fr.yml +32 -14
  86. data/config/locales/ga-IE.yml +0 -9
  87. data/config/locales/gl.yml +21 -9
  88. data/config/locales/hu.yml +0 -5
  89. data/config/locales/it.yml +36 -12
  90. data/config/locales/ja.yml +234 -16
  91. data/config/locales/lb-LU.yml +24 -0
  92. data/config/locales/nl.yml +224 -11
  93. data/config/locales/no.yml +0 -5
  94. data/config/locales/pl.yml +13 -12
  95. data/config/locales/pt-BR.yml +5 -16
  96. data/config/locales/pt.yml +43 -10
  97. data/config/locales/ro-RO.yml +24 -17
  98. data/config/locales/sv.yml +3 -8
  99. data/config/locales/tr-TR.yml +3 -9
  100. data/config/locales/val-ES.yml +1 -0
  101. data/config/locales/zh-CN.yml +0 -4
  102. data/lib/decidim/elections/component.rb +2 -1
  103. data/lib/decidim/elections/test/factories.rb +2 -2
  104. data/lib/decidim/elections/version.rb +1 -1
  105. metadata +31 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f09833ea70c1970efdc0d52cf8014a4bc8cbb2a09d4ca15d49e315d7b02d88f
4
- data.tar.gz: e000962fcfe04a7d1acee472798e65208c7fa9a22dba090a5da6119aaf7013ce
3
+ metadata.gz: bc8a779cca40d6e069fdbdff54905690f2f58dbd33cdcca28c81e8b0c63a2a81
4
+ data.tar.gz: c8453d445d3d6406ef3dc6f27aed2b1ecbeaa8f69e9e8f221d3a0dae8e61c3c7
5
5
  SHA512:
6
- metadata.gz: 95f86d7f46367adeb8f5acbfa57b7cb0a78a0ca1aa4657b5d1e3d77f54bab4fabb20e143559c7e4ce071dbdbb4797dd00ec0d5cd270699461ee7be40a531db79
7
- data.tar.gz: d6048e8719815cb218327d71c12f9a6c81a2a5a6093ea05c9b0ba77585885b76ee62e8069b8510594d32da8340d7667c92688aba9a8dfb499920f20a896784f8
6
+ metadata.gz: 89e34b56ab3fe554dd329b790d60fe79e8d5a53ddfd8829b8aaf29c624ee6e860f4d80d7d4dd6d96fa7daa6bb6bbc4d5dd5eb307df187efdc08d6b579f1ebae5
7
+ data.tar.gz: f0c23adcd2198063a4ce7e9e27a3100c57fe881123d94e1922a891cab82fa1d1fbc8b26c00a10291eb3cc52f8cc26572870489794cad903e3f8483f9c7fae088
@@ -53,7 +53,7 @@ module Decidim
53
53
 
54
54
  def description
55
55
  text = super
56
- text.gsub!(/^<p>/, "<p>#{render :badge}")
56
+ text.sub!(/<p>/, "<p>#{render :badge}")
57
57
  html_truncate(text, length: 100)
58
58
  end
59
59
 
@@ -6,6 +6,10 @@ module Decidim
6
6
  class HighlightedVotingsCell < Decidim::ViewModel
7
7
  delegate :current_user, to: :controller
8
8
 
9
+ cache :show, expires_in: 10.minutes, if: :perform_caching? do
10
+ cache_hash
11
+ end
12
+
9
13
  def show
10
14
  render if highlighted_votings.any?
11
15
  end
@@ -27,6 +31,14 @@ module Decidim
27
31
  def decidim_votings
28
32
  Decidim::Votings::Engine.routes.url_helpers
29
33
  end
34
+
35
+ private
36
+
37
+ def cache_hash
38
+ hash = []
39
+ hash.push(I18n.locale)
40
+ hash.join(Decidim.cache_key_separator)
41
+ end
30
42
  end
31
43
  end
32
44
  end
@@ -16,7 +16,7 @@ module Decidim
16
16
  end
17
17
 
18
18
  def description_text
19
- decidim_sanitize(translated_attribute(current_participatory_space.description))
19
+ decidim_sanitize_editor(translated_attribute(current_participatory_space.description))
20
20
  end
21
21
 
22
22
  def button_show_more_text
@@ -41,7 +41,7 @@ module Decidim
41
41
  # makes the layout look good.
42
42
  def description
43
43
  text = super
44
- text.gsub!(/^<p>/, "<p>#{render :badge}")
44
+ text.sub!(/<p>/, "<p>#{render :badge}")
45
45
  html_truncate(text, length: 100)
46
46
  end
47
47
 
@@ -74,7 +74,7 @@ module Decidim
74
74
  resource: form.current_participatory_space,
75
75
  affected_users: [form.user]
76
76
  }
77
- Decidim::EventsManager.publish(data)
77
+ Decidim::EventsManager.publish(**data)
78
78
  end
79
79
  end
80
80
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Elections
5
+ module Admin
6
+ # This command gets called to report a missing trustee during the tally process.
7
+ class ReportMissingTrustee < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # form - A ReportMissingTrusteeForm object with the information needed to report the missing trustee.
11
+ def initialize(form)
12
+ @form = form
13
+ end
14
+
15
+ # Public: Reports the missing trustee for the Election tally process.
16
+ #
17
+ # Broadcasts :ok if it worked, :invalid otherwise.
18
+ def call
19
+ return broadcast(:invalid) if form.invalid?
20
+
21
+ transaction do
22
+ log_action
23
+ report_missing_trustee
24
+ end
25
+
26
+ broadcast(:ok)
27
+ rescue StandardError => e
28
+ broadcast(:invalid, e.message)
29
+ end
30
+
31
+ private
32
+
33
+ attr_accessor :form
34
+
35
+ delegate :election, :bulletin_board, :trustee, to: :form
36
+
37
+ def log_action
38
+ Decidim.traceability.perform_action!(
39
+ :report_missing_trustee,
40
+ election,
41
+ form.current_user,
42
+ extra: {
43
+ trustee_id: form.trustee_id,
44
+ name: trustee.name,
45
+ nickname: trustee.user.nickname
46
+ },
47
+ visibility: "all"
48
+ )
49
+ end
50
+
51
+ def report_missing_trustee
52
+ bulletin_board.report_missing_trustee(election.id, form.trustee.slug) do |message_id|
53
+ create_election_action(message_id)
54
+ end
55
+ end
56
+
57
+ def create_election_action(message_id)
58
+ Decidim::Elections::Action.create!(
59
+ election: election,
60
+ action: :report_missing_trustee,
61
+ message_id: message_id,
62
+ status: :pending
63
+ )
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -142,7 +142,7 @@ module Decidim
142
142
  affected_users: trustee
143
143
  }
144
144
 
145
- Decidim::EventsManager.publish(data)
145
+ Decidim::EventsManager.publish(**data)
146
146
  end
147
147
 
148
148
  # Since machine_translations return a nested hash but Electionguard and other
@@ -7,7 +7,7 @@ module Decidim
7
7
  class StartTally < Rectify::Command
8
8
  # Public: Initializes the command.
9
9
  #
10
- # form - A VotePeriodForm object with the information needed to start or end the vote period
10
+ # form - An ActionForm object with the information needed to perform an action
11
11
  def initialize(form)
12
12
  @form = form
13
13
  end
@@ -34,13 +34,16 @@ module Decidim
34
34
  attr_reader :form, :ballot_style
35
35
 
36
36
  def create_ballot_style!
37
- attributes = {
38
- code: form.code
37
+ params = {
38
+ code: form.code,
39
+ voting: form.current_participatory_space
39
40
  }
40
41
 
41
- @ballot_style = Decidim::Votings::BallotStyle.create!(
42
- voting: form.current_participatory_space,
43
- attributes: attributes
42
+ @ballot_style = Decidim.traceability.create!(
43
+ Decidim::Votings::BallotStyle,
44
+ form.current_user,
45
+ params,
46
+ visibility: "all"
44
47
  )
45
48
  end
46
49
 
@@ -5,8 +5,9 @@ module Decidim
5
5
  module Admin
6
6
  # A command with the business logic to delete the ballot style
7
7
  class DestroyBallotStyle < Rectify::Command
8
- def initialize(ballot_style)
8
+ def initialize(ballot_style, current_user)
9
9
  @ballot_style = ballot_style
10
+ @current_user = current_user
10
11
  end
11
12
 
12
13
  # Executes the command. Broadcast this events:
@@ -22,10 +23,17 @@ module Decidim
22
23
 
23
24
  private
24
25
 
25
- attr_reader :ballot_style
26
+ attr_reader :ballot_style, :current_user
26
27
 
27
28
  def destroy_ballot_style!
28
- ballot_style.destroy!
29
+ Decidim.traceability.perform_action!(
30
+ :delete,
31
+ ballot_style,
32
+ current_user,
33
+ visibility: "all"
34
+ ) do
35
+ ballot_style.destroy!
36
+ end
29
37
  end
30
38
  end
31
39
  end
@@ -42,7 +42,12 @@ module Decidim
42
42
  code: form.code
43
43
  }
44
44
 
45
- ballot_style.update!(attributes)
45
+ Decidim.traceability.update!(
46
+ ballot_style,
47
+ form.current_user,
48
+ attributes,
49
+ visibility: "all"
50
+ )
46
51
  end
47
52
 
48
53
  def destroy_removed_ballot_style_questions!
@@ -31,7 +31,7 @@ module Decidim
31
31
  end
32
32
 
33
33
  if dataset
34
- CSV.foreach(form.file.tempfile.path, col_sep: ";", headers: true) do |row|
34
+ CSV.foreach(form.file.tempfile.path, col_sep: ";", headers: true, converters: ->(f) { f&.strip }) do |row|
35
35
  CreateDatumJob.perform_later(current_user, dataset, row.fields)
36
36
  end
37
37
  end
@@ -57,11 +57,19 @@ module Decidim
57
57
  end
58
58
 
59
59
  def csv_header_invalid?
60
- CSV.parse_line(File.open(form.file.tempfile.path, &:readline), col_sep: ";").size != expected_header_size
60
+ CSV.parse_line(File.open(form.file.tempfile.path), col_sep: ";", headers: true, header_converters: :symbol).headers != expected_headers
61
61
  end
62
62
 
63
- def expected_header_size
64
- @expected_header_size ||= form.current_participatory_space.has_ballot_styles? ? 9 : 8
63
+ def headers
64
+ [:document_id, :document_type, :date_of_birth, :full_name, :full_address, :postal_code, :mobile_phone_number, :email_address]
65
+ end
66
+
67
+ def ballot_style_headers
68
+ headers.push(:ballot_style_code)
69
+ end
70
+
71
+ def expected_headers
72
+ @expected_headers ||= form.current_participatory_space.has_ballot_styles? ? ballot_style_headers : headers
65
73
  end
66
74
 
67
75
  def csv_rows
@@ -73,7 +81,7 @@ module Decidim
73
81
  end
74
82
 
75
83
  def file_lines_count(file_path)
76
- `wc -l "#{file_path}"`.strip.split(" ")[0].to_i
84
+ `wc -l "#{file_path.shellescape}"`.strip.split(" ")[0].to_i
77
85
  end
78
86
  end
79
87
  end
@@ -14,9 +14,9 @@ module Decidim
14
14
  private
15
15
 
16
16
  def base_query
17
+ # Includes the officers (president and managers) and their correspective decidim users when they(=officers) are present
17
18
  query =
18
19
  collection
19
- # Includes the officers (president and managers) and their correspective decidim users when they(=officers) are present
20
20
  .joins("LEFT JOIN decidim_votings_polling_officers president ON president.presided_polling_station_id = decidim_votings_polling_stations.id
21
21
  LEFT JOIN decidim_users president_user ON president_user.id = president.decidim_user_id
22
22
  LEFT JOIN decidim_votings_polling_officers managers ON managers.managed_polling_station_id = decidim_votings_polling_stations.id
@@ -14,8 +14,8 @@ module Decidim
14
14
  private
15
15
 
16
16
  def base_query
17
+ # Includes the officers (president and managers) and their correspective decidim users when they(=officers) are present
17
18
  query = collection
18
- # Includes the officers (president and managers) and their correspective decidim users when they(=officers) are present
19
19
  .joins("LEFT JOIN decidim_votings_polling_officers president ON president.presided_polling_station_id = decidim_votings_polling_stations.id
20
20
  LEFT JOIN decidim_users president_user ON president_user.id = president.decidim_user_id
21
21
  LEFT JOIN decidim_votings_polling_officers managers ON managers.managed_polling_station_id = decidim_votings_polling_stations.id
@@ -5,8 +5,9 @@ module Decidim
5
5
  module Admin
6
6
  # This controller allows to manage the steps of an election.
7
7
  class StepsController < Admin::ApplicationController
8
+ helper Decidim::ApplicationHelper
8
9
  helper StepsHelper
9
- helper_method :elections, :election, :current_step, :vote_stats, :bulletin_board_server
10
+ helper_method :elections, :election, :current_step, :vote_stats, :bulletin_board_server, :authority_public_key, :election_unique_id, :quorum, :missing_trustees_allowed
10
11
 
11
12
  def index
12
13
  enforce_permission_to :read, :steps, election: election
@@ -22,10 +23,12 @@ module Decidim
22
23
  redirect_to election_steps_path(election) && return unless params[:id] == current_step
23
24
 
24
25
  @form = form(current_step_form_class).from_params(params, election: election)
25
- if @form.pending_action
26
- Decidim::Elections::Admin::UpdateActionStatus.call(@form.pending_action)
27
- return redirect_to election_steps_path(election)
28
- end
26
+ Decidim::Elections::Admin::UpdateActionStatus.call(@form.pending_action) if @form.pending_action
27
+
28
+ # check pending action status mode
29
+ return render json: { status: @form.pending_action&.status } if params[:check_pending_action]
30
+
31
+ return redirect_to election_steps_path(election) if @form.pending_action
29
32
 
30
33
  current_step_command_class.call(@form) do
31
34
  on(:ok) do
@@ -45,8 +48,22 @@ module Decidim
45
48
 
46
49
  private
47
50
 
48
- def bulletin_board_server
49
- Decidim::Elections.bulletin_board.bulletin_board_server
51
+ delegate :bulletin_board_server, :authority_slug, :quorum, to: :bulletin_board_client
52
+
53
+ def bulletin_board_client
54
+ Decidim::Elections.bulletin_board
55
+ end
56
+
57
+ def missing_trustees_allowed
58
+ @missing_trustees_allowed ||= Decidim::Elections.bulletin_board.number_of_trustees - Decidim::Elections.bulletin_board.quorum
59
+ end
60
+
61
+ def election_unique_id
62
+ @election_unique_id ||= Decidim::BulletinBoard::MessageIdentifier.unique_election_id(authority_slug, election.id)
63
+ end
64
+
65
+ def authority_public_key
66
+ @authority_public_key ||= bulletin_board_client.authority_public_key.to_json
50
67
  end
51
68
 
52
69
  def current_step_form_class
@@ -56,6 +73,7 @@ module Decidim
56
73
  "key_ceremony_ended" => VotePeriodForm,
57
74
  "vote" => VotePeriodForm,
58
75
  "vote_ended" => ActionForm,
76
+ "tally" => ReportMissingTrusteeForm,
59
77
  "tally_ended" => ActionForm
60
78
  }[current_step]
61
79
  end
@@ -67,6 +85,7 @@ module Decidim
67
85
  "key_ceremony_ended" => StartVote,
68
86
  "vote" => EndVote,
69
87
  "vote_ended" => StartTally,
88
+ "tally" => ReportMissingTrustee,
70
89
  "tally_ended" => PublishResults
71
90
  }[current_step]
72
91
  end
@@ -60,7 +60,7 @@ module Decidim
60
60
  def destroy
61
61
  enforce_permission_to :delete, :ballot_style, ballot_style: current_ballot_style, voting: current_voting
62
62
 
63
- DestroyBallotStyle.call(current_ballot_style) do
63
+ DestroyBallotStyle.call(current_ballot_style, current_user) do
64
64
  on(:ok) do
65
65
  flash[:notice] = t("destroy.success", scope: "decidim.votings.admin.ballot_styles")
66
66
  end
@@ -7,6 +7,10 @@ module Decidim
7
7
  class ActionForm < Decidim::Form
8
8
  validates :pending_action, absence: true
9
9
 
10
+ def main_button?
11
+ true
12
+ end
13
+
10
14
  def messages
11
15
  @messages ||= {}
12
16
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Elections
5
+ module Admin
6
+ # This class holds a form to report a missing trustee during the tally process.
7
+ class ReportMissingTrusteeForm < ActionForm
8
+ attribute :trustee_id, Integer
9
+
10
+ validates :trustee_id, presence: true
11
+
12
+ def trustee
13
+ @trustee ||= Decidim::Elections::Trustee.find(trustee_id)
14
+ end
15
+
16
+ def main_button?
17
+ false
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -57,6 +57,10 @@ module Decidim
57
57
  @bulletin_board ||= context[:bulletin_board] || Decidim::Elections.bulletin_board
58
58
  end
59
59
 
60
+ def main_button?
61
+ true
62
+ end
63
+
60
64
  private
61
65
 
62
66
  def choose_random_trustees
@@ -7,7 +7,7 @@ module Decidim
7
7
  belongs_to :election, foreign_key: "decidim_elections_election_id", class_name: "Decidim::Elections::Election"
8
8
 
9
9
  enum status: [:pending, :accepted, :rejected]
10
- enum action: [:start_key_ceremony, :start_vote, :end_vote, :start_tally, :publish_results]
10
+ enum action: [:start_key_ceremony, :start_vote, :end_vote, :start_tally, :report_missing_trustee, :publish_results]
11
11
  end
12
12
  end
13
13
  end
@@ -15,6 +15,10 @@ module Decidim
15
15
  exists?(user: user)
16
16
  end
17
17
 
18
+ def self.log_presenter_class_for(_log)
19
+ Decidim::Elections::AdminLog::TrusteePresenter
20
+ end
21
+
18
22
  def self.for(user)
19
23
  find_by(user: user)
20
24
  end
@@ -17,6 +17,8 @@ module Decidim
17
17
  inverse_of: :ballot_style,
18
18
  dependent: :nullify
19
19
 
20
+ alias participatory_space voting
21
+
20
22
  def slug
21
23
  "#{voting.slug}_#{code.parameterize}-#{id}"
22
24
  end
@@ -24,6 +26,10 @@ module Decidim
24
26
  def questions_for(election)
25
27
  questions.where(election: election)
26
28
  end
29
+
30
+ def self.log_presenter_class_for(_log)
31
+ Decidim::Votings::AdminLog::BallotStylePresenter
32
+ end
27
33
  end
28
34
  end
29
35
  end
@@ -23,6 +23,8 @@ module Decidim
23
23
 
24
24
  validates :file, presence: true
25
25
 
26
+ alias participatory_space voting
27
+
26
28
  def self.log_presenter_class_for(_log)
27
29
  Decidim::Votings::Census::AdminLog::DatasetPresenter
28
30
  end
@@ -11,6 +11,12 @@ module Decidim
11
11
 
12
12
  validate :user_and_voting_same_organization
13
13
 
14
+ alias participatory_space voting
15
+
16
+ def self.log_presenter_class_for(_log)
17
+ Decidim::Votings::AdminLog::MonitoringCommitteeMemberPresenter
18
+ end
19
+
14
20
  private
15
21
 
16
22
  # Private: check if the voting and the user have the same organization
@@ -22,6 +22,7 @@ module Decidim
22
22
  validate :either_president_or_manager
23
23
 
24
24
  delegate :name, :nickname, :email, to: :user
25
+ alias participatory_space voting
25
26
 
26
27
  # Allow ransacker to search by presided/managed polling station title
27
28
  %w(managed_station presided_station).each do |table|
@@ -56,6 +57,10 @@ module Decidim
56
57
  presided_polling_station || managed_polling_station
57
58
  end
58
59
 
60
+ def self.log_presenter_class_for(_log)
61
+ Decidim::Votings::AdminLog::PollingOfficerPresenter
62
+ end
63
+
59
64
  private
60
65
 
61
66
  # Private: check if the voting and the user have the same organization
@@ -34,6 +34,8 @@ module Decidim
34
34
  validate :polling_station_managers_same_voting
35
35
  validate :polling_station_president_same_voting
36
36
 
37
+ alias participatory_space voting
38
+
37
39
  # Allow ransacker to search for a key in a hstore column (`title`.`en`)
38
40
  ransacker :title do |parent|
39
41
  Arel::Nodes::InfixOperation.new("->>", parent.table[:title], Arel::Nodes.build_quoted(I18n.locale.to_s))
@@ -61,6 +63,10 @@ module Decidim
61
63
  closures.find_by(election: election)
62
64
  end
63
65
 
66
+ def self.log_presenter_class_for(_log)
67
+ Decidim::Votings::AdminLog::PollingStationPresenter
68
+ end
69
+
64
70
  private
65
71
 
66
72
  # Private: check if the president is in the same voting
@@ -0,0 +1 @@
1
+ import "src/decidim/elections/admin/trustees_process";
@@ -1,4 +1,4 @@
1
- import { Client } from "@codegram/decidim-bulletin_board";
1
+ import { Client } from "@decidim/decidim-bulletin_board";
2
2
 
3
3
  $(() => {
4
4
  const $form = $("form.step");
@@ -0,0 +1,125 @@
1
+ import {
2
+ Client,
3
+ Election,
4
+ MessageParser
5
+ } from "@decidim/decidim-bulletin_board";
6
+
7
+ const WAIT_TIME_MS = 10 * 1_000;
8
+
9
+ $(async () => {
10
+ const $trusteesProcess = $("#trustees_process");
11
+ const $checkingTrustees = $trusteesProcess.find(".trustee");
12
+ const electionUniqueId = $trusteesProcess.data("electionUniqueId");
13
+ const processType = $trusteesProcess.data("processType");
14
+ const bulletinBoardClient = new Client({
15
+ apiEndpointUrl: $trusteesProcess.data("apiEndpointUrl")
16
+ });
17
+ const election = new Election({
18
+ uniqueId: electionUniqueId,
19
+ bulletinBoardClient,
20
+ typesFilter: ["create_election", processType]
21
+ });
22
+
23
+ const authorityPublicKeyJSON = JSON.stringify(
24
+ $trusteesProcess.data("authorityPublicKey")
25
+ );
26
+ const parser = new MessageParser({ authorityPublicKeyJSON });
27
+ const trusteesStatuses = {};
28
+ let lastMessageIndex = 0;
29
+
30
+ const missingTrusteesAllowed = $trusteesProcess.data("missingTrusteesAllowed") || 0;
31
+ const checkPendingActionPath = $trusteesProcess.data("checkPendingActionPath");
32
+
33
+ // Fix buttons formaction, that is not working properly
34
+ const $form = $("form.step");
35
+ $form.find("button").on("click", (event) => {
36
+ $form.attr("action", $(event.currentTarget).attr("formaction"));
37
+ $form.trigger("submit");
38
+ });
39
+
40
+ const updateTrusteesStatuses = async () => {
41
+ await election.getLogEntries();
42
+
43
+ for (
44
+ ;
45
+ lastMessageIndex < election.logEntries.length;
46
+ lastMessageIndex += 1
47
+ ) {
48
+ const { messageIdentifier, decodedData } = await parser.parse(
49
+ election.logEntries[lastMessageIndex]
50
+ );
51
+
52
+ if (messageIdentifier.author.type === "t") {
53
+ trusteesStatuses[messageIdentifier.author.id] = true;
54
+ } else if (
55
+ messageIdentifier.type === "tally" &&
56
+ messageIdentifier.subtype === "missing_trustee" &&
57
+ !(decodedData.trustee_id in trusteesStatuses)
58
+ ) {
59
+ trusteesStatuses[decodedData.trustee_id] = false;
60
+ }
61
+ }
62
+ }
63
+
64
+ const checkPendingAction = async () => {
65
+ if (!checkPendingActionPath) {
66
+ return false
67
+ }
68
+
69
+ try {
70
+ const response = await $.ajax({
71
+ url: checkPendingActionPath,
72
+ method: "PATCH",
73
+ contentType: "application/json",
74
+ headers: {
75
+ "X-CSRF-Token": $("meta[name=csrf-token]").attr("content")
76
+ }
77
+ })
78
+
79
+ return response && response.status === "pending";
80
+ } catch (err) {
81
+ return true;
82
+ }
83
+ }
84
+
85
+ const checkTrusteesActivity = async () => {
86
+ await updateTrusteesStatuses();
87
+ const pendingAction = await checkPendingAction();
88
+ const missingTrustees = Object.values(trusteesStatuses).filter(
89
+ (present) => !present
90
+ ).length;
91
+ const allowReportMissing = missingTrustees < missingTrusteesAllowed;
92
+
93
+ $checkingTrustees.each((_index, trustee) => {
94
+ const $trustee = $(trustee);
95
+ const trusteeSlug = $trustee.data("trusteeSlug");
96
+
97
+ if (trusteeSlug in trusteesStatuses) {
98
+ if (missingTrusteesAllowed > 0) {
99
+ $trustee.find(".js-report-missing-trustee").addClass("hide");
100
+ }
101
+ $trustee.removeClass("loading");
102
+ $trustee.find(".loading").hide();
103
+ if (trusteesStatuses[trusteeSlug]) {
104
+ $trustee.find(".active").removeClass("hide");
105
+ $trustee.find(".missing").addClass("hide");
106
+ } else {
107
+ $trustee.find(".missing").removeClass("hide");
108
+ }
109
+ } else if (allowReportMissing && !pendingAction) {
110
+ $trustee.find(".js-report-missing-trustee").removeClass("hide");
111
+ }
112
+ });
113
+
114
+ if (
115
+ Object.keys(trusteesStatuses).length === $checkingTrustees.length &&
116
+ missingTrustees <= missingTrusteesAllowed && !pendingAction
117
+ ) {
118
+ $(".js-continue-link").removeClass("disabled");
119
+ } else {
120
+ setTimeout(checkTrusteesActivity, WAIT_TIME_MS);
121
+ }
122
+ };
123
+
124
+ await checkTrusteesActivity();
125
+ });