diff --git a/apps/dashboard-app/src/main/js/src/app/common/authentication/authentication.service.js b/apps/dashboard-app/src/main/js/src/app/common/authentication/authentication.service.js index cb0869232..5ace12af7 100644 --- a/apps/dashboard-app/src/main/js/src/app/common/authentication/authentication.service.js +++ b/apps/dashboard-app/src/main/js/src/app/common/authentication/authentication.service.js @@ -1,165 +1,165 @@ (function () { 'use strict'; // -- angular module -- // angular.module('shrine.commmon.authentication') .factory('AuthenticationService', AuthenticationService); AuthenticationService.$inject = ['$http', '$q', '$app', '$rootScope', '$interval', '$location']; function AuthenticationService ($http, $q, $app, $rootScope, $interval, $location) { idleHandle(); // -- private const -- // var Config = { AuthenticationEndpoint: 'user/whoami', FailureResponse: 'AuthenticationFailed' }; // -- public -- // return { login: login, setAuthorizationHeader: setAuthorizationHeader, setCredentials: setCredentials, clearCredentials: clearCredentials }; function idleHandle() { // -- auto logout on idle -- // var twentyMinutes = 20*60*1000; var logoutPromise = $interval(timeout, twentyMinutes); var idleEvent = 'idleEvent'; $rootScope.$on('$destroy', function () { $interval.cancel(logoutPromise); }); $rootScope.$on(idleEvent, function () { $interval.cancel(logoutPromise); logoutPromise = $interval(timeout, twentyMinutes); }); /** * When the interval is called, that means the user has gone idle, so we * clear their credentials then navigate them back to the home page. */ function timeout() { clearCredentials(); - $location.url("/login"); + $app.model.safeLogout(); } $rootScope.idleBroadcast = function() { $rootScope.$broadcast(idleEvent); } } // -- private methods -- // /** * Wrapper for authenticate call. */ function login () { return authenticate(); } /** * Encrypt Authorization Data. * @param username * @param password * @returns {string} * @constructor */ function getAuthorizationData(username, password) { return 'Basic ' + $app.utils.toBase64(username + ':' + password); } /** * Set the Authorization header for requests. * @param username * @param password * @constructor */ function setAuthorizationHeader (username, password) { $http.defaults.headers.common['Authorization'] = getAuthorizationData(username, password); } /** * Set credentials of the current user. * @param username * @param password * @param roles * @constructor */ function setCredentials(username, password, roles) { var data = getAuthorizationData(username, password) $app.utils.setAppUser(username, data, roles); }; /** * Remove the credentials of the current user. */ function clearCredentials () { if($app.globals.currentUser !== undefined) { $app.globals.currentUser.isLoggedIn = false; } $app.utils.deleteAppUser(); $http.defaults.headers.common.Authorization = ' Basic '; } /** * Parse out authentication data. * @param result * @returns {*} */ function parseResult(result) { //reject promise on fail. if(result.data === Config.FailureResponse) { return $q.reject(response); } var response = { success: true, msg: result.data.statusText, userId: result.data.userId, roles: result.data.roles }; return response; } /** * Reject invalid login. * @param result * @returns {Promise} */ function rejectResult (result) { var response = { success: false, msg: "invalid login " + result.data.statusText }; return $q.reject(response); } /** * Authentication Promise. * @returns {*} */ function authenticate (baseUrl) { var url = $app.utils.getUrl(Config.AuthenticationEndpoint); return $http.get(url) .then(parseResult, rejectResult); } } })(); diff --git a/apps/dashboard-app/src/main/js/src/app/diagnostic/diagnostic.model.js b/apps/dashboard-app/src/main/js/src/app/diagnostic/diagnostic.model.js index cc634af0f..97e3f5c12 100644 --- a/apps/dashboard-app/src/main/js/src/app/diagnostic/diagnostic.model.js +++ b/apps/dashboard-app/src/main/js/src/app/diagnostic/diagnostic.model.js @@ -1,208 +1,227 @@ (function (){ 'use strict'; // -- angular module -- // angular.module('shrine-tools') .factory('DiagnosticModel', DiagnosticModel); - DiagnosticModel.$inject = ['$http', '$q', 'UrlGetter']; - function DiagnosticModel (h, q, urlGetter) { + DiagnosticModel.$inject = ['$http', '$q', 'UrlGetter', '$location']; + function DiagnosticModel (h, q, urlGetter, $location) { var toDashboard = {url:''}; var cache = {}; + // used solely for remote dashboard persistence var m = {}; m.remoteSiteStatuses = []; m.siteAlias = ''; // -- private const -- // var Config = { AdapterEndpoint: 'admin/status/adapter', ConfigEndpoint: 'admin/status/config', HubEndpoint: 'admin/status/hub', I2B2Endpoint: 'admin/status/i2b2', KeystoreEndpoint: 'admin/status/keystore', OptionsEndpoint: 'admin/status/optionalParts', ProblemEndpoint: 'admin/status/problems', QepEndpoint: 'admin/status/qep', SummaryEndpoint: 'admin/status/summary' }; // -- public -- // return { getAdapter: getJsonMaker(Config.AdapterEndpoint, 'adapter'), getConfig: getJsonMaker(Config.ConfigEndpoint, 'config', parseConfig), getHub: getJsonMaker(Config.HubEndpoint, 'hub'), getI2B2: getJsonMaker(Config.I2B2Endpoint, 'i2b2'), getKeystore: getJsonMaker(Config.KeystoreEndpoint, 'keystore', storeRemoteSites), getOptionalParts: getJsonMaker(Config.OptionsEndpoint, 'optionalParts'), getProblems: getProblemsMaker(), getQep: getJsonMaker(Config.QepEndpoint, 'qep'), getSummary: getJsonMaker(Config.SummaryEndpoint, 'summary'), + safeLogout: safeLogout, + clearCache: clearCache, map: map, cache: cache, toDashboard: toDashboard, m: m }; function map(func, list) { var result = []; for(var i = 0; i < list.length; i++) { result.push(func(list[i])) } return result; } + /** + * Clears the current remote dashboard before logging out. + */ + function safeLogout() { + clearCache(); + toDashboard.url = ''; + m.siteAlias = ''; + $location.path('/login'); + } + + function clearCache() { + for (var member in cache) { + if(cache.hasOwnProperty(member)) delete cache[member]; + } + } + /** * Method for Handling a failed rest call. * @param failedResult * @returns {*} */ function onFail(failedResult) { return q.reject(failedResult); } /*** * Method for handling a successful rest call. Simply caches it and returns it. * @param result * @param cacheKey * @returns {*} */ function parseJsonResult(result, cacheKey) { cache[cacheKey] = result.data; return result.data; } /** * Still cache and return the result, however, save the RemoteSites outside of the cache, * as we don't want these values to change between cache resets (which occur when switching sites) * @param result * @param cacheKey */ function storeRemoteSites(result, cacheKey) { cache[cacheKey] = result.data; if (m.remoteSiteStatuses.length == 0) { m.remoteSiteStatuses = result.data.remoteSiteStatuses; } return result.data } /** * Parses the json config map and turns it into a nested json object * @param json the flat config map * @param cacheKey a unique identifier for the function */ function parseConfig (json, cacheKey) { var configMap = json.data.configMap; var processed = preProcessJson(configMap); cache[cacheKey] = processed; return processed; } // IE11 doesn't support string includes function stringIncludes(haystack, needle) { var arr = haystack.split(""); for (var i = 0; i < arr.length; i++) { if (arr[i] == needle) { return true; } } return false; } // "explodes" and merges the flag config map. // e.g., {"key.foo": 10, "key.baz": 5} -> {"key": {"foo": 10, "baz": 5}} function preProcessJson (object) { var result = {}; for (var key in object) { if (object.hasOwnProperty(key)) { if (!stringIncludes(key, ".")) { result[key] = object[key] } else { var split = key.split("."); var prev = result; for (var i = 0; i < split.length; i++) { var cur = split[i]; if (!(cur in prev)) { prev[cur] = {} } if (i == split.length - 1) { prev[cur] = object[key]; } else { prev = prev[cur] } } } } } return result; } /** * There's a lot going on here. Essentially, this is a function factory that allows one to * define backend calls just through the path. It also implements a simple caching * strategy. * Essentially the get function only needs to be called once, and from then on it will spit * back a cached promise. This lets you write the code and not care whether it's cached or * not, but also get the caching performance anyways. For this function to work, the * resolver function has to take in the http response and the cache key to set, and make * sure that it caches what it returns (see parseJsonResult or parseConfig). * @param endpoint * @param cacheKey * @param resolverDefault * @returns {Function} */ function getJsonMaker(endpoint, cacheKey, resolverDefault) { var resolver = (typeof resolverDefault !== 'undefined')? function (response) { return resolverDefault(response, cacheKey) }: function (response) { return parseJsonResult(response, cacheKey) }; return function() { var cachedValue = cache[cacheKey]; if (cachedValue === undefined) { var url = urlGetter(endpoint, undefined, toDashboard.url); return h.get(url) .then(resolver, onFail) } else { return q(function(resolver) { resolver(cachedValue)}); } } } function getProblemsMaker() { // Caches the last offset and page size to hold onto it between different views var prevOffset = 0; var prevN = 20; /** * ProblemEndpoint: 'admin/status/problems', * @returns {*} */ return function(offset, n, epoch) { if (offset != null) { prevOffset = offset; } else { offset = prevOffset; } if (n != null) { prevN = n; } else { n = prevN; } var epochString = epoch && isFinite(epoch) ? '&epoch=' + epoch : ''; var url = urlGetter( Config.ProblemEndpoint + '?offset=' + offset + '&n=' + n + epochString, undefined, toDashboard.url ); return h.get(url) .then(parseJsonResult, onFail); } } } })(); diff --git a/apps/dashboard-app/src/main/js/src/app/diagnostic/sidebar/sidebar.js b/apps/dashboard-app/src/main/js/src/app/diagnostic/sidebar/sidebar.js index 36367e60b..4c8a947c5 100755 --- a/apps/dashboard-app/src/main/js/src/app/diagnostic/sidebar/sidebar.js +++ b/apps/dashboard-app/src/main/js/src/app/diagnostic/sidebar/sidebar.js @@ -1,83 +1,81 @@ (function() { 'use strict'; // -- angular -- // angular.module('shrine-tools') .directive('sidebar', Sidebar); /** * - Directive Config - * */ function Sidebar () { var sidebar = { templateUrl: 'src/app/diagnostic/sidebar/sidebar.tpl.html', restrict: 'E', replace: true, link: SidebarLinker, controller: SidebarController, controllerAs: 'vm', scope: { options: '=' } }; return sidebar; } /** * - Controller - * */ SidebarController.$inject = ['$scope','$app']; function SidebarController ($scope, $app) { // -- scope --// var vm = this; vm.toDashboard = $app.model.toDashboard; - + vm.hasHub = function() {return false}; init(); function init() { $app.model.getOptionalParts() - .then(setOptions); - - $app.model.getQep() + .then(setOptions) + .then($app.model.getQep) .then(setQep); - - vm.hasHub = function() {return hasHub(vm.trustModelIsHub, vm.options.isHub, vm.toDashboard.url)}; } function setOptions(data) { vm.options = data; } function setQep(data) { vm.trustModelIsHub = data.trustModelIsHub; + vm.hasHub = function() {return hasHub(vm.trustModelIsHub, vm.options.isHub, vm.toDashboard.url)}; } function hasHub(trustModelIsHub, isHub, toDashboardUrl) { return !trustModelIsHub || isHub && toDashboardUrl == ''; } } /** * Controller renamed to 'vm' * @param scope * @param el * @param attr * @param vm -- renamed to vm. */ SidebarLinker.$inject = ['scope', 'element', 'attributes', 'sbVM'] function SidebarLinker(scope, el, attr, vm) { } })(); diff --git a/apps/dashboard-app/src/main/js/src/app/diagnostic/views/dashboard.controller.js b/apps/dashboard-app/src/main/js/src/app/diagnostic/views/dashboard.controller.js index 31e3d5873..bc270e795 100644 --- a/apps/dashboard-app/src/main/js/src/app/diagnostic/views/dashboard.controller.js +++ b/apps/dashboard-app/src/main/js/src/app/diagnostic/views/dashboard.controller.js @@ -1,83 +1,81 @@ /** * Created by ty on 11/7/16. */ (function () { 'use strict'; // -- register controller with angular -- // angular.module('shrine-tools') .controller('DashboardController', DashboardController); /** * * @type {string[]} */ DashboardController.$inject = ['$app', '$log', '$location']; function DashboardController ($app, $log, $location) { var vm = this; var map = $app.model.map; vm.keyStoreError = false; init(); /** * */ function init () { $app.model.getKeystore() .then(setDashboard, handleFailure); } function handleFailure (failure) { vm.keyStoreError = failure; } /** * * @param keystore */ function setDashboard (keystore) { var modelStatuses = $app.model.m.remoteSiteStatuses; var tempList = []; for (var i = 0; i < modelStatuses.length; i++) { var abbreviatedEntry = modelStatuses[i]; if (abbreviatedEntry.url != "") tempList.push(abbreviatedEntry) } vm.otherDashboards = [['Hub', '']].concat(map(entryToPair, tempList)); vm.otherDashboards.sort(comparator); vm.clearCache = clearCache; vm.switchDashboard = switchDashboard; } function comparator(first, second) { if (first[0] == 'Hub') { return -2; } else { var less = first[0].toLowerCase() < second[0].toLowerCase(); var eq = first[0].toLowerCase() == second[0].toLowerCase(); return less? -1: eq? 0 : 1 } } function switchDashboard(url, alias) { $app.model.toDashboard.url = url; $app.model.m.siteAlias = alias == 'Hub'? '': alias; clearCache(); $location.url("/diagnostic/summary"); } function clearCache() { - for (var member in $app.model.cache) { - if($app.model.cache.hasOwnProperty(member)) delete $app.model.cache[member]; - } + $app.model.clearCache(); } function entryToPair(entry){ return [entry.siteAlias, entry.url]; } } })(); diff --git a/apps/dashboard-app/src/main/js/src/app/header/user-status.js b/apps/dashboard-app/src/main/js/src/app/header/user-status.js index bd66b0a4e..9f86e885d 100755 --- a/apps/dashboard-app/src/main/js/src/app/header/user-status.js +++ b/apps/dashboard-app/src/main/js/src/app/header/user-status.js @@ -1,80 +1,80 @@ (function () { // -- register directive with angular -- // angular.module('shrine-tools') .directive('userStatus', UserStatus); /*** * * @returns {{restict: string, replace: boolean, templateUrl: string, * controller: UserStatusController, controllerAs: string, link: UserStatusLinker, scope: {}}} * @constructor */ function UserStatus () { return { restict: 'E', replace: true, templateUrl: 'src/app/header/user-status.tpl.html', controller: UserStatusController, controllerAs: 'vm', link: UserStatusLinker, scope: { } } } /** * * @type {string[]} */ - UserStatusController.$inject = ['$location', '$app']; - function UserStatusController ($location, $app) { + UserStatusController.$inject = ['$app']; + function UserStatusController ($app, $log) { var vm = this; vm.isUserLoggedIn = isUserLoggedIn; vm.getUsername = getUsername; vm.logout = logout; /** * * @returns {boolean} */ function isUserLoggedIn () { return ($app.globals.currentUser !== undefined && $app.globals.currentUser.isLoggedIn === true); } /** * * @returns {*} */ function getUsername () { return ($app.globals.currentUser) ? $app.globals.currentUser.username : ''; } /** * * */ function logout () { - $location.path('/login'); + $app.model.safeLogout(); } } /** * * @type {string[]} */ UserStatusLinker.$inject = ['scope', 'element', 'attributes']; function UserStatusLinker (s, e, a) { var vm = s.vm; } })();