mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-11 15:45:34 +08:00
Merge pull request #4439 from rekonder/aj_SCI_7027
Session end implementation [SCI-7027]
This commit is contained in:
commit
0ee586a394
9 changed files with 221 additions and 4 deletions
69
app/assets/javascripts/session_end.js
Normal file
69
app/assets/javascripts/session_end.js
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/* globals I18n */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var originalTitle = '';
|
||||||
|
var expireIn;
|
||||||
|
var expireLimit = 900; // 15min
|
||||||
|
var timeoutID;
|
||||||
|
var expirationUrl = $('meta[name=\'expiration-url\']').attr('content');
|
||||||
|
|
||||||
|
var pad = function(i) {
|
||||||
|
var s = ('0' + Math.floor(i));
|
||||||
|
return s.substring(s.length - 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
var newTimerStr = function(expirationTime) {
|
||||||
|
var m = (expirationTime / 60) % 60;
|
||||||
|
var s = (expirationTime % 60);
|
||||||
|
return [m, s].map(pad).join(':');
|
||||||
|
};
|
||||||
|
|
||||||
|
function getSessionEnd() {
|
||||||
|
if (expirationUrl) {
|
||||||
|
$.get(expirationUrl, function(data) {
|
||||||
|
if (data <= 0) {
|
||||||
|
$('#session-finished').modal();
|
||||||
|
} else if (data <= expireLimit + 1) {
|
||||||
|
expireIn = data;
|
||||||
|
originalTitle = document.title;
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
timeoutID = setTimeout(expirationInTime, 1000);
|
||||||
|
} else {
|
||||||
|
timeoutID = setTimeout(getSessionEnd, (data - expireLimit) * 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expirationInTime() {
|
||||||
|
var timeString;
|
||||||
|
if (expireIn > 0) {
|
||||||
|
timeString = newTimerStr(expireIn);
|
||||||
|
document.title = timeString + ' ' + String.fromCodePoint(0x1F62A) + ' ' + originalTitle;
|
||||||
|
$('.expiring').text(I18n.t('devise.sessions.expire_modal.session_end_in.header', { time: timeString }));
|
||||||
|
expireIn -= 1;
|
||||||
|
if (!$('#session-expire').hasClass('in')) {
|
||||||
|
$('#session-expire').modal().off('hide.bs.modal').on('hide.bs.modal', function() {
|
||||||
|
if (expireIn > 0) {
|
||||||
|
$.post($('meta[name=\'revive-url\']').attr('content'));
|
||||||
|
document.title = originalTitle;
|
||||||
|
clearTimeout(timeoutID);
|
||||||
|
timeoutID = setTimeout(getSessionEnd, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
timeoutID = setTimeout(expirationInTime, 1000);
|
||||||
|
} else {
|
||||||
|
document.title = originalTitle;
|
||||||
|
$('#session-expire').modal('hide');
|
||||||
|
$('#session-finished').modal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeoutID = setTimeout(getSessionEnd, 1000);
|
||||||
|
|
||||||
|
$(document).on('click', '.session-login', function() {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
}());
|
39
app/assets/stylesheets/session_expired.scss
Normal file
39
app/assets/stylesheets/session_expired.scss
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
// scss-lint:disable NestingDepth ImportantRule
|
||||||
|
|
||||||
|
.session-modal {
|
||||||
|
.modal-body {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: .25em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instruction-session-collapse {
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: .5em;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.fa-angle-up {
|
||||||
|
margin-left: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
|
||||||
|
.fa-angle-up {
|
||||||
|
@include rotate(-180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ class Users::SessionsController < Devise::SessionsController
|
||||||
layout :session_layout
|
layout :session_layout
|
||||||
after_action :after_sign_in, only: %i(create authenticate_with_two_factor)
|
after_action :after_sign_in, only: %i(create authenticate_with_two_factor)
|
||||||
before_action :remove_authenticate_mesasge_if_root_path, only: :new
|
before_action :remove_authenticate_mesasge_if_root_path, only: :new
|
||||||
|
prepend_before_action :skip_timeout, only: :expire_in
|
||||||
|
|
||||||
rescue_from ActionController::InvalidAuthenticityToken do
|
rescue_from ActionController::InvalidAuthenticityToken do
|
||||||
redirect_to new_user_session_path
|
redirect_to new_user_session_path
|
||||||
|
@ -34,6 +35,16 @@ class Users::SessionsController < Devise::SessionsController
|
||||||
generate_templates_project
|
generate_templates_project
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def expire_in
|
||||||
|
if current_user.remember_created_at.nil?
|
||||||
|
render plain: Devise.timeout_in.to_i - (Time.now.to_i - user_session['last_request_at']).round
|
||||||
|
else
|
||||||
|
render plain: Devise.remember_for - (Time.now.to_i - current_user.remember_created_at.to_i).round
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def revive_session; end
|
||||||
|
|
||||||
def two_factor_recovery
|
def two_factor_recovery
|
||||||
unless session[:otp_user_id]
|
unless session[:otp_user_id]
|
||||||
redirect_to new_user_session_path
|
redirect_to new_user_session_path
|
||||||
|
@ -92,6 +103,10 @@ class Users::SessionsController < Devise::SessionsController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def skip_timeout
|
||||||
|
request.env['devise.skip_trackable'] = true
|
||||||
|
end
|
||||||
|
|
||||||
def remove_authenticate_mesasge_if_root_path
|
def remove_authenticate_mesasge_if_root_path
|
||||||
if session[:user_return_to] == root_path && flash[:alert] == I18n.t('devise.failure.unauthenticated')
|
if session[:user_return_to] == root_path && flash[:alert] == I18n.t('devise.failure.unauthenticated')
|
||||||
flash[:alert] = nil
|
flash[:alert] = nil
|
||||||
|
|
|
@ -7,9 +7,14 @@
|
||||||
<meta name="max-file-size" content="<%= Rails.configuration.x.file_max_size_mb %>">
|
<meta name="max-file-size" content="<%= Rails.configuration.x.file_max_size_mb %>">
|
||||||
<meta name="tiny-mce-assets-url" content="<%= tiny_mce_assets_path %>">
|
<meta name="tiny-mce-assets-url" content="<%= tiny_mce_assets_path %>">
|
||||||
<meta name="highlightjs-url" content="<%= asset_path('highlightjs-github-theme.css') %>">
|
<meta name="highlightjs-url" content="<%= asset_path('highlightjs-github-theme.css') %>">
|
||||||
|
<% if user_signed_in? %>
|
||||||
|
<meta name="expiration-url" content="<%= users_expire_in_path %>">
|
||||||
|
<meta name="revive-url" content="<%= users_revive_session_path %>">
|
||||||
|
<% end %>
|
||||||
<%= stylesheet_link_tag 'application', media: 'all' %>
|
<%= stylesheet_link_tag 'application', media: 'all' %>
|
||||||
<%= javascript_include_tag 'application' %>
|
<%= javascript_include_tag 'application' %>
|
||||||
<%= javascript_pack_tag 'application' %>
|
<%= javascript_pack_tag 'application' %>
|
||||||
|
<%= javascript_include_tag 'session_end' %>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,10 +58,12 @@
|
||||||
|
|
||||||
<% if user_signed_in? %>
|
<% if user_signed_in? %>
|
||||||
<%= render "shared/about_modal" %>
|
<%= render "shared/about_modal" %>
|
||||||
<%= render "shared/file_preview/modal" %>
|
<%= render "shared/file_preview/modal.html.erb" %>
|
||||||
<%= render "shared/file_edit_modal" %>
|
<%= render "shared/file_edit_modal.html.erb" %>
|
||||||
<%= render "shared/marvinjs_modal" %>
|
<%= render "shared/marvinjs_modal.html.erb" %>
|
||||||
<%= render "shared/comments/comments_sidebar" %>
|
<%= render "shared/comments/comments_sidebar.html.erb" %>
|
||||||
|
<%= render "users/sessions/session_expire_modal.html.erb" %>
|
||||||
|
<%= render "users/sessions/session_end_modal.html.erb" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if user_signed_in? && flash[:system_notification_modal] && current_user.show_login_system_notification? %>
|
<% if user_signed_in? && flash[:system_notification_modal] && current_user.show_login_system_notification? %>
|
||||||
|
|
39
app/views/users/sessions/_session_end_modal.html.erb
Normal file
39
app/views/users/sessions/_session_end_modal.html.erb
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<div class="modal session-modal" id="session-finished" tabindex="-1" role="dialog"
|
||||||
|
aria-labelledby="session_expire" data-role="session_expire-modal">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title"><%= t('devise.sessions.expire_modal.session_ended.header' ) %></h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<ul>
|
||||||
|
<li><%= t('devise.sessions.expire_modal.session_ended.description') %></li>
|
||||||
|
<li>
|
||||||
|
<a class="collapse-row">
|
||||||
|
<div class="row-title">
|
||||||
|
<div class="instruction-session-collapse collapsed" data-toggle="collapse" href="#InstructionsSectionFinished" aria-expanded="false">
|
||||||
|
<%= t('devise.sessions.expire_modal.why_see_this') %>
|
||||||
|
<i class="fas fa-angle-up"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<ul class="collapse" id="InstructionsSectionFinished">
|
||||||
|
<li><%= t('devise.sessions.expire_modal.session_end_in.paragraph1') %></li>
|
||||||
|
<li><%= t('devise.sessions.expire_modal.session_end_in.paragraph2') %></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||||
|
<%= t('general.close' ) %>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-primary session-login">
|
||||||
|
<%= t('devise.sessions.new.submit' ) %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
34
app/views/users/sessions/_session_expire_modal.html.erb
Normal file
34
app/views/users/sessions/_session_expire_modal.html.erb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<div class="modal session-modal" id="session-expire" tabindex="-1" role="dialog"
|
||||||
|
aria-labelledby="session-expire" data-role="session-expire-modal">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title expiring"></h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<ul>
|
||||||
|
<li><%= t('devise.sessions.expire_modal.session_end_in.description') %></li>
|
||||||
|
<li>
|
||||||
|
<a class="collapse-row">
|
||||||
|
<div class="row-title">
|
||||||
|
<div class="instruction-session-collapse collapsed" data-toggle="collapse" href="#InstructionsSection" aria-expanded="false">
|
||||||
|
<%= t('devise.sessions.expire_modal.why_see_this') %>
|
||||||
|
<i class="fas fa-angle-up"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<ul class="collapse" id="InstructionsSection">
|
||||||
|
<li><%= t('devise.sessions.expire_modal.session_end_in.paragraph1') %></li>
|
||||||
|
<li><%= t('devise.sessions.expire_modal.session_end_in.paragraph2') %></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" data-dismiss="modal"><%= t('devise.sessions.expire_modal.session_end_in.revive_session' ) %></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -92,6 +92,7 @@ Rails.application.config.assets.precompile += %w(sidebar_toggle.js)
|
||||||
Rails.application.config.assets.precompile += %w(reports/reports_datatable.js)
|
Rails.application.config.assets.precompile += %w(reports/reports_datatable.js)
|
||||||
Rails.application.config.assets.precompile += %w(reports/save_pdf_to_inventory.js)
|
Rails.application.config.assets.precompile += %w(reports/save_pdf_to_inventory.js)
|
||||||
Rails.application.config.assets.precompile += %w(reports/content.js)
|
Rails.application.config.assets.precompile += %w(reports/content.js)
|
||||||
|
Rails.application.config.assets.precompile += %w(session_end.js)
|
||||||
Rails.application.config.assets.precompile += %w(label_templates/label_templates_datatable.js)
|
Rails.application.config.assets.precompile += %w(label_templates/label_templates_datatable.js)
|
||||||
Rails.application.config.assets.precompile += %w(BrowserPrint-3.0.216.min.js)
|
Rails.application.config.assets.precompile += %w(BrowserPrint-3.0.216.min.js)
|
||||||
Rails.application.config.assets.precompile += %w(BrowserPrint-Zebra-1.0.216.min.js)
|
Rails.application.config.assets.precompile += %w(BrowserPrint-Zebra-1.0.216.min.js)
|
||||||
|
|
|
@ -49,6 +49,17 @@ en:
|
||||||
not_correct_code: "Not correct recovery code"
|
not_correct_code: "Not correct recovery code"
|
||||||
create:
|
create:
|
||||||
team_name: "%{user}'s projects"
|
team_name: "%{user}'s projects"
|
||||||
|
expire_modal:
|
||||||
|
why_see_this: 'Why am I seeing this?'
|
||||||
|
session_end_in:
|
||||||
|
header: 'Your session will end in %{time}'
|
||||||
|
description: 'To keep the data you entered into the fields without clicking the Save button, please revive your session and save them.'
|
||||||
|
paragraph1: 'To keep your work secure, SciNote times out sessions after 3 hours of inactivity. '
|
||||||
|
paragraph2: 'To proceed working after the session ends, you’ll have to log in again, starting a new working session.'
|
||||||
|
revive_session: 'Revive my session'
|
||||||
|
session_ended:
|
||||||
|
header: 'To proceed working, please log in again'
|
||||||
|
description: 'If you have any unsaved data, please close this message, copy your text, and paste it back after you log in again.'
|
||||||
unlocks:
|
unlocks:
|
||||||
new:
|
new:
|
||||||
head_title: "Resend unlock instructions"
|
head_title: "Resend unlock instructions"
|
||||||
|
|
|
@ -742,6 +742,8 @@ Rails.application.routes.draw do
|
||||||
get 'users/sign_up_provider' => 'users/registrations#new_with_provider'
|
get 'users/sign_up_provider' => 'users/registrations#new_with_provider'
|
||||||
get 'users/two_factor_recovery' => 'users/sessions#two_factor_recovery'
|
get 'users/two_factor_recovery' => 'users/sessions#two_factor_recovery'
|
||||||
get 'users/two_factor_auth' => 'users/sessions#two_factor_auth'
|
get 'users/two_factor_auth' => 'users/sessions#two_factor_auth'
|
||||||
|
get 'users/expire_in' => 'users/sessions#expire_in'
|
||||||
|
post 'users/revive_session' => 'users/sessions#revive_session'
|
||||||
post 'users/authenticate_with_two_factor' => 'users/sessions#authenticate_with_two_factor'
|
post 'users/authenticate_with_two_factor' => 'users/sessions#authenticate_with_two_factor'
|
||||||
post 'users/authenticate_with_recovery_code' => 'users/sessions#authenticate_with_recovery_code'
|
post 'users/authenticate_with_recovery_code' => 'users/sessions#authenticate_with_recovery_code'
|
||||||
post 'users/complete_sign_up_provider' => 'users/registrations#create_with_provider'
|
post 'users/complete_sign_up_provider' => 'users/registrations#create_with_provider'
|
||||||
|
|
Loading…
Add table
Reference in a new issue