-
Notifications
You must be signed in to change notification settings - Fork 2
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
Session timeout javascript #295
base: main
Are you sure you want to change the base?
Conversation
1. After 20 minutes cookie session timesout and shows a session-ended page.
Session Timeout Javascript verion In settings session cookie age is set to 20 minutes. After 15 minutes, show a warning dialog about session expiry After 20 minutes, show the session ended page.
6cd5a31
to
342f408
Compare
Using the clock and tick API's of cypress to override the time function. Warning appears after 15 minutes and session ends after 20 minutes if no action is taken.
2570a52
to
f308e4c
Compare
<div class="govuk-notification-banner__content"> | ||
<h2 class="govuk-heading-s">Your session can time out</h2> | ||
<div class="govuk-body"> | ||
<p>We will delete your answers if you do not do anything for 20 minutes and you will have to start again.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the 20 be read from the settings value?
</h1> | ||
|
||
<p class="govuk-body"> | ||
Your session has ended because you haven't done anything for over 20 minutes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
{% load csp %} | ||
|
||
{% block title %}Session Ended{% endblock %} | ||
{% block session_ended %}{% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a comment here to say why you have overidden the block
|
||
|
||
def reset_timer(request): | ||
logger.info("Resetting the session timer") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the log statements?
|
||
</body> | ||
{% block session_ended %} | ||
<script type="text/javascript" nonce="{{ request.csp_nonce }}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comments and remove log statements that are not needed
background: rgb(243, 242, 241); | ||
color: rgb(209, 49, 24); | ||
font-size: 16px; | ||
background: rgb(243, 242, 241); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix all your indentation. It should be 2 white space chars everywhere for CSS, HTML and JS
{% endif %} | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> | ||
<meta name="theme-color" content="#0b0c0c"> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<!-- Sets the auto referesh to match with session cookie age which is 20 minutes --> | ||
<!-- <meta http-equiv="refresh" content="1200; url=/session-ended/"> --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this removed? How does it work when JS is disabled?
f308e4c
to
b28cb2b
Compare
b28cb2b
to
f308e4c
Compare
Removed log messages and using SESSION_TIMEOUT param from setting in HTML. Updated Cypress tests to check for model_dialog not be visible at start.
@@ -1,19 +1,22 @@ | |||
{% load static i18n govuk_frontend_django csp %}<!DOCTYPE html> | |||
<html lang="en" class="govuk-template"> | |||
<head> | |||
<head> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't break the indentation unless there's a good reason. Otherwise it's very difficult to check what's actually changed
|
||
</body> | ||
{% block session_ended %} <!-- session-ended block to override in child template --> | ||
<script type="text/javascript" nonce="{{ request.csp_nonce }}"> | ||
var warningTimerId = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use const
or let
. var
should be avoided these days
|
||
// Show warning dialog 15 minutes before session expiry | ||
function showWarning() { | ||
var warningDiv = document.getElementById('modal_dialog'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use 2 whitespace chars for indentation, as elsewhere
|
||
{% block content %} | ||
{% load custom_filters %} | ||
<div class="govuk-grid-row"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 indent
|
||
|
||
@register.filter | ||
def divide_by_60(value): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type hints would be useful here and wherever you can add them in your new code
function resetTimers() { | ||
clearTimeout(warningTimerId); | ||
clearTimeout(expiryTimerId); | ||
let sessionCookieAge = "{{ SESSION_TIMEOUT|safe }}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should be a const
and you should remove the quote marks as it's supposed to be a number, not a string.
clearTimeout(warningTimerId); | ||
clearTimeout(expiryTimerId); | ||
let sessionCookieAge = "{{ SESSION_TIMEOUT|safe }}"; | ||
warningTimerId = setTimeout(showWarning, (sessionCookieAge - 300) * 1000); // 15 minutes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The warning timeout duration should also be a setting like SESSION_TIMEOUT
{% load custom_filters %} | ||
<div class="govuk-grid-row"> | ||
<div class="govuk-grid-column-two-thirds"> | ||
{% error_summary form %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a form. Can the button just link to the start page (if that resets the session)?
cypress/e2e/session_timeout.cy.js
Outdated
cy.get('.govuk-grid-column-two-thirds > .govuk-button').click(); | ||
cy.get('#id_registrar_organisation').clear().type('WeRegister') | ||
cy.get('#id_registrar_name').clear('Test'); | ||
cy.get('#id_registrar_phone').clear('01225672345'); | ||
cy.get('#id_registrar_email').clear('[email protected]'); | ||
cy.get('#id_submit').click(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could reduce this to 1 line with goToRegistrantType
cypress/e2e/session_timeout.cy.js
Outdated
cy.start() | ||
}); | ||
|
||
it('session_timeout_dialog_success', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This string is supposed to be human-readable when looking at test results to understand what the test does. Here you could use it('Displays the timeout warning after 15 minutes',
for instance
cypress/e2e/session_timeout.cy.js
Outdated
cy.get('.govuk-grid-column-two-thirds > .govuk-button').click(); | ||
cy.get('#id_registrar_organisation').clear().type('WeRegister') | ||
cy.get('#id_registrar_name').clear('Test'); | ||
cy.get('#id_registrar_phone').clear('01225672345'); | ||
cy.get('#id_registrar_email').clear('[email protected]'); | ||
cy.get('#id_submit').click(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, use the utility function.
cypress/e2e/session_timeout.cy.js
Outdated
cy.get('#modal_dialog').should('not.be.visible'); | ||
|
||
// Check if the user is not redirected to the session-ended page | ||
cy.url().should('include', '/session-ended/'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an extra step to check if when the Continue button is clicked you go back to the start page.
cypress/e2e/session_timeout.cy.js
Outdated
|
||
}); | ||
|
||
it('session_timeout_session_ended', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you try a test with multiple tabs? Since this is what justified the server-side timeout, we should have an example where the multi-tab handling works.
<p>We will delete your answers if you do not do anything for {{ SESSION_TIMEOUT|divide_by_60 }} minutes and you will have to start | ||
again.</p> | ||
</div> | ||
<button class="govuk-button dialog-button js-dialog-close" data-module="govuk-button" id="session-continue">Continue</button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this data-module
attribute used?
Improved on cypress tests.
cy.clock(); | ||
}); | ||
|
||
it('Displays the timeout warning after 15 minutes', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that the timeout duration is a parameter you should change the description to something like
"displays the timeout warning after the preset duration".
// check if model_dialog doesn't exist | ||
cy.get('#modal_dialog').should('not.be.visible'); | ||
// clock tick | ||
cy.tick(15 * 60 * 1000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tricky here as you can't reuse SESSION_COOKIE_AGE
. However you could redeclare the same variables at the top of this file, with the same value as in the python code, or different ones, it doesn't matter.
cy.goToRegistrantType() | ||
|
||
// clock tick | ||
cy.tick(15 * 60 * 1000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same. Use a constant. Also a few times in your code below.
it('Displays the timeout warning after 15 minutes and continue the session', () => { | ||
// go to RegistrantType page | ||
cy.goToRegistrantType() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just check that the modal dialog isn't visible at this point. It makes the test easier to understand: 1. check it's not visible, 2. let time pass, 3. check if it's visible
@@ -148,7 +150,64 @@ | |||
<script nonce="{{request.csp_nonce}}" src='{% static "js.cookie.min.js" %}'></script> | |||
<script nonce="{{request.csp_nonce}}" src='{% static "cookies.js" %}'></script> | |||
{% endif %} | |||
|
|||
{% load custom_filters %} | |||
<div id="modal_dialog" class="modal"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use a more specific id, like "timeout-warning-modal" ? Also as a reminder, the convention for html ids is to use hyphens not underscores if possible
|
||
// Show warning dialog 15 minutes before session expiry | ||
function showWarning() { | ||
let warningDiv = document.getElementById('modal_dialog'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 character indent please
<div class="govuk-grid-column-two-thirds"> | ||
{% error_summary form %} | ||
<h1 class="govuk-heading-xl"> | ||
Registrar details |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 character indent please
@@ -14,6 +14,8 @@ | |||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> | |||
<meta name="theme-color" content="#0b0c0c"> | |||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |||
<!-- Sets the auto referesh to match with session cookie age which is 20 minutes --> | |||
<meta http-equiv="refresh" content="1200; url=/session-ended/"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- use the variable
- You should put this meta tag in a
noscript
tag I think. Otherwise, if the user has JS there's a risk of both timeout mechanisms to interfere.
</h2> | ||
</div> | ||
<div class="govuk-notification-banner__content"> | ||
<h2 class="govuk-heading-s">Your session can time out</h2> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure your indentation is correct everywhere once and for all, so I don't have to remind you multiple times.
|
||
|
||
def reset_timer(request): | ||
return HttpResponse() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use a docstring, otherwise this function might seem confusing.
This is Javascript version, where we show a session timeout warning banner.
After 15 minutes, we show a warning. If the user clicks continue we extend the session for another 20 minutes.
If no activity happens in 20 minutes, we show a sesssion ended screen.