Commit d77743c1 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch '172-session-expiry-notification' into 'master'

Resolve "Session expiry notification"

Closes #172

See merge request minerva/core!421
parents 1bdd52fc 5204e860
Pipeline #6565 failed with stage
in 9 minutes and 26 seconds
...@@ -100,6 +100,11 @@ public final class Configuration { ...@@ -100,6 +100,11 @@ public final class Configuration {
*/ */
public static final String ANONYMOUS_LOGIN = "anonymous"; public static final String ANONYMOUS_LOGIN = "anonymous";
/**
* Max session length in seconds.
*/
private static int sessionLength = 60 * 120;
/** /**
* Should the application cache be turned on. * Should the application cache be turned on.
*/ */
...@@ -425,4 +430,12 @@ public final class Configuration { ...@@ -425,4 +430,12 @@ public final class Configuration {
return result; return result;
} }
public static int getSessionLength() {
return sessionLength;
}
public static void setSessionLength(int sessionLength) {
Configuration.sessionLength = sessionLength;
}
} }
...@@ -20,6 +20,17 @@ ...@@ -20,6 +20,17 @@
padding-left: 15px; padding-left: 15px;
} }
.minerva-header-right-menu {
height: 36px;
line-height: 35px;
font-size: 13px;
font-weight: 900;
color: #ffffff;
display: inline;
width: auto;
float: right
}
.minerva-header a:hover { .minerva-header a:hover {
background-color: #000000; background-color: #000000;
transition: background-color 0.4s ease-in-out 0s; transition: background-color 0.4s ease-in-out 0s;
...@@ -97,14 +108,14 @@ ...@@ -97,14 +108,14 @@
to(#13ACE0)); to(#13ACE0));
} }
.headerHideDivButton { .minerva-header-hide-div-button {
display: inline; display: inline;
width: auto; width: auto;
height: 36px; height: 36px;
float: left float: left
} }
.headerHideButton { .minerva-header-hide-button {
color: #FFFFFF; color: #FFFFFF;
height: 36px; height: 36px;
line-height: 36px; line-height: 36px;
...@@ -118,12 +129,12 @@ ...@@ -118,12 +129,12 @@
transition: background-color 0.4s ease-in-out 0s; transition: background-color 0.4s ease-in-out 0s;
} }
.headerHideButton:hover { .minerva-header-hide-button:hover {
background-color: #01536D; background-color: #01536D;
transition: background-color 0.4s ease-in-out 0s; transition: background-color 0.4s ease-in-out 0s;
} }
.headerTextBold { .minerva-version-div {
display: inline; display: inline;
width: auto; width: auto;
height: 36px; height: 36px;
...@@ -137,6 +148,32 @@ ...@@ -137,6 +148,32 @@
border-right: 1px solid #9DE1F8; border-right: 1px solid #9DE1F8;
} }
.minerva-session-expire {
background: #EE0000;
display: inline;
width: auto;
height: 36px;
float: left;
line-height: 34px;
padding: 0 0 0 17px;
color: #FFFFFF;
font-weight: 900;
font-size: 13px;
text-align: center;
border-right: 1px solid #9DE1F8;
}
.minerva-extend-session-button {
background-color: #CC0000;
margin-left: 10px;
border: 0px;
}
.minerva-extend-session-button:hover {
background-color: #880000;
transition: background-color 0.4s ease-in-out 0s;
}
.minerva-legend { .minerva-legend {
position: absolute; position: absolute;
bottom: 10px; bottom: 10px;
......
...@@ -15,6 +15,7 @@ var ConfigurationType = { ...@@ -15,6 +15,7 @@ var ConfigurationType = {
REQUEST_ACCOUNT_EMAIL: "REQUEST_ACCOUNT_EMAIL", REQUEST_ACCOUNT_EMAIL: "REQUEST_ACCOUNT_EMAIL",
REQUEST_ACCOUNT_DEFAULT_CONTENT: "REQUEST_ACCOUNT_DEFAULT_CONTENT", REQUEST_ACCOUNT_DEFAULT_CONTENT: "REQUEST_ACCOUNT_DEFAULT_CONTENT",
SIMPLE_COLOR_VAL: "SIMPLE_COLOR_VAL", SIMPLE_COLOR_VAL: "SIMPLE_COLOR_VAL",
SESSION_LENGTH: "SESSION_LENGTH",
SHOW_ELEMENT_ABBREVIATION: "SHOW_ELEMENT_ABBREVIATION", SHOW_ELEMENT_ABBREVIATION: "SHOW_ELEMENT_ABBREVIATION",
SHOW_ELEMENT_ANNOTATIONS: "SHOW_ELEMENT_ANNOTATIONS", SHOW_ELEMENT_ANNOTATIONS: "SHOW_ELEMENT_ANNOTATIONS",
SHOW_ELEMENT_CHARGE: "SHOW_ELEMENT_CHARGE", SHOW_ELEMENT_CHARGE: "SHOW_ELEMENT_CHARGE",
......
...@@ -489,7 +489,7 @@ ServerConnector.getReferenceGenomeUrl = function (queryParams, filterParams) { ...@@ -489,7 +489,7 @@ ServerConnector.getReferenceGenomeUrl = function (queryParams, filterParams) {
return this.getApiUrl({ return this.getApiUrl({
type: "genomics/taxonomies/" + queryParams.organism + "/genomeTypes/" + queryParams.type + "/versions/" + version type: "genomics/taxonomies/" + queryParams.organism + "/genomeTypes/" + queryParams.type + "/versions/" + version
+ "/", + "/",
params: filterParams params: filterParams
}); });
} }
...@@ -539,7 +539,7 @@ ServerConnector.getReferenceGenomeGeneMappingsUrl = function (queryParams, filte ...@@ -539,7 +539,7 @@ ServerConnector.getReferenceGenomeGeneMappingsUrl = function (queryParams, filte
ServerConnector.getAvailableGenomeUrlsUrl = function (queryParams, filterParams) { ServerConnector.getAvailableGenomeUrlsUrl = function (queryParams, filterParams) {
return this.getApiUrl({ return this.getApiUrl({
type: "genomics/taxonomies/" + queryParams.organism.getResource() + "/genomeTypes/" + queryParams.type + "/versions/" + queryParams.version type: "genomics/taxonomies/" + queryParams.organism.getResource() + "/genomeTypes/" + queryParams.type + "/versions/" + queryParams.version
+ ":getAvailableRemoteUrls", + ":getAvailableRemoteUrls",
params: filterParams params: filterParams
}); });
}; };
...@@ -933,6 +933,14 @@ ServerConnector.getConfiguration = function () { ...@@ -933,6 +933,14 @@ ServerConnector.getConfiguration = function () {
} }
}; };
/**
*
* @returns {Promise}
*/
ServerConnector.extendSession = function () {
return this.sendGetRequest(this.getConfigurationUrl())
};
ServerConnector.getConfigurationParam = function (paramId) { ServerConnector.getConfigurationParam = function (paramId) {
if (paramId === undefined) { if (paramId === undefined) {
return Promise.reject(new Error("Unknown param type")); return Promise.reject(new Error("Unknown param type"));
......
...@@ -15,12 +15,33 @@ var logger = require('./logger'); ...@@ -15,12 +15,33 @@ var logger = require('./logger');
* @constructor * @constructor
*/ */
function SessionData(project) { function SessionData(project) {
var self = this;
if (project === undefined) { if (project === undefined) {
throw new Error("Project must be passed as an argument"); throw new Error("Project must be passed as an argument");
} }
this.setProject(project); self.setProject(project);
ServerConnector.addListener("onDataLoadStart", function () {
self.setLastRequestTimeStamp(Math.floor(Date.now() / 1000));
});
} }
/**
*
* @param {number} timestamp time stamp in seconds
*/
SessionData.prototype.setLastRequestTimeStamp = function (timestamp) {
this._lastRequestTimeStamp = timestamp;
};
/**
*
* @returns {number} time stamp in seconds
*/
SessionData.prototype.getLastRequestTimeStamp = function () {
return this._lastRequestTimeStamp;
};
/** /**
* *
* @param {Project} project * @param {Project} project
......
...@@ -36,7 +36,7 @@ OverviewDialog.prototype.constructor = OverviewDialog; ...@@ -36,7 +36,7 @@ OverviewDialog.prototype.constructor = OverviewDialog;
/** /**
* *
* @param {number} overviewImageId * @param {number} [overviewImageId]
*/ */
OverviewDialog.prototype.showOverview = function (overviewImageId) { OverviewDialog.prototype.showOverview = function (overviewImageId) {
var self = this; var self = this;
......
...@@ -5,11 +5,13 @@ var Promise = require("bluebird"); ...@@ -5,11 +5,13 @@ var Promise = require("bluebird");
/* exported logger */ /* exported logger */
var AbstractGuiElement = require('../AbstractGuiElement'); var AbstractGuiElement = require('../AbstractGuiElement');
var ConfigurationType = require('../../ConfigurationType');
var GuiConnector = require('../../GuiConnector'); var GuiConnector = require('../../GuiConnector');
var OverviewDialog = require('../OverviewDialog'); var OverviewDialog = require('../OverviewDialog');
var PanelControlElementType = require('../PanelControlElementType'); var PanelControlElementType = require('../PanelControlElementType');
var Functions = require('../../Functions'); var Functions = require('../../Functions');
// noinspection JSUnusedLocalSymbols
var logger = require('../../logger'); var logger = require('../../logger');
/** /**
...@@ -30,6 +32,12 @@ function TopMenu(params) { ...@@ -30,6 +32,12 @@ function TopMenu(params) {
var self = this; var self = this;
self._createGui(); self._createGui();
self._cronFunction = function () {
return self.checkIfSessionIsGoingToExpire();
};
setInterval(self._cronFunction, 1000);
} }
TopMenu.prototype = Object.create(AbstractGuiElement.prototype); TopMenu.prototype = Object.create(AbstractGuiElement.prototype);
...@@ -42,43 +50,43 @@ TopMenu.prototype.constructor = TopMenu; ...@@ -42,43 +50,43 @@ TopMenu.prototype.constructor = TopMenu;
TopMenu.prototype._createGui = function () { TopMenu.prototype._createGui = function () {
var self = this; var self = this;
var overviewDialogDiv = Functions.createElement({ var overviewDialogDiv = Functions.createElement({type: "div"});
type: "div",
name: "overviewDialog"
});
self.getElement().appendChild(overviewDialogDiv); self.getElement().appendChild(overviewDialogDiv);
self.setControlElement(PanelControlElementType.OVERVIEW_DIALOG_DIV, overviewDialogDiv); self.setControlElement(PanelControlElementType.OVERVIEW_DIALOG_DIV, overviewDialogDiv);
var hideButtonDiv = Functions.createElement({ var hideButtonDiv = Functions.createElement({
type: "div", type: "div",
className: "headerHideDivButton" className: "minerva-header-hide-div-button"
}); });
self.getElement().appendChild(hideButtonDiv); self.getElement().appendChild(hideButtonDiv);
var hideButton = Functions.createElement({ var hideButton = Functions.createElement({
type: "button", type: "button",
className: "headerHideButton", className: "minerva-header-hide-button"
name: "hideButton"
}); });
hideButtonDiv.appendChild(hideButton); hideButtonDiv.appendChild(hideButton);
self.setControlElement(PanelControlElementType.MENU_HIDE_LEFT_PANEL_BUTTON, hideButton); self.setControlElement(PanelControlElementType.MENU_HIDE_LEFT_PANEL_BUTTON, hideButton);
var hideButtonIcon = Functions.createElement({ var hideButtonIcon = Functions.createElement({
type: "i", type: "i",
className: "fa fa-chevron-left", className: "fa fa-chevron-left"
name: "hideButtonIcon"
}); });
hideButton.appendChild(hideButtonIcon); hideButton.appendChild(hideButtonIcon);
self.setControlElement(PanelControlElementType.MENU_HIDE_LEFT_PANEL_BUTTON_ICON, hideButtonIcon); self.setControlElement(PanelControlElementType.MENU_HIDE_LEFT_PANEL_BUTTON_ICON, hideButtonIcon);
var versionDiv = Functions.createElement({ var versionDiv = Functions.createElement({
type: "div", type: "div",
className: "headerTextBold", className: "minerva-version-div"
name: "versionDiv"
}); });
self.getElement().appendChild(versionDiv); self.getElement().appendChild(versionDiv);
self.setControlElement(PanelControlElementType.MENU_VERSION_DIV, versionDiv); self.setControlElement(PanelControlElementType.MENU_VERSION_DIV, versionDiv);
self.getElement().appendChild(Functions.createElement({
type: "div",
className: "minerva-session-expire",
style: "display:none;"
}));
var showOverviewDiv = Functions.createElement({ var showOverviewDiv = Functions.createElement({
type: "div", type: "div",
style: "float: left;" style: "float: left;"
...@@ -88,7 +96,6 @@ TopMenu.prototype._createGui = function () { ...@@ -88,7 +96,6 @@ TopMenu.prototype._createGui = function () {
var showOverviewButton = Functions.createElement({ var showOverviewButton = Functions.createElement({
type: "button", type: "button",
className: "minerva-overview-button", className: "minerva-overview-button",
name: "showOverviewButton",
content: "<i class='fa fa-sitemap' style='font-size:18px; font-weight:400; padding-right:10px;'></i><span >SHOW OVERVIEW</span>", content: "<i class='fa fa-sitemap' style='font-size:18px; font-weight:400; padding-right:10px;'></i><span >SHOW OVERVIEW</span>",
style: "display:none", style: "display:none",
xss: false xss: false
...@@ -98,7 +105,7 @@ TopMenu.prototype._createGui = function () { ...@@ -98,7 +105,7 @@ TopMenu.prototype._createGui = function () {
var rightHeaderMenuDiv = Functions.createElement({ var rightHeaderMenuDiv = Functions.createElement({
type: "div", type: "div",
className: "rightHeaderMenu" className: "minerva-header-right-menu"
}); });
self.getElement().appendChild(rightHeaderMenuDiv); self.getElement().appendChild(rightHeaderMenuDiv);
...@@ -110,8 +117,7 @@ TopMenu.prototype._createGui = function () { ...@@ -110,8 +117,7 @@ TopMenu.prototype._createGui = function () {
var legendCheckbox = Functions.createElement({ var legendCheckbox = Functions.createElement({
type: "input", type: "input",
inputType: "checkbox", inputType: "checkbox"
name: "legendCheckbox"
}); });
div4checkboxes.appendChild(legendCheckbox); div4checkboxes.appendChild(legendCheckbox);
self.setControlElement(PanelControlElementType.MENU_LEGEND_CHECKBOX, legendCheckbox); self.setControlElement(PanelControlElementType.MENU_LEGEND_CHECKBOX, legendCheckbox);
...@@ -137,7 +143,6 @@ TopMenu.prototype._createGui = function () { ...@@ -137,7 +143,6 @@ TopMenu.prototype._createGui = function () {
var refreshCommentButton = Functions.createElement({ var refreshCommentButton = Functions.createElement({
type: "button", type: "button",
className: "minerva-overview-button", className: "minerva-overview-button",
name: "refreshCommentButton",
content: "<i class='fa fa-refresh' style='font-size:21px; font-weight:400;'></i>", content: "<i class='fa fa-refresh' style='font-size:21px; font-weight:400;'></i>",
style: "display:none", style: "display:none",
xss: false xss: false
...@@ -148,7 +153,6 @@ TopMenu.prototype._createGui = function () { ...@@ -148,7 +153,6 @@ TopMenu.prototype._createGui = function () {
var clearButton = Functions.createElement({ var clearButton = Functions.createElement({
type: "button", type: "button",
className: "minerva-overview-button", className: "minerva-overview-button",
name: "clearButton",
content: "<i class='fa fa-times' style='font-size:18px; font-weight:300; padding-right:10px;'></i>CLEAR", content: "<i class='fa fa-times' style='font-size:18px; font-weight:300; padding-right:10px;'></i>CLEAR",
xss: false xss: false
}); });
...@@ -187,16 +191,15 @@ TopMenu.prototype.init = function () { ...@@ -187,16 +191,15 @@ TopMenu.prototype.init = function () {
commentCheckbox.onclick = function () { commentCheckbox.onclick = function () {
ServerConnector.getSessionData(project).setShowComments(commentCheckbox.checked); ServerConnector.getSessionData(project).setShowComments(commentCheckbox.checked);
if (commentCheckbox.checked) { if (commentCheckbox.checked) {
$(refreshCommentButton).css("display","inline"); $(refreshCommentButton).css("display", "inline");
} else { } else {
$(refreshCommentButton).css("display","none"); $(refreshCommentButton).css("display", "none");
} }
return self.getMap().refreshComments().then(null, GuiConnector.alert); return self.getMap().refreshComments().then(null, GuiConnector.alert);
}; };
refreshCommentButton.onclick = (function () { refreshCommentButton.onclick = (function () {
return function () { return function () {
self.getMap().refreshComments(); return self.getMap().refreshComments();
return false;
}; };
})(); })();
...@@ -207,16 +210,18 @@ TopMenu.prototype.init = function () { ...@@ -207,16 +210,18 @@ TopMenu.prototype.init = function () {
}; };
})(); })();
if (project.getTopOverviewImage() !== undefined && project.getTopOverviewImage() !== null) { if (project.getTopOverviewImage() !== undefined) {
self._overviewDialog = new OverviewDialog({ self._overviewDialog = new OverviewDialog({
customMap: self.getMap(), customMap: self.getMap(),
configuration: self.getConfiguration(),
project: self.getProject(),
element: self.getControlElement(PanelControlElementType.OVERVIEW_DIALOG_DIV) element: self.getControlElement(PanelControlElementType.OVERVIEW_DIALOG_DIV)
}); });
var showOverviewButton = self.getControlElement(PanelControlElementType.MENU_SHOW_OVERVIEW_BUTTON); var showOverviewButton = self.getControlElement(PanelControlElementType.MENU_SHOW_OVERVIEW_BUTTON);
showOverviewButton.onclick = function () { showOverviewButton.onclick = function () {
return self._overviewDialog.showOverview(); return self._overviewDialog.showOverview();
}; };
$(showOverviewButton).css("display","inline-block"); $(showOverviewButton).css("display", "inline-block");
} }
if (ServerConnector.getSessionData().getShowComments()) { if (ServerConnector.getSessionData().getShowComments()) {
...@@ -268,6 +273,7 @@ TopMenu.prototype.destroy = function () { ...@@ -268,6 +273,7 @@ TopMenu.prototype.destroy = function () {
if (self._overviewDialog !== undefined) { if (self._overviewDialog !== undefined) {
self._overviewDialog.destroy(); self._overviewDialog.destroy();
} }
clearInterval(self._cronFunction);
return Promise.resolve(); return Promise.resolve();
}; };
...@@ -284,4 +290,57 @@ TopMenu.prototype.toggleLegend = function () { ...@@ -284,4 +290,57 @@ TopMenu.prototype.toggleLegend = function () {
} }
}; };
/**
*
* @returns {Promise}
*/
TopMenu.prototype.checkIfSessionIsGoingToExpire = function () {
var self = this;
var lastAccessTimestamp = self.getServerConnector().getSessionData().getLastRequestTimeStamp();
var sessionInactivityOption = self.getConfiguration().getOption(ConfigurationType.SESSION_LENGTH);
var sessionInactivityLength = parseInt(sessionInactivityOption.getValue());
var sessionExpireTimestamp = lastAccessTimestamp + sessionInactivityLength;
var currentTimestamp = Math.floor(Date.now() / 1000);
//if session is going to expire in 10 minutes show information
if (sessionExpireTimestamp - currentTimestamp < 10 * 60) {
self.showSessionExpire(sessionExpireTimestamp - currentTimestamp);
} else {
self.hideSessionExpire();
}
//if session expired
if (sessionExpireTimestamp < currentTimestamp) {
return self.getServerConnector().logout();
}
return Promise.resolve();
};
/**
*
* @param {number} timeInSeconds
*/
TopMenu.prototype.showSessionExpire = function (timeInSeconds) {
var self = this;
var minutes = Math.floor(timeInSeconds / 60);
var seconds = Math.floor(timeInSeconds - minutes * 60);
var message = "Session expires in " + minutes + " minutes " + seconds + " seconds";
var button = Functions.createElement({
type: "button",
content: "EXTEND",
className: "minerva-extend-session-button",
onclick: function () {
return self.getServerConnector().extendSession();
}
});
$(".minerva-session-expire", self.getElement()).empty().append("<span>" + message + "</span>").append(button).show();
};
/**
*
*/
TopMenu.prototype.hideSessionExpire = function () {
$(".minerva-session-expire", this.getElement()).empty().hide();
};
module.exports = TopMenu; module.exports = TopMenu;
\ No newline at end of file
...@@ -298,7 +298,11 @@ Project.prototype.getTopOverviewImage = function () { ...@@ -298,7 +298,11 @@ Project.prototype.getTopOverviewImage = function () {
* @param {OverviewImage} topOverviewImage * @param {OverviewImage} topOverviewImage
*/ */
Project.prototype.setTopOverviewImage = function (topOverviewImage) { Project.prototype.setTopOverviewImage = function (topOverviewImage) {
this._topOverviewImage = topOverviewImage; if (topOverviewImage === null) {
this._topOverviewImage = undefined;
} else {
this._topOverviewImage = topOverviewImage;
}
}; };