Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Countdown until logout #334

Merged
merged 12 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions SequentConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,6 @@ var SequentConfigData = {
// Default: '/admin/login'
defaultRoute: '/admin/login',

timeoutSeconds: 3600,

publicURL: "https://sequent/elections/public/",

// if we are in debug mode or not
Expand Down Expand Up @@ -224,7 +222,10 @@ var SequentConfigData = {
},

mainVersion: '8.0.0',
repoVersions: []
repoVersions: [],

// Number of seconds after which an authentication token expires.
authTokenExpirationSeconds: 600
};

angular.module('SequentConfig', [])
Expand Down
130 changes: 73 additions & 57 deletions avBooth/booth-directive/booth-directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,63 +222,6 @@ angular.module('avBooth')
);
}

// After cookies expires, redirect to login. But only if cookies do
// expire.
function autoredirectToLoginAfterTimeout() {
// demo and live preview don't need to expire
if (scope.isDemo || scope.isPreview) {
return;
}

var election = (
(!!scope.parentElection) ?
scope.parentElection :
scope.election
);

if (
ConfigService.cookies.expires &&
(
!election ||
!election.presentation ||
!election.presentation.extra_options ||
!election.presentation.extra_options.booth_log_out__disable
)
) {
var minutes = ConfigService.cookies.expires;
setTimeout(
function () { logoutAndRedirect( /* isSuccess */ false); },
60*1000*minutes
);

setTimeout(
function () {
$modal.open({
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: "avBooth/invalid-answers-controller/invalid-answers-controller.html",
controller: "InvalidAnswersController",
size: 'sm',
resolve: {
errors: function() { return []; },
data: function() {
return {
errors: [],
header: "avBooth.logoutWarnModal.header",
body: "avBooth.logoutWarnModal.body",
continue: "avBooth.logoutWarnModal.confirm"
};
}
}
});
},
60*1000*(minutes - 1)
);

}
}
autoredirectToLoginAfterTimeout();

function checkCookies(electionId) {
if (scope.isDemo || scope.isPreview) {
return;
Expand Down Expand Up @@ -750,6 +693,78 @@ angular.module('avBooth')
scope.isDemo = false;
}

var startTimeMs = Date.now();

function getSessionStartTime() {
readVoteCredentials();
return scope.currentElectionCredentials && scope.currentElectionCredentials.sessionStartedAtMs || startTimeMs;
}

// After cookies expires, redirect to login. But only if cookies do
// expire.
function autoredirectToLoginAfterTimeout() {
// demo and live preview don't need to expire
if (scope.isDemo || scope.isPreview) {
return;
}

var election = (
(!!scope.parentElection) ?
scope.parentElection :
scope.election
);

if (
ConfigService.authTokenExpirationSeconds &&
(
!election ||
!election.presentation ||
!election.presentation.extra_options ||
!election.presentation.extra_options.booth_log_out__disable
)
) {

var logoutTimeMs = getSessionStartTime() + ConfigService.authTokenExpirationSeconds * 1000;

setTimeout(
function () { logoutAndRedirect( /* isSuccess */ false); },
Math.max(logoutTimeMs - Date.now(), 0)
);

var modalTimeMs = logoutTimeMs - 60 * 1000;

if (modalTimeMs < Date.now()) {
return;
}

setTimeout(
function () {
$modal.open({
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: "avBooth/invalid-answers-controller/invalid-answers-controller.html",
controller: "InvalidAnswersController",
size: 'sm',
resolve: {
errors: function() { return []; },
data: function() {
return {
errors: [],
header: "avBooth.logoutWarnModal.header",
body: "avBooth.logoutWarnModal.body",
continue: "avBooth.logoutWarnModal.confirm"
};
}
}
});
},
modalTimeMs - Date.now()
);

}
}
autoredirectToLoginAfterTimeout();

function simpleGetElection(electionId) {
if (!electionId) {
var future = $q.defer();
Expand Down Expand Up @@ -1144,6 +1159,7 @@ angular.module('avBooth')
next: next,
redirectToLogin: redirectToLogin,
checkFixToBottom: checkFixToBottom,
getSessionStartTime: getSessionStartTime,

// stateData stores information used by the directive being shown.
// Its content depends on the current state.
Expand Down
5 changes: 5 additions & 0 deletions locales/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
"showPdf": {
"showPdfButton": "Mostrar PDF"
},
"countdownTooltip": {
"title": "La teva sessió expirarà.",
"contentMins": "Tens __mins__ minuts per a emetre el teu vot.",
"contentSecs": "Tens __secs__ segons per a emetre el teu vot."
},
"hashForVoteNotCastModal": {
"header": "Vot no emès",
"body": "Està a punt de copiar el Localitzador de el Cot, però <strong>el seu vot encara no s'ha emès</strong>. Si voleu buscar el Localitzador de el Vot, no el trobarà. Qual la raó per la que vam mostrar el Localitzador de l'Vot en aquest moment és perquè pugui auditar la correcció de l'vot xifrat abans d'emetre'l. Si aquesta és la raó per la qual vol copiar el Localitzador de l'Vot, procedeixi a copiar-lo i després auditi el seu vot.",
Expand Down
5 changes: 5 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
"showPdfButton": "Show PDF",
"pdfTextDescription": "Please read the PDF before voting"
},
"countdownTooltip": {
"title": "Your session is going to expire.",
"contentMins": "You have __mins__ minutes left to cast your vote.",
"contentSecs": "You have __secs__ seconds left to cast your vote."
},
"electionChooser": {
"hasVoted": {
"title": "Success!",
Expand Down
5 changes: 5 additions & 0 deletions locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
"showPdfButton": "Mostrar PDF",
"pdfTextDescription": "Por favor lea el PDF antes de votar"
},
"countdownTooltip": {
"title": "Tu sesión va a expirar.",
"contentMins": "Tienes __mins__ minutos para emitir tu voto.",
"contentSecs": "Tienes __secs__ segundos para emitir tu voto."
},
"demoModeModal": {
"header": "Cabina de votación de demo",
"body": "Está ingresando a una cabina de votación de demostración. <strong>Su voto NO se emitirá</strong>. Esta cabina de votación solo tiene fines demostrativos.",
Expand Down
5 changes: 5 additions & 0 deletions locales/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
"body": "No puede continuarse porque la papeleta no es paritaria y en cremallera. Por favor, comprueba que tu selección esté compuesta de forma que detrás de una mujer luego va un hombre y así sucesivamente.",
"continue": "Revisar mi papeleta"
},
"countdownTooltip": {
"title": "Istunnon vanhenemisaika lähestyy.",
"contentMins": "Sinulla on __mins__ minuuttia aikaa äänestyksen tekemiseen.",
"contentSecs": "Sinulla on __secs__ sekuntia aikaa äänestyksen tekemiseen."
},
"thisisATest": "<span class=\"glyphicon glyphicon-info-sign\" aria-hidden=\"true\"></span> <strong>HUOM!</strong> Tämä on testiäänestys",
"loadingElectionTitle": "Vaalin tiedot latautuu. Odota, kiitos... ",
"stepNumber": "vaihe __num__ yhteensä __total__ vaiheesta",
Expand Down
5 changes: 5 additions & 0 deletions locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
"showPdfButton": "Afficher le PDF",
"pdfTextDescription": "Veuillez lire le PDF avant de voter"
},
"countdownTooltip": {
"title": "Votre session expire bientôt.",
"contentMins": "Il vous reste __mins__ minutes pour voter.",
"contentSecs": "Il vous reste __secs__ secondes pour voter."
},
"electionChooser": {
"hasVoted": {
"title": "Succ\u00e8s !",
Expand Down
5 changes: 5 additions & 0 deletions locales/gl.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
"showPdf": {
"showPdfButton": "Mostrar PDF"
},
"countdownTooltip": {
"title": "A túa sesión vai expirar.",
"contentMins": "Tes __mins__ minutos para emitir o teu voto.",
"contentSecs": "Tes __secs__ segundos para emitir o teu voto."
},
"confirmAuditBallot": {
"header": "¿Realmente quieres auditar tu papeleta?",
"body": "La auditoría de la papeleta lo invalidará y tendrás que iniciar el proceso de votación de nuevo si deseas emitir tu voto. El proceso de auditoría de la papeleta permite verificar que está codificada correctamente. Hacer este proceso requiere que unos conocimientos técnicos importantes, por lo que no se recomienda si no sabes lo que estás haciendo. <br/> <br/><strong>Si lo que desea es emitir su voto, en <u>Cancelar</u> para volver a la pantalla de revisión de votación.</strong>",
Expand Down
5 changes: 5 additions & 0 deletions locales/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
"body": "Ifall du kontrollerar din röst annulleras din tidigare röst och du måste lagra en ny. Kontrollen ger dit möjligheten att se till att din röst verkligen har registrerats i den elektroniska valurnan. Att göra detta kräver tekniskt kunnande, så undvik att göra det ifall du inte är säker på vad du gör. <br/><br/><strong>Ifall du enbart vill lagra din röst, klicka på <u>Avbryt</u> för att återgå till vyn över röstens sammandrag.</strong>",
"confirm": "Ja, jag är säker på att jag vill ANNULLERA min tidigare röst för att kontrollera den"
},
"countdownTooltip": {
"title": "Din session kommer att gå ut.",
"contentMins": "Du har __mins__ minuter kvar att rösta.",
"contentSecs": "Du har __secs__ sekunder kvar att rösta."
},
"planchaSelect": "välj alla",
"planchaDeselect": "ta bort alla val",
"showSelectedOptionPoints": "(__points__ points)",
Expand Down