Index: config/routes.rb =================================================================== --- config/routes.rb (revision 12244) +++ config/routes.rb (working copy) @@ -17,6 +17,8 @@ RedmineApp::Application.routes.draw do root :to => 'welcome#index', :as => 'home' + + get 'session_heartbeat', :to => 'application#session_heartbeat' match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post] match 'logout', :to => 'account#logout', :as => 'signout', :via => [:get, :post] Index: public/javascripts/application.js =================================================================== --- public/javascripts/application.js (revision 12244) +++ public/javascripts/application.js (working copy) @@ -591,3 +591,18 @@ $(document).ready(setupAjaxIndicator); $(document).ready(hideOnLoad); $(document).ready(addFormObserversForDoubleSubmit); + +function SessionHeartbeat() { + $.ajax( { + url: '/session_heartbeat', + success: function(data) { + if(data.expired) { + alert(data.message); + } + else if(data.remain > 0) { + setTimeout(SessionHeartbeat, data.remain); + } + } + } + ); +} \ No newline at end of file Index: app/controllers/application_controller.rb =================================================================== --- app/controllers/application_controller.rb (revision 12244) +++ app/controllers/application_controller.rb (working copy) @@ -48,7 +48,28 @@ include Redmine::MenuManager::MenuController helper Redmine::MenuManager::MenuHelper + def session_heartbeat + remain = 0 + if Setting.session_lifetime? && session[:ctime] + remain = (Setting.session_lifetime.to_i * 60) - (Time.now.utc.to_i - session[:ctime].to_i) + end + if Setting.session_timeout? && session[:atime] + if remain > 0 + remain = [remain, (Setting.session_timeout.to_i * 60) - (Time.now.utc.to_i - session[:atime].to_i)].min + else + remain = (Setting.session_timeout.to_i * 60) - (Time.now.utc.to_i - session[:atime].to_i) + end + end + if session_expired? || remain <= 0 + render json: { expired: true, message: l(:error_session_expired) } + else + render json: { expired: false, remain: (remain * 1000) } + end + end + def session_expiration + # Skip session heartbeat + return if ((params[:controller] == 'application') && (params[:action] = 'session_heartbeat')) if session[:user_id] if session_expired? && !try_to_autologin reset_session Index: app/helpers/application_helper.rb =================================================================== --- app/helpers/application_helper.rb (revision 12244) +++ app/helpers/application_helper.rb (working copy) @@ -1227,6 +1227,14 @@ unless User.current.pref.warn_on_leaving_unsaved == '0' tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") end + if User.current && (!User.current.anonymous?) && (Setting.session_timeout || Setting.session_lifetime) + lifetime = Setting.session_lifetime ? Setting.session_lifetime.to_i : 0 + timeout = Setting.session_timeout ? Setting.session_timeout.to_i : 0 + timeout = lifetime if lifetime > 0 && lifetime < timeout + unless timeout == 0 + tags << "\n".html_safe + javascript_tag("setTimeout(SessionHeartbeat, #{timeout * 60000});") + end + end tags end