Fixes #3525 - Show modal infomation 30 seconds before a session expires.
This commit is contained in:
parent
bd8af1c402
commit
2858a85050
5 changed files with 100 additions and 24 deletions
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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'
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue