From 110d70bde5bbb0ec675623a7c73d9377f772b87a Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Fri, 10 Jan 2020 01:24:11 -0500 Subject: [PATCH] add ssh keys page, add support for dates --- package.json | 2 + src/_helpers/router.js | 2 + src/_helpers/util.js | 10 + src/_services/user.service.js | 15 + src/_store/index.js | 18 +- src/_store/users.module.js | 72 +- src/account/profile/PolicyPage.vue | 2 +- src/account/profile/ProfilePage.vue | 2 + src/account/profile/SshKeysPage.vue | 157 ++ src/index.html | 3 +- src/index.js | 2 + src/public/bootstrap.min.css | 7 + src/public/fontawesome-5.3.1-all.css | 5 + src/public/vue-datetime.css | 2106 ++++++++++++++++++++++++++ 14 files changed, 2398 insertions(+), 5 deletions(-) create mode 100644 src/account/profile/SshKeysPage.vue create mode 100644 src/public/bootstrap.min.css create mode 100644 src/public/fontawesome-5.3.1-all.css create mode 100644 src/public/vue-datetime.css diff --git a/package.json b/package.json index a6cf3d2..456a833 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,12 @@ "start": "webpack-dev-server --open" }, "dependencies": { + "luxon": "^1.21.3", "qrcode": "^1.4.4", "safe-eval": "^0.4.1", "vee-validate": "^2.2.8", "vue": "^2.6.10", + "vue-datetime": "^1.0.0-beta.11", "vue-router": "^3.0.6", "vue-select": "^3.4.0", "vue-sidebar-menu": "^4.4.3", diff --git a/src/_helpers/router.js b/src/_helpers/router.js index 172f4b3..1380c9a 100644 --- a/src/_helpers/router.js +++ b/src/_helpers/router.js @@ -12,6 +12,7 @@ import ActionPage from '../account/profile/ActionPage' import PolicyPage from '../account/profile/PolicyPage' import NotificationsPage from '../account/NotificationsPage' import ChangePasswordPage from '../account/profile/ChangePasswordPage' +import SshKeysPage from '../account/profile/SshKeysPage' import NetworksPage from '../account/NetworksPage' import NewNetworkPage from '../account/NewNetworkPage' import NetworkPage from '../account/NetworkPage' @@ -49,6 +50,7 @@ export const router = new Router({ { path: '/me/policy', component: PolicyPage }, { path: '/me/action', component: ActionPage }, { path: '/me/changePassword', component: ChangePasswordPage }, + { path: '/me/keys', component: SshKeysPage }, { path: '/notifications', component: NotificationsPage }, { path: '/bubbles', component: NetworksPage , diff --git a/src/_helpers/util.js b/src/_helpers/util.js index 082b1fe..44b3b6b 100644 --- a/src/_helpers/util.js +++ b/src/_helpers/util.js @@ -161,5 +161,15 @@ export const util = { } return false; }; + }, + + userHasLocale: function(user) { + return !(typeof user === 'undefined' || user === null || !user.hasOwnProperty('locale') || user.locale === null || user.locale === '' || user.locale === 'detect'); + }, + + jsLocale: function (user, detectedLocale) { + const loc = util.userHasLocale(user) ? user.locale : detectedLocale; + return loc === null ? null : loc.replace('_', '-').toLowerCase(); } + }; diff --git a/src/_services/user.service.js b/src/_services/user.service.js index 08090ff..5277d63 100644 --- a/src/_services/user.service.js +++ b/src/_services/user.service.js @@ -13,6 +13,9 @@ export const userService = { addPolicyContactById, removePolicyContactByUuid, setLocale, + addSshKeyByUserId, + removeSshKeyByUserId, + listSshKeysByUserId, updateUser, deleteUser, approveAction, @@ -120,6 +123,18 @@ function setLocale(locale, messages, errors) { } } +function addSshKeyByUserId(userId, sshKey, messages, errors) { + return fetch(`${config.apiUrl}/users/${userId}/keys`, util.putWithAuth(sshKey)).then(util.handleCrudResponse(messages, errors)); +} + +function removeSshKeyByUserId(userId, sshKeyId, messages, errors) { + return fetch(`${config.apiUrl}/users/${userId}/keys/${sshKeyId}`, util.deleteWithAuth()).then(util.handleCrudResponse(messages, errors)); +} + +function listSshKeysByUserId(userId, messages, errors) { + return fetch(`${config.apiUrl}/users/${userId}/keys`, util.getWithAuth()).then(util.handleCrudResponse(messages, errors)); +} + function updateUser(user, messages, errors) { return fetch(`${config.apiUrl}/users/${user.uuid}`, util.postWithAuth(user)).then(util.handleCrudResponse(messages, errors)); } diff --git a/src/_store/index.js b/src/_store/index.js index 67b691d..2b62c10 100644 --- a/src/_store/index.js +++ b/src/_store/index.js @@ -46,7 +46,23 @@ function evalInContext(vue, string) { String.prototype.parseMessage = function (vue, ctx) { const context = (typeof ctx !== 'undefined' && ctx !== null) ? Object.assign(vue, ctx) : vue; - return this ? ''+this.replace(/{{[\w\._]*?}}/g, match => { + return this ? ''+this.replace(/{{[\w][\w\._]*?}}/g, match => { + const expression = match.slice(2, -2); + return evalInContext(context, expression) + }) : ''; +}; + +String.prototype.parseDateMessage = function (millis, messages) { + const date = new Date(millis); + const context = { + YYYY: date.getFullYear(), + MMM: messages['label_date_month_'+date.getMonth()], + M: messages['label_date_month_short_'+date.getMonth()], + EEE: messages['label_date_day_'+date.getDay()], + E: messages['label_date_day_short_'+date.getDay()], + d: date.getDate() + }; + return this ? ''+this.replace(/{{[\w]+?}}/g, match => { const expression = match.slice(2, -2); return evalInContext(context, expression) }) : ''; diff --git a/src/_store/users.module.js b/src/_store/users.module.js index c5be72f..d97f1b7 100644 --- a/src/_store/users.module.js +++ b/src/_store/users.module.js @@ -5,14 +5,17 @@ import { util } from '../_helpers'; const state = { loading: { users: false, user: false, updating: false, deleting: false, - policy: false, updatingPolicy: false, addPolicyContact: false, removePolicyContact: false + policy: false, updatingPolicy: false, addPolicyContact: false, removePolicyContact: false, + listSshKeys: false, addSshKey: false, removeSshKey: false }, errors: {}, users: null, user: null, policy: {}, contact: null, - authenticator: {} + authenticator: {}, + sshKey: null, + sshKeys: [] }; export const CONTACT_TYPE_AUTHENTICATOR = 'authenticator'; @@ -113,6 +116,33 @@ const actions = { ); }, + addSshKeyByUserId({ commit }, {userId, sshKey, messages, errors}) { + commit('addSshKeyByUserIdRequest'); + userService.addSshKeyByUserId(userId, sshKey, messages, errors) + .then( + key => commit('addSshKeyByUserIdSuccess', key), + error => commit('addSshKeyByUserIdFailure', error) + ); + }, + + removeSshKeyByUserId({ commit }, {userId, sshKeyId, messages, errors}) { + commit('removeSshKeyByUserIdRequest'); + userService.removeSshKeyByUserId(userId, sshKeyId, messages, errors) + .then( + ok => commit('removeSshKeyByUserIdSuccess', sshKeyId), + error => commit('removeSshKeyByUserIdFailure', error) + ); + }, + + listSshKeysByUserId({ commit }, {userId, messages, errors}) { + commit('listSshKeysByUserIdRequest'); + userService.listSshKeysByUserId(userId, messages, errors) + .then( + sshKeys => commit('listSshKeysByUserIdSuccess', sshKeys), + error => commit('listSshKeysByUserIdFailure', error) + ); + }, + delete({ commit }, {userId, messages, errors}) { commit('deleteRequest', userId); userService.deleteUser(userId, messages, errors) @@ -217,6 +247,44 @@ const mutations = { state.errors.update = error; }, + addSshKeyByUserIdRequest(state) { + state.loading.addSshKey = true; + }, + addSshKeyByUserIdSuccess(state, sshKey) { + state.loading.addSshKey = false; + state.sshKey = sshKey; + state.sshKeys.push(sshKey); + }, + addSshKeyByUserIdFailure(state, error) { + state.loading.addSshKey = false; + state.errors.sshKey = error; + }, + + removeSshKeyByUserIdRequest(state) { + state.loading.removeSshKey = true; + }, + removeSshKeyByUserIdSuccess(state, sshKeyId) { + state.loading.removeSshKey = false; + state.sshKey = null; + state.sshKeys = state.sshKeys.filter(function(k) { return k.uuid !== sshKeyId; }) + }, + removeSshKeyByUserIdFailure(state, error) { + state.loading.removeSshKey = false; + state.errors.sshKey = error; + }, + + listSshKeysByUserIdRequest(state) { + state.loading.listSshKeys = true; + }, + listSshKeysByUserIdSuccess(state, sshKeys) { + state.loading.listSshKeys = false; + state.sshKeys = sshKeys; + }, + listSshKeysByUserIdFailure(state, error) { + state.loading.listSshKeys = false; + state.errors.sshKey = error; + }, + deleteRequest(state, id) { // todo: use proper delete API // add 'deleting:true' property to user being deleted diff --git a/src/account/profile/PolicyPage.vue b/src/account/profile/PolicyPage.vue index c101eeb..742e62d 100644 --- a/src/account/profile/PolicyPage.vue +++ b/src/account/profile/PolicyPage.vue @@ -254,9 +254,9 @@ +

{{messages.form_title_account_add_contact}}

-