From 8d3aef3d86f79b78144a36363ef0c764a3e0915a Mon Sep 17 00:00:00 2001 From: leio10 Date: Fri, 26 Mar 2021 14:37:22 +0100 Subject: [PATCH] Improve vote flow (#7682) --- .prettierrc | 4 +- .../key_ceremony.js.es6 | 0 .../{trustee_zone => trustee}/tally.js.es6 | 0 .../{ => trustee}/trustee_zone.js.es6 | 0 .../elections/voter/casting-vote.js.es6 | 15 ++++ .../decidim/elections/voter/new-vote.js.es6 | 81 +++++++++++++++++++ .../elections/voter/setup-preview.js.es6 | 79 ++++++++++++++++++ .../decidim/elections/voter/setup-vote.js.es6 | 58 +++++++++++++ .../verify-vote.js.es6} | 39 ++++----- .../decidim/elections/{ => voter}/vote.js.es6 | 0 .../vote_questions.component.js.es6 | 0 .../votings/voting-description-cell.js.es6 | 10 +-- .../elections/election_vote_cta/show.erb | 2 +- .../elections/election_vote_cta_cell.rb | 15 +++- .../decidim/elections/voter/cast_vote.rb | 4 +- .../decidim/elections/votes_controller.rb | 72 ++++++++--------- .../elections/votes/vote_accepted_event.rb | 2 +- .../{ballot => voter}/verify_vote_form.rb | 6 +- .../{encrypted_vote_form.rb => vote_form.rb} | 20 +++-- .../trustee_zone/elections/show.html.erb | 2 +- .../trustee_zone/trustees/show.html.erb | 2 +- .../votes/_election_votes_confirmed.html.erb | 28 ------- .../_election_votes_steps_header.html.erb | 12 --- ...header.html.erb => _focus_header.html.erb} | 0 ...erb => _new_ballot_decision_step.html.erb} | 10 ++- ...rm.html.erb => _new_confirm_step.html.erb} | 4 +- ....erb => _new_confirm_step_footer.html.erb} | 1 - ...html.erb => _new_encrypting_step.html.erb} | 2 +- ...estion.html.erb => _new_question.html.erb} | 2 +- ....html.erb => _new_question_modal.html.erb} | 0 .../elections/votes/_show_casted.html.erb | 26 ++++++ .../elections/votes/_show_casting.html.erb | 25 ++++++ ..._failed.html.erb => _show_failed.html.erb} | 8 +- .../elections/votes/cast_failed.js.erb | 1 - .../elections/votes/cast_success.js.erb | 1 - .../decidim/elections/votes/new.html.erb | 42 +++++----- .../decidim/elections/votes/show.html.erb | 11 +++ .../decidim/elections/votes/verify.html.erb | 15 ++-- .../decidim/_election_votes_header.html.erb | 2 +- decidim-elections/config/locales/en.yml | 19 +++-- .../lib/decidim/elections/engine.rb | 3 +- .../decidim/elections/voter/cast_vote_spec.rb | 12 ++- .../votes/vote_accepted_event_spec.rb | 2 +- .../verify_vote_form_spec.rb | 8 +- ...ed_vote_form_spec.rb => vote_form_spec.rb} | 24 ++---- 45 files changed, 453 insertions(+), 216 deletions(-) rename decidim-elections/app/assets/javascripts/decidim/elections/{trustee_zone => trustee}/key_ceremony.js.es6 (100%) rename decidim-elections/app/assets/javascripts/decidim/elections/{trustee_zone => trustee}/tally.js.es6 (100%) rename decidim-elections/app/assets/javascripts/decidim/elections/{ => trustee}/trustee_zone.js.es6 (100%) create mode 100644 decidim-elections/app/assets/javascripts/decidim/elections/voter/casting-vote.js.es6 create mode 100644 decidim-elections/app/assets/javascripts/decidim/elections/voter/new-vote.js.es6 create mode 100644 decidim-elections/app/assets/javascripts/decidim/elections/voter/setup-preview.js.es6 create mode 100644 decidim-elections/app/assets/javascripts/decidim/elections/voter/setup-vote.js.es6 rename decidim-elections/app/assets/javascripts/decidim/elections/{vote_verify.js.es6 => voter/verify-vote.js.es6} (64%) rename decidim-elections/app/assets/javascripts/decidim/elections/{ => voter}/vote.js.es6 (100%) rename decidim-elections/app/assets/javascripts/decidim/elections/{ => voter}/vote_questions.component.js.es6 (100%) rename decidim-elections/app/forms/decidim/elections/{ballot => voter}/verify_vote_form.rb (75%) rename decidim-elections/app/forms/decidim/elections/voter/{encrypted_vote_form.rb => vote_form.rb} (61%) delete mode 100644 decidim-elections/app/views/decidim/elections/votes/_election_votes_confirmed.html.erb delete mode 100644 decidim-elections/app/views/decidim/elections/votes/_election_votes_steps_header.html.erb rename decidim-elections/app/views/decidim/elections/votes/{_election_votes_header.html.erb => _focus_header.html.erb} (100%) rename decidim-elections/app/views/decidim/elections/votes/{_election_votes_ballot_decision.html.erb => _new_ballot_decision_step.html.erb} (63%) rename decidim-elections/app/views/decidim/elections/votes/{_election_votes_confirm.html.erb => _new_confirm_step.html.erb} (92%) rename decidim-elections/app/views/decidim/elections/votes/{_election_votes_confirm_footer.html.erb => _new_confirm_step_footer.html.erb} (95%) rename decidim-elections/app/views/decidim/elections/votes/{_election_votes_encrypting.html.erb => _new_encrypting_step.html.erb} (84%) rename decidim-elections/app/views/decidim/elections/votes/{_election_votes_question.html.erb => _new_question.html.erb} (96%) rename decidim-elections/app/views/decidim/elections/votes/{_election_votes_modal.html.erb => _new_question_modal.html.erb} (100%) create mode 100644 decidim-elections/app/views/decidim/elections/votes/_show_casted.html.erb create mode 100644 decidim-elections/app/views/decidim/elections/votes/_show_casting.html.erb rename decidim-elections/app/views/decidim/elections/votes/{_election_votes_failed.html.erb => _show_failed.html.erb} (70%) delete mode 100644 decidim-elections/app/views/decidim/elections/votes/cast_failed.js.erb delete mode 100644 decidim-elections/app/views/decidim/elections/votes/cast_success.js.erb create mode 100644 decidim-elections/app/views/decidim/elections/votes/show.html.erb rename decidim-elections/spec/forms/decidim/elections/{ballot => voter}/verify_vote_form_spec.rb (75%) rename decidim-elections/spec/forms/decidim/elections/voter/{encrypted_vote_form_spec.rb => vote_form_spec.rb} (74%) diff --git a/.prettierrc b/.prettierrc index 8f4d58a7b5554..1a8654abc2805 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,3 @@ { - "trailingComma": true -} + "trailingComma": "none" +} \ No newline at end of file diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/trustee_zone/key_ceremony.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/trustee/key_ceremony.js.es6 similarity index 100% rename from decidim-elections/app/assets/javascripts/decidim/elections/trustee_zone/key_ceremony.js.es6 rename to decidim-elections/app/assets/javascripts/decidim/elections/trustee/key_ceremony.js.es6 diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/trustee_zone/tally.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/trustee/tally.js.es6 similarity index 100% rename from decidim-elections/app/assets/javascripts/decidim/elections/trustee_zone/tally.js.es6 rename to decidim-elections/app/assets/javascripts/decidim/elections/trustee/tally.js.es6 diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/trustee_zone.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/trustee/trustee_zone.js.es6 similarity index 100% rename from decidim-elections/app/assets/javascripts/decidim/elections/trustee_zone.js.es6 rename to decidim-elections/app/assets/javascripts/decidim/elections/trustee/trustee_zone.js.es6 diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/voter/casting-vote.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/voter/casting-vote.js.es6 new file mode 100644 index 0000000000000..a9661a3da2fc1 --- /dev/null +++ b/decidim-elections/app/assets/javascripts/decidim/elections/voter/casting-vote.js.es6 @@ -0,0 +1,15 @@ +// = require decidim/bulletin_board/decidim-bulletin_board + +$(async () => { + const $castingVoteWrapper = $(".casting-vote-wrapper"); + const { Client } = decidimBulletinBoard; + + const bulletinBoardClient = new Client({ + apiEndpointUrl: $castingVoteWrapper.data("apiEndpointUrl") + }); + const messageId = $castingVoteWrapper.data("messageId"); + + await bulletinBoardClient.waitForPendingMessageToBeProcessed(messageId); + + $("form.update_vote_status").trigger("submit"); +}); diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/voter/new-vote.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/voter/new-vote.js.es6 new file mode 100644 index 0000000000000..c4876a5b9ba36 --- /dev/null +++ b/decidim-elections/app/assets/javascripts/decidim/elections/voter/new-vote.js.es6 @@ -0,0 +1,81 @@ +/* eslint-disable no-console */ +// = require ./vote_questions.component + +$(async () => { + const { VoteQuestionsComponent, setupVoteComponent } = window.Decidim; + + // UI Elements + const $voteWrapper = $(".vote-wrapper"); + const $ballotHash = $voteWrapper.find(".ballot-hash"); + + // Use the questions component + const questionsComponent = new VoteQuestionsComponent($voteWrapper); + questionsComponent.init(); + $(document).on("on.zf.toggler", () => { + // continue and back btn + questionsComponent.init(); + }); + + // Get the vote component and bind it to all UI events + const voteComponent = setupVoteComponent($voteWrapper); + await voteComponent.bindEvents({ + onBindEncryptButton(onEventTriggered) { + $(".button.confirm").on("click", onEventTriggered); + }, + onStart() {}, + onVoteEncryption(validVoteFn) { + const getFormData = (formData) => { + return formData.serializeArray().reduce((acc, { name, value }) => { + if (!acc[name]) { + acc[name] = []; + } + acc[name] = [...acc[name], `${name}_${value}`]; + return acc; + }, {}); + }; + const formData = getFormData($voteWrapper.find(".answer_input")); + validVoteFn(formData); + }, + castOrAuditBallot({ encryptedData, encryptedDataHash }) { + $voteWrapper.find("#encrypting").addClass("hide"); + $ballotHash.text(`Your ballot identifier is: ${encryptedDataHash}`); + $voteWrapper.find("#ballot_decision").removeClass("hide"); + + const $form = $("form.new_vote"); + $("#vote_encrypted_data", $form).val(encryptedData); + $("#vote_encrypted_data_hash", $form).val(encryptedDataHash); + }, + onBindAuditBallotButton(onEventTriggered) { + $(".audit_ballot").on("click", onEventTriggered); + }, + onBindCastBallotButton(onEventTriggered) { + $(".cast_ballot").on("click", onEventTriggered); + }, + onAuditBallot(auditedData, auditedDataFileName) { + const vote = JSON.stringify(auditedData); + const link = document.createElement("a"); + $voteWrapper.find(".button.cast_ballot").addClass("hide"); + $voteWrapper.find(".button.back").removeClass("hide"); + questionsComponent.voteCasted = true; + + link.setAttribute("href", `data:text/plain;charset=utf-8,${vote}`); + link.setAttribute("download", auditedDataFileName); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }, + onAuditComplete() { + console.log("Audit completed"); + }, + onCastBallot() { + questionsComponent.voteCasted = true; + $(".cast_ballot").prop("disabled", true); + }, + onCastComplete() { + console.log("Cast completed"); + }, + onInvalid() { + console.log("Something went wrong."); + } + }); +}); diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/voter/setup-preview.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/voter/setup-preview.js.es6 new file mode 100644 index 0000000000000..5641a59d27a88 --- /dev/null +++ b/decidim-elections/app/assets/javascripts/decidim/elections/voter/setup-preview.js.es6 @@ -0,0 +1,79 @@ +// The wait time used to simulate the encryption of the vote during the preview +const FAKE_ENCRYPTION_TIME = 1000; + +((exports) => { + class PreviewVoteComponent { + constructor({ electionUniqueId, voterUniqueId }) { + this.electionUniqueId = electionUniqueId; + this.voterUniqueId = voterUniqueId; + } + + async bindEvents({ + onBindEncryptButton, + onStart, + onVoteEncryption, + castOrAuditBallot, + onBindAuditBallotButton, + onBindCastBallotButton, + onAuditBallot, + onCastBallot, + onAuditComplete, + onCastComplete, + onInvalid + }) { + onBindEncryptButton(async () => { + onStart(); + onVoteEncryption( + (plainVote) => { + this.fakeEncrypt(plainVote).then((ballot) => { + castOrAuditBallot(ballot); + onBindAuditBallotButton(() => { + onAuditBallot( + ballot, + `${this.voterUniqueId}-election-${this.electionUniqueId}.txt` + ); + onAuditComplete(); + }); + + onBindCastBallotButton(async () => { + await onCastBallot(ballot); + onCastComplete(); + }); + }); + }, + () => { + onInvalid(); + } + ); + }); + } + async fakeEncrypt(plainVote) { + await new Promise((resolve) => setTimeout(resolve, FAKE_ENCRYPTION_TIME)); + + return { + encryptedData: plainVote, + encryptedDataHash: this.generateHexString(64), + auditableData: plainVote + }; + } + generateHexString(length) { + return Array(length). + fill(""). + map(() => Math.random().toString(16).charAt(2)). + join(""); + } + } + + const setupVoteComponent = ($voteWrapper) => { + const voterUniqueId = $voteWrapper.data("voterId"); + const electionUniqueId = $voteWrapper.data("electionUniqueId"); + + return new PreviewVoteComponent({ + electionUniqueId, + voterUniqueId + }); + }; + + exports.Decidim = exports.Decidim || {}; + exports.Decidim.setupVoteComponent = setupVoteComponent; +})(window); diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/voter/setup-vote.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/voter/setup-vote.js.es6 new file mode 100644 index 0000000000000..d8c6b5a2ec522 --- /dev/null +++ b/decidim-elections/app/assets/javascripts/decidim/elections/voter/setup-vote.js.es6 @@ -0,0 +1,58 @@ +// = require decidim/bulletin_board/decidim-bulletin_board +// = require decidim/bulletin_board/dummy-voting-scheme + +// = require decidim/bulletin_board/election_guard-voting-scheme +// Note: these gems will be moved to the application in the next release +// = require voting_schemes/dummy/dummy +// = require voting_schemes/electionguard/electionguard + +((exports) => { + const setupVoteComponent = ($voteWrapper) => { + const { VoteComponent } = window.decidimBulletinBoard; + const { + VoterWrapperAdapter: DummyVoterWrapperAdapter + } = window.dummyVotingScheme; + const { + VoterWrapperAdapter: ElectionGuardVoterWrapperAdapter + } = window.electionGuardVotingScheme; + + // Data + const bulletinBoardClientParams = { + apiEndpointUrl: $voteWrapper.data("apiEndpointUrl") + }; + const electionUniqueId = $voteWrapper.data("electionUniqueId"); + const authorityPublicKeyJSON = JSON.stringify( + $voteWrapper.data("authorityPublicKey") + ); + const voterUniqueId = $voteWrapper.data("voterId"); + const schemeName = $voteWrapper.data("schemeName"); + + // Use the correct voter wrapper adapter + let voterWrapperAdapter = null; + + if (schemeName === "dummy") { + voterWrapperAdapter = new DummyVoterWrapperAdapter({ + voterId: voterUniqueId + }); + } else if (schemeName === "electionguard") { + voterWrapperAdapter = new ElectionGuardVoterWrapperAdapter({ + voterId: voterUniqueId, + workerUrl: "/assets/electionguard/webworker.js" + }); + } else { + throw new Error(`Voting scheme ${schemeName} not supported.`); + } + + // Returns the vote component + return new VoteComponent({ + bulletinBoardClientParams, + authorityPublicKeyJSON, + electionUniqueId, + voterUniqueId, + voterWrapperAdapter + }); + }; + + exports.Decidim = exports.Decidim || {}; + exports.Decidim.setupVoteComponent = setupVoteComponent; +})(window); diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/vote_verify.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/voter/verify-vote.js.es6 similarity index 64% rename from decidim-elections/app/assets/javascripts/decidim/elections/vote_verify.js.es6 rename to decidim-elections/app/assets/javascripts/decidim/elections/voter/verify-vote.js.es6 index c15212208df25..aa05a45047736 100644 --- a/decidim-elections/app/assets/javascripts/decidim/elections/vote_verify.js.es6 +++ b/decidim-elections/app/assets/javascripts/decidim/elections/voter/verify-vote.js.es6 @@ -4,7 +4,7 @@ $(() => { const { Client } = decidimBulletinBoard; - const $voteVerifyWrapper = $(".vote-verify-wrapper"); + const $voteVerifyWrapper = $(".verify-vote-wrapper"); const $verifySubmitButton = $voteVerifyWrapper.find("a.focus__next.confirm"); let $formData = $voteVerifyWrapper.find(".vote-identifier"); @@ -14,7 +14,7 @@ $(() => { onVoteIdentifierChange(); } - initStep() + initStep(); function onVoteIdentifierChange() { $formData.on("keyup input", (event) => { @@ -26,9 +26,9 @@ $(() => { function toggleVerifyButton() { if ($formData.val().length > 5) { - $($verifySubmitButton).removeClass("disabled") + $($verifySubmitButton).removeClass("disabled"); } else { - $($verifySubmitButton).addClass("disabled") + $($verifySubmitButton).addClass("disabled"); } } @@ -47,25 +47,26 @@ $(() => { function verifyVoteIdentifier() { const bulletinBoardClient = new Client({ - apiEndpointUrl: $voteVerifyWrapper.data("apiEndpointUrl"), - wsEndpointUrl: $voteVerifyWrapper.data("websocketUrl") + apiEndpointUrl: $voteVerifyWrapper.data("apiEndpointUrl") }); - bulletinBoardClient.getLogEntry({ - electionUniqueId: $voteVerifyWrapper.data("electionUniqueId"), - contentHash: $formData.val() - }).then((result) => { - if (result) { - hideErrorCallout(); - $voteVerifyWrapper.find(".verify-vote-success").removeClass("hide"); - } else { - hideSuccessCallout(); - $voteVerifyWrapper.find(".verify-vote-error").removeClass("hide"); - } - }) + bulletinBoardClient. + getLogEntry({ + electionUniqueId: $voteVerifyWrapper.data("electionUniqueId"), + contentHash: $formData.val() + }). + then((result) => { + if (result) { + hideErrorCallout(); + $voteVerifyWrapper.find(".verify-vote-success").removeClass("hide"); + } else { + hideSuccessCallout(); + $voteVerifyWrapper.find(".verify-vote-error").removeClass("hide"); + } + }); } $(document).on("on.zf.toggler", (event) => { - initStep() + initStep(); }); }); diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/vote.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/voter/vote.js.es6 similarity index 100% rename from decidim-elections/app/assets/javascripts/decidim/elections/vote.js.es6 rename to decidim-elections/app/assets/javascripts/decidim/elections/voter/vote.js.es6 diff --git a/decidim-elections/app/assets/javascripts/decidim/elections/vote_questions.component.js.es6 b/decidim-elections/app/assets/javascripts/decidim/elections/voter/vote_questions.component.js.es6 similarity index 100% rename from decidim-elections/app/assets/javascripts/decidim/elections/vote_questions.component.js.es6 rename to decidim-elections/app/assets/javascripts/decidim/elections/voter/vote_questions.component.js.es6 diff --git a/decidim-elections/app/assets/javascripts/decidim/votings/voting-description-cell.js.es6 b/decidim-elections/app/assets/javascripts/decidim/votings/voting-description-cell.js.es6 index 90c8244642cd2..b368ed2f80dd1 100644 --- a/decidim-elections/app/assets/javascripts/decidim/votings/voting-description-cell.js.es6 +++ b/decidim-elections/app/assets/javascripts/decidim/votings/voting-description-cell.js.es6 @@ -5,10 +5,10 @@ $(() => { const unit = $("html").css("font-size"); if (typeof count !== "undefined" && count > 0) { - return (parseInt(unit, 0) * count); + return (parseInt(unit, 10) || 0) * count; } - return parseInt(unit, 0); - } + return parseInt(unit, 10) || 0; + }; const $button = $(".voting-description-cell .content-height-toggler .button"); const $content = $button.closest(".voting-description-cell").find(".content"); @@ -22,7 +22,7 @@ $(() => { if (contentHeight < contentMaxHeight) { $button.hide(); } else { - $content.css("max-height", contentMaxHeight) + $content.css("max-height", contentMaxHeight); } $button.on("click", (event) => { @@ -38,4 +38,4 @@ $(() => { $buttonTextLess.toggleClass("hide"); $buttonTextMore.toggleClass("hide"); }); -}) +}); diff --git a/decidim-elections/app/cells/decidim/elections/election_vote_cta/show.erb b/decidim-elections/app/cells/decidim/elections/election_vote_cta/show.erb index 016a954a70d15..494d773859052 100644 --- a/decidim-elections/app/cells/decidim/elections/election_vote_cta/show.erb +++ b/decidim-elections/app/cells/decidim/elections/election_vote_cta/show.erb @@ -22,7 +22,7 @@ <% if model.started? %> <%= t("verify.already_voted", scope: "decidim.elections.elections.show") %> - <%= link_to t("verify.verify_here", scope: "decidim.elections.elections.show"), verify_election_vote_path %> + <%= link_to t("verify.verify_here", scope: "decidim.elections.elections.show"), election_vote_verify_path %> <% else %> <%= t("verify.will_verify", scope: "decidim.elections.elections.show") %> <% end %> diff --git a/decidim-elections/app/cells/decidim/elections/election_vote_cta_cell.rb b/decidim-elections/app/cells/decidim/elections/election_vote_cta_cell.rb index 6113d9d9cc1bb..ec122bbc16bf4 100644 --- a/decidim-elections/app/cells/decidim/elections/election_vote_cta_cell.rb +++ b/decidim-elections/app/cells/decidim/elections/election_vote_cta_cell.rb @@ -34,16 +34,19 @@ def vote_action_button_text end end - def verify_election_vote_path - engine_router.verify_election_vote_path( + def election_vote_verify_path + engine_router.election_vote_verify_path( "#{key_participatory_space_slug}": current_participatory_space.slug, component_id: current_component.id, - election_id: model.id + election_id: model.id, + vote_id: "_" ) end def callout_text - if last_vote_accepted? + if last_vote_pending? + t("callout.pending_vote", scope: "decidim.elections.elections.show") + elsif last_vote_accepted? t("callout.already_voted", scope: "decidim.elections.elections.show") else t("callout.vote_rejected", scope: "decidim.elections.elections.show") @@ -54,6 +57,10 @@ def already_voted? last_vote.present? end + def last_vote_pending? + !!last_vote&.pending? + end + def last_vote_accepted? !!last_vote&.accepted? end diff --git a/decidim-elections/app/commands/decidim/elections/voter/cast_vote.rb b/decidim-elections/app/commands/decidim/elections/voter/cast_vote.rb index 3a15cf4d3cde6..36d06a9909ac8 100644 --- a/decidim-elections/app/commands/decidim/elections/voter/cast_vote.rb +++ b/decidim-elections/app/commands/decidim/elections/voter/cast_vote.rb @@ -34,7 +34,7 @@ def call delegate :bulletin_board, to: :form def cast_vote - bulletin_board.cast_vote(form.election_id, form.voter_id, form.encrypted_vote) do |message_id| + bulletin_board.cast_vote(form.election_id, form.voter_id, form.encrypted_data) do |message_id| create_vote(message_id) end end @@ -48,7 +48,7 @@ def create_vote(message_id) message_id: message_id, election: form.election, voter_id: form.voter_id, - encrypted_vote_hash: form.encrypted_vote_hash, + encrypted_vote_hash: form.encrypted_data_hash, status: :pending, user: user ) diff --git a/decidim-elections/app/controllers/decidim/elections/votes_controller.rb b/decidim-elections/app/controllers/decidim/elections/votes_controller.rb index 7ba7d320c1528..f18e8f4ab457d 100644 --- a/decidim-elections/app/controllers/decidim/elections/votes_controller.rb +++ b/decidim-elections/app/controllers/decidim/elections/votes_controller.rb @@ -8,64 +8,66 @@ class VotesController < Decidim::Elections::ApplicationController include FormFactory helper VotesHelper - helper_method :elections, :election, :questions, :questions_count, :booth_mode, :vote, :bulletin_board_server, :authority_public_key, :scheme_name + helper_method :elections, :election, :questions, :questions_count, :preview_mode?, :vote, :bulletin_board_server, :authority_public_key, :scheme_name, :election_unique_id delegate :count, to: :questions, prefix: true def new - return redirect_to(return_path, alert: t("votes.messages.not_allowed", scope: "decidim.elections")) if booth_mode.nil? - return redirect_to(pending_vote_path) if pending_vote? + return redirect_to(return_path, alert: t("votes.messages.not_allowed", scope: "decidim.elections")) unless vote_mode? || preview_mode? + return redirect_to(election_vote_path(election, id: pending_vote.encrypted_vote_hash)) if pending_vote - @form = form(Voter::EncryptedVoteForm).instance(election: election) + @form = form(Voter::VoteForm).instance(election: election) end - def update - Voter::UpdateVoteStatus.call(vote) do - on(:ok) do - flash[:notice] = I18n.t("votes.update.success", scope: "decidim.elections") - end - on(:invalid) do - flash[:alert] = I18n.t("votes.update.error", scope: "decidim.elections") - end + def create + if vote_mode? + @form = form(Voter::VoteForm).from_params(params, election: election) + Voter::CastVote.call(@form) end + + redirect_to election_vote_path(election, id: params[:vote][:encrypted_data_hash]) end - def cast - @form = form(Voter::EncryptedVoteForm).from_params(params, election: election) - return render :cast_success, locals: { message_id: "PreviewMessageId", vote_id: nil } if preview? + def show; end - Voter::CastVote.call(@form) do - on(:ok) do |vote| - render :cast_success, locals: { message_id: vote.message_id, vote_id: vote.id } + def update + Voter::UpdateVoteStatus.call(vote) do + on(:ok) do + redirect_to election_vote_path(election, id: vote.encrypted_vote_hash) end on(:invalid) do - render :cast_failed + flash[:alert] = I18n.t("votes.update.error", scope: "decidim.elections") + redirect_to election end end end def verify - @form = form(Ballot::VerifyVoteForm).instance(election: election) + @form = form(Voter::VerifyVoteForm).instance(election: election) end private delegate :bulletin_board_server, :scheme_name, to: :bulletin_board_client + def election_unique_id + @election_unique_id ||= Decidim::BulletinBoard::MessageIdentifier.unique_election_id(bulletin_board_client.authority_slug, election.id) + end + def vote - @vote ||= Decidim::Elections::Vote.find_by(id: params[:vote_id]) + @vote ||= Decidim::Elections::Vote.find_by(encrypted_vote_hash: params[:id]) if params[:id] end - def pending_vote? - Decidim::Elections::Votes::PendingVotes.for.exists?(user: current_user, election: election) + def vote_mode? + return @vote_mode if defined?(@vote_mode) + + @vote_mode = allowed_to? :vote, :election, election: election end - def booth_mode - @booth_mode ||= if allowed_to? :vote, :election, election: election - :vote - elsif allowed_to? :preview, :election, election: election - :preview - end + def preview_mode? + return @preview_mode if defined?(@preview_mode) + + @preview_mode = !vote_mode? && allowed_to?(:preview, :election, election: election) end def return_path @@ -76,12 +78,8 @@ def return_path end end - def pending_vote_path - @pending_vote_path ||= if allowed_to? :view, :election, election: election - verify_election_vote_path(election) - else - elections_path - end + def pending_vote + @pending_vote ||= Decidim::Elections::Votes::PendingVotes.for.find_by(user: current_user, election: election) end def bulletin_board_client @@ -103,10 +101,6 @@ def election def questions @questions ||= election.questions.includes(:answers).order(weight: :asc, id: :asc) end - - def preview? - booth_mode == :preview - end end end end diff --git a/decidim-elections/app/events/decidim/elections/votes/vote_accepted_event.rb b/decidim-elections/app/events/decidim/elections/votes/vote_accepted_event.rb index 8697266d89e6a..08c763a6a3ac4 100644 --- a/decidim-elections/app/events/decidim/elections/votes/vote_accepted_event.rb +++ b/decidim-elections/app/events/decidim/elections/votes/vote_accepted_event.rb @@ -16,7 +16,7 @@ def encrypted_vote_hash end def verify_url - Decidim::EngineRouter.main_proxy(resource.component).verify_election_vote_url(resource) + Decidim::EngineRouter.main_proxy(resource.component).election_vote_verify_url(resource, vote_id: encrypted_vote_hash) end end end diff --git a/decidim-elections/app/forms/decidim/elections/ballot/verify_vote_form.rb b/decidim-elections/app/forms/decidim/elections/voter/verify_vote_form.rb similarity index 75% rename from decidim-elections/app/forms/decidim/elections/ballot/verify_vote_form.rb rename to decidim-elections/app/forms/decidim/elections/voter/verify_vote_form.rb index 72ff7179c296f..15144d4e0e675 100644 --- a/decidim-elections/app/forms/decidim/elections/ballot/verify_vote_form.rb +++ b/decidim-elections/app/forms/decidim/elections/voter/verify_vote_form.rb @@ -2,7 +2,7 @@ module Decidim module Elections - module Ballot + module Voter # This class holds the data to verify a vote. class VerifyVoteForm < Decidim::Form attribute :vote_identifier, String @@ -11,10 +11,6 @@ class VerifyVoteForm < Decidim::Form delegate :id, to: :election, prefix: true - def election_unique_id - @election_unique_id ||= Decidim::BulletinBoard::MessageIdentifier.unique_election_id(bulletin_board.authority_slug, election_id) - end - # Public: returns the associated election for the vote. def election @election ||= context.election diff --git a/decidim-elections/app/forms/decidim/elections/voter/encrypted_vote_form.rb b/decidim-elections/app/forms/decidim/elections/voter/vote_form.rb similarity index 61% rename from decidim-elections/app/forms/decidim/elections/voter/encrypted_vote_form.rb rename to decidim-elections/app/forms/decidim/elections/voter/vote_form.rb index 6e3132a8eceaa..ccd3ace8bc902 100644 --- a/decidim-elections/app/forms/decidim/elections/voter/encrypted_vote_form.rb +++ b/decidim-elections/app/forms/decidim/elections/voter/vote_form.rb @@ -4,19 +4,17 @@ module Decidim module Elections module Voter # This class holds the data to cast a vote. - class EncryptedVoteForm < Decidim::Form - attribute :encrypted_vote, String - attribute :encrypted_vote_hash, String + class VoteForm < Decidim::Form + mimic :vote - validates :encrypted_vote, :encrypted_vote_hash, :current_user, :election, presence: true + attribute :encrypted_data, String + attribute :encrypted_data_hash, String + + validates :encrypted_data, :encrypted_data_hash, :current_user, :election, presence: true validate :hash_is_valid delegate :id, to: :election, prefix: true - def election_unique_id - @election_unique_id ||= Decidim::BulletinBoard::MessageIdentifier.unique_election_id(bulletin_board.authority_name.parameterize, election_id) - end - # Public: computes a unique id for the voter/election pair. def voter_id @voter_id ||= Digest::SHA256.hexdigest([current_user.created_at, current_user.id, election.id, bulletin_board.authority_name.parameterize].join(".")) @@ -32,16 +30,16 @@ def bulletin_board end def current_user - @current_user ||= context[:current_user] + @current_user ||= context.current_user end private # Private: check if the hash sent by the browser is correct. def hash_is_valid - return if encrypted_vote.blank? || encrypted_vote_hash.blank? + return if encrypted_data.blank? || encrypted_data_hash.blank? - errors.add(:encrypted_vote_hash, :invalid) if Digest::SHA256.hexdigest(encrypted_vote) != encrypted_vote_hash + errors.add(:encrypted_data_hash, :invalid) if Digest::SHA256.hexdigest(encrypted_data) != encrypted_data_hash end end end diff --git a/decidim-elections/app/views/decidim/elections/trustee_zone/elections/show.html.erb b/decidim-elections/app/views/decidim/elections/trustee_zone/elections/show.html.erb index edf405f37d924..f3dc5709af422 100644 --- a/decidim-elections/app/views/decidim/elections/trustee_zone/elections/show.html.erb +++ b/decidim-elections/app/views/decidim/elections/trustee_zone/elections/show.html.erb @@ -18,5 +18,5 @@ <%= render("#{current_step}_steps") %> - <%= javascript_include_tag "decidim/elections/trustee_zone/#{current_step}", integrity: true %> + <%= javascript_include_tag "decidim/elections/trustee/#{current_step}", integrity: true %> <% end %> diff --git a/decidim-elections/app/views/decidim/elections/trustee_zone/trustees/show.html.erb b/decidim-elections/app/views/decidim/elections/trustee_zone/trustees/show.html.erb index 5aa7b2f0c1789..ced325e2b700c 100644 --- a/decidim-elections/app/views/decidim/elections/trustee_zone/trustees/show.html.erb +++ b/decidim-elections/app/views/decidim/elections/trustee_zone/trustees/show.html.erb @@ -99,4 +99,4 @@ <% end %> -<%= javascript_include_tag "decidim/elections/trustee_zone", integrity: true %> +<%= javascript_include_tag "decidim/elections/trustee/trustee_zone", integrity: true %> diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_confirmed.html.erb b/decidim-elections/app/views/decidim/elections/votes/_election_votes_confirmed.html.erb deleted file mode 100644 index f79c11215daf4..0000000000000 --- a/decidim-elections/app/views/decidim/elections/votes/_election_votes_confirmed.html.erb +++ /dev/null @@ -1,28 +0,0 @@ -<%= render("election_votes_header", header_title: t("decidim.elections.votes.header.confirmed")) %> - -
-
- -
"> -

- <%= t("decidim.elections.votes.confirmed.header") %> -

- -

<%= t("decidim.elections.votes.confirmed.lead") %>

-
- <%= t("decidim.elections.votes.confirmed.text", e_vote_poll_id: encrypted_vote_hash).html_safe %> -

- <%= t("decidim.elections.votes.confirmed.verify_link", link: verify_election_vote_path(election)).html_safe %> -

-
- - <%= link_to :elections, class: "button" do %> - <%= t("decidim.elections.votes.confirmed.back") %> - <% end %> -
- <%= t("decidim.elections.votes.confirmed.experience") %> - <%= link_to t("decidim.elections.votes.confirmed.feedback"), election_feedback_path(election) %> -
-
-
-
diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_steps_header.html.erb b/decidim-elections/app/views/decidim/elections/votes/_election_votes_steps_header.html.erb deleted file mode 100644 index 9b109ba68e95d..0000000000000 --- a/decidim-elections/app/views/decidim/elections/votes/_election_votes_steps_header.html.erb +++ /dev/null @@ -1,12 +0,0 @@ -
-
-
- - <%= t("decidim.elections.votes.new.question_steps", current_step: step + 1, total_steps: questions_count) %> - -
-
- <%= translated_attribute(election.title) %> -
-
-
diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_header.html.erb b/decidim-elections/app/views/decidim/elections/votes/_focus_header.html.erb similarity index 100% rename from decidim-elections/app/views/decidim/elections/votes/_election_votes_header.html.erb rename to decidim-elections/app/views/decidim/elections/votes/_focus_header.html.erb diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_ballot_decision.html.erb b/decidim-elections/app/views/decidim/elections/votes/_new_ballot_decision_step.html.erb similarity index 63% rename from decidim-elections/app/views/decidim/elections/votes/_election_votes_ballot_decision.html.erb rename to decidim-elections/app/views/decidim/elections/votes/_new_ballot_decision_step.html.erb index 77a0671cde694..3bcaeda319d68 100644 --- a/decidim-elections/app/views/decidim/elections/votes/_election_votes_ballot_decision.html.erb +++ b/decidim-elections/app/views/decidim/elections/votes/_new_ballot_decision_step.html.erb @@ -1,4 +1,4 @@ -<%= render("election_votes_header", header_title: t("decidim.elections.votes.header.ballot_decision")) %> +<%= render("focus_header", header_title: t("decidim.elections.votes.header.ballot_decision")) %>
@@ -18,9 +18,11 @@
- - <%= t("decidim.elections.votes.ballot_decision.cast") %> - + <%= decidim_form_for(@form, url: election_votes_path(election), html: { autocomplete: "off" }) do |f| %> + <%= f.hidden_field :encrypted_data %> + <%= f.hidden_field :encrypted_data_hash %> + <%= f.submit t("decidim.elections.votes.ballot_decision.cast"), class: "button cast_ballot" %> + <% end %>
<%= link_to election_path(election), class: "button back hide" do %> <%= t("decidim.elections.votes.ballot_decision.back") %> diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_confirm.html.erb b/decidim-elections/app/views/decidim/elections/votes/_new_confirm_step.html.erb similarity index 92% rename from decidim-elections/app/views/decidim/elections/votes/_election_votes_confirm.html.erb rename to decidim-elections/app/views/decidim/elections/votes/_new_confirm_step.html.erb index ae419640f5270..449e476addb52 100644 --- a/decidim-elections/app/views/decidim/elections/votes/_election_votes_confirm.html.erb +++ b/decidim-elections/app/views/decidim/elections/votes/_new_confirm_step.html.erb @@ -1,4 +1,4 @@ -<%= render("election_votes_header", header_title: t("decidim.elections.votes.header.confirm")) %> +<%= render("focus_header", header_title: t("decidim.elections.votes.header.confirm")) %>
@@ -50,4 +50,4 @@
-<%= render("election_votes_confirm_footer") %> +<%= render("new_confirm_step_footer") %> diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_confirm_footer.html.erb b/decidim-elections/app/views/decidim/elections/votes/_new_confirm_step_footer.html.erb similarity index 95% rename from decidim-elections/app/views/decidim/elections/votes/_election_votes_confirm_footer.html.erb rename to decidim-elections/app/views/decidim/elections/votes/_new_confirm_step_footer.html.erb index d6eb889102eb3..69c0186879f78 100644 --- a/decidim-elections/app/views/decidim/elections/votes/_election_votes_confirm_footer.html.erb +++ b/decidim-elections/app/views/decidim/elections/votes/_new_confirm_step_footer.html.erb @@ -13,7 +13,6 @@ "#", class: "button focus__next confirm", data: { - booth_mode: booth_mode, toggle: ["encrypting", "step-#{questions_count}"].join(" ") } ) do %> diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_encrypting.html.erb b/decidim-elections/app/views/decidim/elections/votes/_new_encrypting_step.html.erb similarity index 84% rename from decidim-elections/app/views/decidim/elections/votes/_election_votes_encrypting.html.erb rename to decidim-elections/app/views/decidim/elections/votes/_new_encrypting_step.html.erb index 86a7ea9402fbc..f2221cd3fe4ba 100644 --- a/decidim-elections/app/views/decidim/elections/votes/_election_votes_encrypting.html.erb +++ b/decidim-elections/app/views/decidim/elections/votes/_new_encrypting_step.html.erb @@ -1,4 +1,4 @@ -<%= render("election_votes_header", header_title: t("decidim.elections.votes.header.encrypting")) %> +<%= render("focus_header", header_title: t("decidim.elections.votes.header.encrypting")) %>

diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_question.html.erb b/decidim-elections/app/views/decidim/elections/votes/_new_question.html.erb similarity index 96% rename from decidim-elections/app/views/decidim/elections/votes/_election_votes_question.html.erb rename to decidim-elections/app/views/decidim/elections/votes/_new_question.html.erb index ea7f696654d4f..d499a320a92ee 100644 --- a/decidim-elections/app/views/decidim/elections/votes/_election_votes_question.html.erb +++ b/decidim-elections/app/views/decidim/elections/votes/_new_question.html.erb @@ -24,7 +24,7 @@ <% end %> - <%= render("election_votes_modal", answer: answer) if more_information?(answer) %> + <%= render("new_question_modal", answer: answer) if more_information?(answer) %> <% end %> <% if question.min_selections == 0 %> diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_modal.html.erb b/decidim-elections/app/views/decidim/elections/votes/_new_question_modal.html.erb similarity index 100% rename from decidim-elections/app/views/decidim/elections/votes/_election_votes_modal.html.erb rename to decidim-elections/app/views/decidim/elections/votes/_new_question_modal.html.erb diff --git a/decidim-elections/app/views/decidim/elections/votes/_show_casted.html.erb b/decidim-elections/app/views/decidim/elections/votes/_show_casted.html.erb new file mode 100644 index 0000000000000..9a2dd4b4ff874 --- /dev/null +++ b/decidim-elections/app/views/decidim/elections/votes/_show_casted.html.erb @@ -0,0 +1,26 @@ +<%= render("focus_header", header_title: t("decidim.elections.votes.header.confirmed")) %> + +
+
+

+ <%= t("decidim.elections.votes.confirmed.header") %> +

+ +

<%= t("decidim.elections.votes.confirmed.lead") %>

+
+ <%= t("decidim.elections.votes.confirmed.text", e_vote_poll_id: params[:id]).html_safe %> +

+ <%= t("decidim.elections.votes.confirmed.verify_link", link: election_vote_verify_path(election, vote_id: params[:id])).html_safe %> +

+
+ + <%= link_to :elections, class: "button" do %> + <%= t("decidim.elections.votes.confirmed.back") %> + <% end %> + +
+ <%= t("decidim.elections.votes.confirmed.experience") %> + <%= link_to t("decidim.elections.votes.confirmed.feedback"), election_feedback_path(election) %> +
+
+
diff --git a/decidim-elections/app/views/decidim/elections/votes/_show_casting.html.erb b/decidim-elections/app/views/decidim/elections/votes/_show_casting.html.erb new file mode 100644 index 0000000000000..6595851a25a40 --- /dev/null +++ b/decidim-elections/app/views/decidim/elections/votes/_show_casting.html.erb @@ -0,0 +1,25 @@ +<%= render("focus_header", header_title: t("decidim.elections.votes.header.casting")) %> +
+
+

+ <%= t("decidim.elections.votes.casting.header") %> +

+ +

+ <%= t("decidim.elections.votes.casting.text") %> +

+
+ <%= form_tag election_vote_path(election, id: vote.encrypted_vote_hash), method: :patch, class: "update_vote_status" %> +
+ +<%= javascript_include_tag "decidim/elections/voter/casting-vote", integrity: true %> diff --git a/decidim-elections/app/views/decidim/elections/votes/_election_votes_failed.html.erb b/decidim-elections/app/views/decidim/elections/votes/_show_failed.html.erb similarity index 70% rename from decidim-elections/app/views/decidim/elections/votes/_election_votes_failed.html.erb rename to decidim-elections/app/views/decidim/elections/votes/_show_failed.html.erb index cbdb4b0c85ca0..84a30cb1e06a1 100644 --- a/decidim-elections/app/views/decidim/elections/votes/_election_votes_failed.html.erb +++ b/decidim-elections/app/views/decidim/elections/votes/_show_failed.html.erb @@ -1,4 +1,4 @@ -<%= render("election_votes_header", header_title: t("decidim.elections.votes.header.confirmed")) %> +<%= render("focus_header", header_title: t("decidim.elections.votes.header.failed")) %>
@@ -6,13 +6,15 @@ <%= t("decidim.elections.votes.failed.header") %>

<%= t("decidim.elections.votes.failed.lead") %>

+
<%= t("decidim.elections.votes.failed.text") %>
- <%= link_to :elections, class: "button" do %> - <%= t("decidim.elections.votes.confirmed.back") %> + <%= link_to new_election_vote_path(election), class: "button" do %> + <%= t("decidim.elections.votes.failed.try_again") %> <% end %> +
<%= t("decidim.elections.votes.confirmed.experience") %> <%= link_to t("decidim.elections.votes.confirmed.feedback"), election_feedback_path(election) %> diff --git a/decidim-elections/app/views/decidim/elections/votes/cast_failed.js.erb b/decidim-elections/app/views/decidim/elections/votes/cast_failed.js.erb deleted file mode 100644 index 22a5898b70647..0000000000000 --- a/decidim-elections/app/views/decidim/elections/votes/cast_failed.js.erb +++ /dev/null @@ -1 +0,0 @@ -$('#confirmed_page').html('<%= j(render(partial: "election_votes_failed")) %>') diff --git a/decidim-elections/app/views/decidim/elections/votes/cast_success.js.erb b/decidim-elections/app/views/decidim/elections/votes/cast_success.js.erb deleted file mode 100644 index ed82abe996863..0000000000000 --- a/decidim-elections/app/views/decidim/elections/votes/cast_success.js.erb +++ /dev/null @@ -1 +0,0 @@ -$('#confirmed_page').html('<%= j(render(partial: "election_votes_confirmed", locals: { encrypted_vote_hash: @form.encrypted_vote_hash, message_id: message_id, vote_id: vote_id })) %>') diff --git a/decidim-elections/app/views/decidim/elections/votes/new.html.erb b/decidim-elections/app/views/decidim/elections/votes/new.html.erb index 28d5455a80146..9e0cb99c6bc12 100644 --- a/decidim-elections/app/views/decidim/elections/votes/new.html.erb +++ b/decidim-elections/app/views/decidim/elections/votes/new.html.erb @@ -2,26 +2,30 @@ data-election-id="<%= election.id %>" data-api-endpoint-url="<%= bulletin_board_server %>" data-authority-public-key="<%= authority_public_key %>" - data-election-unique-id="<%= @form.election_unique_id %>" + data-election-unique-id="<%= election_unique_id %>" data-voter-id="<%= @form.voter_id %>" - data-cast-vote-url="<%= cast_election_vote_url(election) %>" - data-update-vote-status-url="<%= election_vote_url(election) %>" - data-scheme-name="<%= scheme_name %>" - data-booth-mode="<%= booth_mode %>"> + data-scheme-name="<%= scheme_name %>"> <% questions.each_with_index do |step_question, step_index| %>
" data-toggler=".hide"> - <%= render( - "election_votes_steps_header", - step: step_index, - questions_count: questions_count - ) %> +
+
+
+ + <%= t("decidim.elections.votes.new.question_steps", current_step: step_index + 1, total_steps: questions_count) %> + +
+
+ <%= translated_attribute(election.title) %> +
+
+
<%= render( - "election_votes_question", + "new_question", question: step_question ) %>
@@ -38,21 +42,23 @@
<%= render( - "election_votes_confirm", + "new_confirm_step", questions: questions ) %>
- <%= render("election_votes_encrypting") %> + <%= render("new_encrypting_step") %>
- <%= render("election_votes_ballot_decision") %> -
- -
+ <%= render("new_ballot_decision_step") %>
-<%= javascript_include_tag "decidim/elections/vote", integrity: true %> +<% if preview_mode? %> + <%= javascript_include_tag "decidim/elections/voter/setup-preview", integrity: true %> +<% else %> + <%= javascript_include_tag "decidim/elections/voter/setup-vote", integrity: true %> +<% end %> +<%= javascript_include_tag "decidim/elections/voter/new-vote", integrity: true %> diff --git a/decidim-elections/app/views/decidim/elections/votes/show.html.erb b/decidim-elections/app/views/decidim/elections/votes/show.html.erb new file mode 100644 index 0000000000000..f5d6771659a81 --- /dev/null +++ b/decidim-elections/app/views/decidim/elections/votes/show.html.erb @@ -0,0 +1,11 @@ +
+
+ <% if vote&.pending? %> + <%= render("show_casting") %> + <% elsif vote&.accepted? || preview_mode? %> + <%= render("show_casted") %> + <% else %> + <%= render("show_failed") %> + <% end %> +
+
diff --git a/decidim-elections/app/views/decidim/elections/votes/verify.html.erb b/decidim-elections/app/views/decidim/elections/votes/verify.html.erb index 0dd09c7432419..4b18eec6cf96d 100644 --- a/decidim-elections/app/views/decidim/elections/votes/verify.html.erb +++ b/decidim-elections/app/views/decidim/elections/votes/verify.html.erb @@ -1,7 +1,7 @@ -
+ data-api-endpoint-url="<%= bulletin_board_server %>" + data-election-unique-id="<%= election_unique_id %>">
@@ -52,15 +52,12 @@
<%= link_to( "#", - class: "button focus__next confirm", - data: { - booth_mode: booth_mode - } + class: "button focus__next confirm" ) do %> <%= t("decidim.elections.votes.verify.form.submit") %> @@ -75,4 +72,4 @@
-<%= javascript_include_tag "decidim/elections/vote_verify", integrity: true %> +<%= javascript_include_tag "decidim/elections/voter/verify-vote", integrity: true %> diff --git a/decidim-elections/app/views/layouts/decidim/_election_votes_header.html.erb b/decidim-elections/app/views/layouts/decidim/_election_votes_header.html.erb index 3d5d42407c5c5..c2e813b6a154e 100644 --- a/decidim-elections/app/views/layouts/decidim/_election_votes_header.html.erb +++ b/decidim-elections/app/views/layouts/decidim/_election_votes_header.html.erb @@ -1,4 +1,4 @@ -<% if booth_mode == :preview %> +<% if preview_mode? %>
<%= icon :warning %> <%= t("decidim.elections.votes.new.preview_alert") %>
<% end %>
diff --git a/decidim-elections/config/locales/en.yml b/decidim-elections/config/locales/en.yml index 4bfc2596019e7..69f9da7737d22 100644 --- a/decidim-elections/config/locales/en.yml +++ b/decidim-elections/config/locales/en.yml @@ -373,6 +373,7 @@ en: back: Available elections callout: already_voted: You have already voted in this election. You can change your vote or verify it. + pending_vote: Your vote is being casted on the server. vote_rejected: It was not possible to verify your vote. Please cast it again. preview: Preview verify: @@ -520,7 +521,10 @@ en: back: Start voting process again cast: Cast ballot description: Here, you have the options to cast your ballot so that it's properly counted or, alternatively, you can audit that your ballot was correctly encrypted. For security reasons, auditing your ballot will spoil it. That means, to cast your vote, you will need to restart the voting process. - header: 'Ballot is encrypted: cast or audit it' + header: 'Ballot is encrypted: cast it or audit it' + casting: + header: Casting the vote... + text: Your ballot is being casted on the ballot box. confirm: answer: Answer answer_number: answer %{number} @@ -532,7 +536,6 @@ en: question: Question %{count} confirmed: back: Back to elections - error: Sorry, there was an error confirming the vote. Please vote again. experience: How was your experience? feedback: Give us some feedback header: Vote confirmed @@ -540,17 +543,20 @@ en: text: 'You can check that your vote has been successfully added to the ballot box with the following identifier: %{e_vote_poll_id}' verify_link: To check it, copy the identifier and paste it on the vote verification page encrypting: - header: Encoding vote... - text: Your vote is being encrypted to ensure you can cast it anonymously. + header: Encrypting the vote... + text: Your ballot is being encrypted to ensure the secret of your vote. failed: header: Vote failed lead: Your vote has not been casted! text: Something went wrong, please try it again. + try_again: Try again header: ballot_decision: Cast or audit your vote + casting: Casting the vote confirm: Confirm your vote confirmed: Vote confirmed - encrypting: Confirming vote + encrypting: Encrypting the vote + failed: Vote failed messages: not_allowed: You are not allowed to vote on this election at this moment. modal: @@ -564,8 +570,7 @@ en: question_steps: Question %{current_step} of %{total_steps} selections: "%{selected} of %{max_selections}
selections" update: - error: There was a problem updating the vote status - success: Vote status successfully updated + error: There was a problem updating the vote status. Please, vote again. verify: content: heading: Verify your vote diff --git a/decidim-elections/lib/decidim/elections/engine.rb b/decidim-elections/lib/decidim/elections/engine.rb index af0ccac611821..2157dc3f30f3a 100644 --- a/decidim-elections/lib/decidim/elections/engine.rb +++ b/decidim-elections/lib/decidim/elections/engine.rb @@ -15,8 +15,7 @@ class Engine < ::Rails::Engine post :answer end - resource :vote, only: [:new, :update] do - post :cast + resources :votes, only: [:new, :create, :update, :show] do get :verify end end diff --git a/decidim-elections/spec/commands/decidim/elections/voter/cast_vote_spec.rb b/decidim-elections/spec/commands/decidim/elections/voter/cast_vote_spec.rb index 19ef6175dfaea..0d1c13c202810 100644 --- a/decidim-elections/spec/commands/decidim/elections/voter/cast_vote_spec.rb +++ b/decidim-elections/spec/commands/decidim/elections/voter/cast_vote_spec.rb @@ -8,11 +8,10 @@ let(:form) do double( invalid?: invalid, - encrypted_vote: encrypted_vote, - encrypted_vote_hash: encrypted_vote_hash, + encrypted_data: encrypted_data, + encrypted_data_hash: encrypted_data_hash, election: election, election_id: election_id, - election_unique_id: election_unique_id, voter_id: voter_id, bulletin_board: bulletin_board, current_user: user, @@ -20,11 +19,10 @@ ) end let(:invalid) { false } - let(:encrypted_vote) { { question_1: "aNsWeR 1" }.to_json } - let(:encrypted_vote_hash) { "1234" } + let(:encrypted_data) { { question_1: "aNsWeR 1" }.to_json } + let(:encrypted_data_hash) { "1234" } let(:election) { create(:election) } let(:election_id) { election.id } - let(:election_unique_id) { "decidim-test-authority.#{election.id}" } let(:voter_id) { "voter.1" } let(:organization) { create(:organization) } let(:user) { create :user, :confirmed, organization: organization } @@ -59,7 +57,7 @@ it "calls the bulletin board cast_vote method with the correct params" do subject.call - expect(bulletin_board).to have_received(cast_vote_method).with(election_id, voter_id, encrypted_vote) + expect(bulletin_board).to have_received(cast_vote_method).with(election_id, voter_id, encrypted_data) end context "when the form is not valid" do diff --git a/decidim-elections/spec/events/decidim/elections/votes/vote_accepted_event_spec.rb b/decidim-elections/spec/events/decidim/elections/votes/vote_accepted_event_spec.rb index 63cce7c77a2fb..51a12a7a75839 100644 --- a/decidim-elections/spec/events/decidim/elections/votes/vote_accepted_event_spec.rb +++ b/decidim-elections/spec/events/decidim/elections/votes/vote_accepted_event_spec.rb @@ -11,7 +11,7 @@ let(:resource) { vote.election } let(:encrypted_vote_hash) { vote.encrypted_vote_hash } let(:resource_name) { resource.title["en"] } - let(:verify_url) { Decidim::EngineRouter.main_proxy(resource.component).verify_election_vote_url(resource) } + let(:verify_url) { Decidim::EngineRouter.main_proxy(resource.component).election_vote_verify_url(resource, vote_id: encrypted_vote_hash) } it_behaves_like "a simple event" diff --git a/decidim-elections/spec/forms/decidim/elections/ballot/verify_vote_form_spec.rb b/decidim-elections/spec/forms/decidim/elections/voter/verify_vote_form_spec.rb similarity index 75% rename from decidim-elections/spec/forms/decidim/elections/ballot/verify_vote_form_spec.rb rename to decidim-elections/spec/forms/decidim/elections/voter/verify_vote_form_spec.rb index 94c67276b249c..bd9863f60d4ea 100644 --- a/decidim-elections/spec/forms/decidim/elections/ballot/verify_vote_form_spec.rb +++ b/decidim-elections/spec/forms/decidim/elections/voter/verify_vote_form_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe Decidim::Elections::Ballot::VerifyVoteForm do +describe Decidim::Elections::Voter::VerifyVoteForm do subject { described_class.from_params(params).with_context(context) } let(:params) do @@ -36,10 +36,4 @@ it { is_expected.to be_invalid } end - - describe ".election_unique_id" do - it "returns the election unique id" do - expect(subject.election_unique_id).to eq("decidim-test-authority.#{election.id}") - end - end end diff --git a/decidim-elections/spec/forms/decidim/elections/voter/encrypted_vote_form_spec.rb b/decidim-elections/spec/forms/decidim/elections/voter/vote_form_spec.rb similarity index 74% rename from decidim-elections/spec/forms/decidim/elections/voter/encrypted_vote_form_spec.rb rename to decidim-elections/spec/forms/decidim/elections/voter/vote_form_spec.rb index 939d23c6aa08f..a103ff17957a5 100644 --- a/decidim-elections/spec/forms/decidim/elections/voter/encrypted_vote_form_spec.rb +++ b/decidim-elections/spec/forms/decidim/elections/voter/vote_form_spec.rb @@ -2,13 +2,13 @@ require "spec_helper" -describe Decidim::Elections::Voter::EncryptedVoteForm do +describe Decidim::Elections::Voter::VoteForm do subject { described_class.from_params(params).with_context(context) } let(:params) do { - encrypted_vote: "{ \"question_1\": \"aNsWeR 1\" }", - encrypted_vote_hash: "f149b928f7a00eae7e634fc5db0c3cc5531eefb81f49febce8da5bb4a153548b" + encrypted_data: "{ \"question_1\": \"aNsWeR 1\" }", + encrypted_data_hash: "f149b928f7a00eae7e634fc5db0c3cc5531eefb81f49febce8da5bb4a153548b" } end let(:context) do @@ -56,31 +56,17 @@ end context "when the current user is not present" do - let(:context) do - { - election: create(:election) - } - end + let(:user) { nil } it { is_expected.to be_invalid } end context "when the election is not present" do - let(:context) do - { - current_user: create(:user) - } - end + let(:election) { nil } it { is_expected.to be_invalid } end - describe ".election_unique_id" do - it "returns the election unique id" do - expect(subject.election_unique_id).to eq("decidim-test-authority.#{election.id}") - end - end - describe ".voter_id" do it "returns the voter unique id" do expect(subject.voter_id).to eq(Digest::SHA256.hexdigest([user.created_at, user.id, election.id, "decidim-test-authority"].join(".")))