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 '#'
return if location is '#login' return if location is '#login'
return if location is '#logout' return if location is '#logout'
return if location is '#session_timeout'
return if location is '#keyboard_shortcuts' return if location is '#keyboard_shortcuts'
# remember requested url # remember requested url

View file

@ -1,31 +1,67 @@
class SessionTimeout extends App.Controller class SessionTimeout extends App.Controller
lastEvent = 0 lastEvent: 0
warningDialog: undefined
intervalCheck: 5000
showLogoutWarningBefore: -(30 * 1000)
timeTillLogout: undefined
constructor: -> constructor: ->
super super
lastEvent = new Date().getTime() @lastEvent = @currentTime()
checkTimeout = =>
return if new Date().getTime() - 1000 < lastEvent
lastEvent = new Date().getTime()
@checkLogout()
# reset timeout on mouse move # reset timeout on mouse move
$(document).off('keyup.session_timeout').on('keyup.session_timeout', checkTimeout) $(document).off('keyup.session_timeout').on('keyup.session_timeout', @checkTimeout)
$(document).off('mousemove.session_timeout').on('mousemove.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) @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: => checkLogout: =>
return if App.Session.get() is undefined 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() @quitApp()
currentTime: ->
new Date().getTime()
quitApp: => quitApp: =>
return if App.Session.get() is undefined return if App.Session.get() is undefined
@navigate '#logout'
@logoutWarningClose()
App.Auth.logout(false, =>
@navigate '#session_timeout'
)
getTimeout: -> getTimeout: ->
user = App.User.find(App.Session.get().id) user = App.User.find(App.Session.get().id)
@ -43,4 +79,31 @@ class SessionTimeout extends App.Controller
return timeout * 1000 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') App.Config.set('session_timeout', SessionTimeout, 'Plugins')

View file

@ -16,8 +16,15 @@ class Login extends App.ControllerFullPage
@navigate '#' @navigate '#'
return 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' @title 'Sign in'
@render() @render(data)
@navupdate '#login' @navupdate '#login'
# observe config changes related to login page # 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('login', Login, 'Routes')
App.Config.set('session_timeout', Login, 'Routes')

View file

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

View file

@ -49,20 +49,21 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
end end
it 'does logout user' do 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 end
it 'does not logout user', authenticated_as: :admin do it 'does not logout user', authenticated_as: :admin do
sleep 1.5 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
end end
context 'Logout by frontend plugin - Setting change', authenticated_as: :admin do context 'Logout by frontend plugin - Setting change', authenticated_as: :admin do
it 'does logout user' 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' }) 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
end end
@ -73,7 +74,7 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
end end
it 'does logout user' do 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
end end
@ -84,7 +85,7 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
end end
it 'does logout user' do 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
end end
@ -95,7 +96,7 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
end end
it 'does logout user' do 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
end end
@ -109,7 +110,7 @@ RSpec.describe 'Dashboard', type: :system, authenticated_as: true do
# backend tests for the rest # backend tests for the rest
session = ActiveRecord::SessionStore::Session.all.detect { |s| s.data['user_id'] == admin.id } session = ActiveRecord::SessionStore::Session.all.detect { |s| s.data['user_id'] == admin.id }
SessionTimeoutJob.destroy_session(admin, session) 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 end
end end