X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/69487544de1e7fa7c636473e338fe90dde6c3c06..58be2f1c488248d11dfb2ad730b6a8d56e557e63:/apps/workbench/app/assets/javascripts/models/session_db.js?ds=sidebyside diff --git a/apps/workbench/app/assets/javascripts/models/session_db.js b/apps/workbench/app/assets/javascripts/models/session_db.js index 058d450287..01b0d72728 100644 --- a/apps/workbench/app/assets/javascripts/models/session_db.js +++ b/apps/workbench/app/assets/javascripts/models/session_db.js @@ -2,19 +2,39 @@ // // SPDX-License-Identifier: AGPL-3.0 -window.models = window.models || {} -window.models.SessionDB = function() { +window.SessionDB = function() { var db = this Object.assign(db, { - loadAll: function() { + discoveryCache: {}, + loadFromLocalStorage: function() { try { return JSON.parse(window.localStorage.getItem('sessions')) || {} } catch(e) {} return {} }, + loadAll: function() { + var all = db.loadFromLocalStorage() + if (window.defaultSession) { + window.defaultSession.isFromRails = true + all[window.defaultSession.user.uuid.slice(0, 5)] = window.defaultSession + } + return all + }, + loadActive: function() { + var sessions = db.loadAll() + Object.keys(sessions).forEach(function(key) { + if (!sessions[key].token) + delete sessions[key] + }) + return sessions + }, save: function(k, v) { var sessions = db.loadAll() sessions[k] = v + Object.keys(sessions).forEach(function(key) { + if (sessions[key].isFromRails) + delete sessions[key] + }) window.localStorage.setItem('sessions', JSON.stringify(sessions)) }, trash: function(k) { @@ -22,27 +42,50 @@ window.models.SessionDB = function() { delete sessions[k] window.localStorage.setItem('sessions', JSON.stringify(sessions)) }, - login: function(host) { - // Initiate login procedure with given API host (which can - // optionally include scheme://). + findAPI: function(url) { + // Given a Workbench or API host or URL, return a promise + // for the corresponding API server's base URL. Typical + // use: + // sessionDB.findAPI('https://workbench.example/foo').then(sessionDB.login) + if (url.indexOf('://') < 0) + url = 'https://' + url + url = new URL(url) + return m.request(url.origin + '/discovery/v1/apis/arvados/v1/rest').then(function() { + return url.origin + '/' + }).catch(function(err) { + // If url is a Workbench site (and isn't too old), + // /status.json will tell us its API host. + return m.request(url.origin + '/status.json').then(function(resp) { + if (!resp.apiBaseURL) + throw 'no apiBaseURL in status response' + return resp.apiBaseURL + }) + }) + }, + login: function(baseURL) { + // Initiate login procedure with given API base URL (e.g., + // "http://api.example/"). // // Any page that has a button that invokes login() must // also call checkForNewToken() on (at least) its first // render. Otherwise, the login procedure can't be // completed. - var baseURL = host - if (baseURL.indexOf('://') < 0) - baseURL = 'https://' + baseURL - if (!baseURL.endsWith('/')) - baseURL = baseURL + '/' - document.location = baseURL + 'login?return_to=' + encodeURIComponent(document.location.href+'?baseURL='+encodeURIComponent(baseURL)) + document.location = baseURL + 'login?return_to=' + encodeURIComponent(document.location.href.replace(/\?.*/, '')+'?baseURL='+encodeURIComponent(baseURL)) return false }, + logout: function(k) { + // Forget the token, but leave the other info in the db so + // the user can log in again without providing the login + // host again. + var sessions = db.loadAll() + delete sessions[k].token + db.save(k, sessions[k]) + }, checkForNewToken: function() { // If there's a token and baseURL in the location bar (i.e., // we just landed here after a successful login), save it and // scrub the location bar. - if (!document.location.search.startsWith('?')) + if (document.location.search[0] != '?') return var params = {} document.location.search.slice(1).split('&').map(function(kv) { @@ -77,7 +120,39 @@ window.models.SessionDB = function() { db.trash(key) }) }) - // m.request(session.baseURL + 'discovery/v1/apis/arvados/v1/rest').then(function(dd) {}) + }, + // Return the Workbench base URL advertised by the session's + // API server, or a reasonable guess, or (if neither strategy + // works out) null. + workbenchBaseURL: function(session) { + var dd = db.discoveryDoc(session)() + if (!dd) + // Don't fall back to guessing until we receive the discovery doc + return null + if (dd.workbenchUrl) + return dd.workbenchUrl + // Guess workbench.{apihostport} is a Workbench... unless + // the host part of apihostport is an IPv4 or [IPv6] + // address. + if (!session.baseURL.match('://(\\[|\\d+\\.\\d+\\.\\d+\\.\\d+[:/])')) + return session.baseURL.replace('://', '://workbench.') + return null + }, + // Return a m.stream that will get fulfilled with the + // discovery doc from a session's API server. + discoveryDoc: function(session) { + var cache = db.discoveryCache[session.baseURL] + if (!cache) { + db.discoveryCache[session.baseURL] = cache = m.stream() + m.request(session.baseURL+'discovery/v1/apis/arvados/v1/rest').then(cache) + } + return cache + }, + request: function(session, path, opts) { + opts = opts || {} + opts.headers = opts.headers || {} + opts.headers.authorization = 'OAuth2 '+ session.token + return m.request(session.baseURL + path, opts) }, }) }