Fixes #3525 - Show modal infomation 30 seconds before a session expires.

This commit is contained in:
Rolf Schmidt 2021-05-10 13:43:50 +00:00 committed by Thorsten Eckel
parent bd8af1c402
commit 2858a85050
5 changed files with 100 additions and 24 deletions

View file

@ -273,6 +273,7 @@ class App.Controller extends Spine.Controller
return if location is '#'
return if location is '#login'
return if location is '#logout'
return if location is '#session_timeout'
return if location is '#keyboard_shortcuts'
# remember requested url

View file

@ -1,31 +1,67 @@
class SessionTimeout extends App.Controller
lastEvent = 0
lastEvent: 0
warningDialog: undefined
intervalCheck: 5000
showLogoutWarningBefore: -(30 * 1000)
timeTillLogout: undefined
constructor: ->
super
lastEvent = new Date().getTime()
checkTimeout = =>
return if new Date().getTime() - 1000 < lastEvent
lastEvent = new Date().getTime()
@checkLogout()
@lastEvent = @currentTime()
# reset timeout on mouse move
$(document).off('keyup.session_timeout').on('keyup.session_timeout', checkTimeout)
$(document).off('mousemove.session_timeout').on('mousemove.session_timeout', checkTimeout)
$(document).off('keyup.session_timeout').on('keyup.session_timeout', @checkTimeout)
$(document).off('mousemove.session_timeout').on('mousemove.session_timeout', @checkTimeout)
@controllerBind('config_update', checkTimeout)
# lisen to remote events
@controllerBind('config_update', @checkTimeout)
@controllerBind('session_timeout', @quitApp)
@interval(@checkLogout, 5000, 'session_timeout')
# check interfall of session timeouts
@interval(@checkLogout, @intervalCheck, 'session_timeout')
checkTimeout: =>
getTime = @currentTime()
return if getTime - 2000 < @lastEvent
@lastEvent = getTime
# return if time till logout is far away
return if @timeTillLogout && @timeTillLogout > 20000
@checkLogout()
checkLogout: =>
return if App.Session.get() is undefined
return if lastEvent + @getTimeout() > new Date().getTime()
@timeTillLogout = @currentTime() - (@lastEvent + @getTimeout())
# close logut warning
if @timeTillLogout < @showLogoutWarningBefore
return if !@logoutWarningExists()
@logoutWarningClose()
return
# show logut warning
if @timeTillLogout <= 0
@logoutWarningShow()
return
@quitApp()
currentTime: ->
new Date().getTime()
quitApp: =>
return if App.Session.get() is undefined
@navigate '#logout'
@logoutWarningClose()
App.Auth.logout(false, =>
@navigate '#session_timeout'
)
getTimeout: ->
user = App.User.find(App.Session.get().id)
@ -43,4 +79,31 @@ class SessionTimeout extends App.Controller
return timeout * 1000
logoutWarningExists: =>
return true if @warningDialog
false
logoutWarningClose: =>
return false if !@warningDialog
@warningDialog.close()
@warningDialog = undefined
logoutWarningShow: =>
return if @warningDialog
@warningDialog = new App.ControllerModal(
head: 'Session'
message: 'Due to inactivity are automatically logged out within the next 30 seconds.'
keyboard: true
backdrop: true
buttonClose: true
buttonSubmit: 'Continue session'
onSubmit: =>
@lastEvent = @currentTime()
@checkLogout()
)
release: ->
@logoutWarningClose()
App.Config.set('session_timeout', SessionTimeout, 'Plugins')

View file

@ -16,8 +16,15 @@ class Login extends App.ControllerFullPage
@navigate '#'
return
# show session timeout message on login screen
data = {}
if window.location.hash is '#session_timeout'
data = {
errorMessage: App.i18n.translateContent('Due to inactivity you are automatically logged out.')
}
@title 'Sign in'
@render()
@render(data)
@navupdate '#login'
# observe config changes related to login page
@ -102,3 +109,4 @@ class Login extends App.ControllerFullPage
)
App.Config.set('login', Login, 'Routes')
App.Config.set('session_timeout', Login, 'Routes')

View file

@ -43,7 +43,7 @@ class App.Auth
@_loginError()
)
@logout: ->
@logout: (rerender = true, callback) ->
App.Log.debug 'Auth', 'logout'
# abort all AJAX requests
@ -66,7 +66,7 @@ class App.Auth
success: =>
# set logout (config, session, ...)
@_logout()
@_logout(rerender, callback)
error: (xhr, statusText, error) =>
@_loginError()
@ -147,7 +147,7 @@ class App.Auth
if _.isFunction(App[model].updateAttributes)
App[model].updateAttributes(attributes)
@_logout: (rerender = true) ->
@_logout: (rerender = true, callback) ->
App.Log.debug 'Auth', '_logout'
App.TaskManager.reset()
@ -169,6 +169,9 @@ class App.Auth
)
App.Event.trigger('clearStore')
if callback
callback()
@_loginError: ->
App.Log.debug 'Auth', '_loginError:error'

View file

@ -49,20 +49,21 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
end
it 'does logout user' do
expect(page).to have_text('Sign in', wait: 20)
expect(page).to have_text('Due to inactivity are automatically logged out within the next 30 seconds.', wait: 20)
expect(page).to have_text('Due to inactivity you are automatically logged out.', wait: 20)
end
it 'does not logout user', authenticated_as: :admin do
sleep 1.5
expect(page).to have_no_text('Sign in', wait: 0)
expect(page).to have_no_text('Due to inactivity you are automatically logged out.', wait: 0)
end
end
context 'Logout by frontend plugin - Setting change', authenticated_as: :admin do
it 'does logout user' do
expect(page).to have_no_text('Sign in')
expect(page).to have_no_text('Due to inactivity you are automatically logged out.')
Setting.set('session_timeout', { default: '1' })
expect(page).to have_text('Sign in', wait: 20)
expect(page).to have_text('Due to inactivity you are automatically logged out.', wait: 20)
end
end
@ -73,7 +74,7 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
end
it 'does logout user' do
expect(page).to have_text('Sign in', wait: 20)
expect(page).to have_text('Due to inactivity you are automatically logged out.', wait: 20)
end
end
@ -84,7 +85,7 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
end
it 'does logout user' do
expect(page).to have_text('Sign in', wait: 20)
expect(page).to have_text('Due to inactivity you are automatically logged out.', wait: 20)
end
end
@ -95,7 +96,7 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
end
it 'does logout user' do
expect(page).to have_text('Sign in', wait: 20)
expect(page).to have_text('Due to inactivity you are automatically logged out.', wait: 20)
end
end
@ -109,7 +110,7 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
# backend tests for the rest
session = ActiveRecord::SessionStore::Session.all.detect { |s| s.data['user_id'] == admin.id }
SessionTimeoutJob.destroy_session(admin, session)
expect(page).to have_text('Sign in', wait: 20)
expect(page).to have_text('Due to inactivity you are automatically logged out.', wait: 20)
end
end
end