decidim-elections 0.25.0.rc4 → 0.26.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) 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/create_monitoring_committee_member.rb +1 -1
  12. data/app/commands/decidim/votings/admin/create_polling_officer.rb +1 -1
  13. data/app/commands/decidim/votings/admin/destroy_ballot_style.rb +11 -3
  14. data/app/commands/decidim/votings/admin/update_ballot_style.rb +6 -1
  15. data/app/commands/decidim/votings/census/admin/create_dataset.rb +13 -5
  16. data/app/controllers/concerns/decidim/monitoring_committee_polling_station_closures/admin/filterable.rb +1 -1
  17. data/app/controllers/concerns/decidim/polling_stations/admin/filterable.rb +1 -1
  18. data/app/controllers/decidim/elections/admin/steps_controller.rb +26 -7
  19. data/app/controllers/decidim/votings/admin/ballot_styles_controller.rb +1 -1
  20. data/app/forms/decidim/elections/admin/action_form.rb +4 -0
  21. data/app/forms/decidim/elections/admin/report_missing_trustee_form.rb +22 -0
  22. data/app/forms/decidim/elections/admin/setup_form.rb +4 -0
  23. data/app/models/decidim/elections/action.rb +1 -1
  24. data/app/models/decidim/elections/trustee.rb +4 -0
  25. data/app/models/decidim/votings/ballot_style.rb +6 -0
  26. data/app/models/decidim/votings/census/dataset.rb +2 -0
  27. data/app/models/decidim/votings/monitoring_committee_member.rb +6 -0
  28. data/app/models/decidim/votings/polling_officer.rb +5 -0
  29. data/app/models/decidim/votings/polling_station.rb +6 -0
  30. data/app/packs/entrypoints/decidim_elections_admin_trustees_process.js +1 -0
  31. data/app/packs/src/decidim/elections/admin/pending_action.js +1 -1
  32. data/app/packs/src/decidim/elections/admin/trustees_process.js +125 -0
  33. data/app/packs/src/decidim/elections/election_log.js +89 -73
  34. data/app/packs/src/decidim/elections/trustee/key_ceremony.js +3 -3
  35. data/app/packs/src/decidim/elections/trustee/tally.js +3 -3
  36. data/app/packs/src/decidim/elections/trustee/trustee_zone.js +29 -18
  37. data/app/packs/src/decidim/elections/voter/casting-vote.js +1 -1
  38. data/app/packs/src/decidim/elections/voter/setup-vote.js +5 -5
  39. data/app/packs/src/decidim/elections/voter/verify-vote.js +1 -1
  40. data/app/packs/src/decidim/votings/in-person-vote.js +1 -1
  41. data/app/presenters/decidim/elections/admin_log/election_presenter.rb +34 -9
  42. data/app/presenters/decidim/elections/admin_log/trustee_presenter.rb +50 -0
  43. data/app/presenters/decidim/elections/trustee_presenter.rb +5 -1
  44. data/app/presenters/decidim/votings/admin_log/ballot_style_presenter.rb +35 -0
  45. data/app/presenters/decidim/votings/admin_log/monitoring_committee_member_presenter.rb +50 -0
  46. data/app/presenters/decidim/votings/admin_log/polling_officer_presenter.rb +50 -0
  47. data/app/presenters/decidim/votings/admin_log/polling_station_presenter.rb +29 -0
  48. data/app/presenters/decidim/votings/admin_log/voting_presenter.rb +1 -1
  49. data/app/presenters/decidim/votings/census/admin_log/dataset_presenter.rb +7 -6
  50. data/app/services/decidim/votings/voting_search.rb +2 -2
  51. data/app/views/decidim/elections/admin/steps/_create_election.html.erb +3 -3
  52. data/app/views/decidim/elections/admin/steps/_key_ceremony.html.erb +44 -9
  53. data/app/views/decidim/elections/admin/steps/_tally.html.erb +60 -10
  54. data/app/views/decidim/elections/admin/steps/index.html.erb +17 -15
  55. data/app/views/decidim/elections/elections/_filters_small_view.html.erb +3 -3
  56. data/app/views/decidim/elections/elections/election_log.html.erb +1 -1
  57. data/app/views/decidim/elections/elections/show.html.erb +1 -1
  58. data/app/views/decidim/elections/trustee_zone/elections/show.html.erb +1 -1
  59. data/app/views/decidim/elections/trustee_zone/trustees/show.html.erb +1 -1
  60. data/app/views/decidim/elections/votes/_onboarding_modal.html.erb +1 -1
  61. data/app/views/decidim/elections/votes/_show_casted.html.erb +1 -1
  62. data/app/views/decidim/elections/votes/_show_casting.html.erb +1 -1
  63. data/app/views/decidim/elections/votes/new.html.erb +3 -3
  64. data/app/views/decidim/elections/votes/verify.html.erb +1 -1
  65. data/app/views/decidim/votings/admin/votings/index.html.erb +1 -1
  66. data/app/views/decidim/votings/polling_officer_zone/closures/_modal_ballots_count_error.html.erb +3 -2
  67. data/app/views/decidim/votings/polling_officer_zone/closures/_modal_ballots_results_count_error.html.erb +3 -2
  68. data/app/views/decidim/votings/polling_officer_zone/closures/_sign_form.html.erb +4 -3
  69. data/app/views/decidim/votings/polling_officer_zone/closures/edit.html.erb +1 -1
  70. data/app/views/decidim/votings/polling_officer_zone/closures/new.html.erb +1 -1
  71. data/app/views/decidim/votings/polling_officer_zone/in_person_votes/new.html.erb +1 -1
  72. data/app/views/decidim/votings/polling_officer_zone/in_person_votes/show.html.erb +1 -1
  73. data/app/views/decidim/votings/votings/_filters_small_view.html.erb +3 -3
  74. data/app/views/decidim/votings/votings/_promoted_voting.html.erb +1 -1
  75. data/config/assets.rb +1 -0
  76. data/config/locales/ca.yml +67 -80
  77. data/config/locales/cs.yml +41 -11
  78. data/config/locales/de.yml +0 -13
  79. data/config/locales/en.yml +41 -11
  80. data/config/locales/es-MX.yml +151 -13
  81. data/config/locales/es-PY.yml +151 -13
  82. data/config/locales/es.yml +192 -11
  83. data/config/locales/eu.yml +1344 -0
  84. data/config/locales/fi-plain.yml +41 -11
  85. data/config/locales/fi.yml +41 -11
  86. data/config/locales/fr-CA.yml +124 -5
  87. data/config/locales/fr.yml +124 -5
  88. data/config/locales/ga-IE.yml +371 -0
  89. data/config/locales/gl.yml +34 -1
  90. data/config/locales/it.yml +33 -11
  91. data/config/locales/ja.yml +545 -16
  92. data/config/locales/lb-LU.yml +24 -0
  93. data/config/locales/lb.yml +25 -0
  94. data/config/locales/nl.yml +224 -6
  95. data/config/locales/pl.yml +6 -11
  96. data/config/locales/pt-BR.yml +1 -14
  97. data/config/locales/pt.yml +1169 -2
  98. data/config/locales/ro-RO.yml +267 -51
  99. data/config/locales/sv.yml +89 -8
  100. data/config/locales/tr-TR.yml +0 -4
  101. data/config/locales/val-ES.yml +1 -0
  102. data/config/locales/zh-CN.yml +0 -4
  103. data/lib/decidim/elections/component.rb +2 -1
  104. data/lib/decidim/elections/engine.rb +4 -0
  105. data/lib/decidim/elections/test/factories.rb +2 -2
  106. data/lib/decidim/elections/version.rb +1 -1
  107. metadata +33 -22
@@ -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
+ });
@@ -2,144 +2,160 @@
2
2
  * This file is responsible to get LogEntries
3
3
  * for an election for the election log.
4
4
  */
5
- import { Client, MessageParser } from "@codegram/decidim-bulletin_board";
5
+ import { Client, MessageParser } from "@decidim/decidim-bulletin_board";
6
6
 
7
7
  $(async () => {
8
8
  // UI Elements
9
9
  const $electionLog = $(".election-log");
10
- const $createElectionStep = $electionLog.find("#create-election-step")
11
- const $keyCeremonyStep = $electionLog.find("#key-ceremony-step")
12
- const $voteStep = $electionLog.find("#vote-step")
13
- const $tallyStep = $electionLog.find("#tally-step")
14
- const $resultStep = $electionLog.find("#results-step")
10
+ const $createElectionStep = $electionLog.find("#create-election-step");
11
+ const $keyCeremonyStep = $electionLog.find("#key-ceremony-step");
12
+ const $voteStep = $electionLog.find("#vote-step");
13
+ const $tallyStep = $electionLog.find("#tally-step");
14
+ const $resultStep = $electionLog.find("#results-step");
15
15
 
16
16
  // Data
17
- const authorityPublicKeyJSON = JSON.stringify($electionLog.data("authorityPublicKey"))
17
+ const authorityPublicKeyJSON = JSON.stringify(
18
+ $electionLog.data("authorityPublicKey")
19
+ );
18
20
  const bulletinBoardClient = new Client({
19
21
  apiEndpointUrl: $electionLog.data("apiEndpointUrl")
20
22
  });
21
- const electionUniqueId = `${$electionLog.data("authoritySlug")}.${$electionLog.data("electionId")}`
22
- const parser = new MessageParser({ authorityPublicKeyJSON })
23
- const logEntries = await bulletinBoardClient.getElectionLogEntries({electionUniqueId: electionUniqueId, types: ["create_election", "start_key_ceremony", "end_key_ceremony", "start_vote", "end_vote", "start_tally", "end_tally", "publish_results"]});
23
+ const electionUniqueId = `${$electionLog.data(
24
+ "authoritySlug"
25
+ )}.${$electionLog.data("electionId")}`;
26
+ const parser = new MessageParser({ authorityPublicKeyJSON });
27
+ const logEntries = await bulletinBoardClient.getElectionLogEntries({
28
+ electionUniqueId: electionUniqueId,
29
+ types: [
30
+ "create_election",
31
+ "start_key_ceremony",
32
+ "end_key_ceremony",
33
+ "start_vote",
34
+ "end_vote",
35
+ "start_tally",
36
+ "end_tally",
37
+ "publish_results"
38
+ ]
39
+ });
24
40
 
25
41
  // Functions to be used for each step
26
42
 
27
43
  // adds the `iat` of the message to the UI
28
44
  const setMessageTime = async (logEntryStep, uiStep) => {
29
45
  if (!logEntryStep.signedData) {
30
- uiStep.find(".time").html("")
31
- return
46
+ uiStep.find(".time").html("");
47
+ return;
32
48
  }
33
49
 
34
- const parsedData = await parser.parse(logEntryStep)
35
- const messageTime = new Date(parsedData.decodedData.iat * 1000)
36
- const year = messageTime.toDateString()
37
- const time = messageTime.toLocaleTimeString()
50
+ const parsedData = await parser.parse(logEntryStep);
51
+ const messageTime = new Date(parsedData.decodedData.iat * 1000);
52
+ const year = messageTime.toDateString();
53
+ const time = messageTime.toLocaleTimeString();
38
54
 
39
- uiStep.find(".time").html(`${year} ${time}`)
40
- }
55
+ uiStep.find(".time").html(`${year} ${time}`);
56
+ };
41
57
 
42
58
  // adds the chained Hash of the message to the UI
43
59
  const addChainedHash = (logEntryStep, uiStep) => {
44
- uiStep.find(".card__footer--transparent").removeClass("hide")
45
- uiStep.find(".chained-hash").html(logEntryStep.chainedHash)
46
- }
60
+ uiStep.find(".card__footer--transparent").removeClass("hide");
61
+ uiStep.find(".chained-hash").html(logEntryStep.chainedHash);
62
+ };
47
63
 
48
64
  // finds the logEntry for each step
49
65
  const getLogEntryByMessageId = (step) => {
50
- return logEntries.find((logEntry) => logEntry.messageId.includes(step))
51
- }
66
+ return logEntries.find((logEntry) => logEntry.messageId.includes(step));
67
+ };
52
68
 
53
69
  // CREATE ELECTION STEP
54
- const createElectionLogEntry = getLogEntryByMessageId("create_election")
70
+ const createElectionLogEntry = getLogEntryByMessageId("create_election");
55
71
  if (createElectionLogEntry) {
56
- $createElectionStep.find(".no-election-created").addClass("hide")
57
- $createElectionStep.find(".election-created").removeClass("hide")
72
+ $createElectionStep.find(".no-election-created").addClass("hide");
73
+ $createElectionStep.find(".election-created").removeClass("hide");
58
74
 
59
- await setMessageTime(createElectionLogEntry, $createElectionStep)
75
+ await setMessageTime(createElectionLogEntry, $createElectionStep);
60
76
 
61
- addChainedHash(createElectionLogEntry, $createElectionStep)
77
+ addChainedHash(createElectionLogEntry, $createElectionStep);
62
78
  }
63
79
 
64
80
  // KEY CEREMONY STEP
65
- const startKeyCeremonyLogEntry = getLogEntryByMessageId("start_key_ceremony")
66
- const endKeyCeremonyLogEntry = getLogEntryByMessageId("end_key_ceremony")
81
+ const startKeyCeremonyLogEntry = getLogEntryByMessageId("start_key_ceremony");
82
+ const endKeyCeremonyLogEntry = getLogEntryByMessageId("end_key_ceremony");
67
83
 
68
84
  if (startKeyCeremonyLogEntry && !endKeyCeremonyLogEntry) {
69
- $keyCeremonyStep.find(".key-ceremony-not-started").addClass("hide")
70
- $keyCeremonyStep.find(".card__text").removeClass("hide")
85
+ $keyCeremonyStep.find(".key-ceremony-not-started").addClass("hide");
86
+ $keyCeremonyStep.find(".card__text").removeClass("hide");
71
87
 
72
- await setMessageTime(startKeyCeremonyLogEntry, $keyCeremonyStep)
88
+ await setMessageTime(startKeyCeremonyLogEntry, $keyCeremonyStep);
73
89
 
74
- $keyCeremonyStep.find(".key-ceremony-started").removeClass("hide")
75
- addChainedHash(startKeyCeremonyLogEntry, $keyCeremonyStep)
90
+ $keyCeremonyStep.find(".key-ceremony-started").removeClass("hide");
91
+ addChainedHash(startKeyCeremonyLogEntry, $keyCeremonyStep);
76
92
  } else if (endKeyCeremonyLogEntry) {
77
- $keyCeremonyStep.find(".key-ceremony-not-started").addClass("hide")
78
- $keyCeremonyStep.find(".card__text").removeClass("hide")
93
+ $keyCeremonyStep.find(".key-ceremony-not-started").addClass("hide");
94
+ $keyCeremonyStep.find(".card__text").removeClass("hide");
79
95
 
80
- await setMessageTime(endKeyCeremonyLogEntry, $keyCeremonyStep)
96
+ await setMessageTime(endKeyCeremonyLogEntry, $keyCeremonyStep);
81
97
 
82
- $keyCeremonyStep.find(".key-ceremony-started").addClass("hide")
83
- $keyCeremonyStep.find(".key-ceremony-completed").removeClass("hide")
84
- addChainedHash(endKeyCeremonyLogEntry, $keyCeremonyStep)
98
+ $keyCeremonyStep.find(".key-ceremony-started").addClass("hide");
99
+ $keyCeremonyStep.find(".key-ceremony-completed").removeClass("hide");
100
+ addChainedHash(endKeyCeremonyLogEntry, $keyCeremonyStep);
85
101
  }
86
102
 
87
103
  // VOTING STEP
88
- const startVoteLogEntry = getLogEntryByMessageId("start_vote")
89
- const endVoteLogEntry = getLogEntryByMessageId("end_vote")
104
+ const startVoteLogEntry = getLogEntryByMessageId("start_vote");
105
+ const endVoteLogEntry = getLogEntryByMessageId("end_vote");
90
106
 
91
107
  if (startVoteLogEntry && !endVoteLogEntry) {
92
- $voteStep.find(".vote-not-started").addClass("hide")
93
- $voteStep.find(".card__text").removeClass("hide")
108
+ $voteStep.find(".vote-not-started").addClass("hide");
109
+ $voteStep.find(".card__text").removeClass("hide");
94
110
 
95
- await setMessageTime(startVoteLogEntry, $voteStep)
111
+ await setMessageTime(startVoteLogEntry, $voteStep);
96
112
 
97
- $voteStep.find(".vote-started").removeClass("hide")
98
- addChainedHash(startVoteLogEntry, $voteStep)
113
+ $voteStep.find(".vote-started").removeClass("hide");
114
+ addChainedHash(startVoteLogEntry, $voteStep);
99
115
  } else if (endVoteLogEntry) {
100
- $voteStep.find(".vote-not-started").addClass("hide")
101
- $voteStep.find(".card__text").removeClass("hide")
116
+ $voteStep.find(".vote-not-started").addClass("hide");
117
+ $voteStep.find(".card__text").removeClass("hide");
102
118
 
103
- await setMessageTime(endVoteLogEntry, $voteStep)
119
+ await setMessageTime(endVoteLogEntry, $voteStep);
104
120
 
105
- $voteStep.find(".vote-started").addClass("hide")
106
- $voteStep.find(".vote-completed").removeClass("hide")
107
- addChainedHash(endVoteLogEntry, $voteStep)
121
+ $voteStep.find(".vote-started").addClass("hide");
122
+ $voteStep.find(".vote-completed").removeClass("hide");
123
+ addChainedHash(endVoteLogEntry, $voteStep);
108
124
  }
109
125
 
110
126
  // TALLY STEP
111
- const startTallyLogEntry = getLogEntryByMessageId("start_tally")
112
- const endTallyLogEntry = getLogEntryByMessageId("end_tally")
127
+ const startTallyLogEntry = getLogEntryByMessageId("start_tally");
128
+ const endTallyLogEntry = getLogEntryByMessageId("end_tally");
113
129
 
114
130
  if (startTallyLogEntry && !endTallyLogEntry) {
115
- $tallyStep.find(".tally-not-started").addClass("hide")
116
- $tallyStep.find(".card__text").removeClass("hide")
131
+ $tallyStep.find(".tally-not-started").addClass("hide");
132
+ $tallyStep.find(".card__text").removeClass("hide");
117
133
 
118
- await setMessageTime(startTallyLogEntry, $tallyStep)
134
+ await setMessageTime(startTallyLogEntry, $tallyStep);
119
135
 
120
- $tallyStep.find(".tally-started").removeClass("hide")
121
- addChainedHash(startTallyLogEntry, $tallyStep)
136
+ $tallyStep.find(".tally-started").removeClass("hide");
137
+ addChainedHash(startTallyLogEntry, $tallyStep);
122
138
  } else if (endTallyLogEntry) {
123
- $tallyStep.find(".tally-not-started").addClass("hide")
124
- $tallyStep.find(".card__text").removeClass("hide")
139
+ $tallyStep.find(".tally-not-started").addClass("hide");
140
+ $tallyStep.find(".card__text").removeClass("hide");
125
141
 
126
- await setMessageTime(endTallyLogEntry, $tallyStep)
142
+ await setMessageTime(endTallyLogEntry, $tallyStep);
127
143
 
128
- $tallyStep.find(".tally-started").addClass("hide")
129
- $tallyStep.find(".tally-completed").removeClass("hide")
130
- addChainedHash(endTallyLogEntry, $tallyStep)
144
+ $tallyStep.find(".tally-started").addClass("hide");
145
+ $tallyStep.find(".tally-completed").removeClass("hide");
146
+ addChainedHash(endTallyLogEntry, $tallyStep);
131
147
  }
132
148
 
133
149
  // RESULTS STEP
134
- const resultsLogEntry = getLogEntryByMessageId("publish_results")
150
+ const resultsLogEntry = getLogEntryByMessageId("publish_results");
135
151
 
136
152
  if (resultsLogEntry) {
137
- $resultStep.find(".results-not-published").addClass("hide")
138
- $resultStep.find(".card__text").removeClass("hide")
153
+ $resultStep.find(".results-not-published").addClass("hide");
154
+ $resultStep.find(".card__text").removeClass("hide");
139
155
 
140
- await setMessageTime(resultsLogEntry, $resultStep)
156
+ await setMessageTime(resultsLogEntry, $resultStep);
141
157
 
142
- $resultStep.find(".results-published").removeClass("hide")
143
- addChainedHash(resultsLogEntry, $resultStep)
158
+ $resultStep.find(".results-published").removeClass("hide");
159
+ addChainedHash(resultsLogEntry, $resultStep);
144
160
  }
145
161
  });
@@ -3,10 +3,10 @@ import {
3
3
  MessageIdentifier,
4
4
  IdentificationKeys,
5
5
  MESSAGE_RECEIVED
6
- } from "@codegram/decidim-bulletin_board";
6
+ } from "@decidim/decidim-bulletin_board";
7
7
 
8
- import { TrusteeWrapperAdapter as DummyTrusteeWrapperAdapter } from "@codegram/voting_schemes-dummy";
9
- import { TrusteeWrapperAdapter as ElectionGuardTrusteeWrapperAdapter } from "@codegram/voting_schemes-electionguard";
8
+ import { TrusteeWrapperAdapter as DummyTrusteeWrapperAdapter } from "@decidim/voting_schemes-dummy";
9
+ import { TrusteeWrapperAdapter as ElectionGuardTrusteeWrapperAdapter } from "@decidim/voting_schemes-electionguard";
10
10
 
11
11
  /**
12
12
  * This file is responsible to generate election keys,
@@ -3,10 +3,10 @@ import {
3
3
  IdentificationKeys,
4
4
  MessageIdentifier,
5
5
  MESSAGE_RECEIVED
6
- } from "@codegram/decidim-bulletin_board";
6
+ } from "@decidim/decidim-bulletin_board";
7
7
 
8
- import { TrusteeWrapperAdapter as DummyTrusteeWrapperAdapter } from "@codegram/voting_schemes-dummy";
9
- import { TrusteeWrapperAdapter as ElectionGuardTrusteeWrapperAdapter } from "@codegram/voting_schemes-electionguard";
8
+ import { TrusteeWrapperAdapter as DummyTrusteeWrapperAdapter } from "@decidim/voting_schemes-dummy";
9
+ import { TrusteeWrapperAdapter as ElectionGuardTrusteeWrapperAdapter } from "@decidim/voting_schemes-electionguard";
10
10
 
11
11
  $(() => {
12
12
  // UI Elements
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable require-jsdoc, no-alert, func-style */
2
2
 
3
- import { IdentificationKeys } from "@codegram/decidim-bulletin_board";
3
+ import { IdentificationKeys } from "@decidim/decidim-bulletin_board";
4
4
 
5
5
  $(() => {
6
6
  function identificationKeys() {
@@ -8,7 +8,10 @@ $(() => {
8
8
  const $trusteeSlug = $("#trustee_slug", $form);
9
9
  const $trusteePublicKey = $("#trustee_public_key", $form);
10
10
 
11
- window.trusteeIdentificationKeys = new IdentificationKeys($trusteeSlug.val(), $trusteePublicKey.val());
11
+ window.trusteeIdentificationKeys = new IdentificationKeys(
12
+ $trusteeSlug.val(),
13
+ $trusteePublicKey.val()
14
+ );
12
15
  if (!window.trusteeIdentificationKeys.browserSupport) {
13
16
  $("#not_supported_browser").addClass("visible");
14
17
  return;
@@ -18,13 +21,18 @@ $(() => {
18
21
  const $generate = $("#generate_identification_keys");
19
22
  const $upload = $("#upload_identification_keys");
20
23
 
21
- $("button", $generate).click(() => {
22
- window.trusteeIdentificationKeys.generate().then(() => {
23
- $trusteePublicKey.val(JSON.stringify(window.trusteeIdentificationKeys.publicKey));
24
- $submit.addClass("visible");
25
- }).catch(() => {
26
- alert($generate.data("error"))
27
- });
24
+ $("button", $generate).on("click", () => {
25
+ window.trusteeIdentificationKeys.
26
+ generate().
27
+ then(() => {
28
+ $trusteePublicKey.val(
29
+ JSON.stringify(window.trusteeIdentificationKeys.publicKey)
30
+ );
31
+ $submit.addClass("visible");
32
+ }).
33
+ catch(() => {
34
+ alert($generate.data("error"));
35
+ });
28
36
  });
29
37
 
30
38
  $("button.hollow", $submit).click(() => {
@@ -33,12 +41,15 @@ $(() => {
33
41
  });
34
42
 
35
43
  $("button", $upload).click(() => {
36
- window.trusteeIdentificationKeys.upload().then(() => {
37
- $upload.addClass("hide");
38
- }).catch((errorMessage) => {
39
- alert($upload.data(errorMessage));
40
- });
41
- })
44
+ window.trusteeIdentificationKeys.
45
+ upload().
46
+ then(() => {
47
+ $upload.addClass("hide");
48
+ }).
49
+ catch((errorMessage) => {
50
+ alert($upload.data(errorMessage));
51
+ });
52
+ });
42
53
 
43
54
  window.trusteeIdentificationKeys.present((result) => {
44
55
  $upload.toggleClass("hide", result);
@@ -46,6 +57,6 @@ $(() => {
46
57
  }
47
58
 
48
59
  $(document).ready(() => {
49
- identificationKeys()
50
- })
51
- })
60
+ identificationKeys();
61
+ });
62
+ });
@@ -1,4 +1,4 @@
1
- import { Client } from "@codegram/decidim-bulletin_board";
1
+ import { Client } from "@decidim/decidim-bulletin_board";
2
2
 
3
3
  $(async () => {
4
4
  const $castingVoteWrapper = $(".casting-vote-wrapper");
@@ -1,11 +1,12 @@
1
1
  /* eslint-disable require-jsdoc */
2
2
 
3
- import { VoteComponent } from "@codegram/decidim-bulletin_board";
3
+ import { VoteComponent } from "@decidim/decidim-bulletin_board";
4
4
 
5
- import * as VotingSchemesDummy from "@codegram/voting_schemes-dummy";
5
+ import * as VotingSchemesDummy from "@decidim/voting_schemes-dummy";
6
6
  const DummyVoterWrapperAdapter = VotingSchemesDummy.VoterWrapperAdapter;
7
- import * as VotingSchemesElectionGuard from "@codegram/voting_schemes-electionguard";
8
- const ElectionGuardVoterWrapperAdapter = VotingSchemesElectionGuard.VoterWrapperAdapter;
7
+ import * as VotingSchemesElectionGuard from "@decidim/voting_schemes-electionguard";
8
+ const ElectionGuardVoterWrapperAdapter =
9
+ VotingSchemesElectionGuard.VoterWrapperAdapter;
9
10
 
10
11
  export default function setupVoteComponent($voteWrapper) {
11
12
  // Data
@@ -47,4 +48,3 @@ export default function setupVoteComponent($voteWrapper) {
47
48
 
48
49
  window.Decidim = window.Decidim || {};
49
50
  window.Decidim.setupVoteComponent = setupVoteComponent;
50
-
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable require-jsdoc, prefer-template, func-style, id-length, no-use-before-define, init-declarations, no-invalid-this */
2
2
  /* eslint no-unused-vars: ["error", { "args": "none" }] */
3
3
 
4
- import { Client } from "@codegram/decidim-bulletin_board";
4
+ import { Client } from "@decidim/decidim-bulletin_board";
5
5
 
6
6
  $(() => {
7
7
  const $voteVerifyWrapper = $(".verify-vote-wrapper");
@@ -1,4 +1,4 @@
1
- import { Client } from "@codegram/decidim-bulletin_board";
1
+ import { Client } from "@decidim/decidim-bulletin_board";
2
2
 
3
3
  $(async () => {
4
4
  const $inPersonVoteWrapper = $(".in-person-vote-wrapper");
@@ -15,26 +15,51 @@ module Decidim
15
15
  class ElectionPresenter < Decidim::Log::BasePresenter
16
16
  private
17
17
 
18
- def diff_fields_mapping
19
- {
20
- name: :i18n,
21
- published_at: :date,
22
- weight: :integer
23
- }
24
- end
25
-
26
18
  def i18n_labels_scope
27
19
  "activemodel.attributes.election"
28
20
  end
29
21
 
30
22
  def action_string
31
23
  case action
32
- when "publish", "unpublish", "setup", "start_key_ceremony", "start_vote", "end_vote", "start_tally", "publish_results"
24
+ when "publish", "unpublish", "create", "delete", "update",
25
+ "setup", "start_key_ceremony", "start_vote", "end_vote", "start_tally", "report_missing_trustee", "publish_results"
33
26
  "decidim.elections.admin_log.election.#{action}"
34
27
  else
35
28
  super
36
29
  end
37
30
  end
31
+
32
+ def i18n_params
33
+ super.merge(trustee_info)
34
+ end
35
+
36
+ def trustee_info
37
+ return {} unless action == "report_missing_trustee"
38
+
39
+ {
40
+ trustee_name: if trustee
41
+ Decidim::Log::UserPresenter.new(trustee.user, h, trustee_extra).present
42
+ else
43
+ trustee_extra["name"]
44
+ end
45
+ }
46
+ end
47
+
48
+ def trustee
49
+ @trustee ||= Decidim::Elections::Trustee.find(action_log.extra["extra"]["trustee_id"]) if action_log.extra["extra"]["trustee_id"]
50
+ end
51
+
52
+ def trustee_extra
53
+ info = {
54
+ "name" => trustee.name,
55
+ "nickname" => trustee.user&.nickname
56
+ }
57
+
58
+ info["name"] ||= action_log.extra["extra"]["name"]
59
+ info["nickname"] ||= action_log.extra["extra"]["nickname"]
60
+
61
+ info
62
+ end
38
63
  end
39
64
  end
40
65
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Elections
5
+ module AdminLog
6
+ # This class holds the logic to present a `Decidim::Trustee`
7
+ # for the `AdminLog` log.
8
+ #
9
+ # Usage should be automatic and you shouldn't need to call this class
10
+ # directly, but here's an example:
11
+ #
12
+ # action_log = Decidim::ActionLog.last
13
+ # view_helpers # => this comes from the views
14
+ # TrusteePresenter.new(action_log, view_helpers).present
15
+ class TrusteePresenter < Decidim::Log::BasePresenter
16
+ private
17
+
18
+ def trustee_user
19
+ @trustee_user ||= action_log.resource&.user
20
+ end
21
+
22
+ def trustee_user_extra
23
+ {
24
+ "name" => trustee_user.name,
25
+ "nickname" => trustee_user.nickname
26
+ }
27
+ end
28
+
29
+ def trustee_user_presenter
30
+ @trustee_user_presenter ||= Decidim::Log::UserPresenter.new(trustee_user, h, trustee_user_extra)
31
+ end
32
+
33
+ def i18n_params
34
+ super.merge(
35
+ trustee_user: trustee_user.present? ? trustee_user_presenter.present : resource_presenter.try(:present)
36
+ )
37
+ end
38
+
39
+ def action_string
40
+ case action
41
+ when "create"
42
+ "decidim.elections.admin_log.trustee.#{action}"
43
+ else
44
+ super
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -11,11 +11,15 @@ module Decidim
11
11
  end
12
12
 
13
13
  def public_key_thumbprint
14
- @public_key_thumbprint ||= jwk_thumbprint(JSON.parse(trustee.public_key)) if trustee.public_key.present?
14
+ @public_key_thumbprint ||= format_thumbprint(jwk_thumbprint(JSON.parse(trustee.public_key))) if trustee.public_key.present?
15
15
  end
16
16
 
17
17
  private
18
18
 
19
+ def format_thumbprint(thumbprint)
20
+ "<pre class='text-small text-muted'>#{thumbprint[0..14]}\n#{thumbprint[15..-16]}\n#{thumbprint[-15..-1]}</pre>".html_safe
21
+ end
22
+
19
23
  def jwk_thumbprint(key)
20
24
  Base64.urlsafe_encode64(Digest::SHA256.digest(key.slice("e", "kty", "n").to_json), padding: false)
21
25
  end