diff --git a/src/_helpers/router.js b/src/_helpers/router.js index aee0e2f..00a4bc9 100644 --- a/src/_helpers/router.js +++ b/src/_helpers/router.js @@ -69,6 +69,7 @@ export const router = new Router({ { path: '/me', component: ProfilePage }, { path: '/me/policy', component: PolicyPage }, + { path: '/me/download/:uuid', redirect: r => ({ path: '/me/policy', query: { download: r.params.uuid } }) }, { path: '/me/action', component: ActionPage }, { path: '/me/changePassword', component: ChangePasswordPage }, { path: '/me/setPassword/:code', component: SetPasswordPage }, diff --git a/src/_helpers/util.js b/src/_helpers/util.js index 236e2a0..5b718d0 100644 --- a/src/_helpers/util.js +++ b/src/_helpers/util.js @@ -155,18 +155,20 @@ export const util = { return function (response) { return response.text().then(text => { if (!response.ok) { + let errData = JSON.parse('' + text) || text; + if (Array.isArray(errData)) errData = errData[0]; + if (response.status === 404) { // todo: show nicer error message - const errData = JSON.parse(''+text); - console.log('handleCrudResponse: received 404: ' + text); + console.log('handlePlaintextResponse: received 404: ' + (errData.resource || errData)); } else if (response.status === 422) { - const errData = JSON.parse(''+text); - console.log('handleCrudResponse: received 422, error: ' + text); + console.log('handlePlaintextResponse: received 422, error: ' + + ((errData.message + ": " + errData.invalidValue) || errData)); util.setValidationErrors(errData, messages, errors); } - const error = (data && data.message) || response.statusText; + const error = errData.message || errData || response.statusText; return Promise.reject(error); } return text; @@ -174,6 +176,28 @@ export const util = { } }, + handleDataToDownloadAsFile: function(fileName, mimeType) { + return function(data) { + // Original taken from: https://javascript.info/blob#blob-as-url + const uri = URL.createObjectURL(new Blob([data], {type: mimeType})); + try { + util.downloadURI(uri, fileName); + } catch(err) { + return Promise.reject(err); + } finally { + URL.revokeObjectURL(uri); + } + return 'ok'; + }; + }, + + downloadURI: function(uri, name) { + const link = document.createElement("a"); + link.download = name; + link.href = uri; + link.click(); + }, + setValidationErrors: function(data, messages, errors, enableTotpModal) { const errs = []; for (let i=0; i { + try { + return JSON.stringify(JSON.parse(text, (_, v) => typeof v === 'string' ? (JSON.parse(v) || v) : v), + null, '\t'); + } catch(err) { + Promise.reject(text || err); + } + }) + .then(util.handleDataToDownloadAsFile(fileName, 'application/json')); +} + function getUserById(userId, messages, errors) { return fetch(`${config.apiUrl}/users/${userId}`, util.getWithAuth()).then(util.handleCrudResponse(messages, errors)); } @@ -227,4 +249,4 @@ function handleAuthResponse(messages, errors) { return data; }); }; -} \ No newline at end of file +} diff --git a/src/_store/account.module.js b/src/_store/account.module.js index 7ebba7f..3adcd9b 100644 --- a/src/_store/account.module.js +++ b/src/_store/account.module.js @@ -19,7 +19,9 @@ const defaultStatus = { authenticating: false, sendingVerification: false, sendingResetPasswordMessage: false, - registrationError: null + registrationError: null, + requestAccountDownloadRequestSent: false, + downloadingAccount: false }; const state = { @@ -179,6 +181,18 @@ const actions = { }, error => commit('resendVerificationCodeFailure', error) ); + }, + requestAccountDownload({ commit }, {messages, errors}) { + commit('requestAccountDownloadRequest'); + userService.requestAccountDownload(messages, errors) + .then(ok => commit('requestAccountDownloadSuccess'), + error => commit('requestAccountDownloadFailure', error)); + }, + downloadAccount({ commit }, {token, messages, errors}) { + commit('downloadAccountRequest'); + userService.downloadAccount(token, messages, errors) + .then(ok => commit('downloadAccountSuccess'), + error => commit('downloadAccountFailure', error)); } }; @@ -367,6 +381,33 @@ const mutations = { resendVerificationCodeFailure(state, error) { state.status = Object.assign({}, state.status, {sendingVerification: false}); state.actionStatus = { error: error, type: 'verify' }; + }, + + requestAccountDownloadRequest(state) { + state.status = Object.assign({}, state.status, + { downloadingAccount: false, requestAccountDownloadRequestSent: false }); + state.actionStatus = { requesting: true, type: 'requestDownload' }; + }, + requestAccountDownloadSuccess(state) { + state.status = Object.assign({}, state.status, { requestAccountDownloadRequestSent: true }); + state.actionStatus = { success: true, type: 'requestDownload' }; + }, + requestAccountDownloadFailure(state, error) { + state.actionStatus = { error: error, type: 'requestDownload' }; + console.log('requestAccountDownloadFailure: ' + JSON.stringify(error)); + }, + + downloadAccountRequest(state) { + state.status = Object.assign({}, state.status, { downloadingAccount: true }); + state.actionStatus = { requesting: true, type: 'download' }; + }, + downloadAccountSuccess(state) { + state.status = Object.assign({}, state.status, { downloadingAccount: false }); + state.actionStatus = { success: true, type: 'download' }; + }, + downloadAccountFailure(state, error) { + state.actionStatus = { error: error, type: 'download' }; + console.log('downloadAccountFailure: ' + JSON.stringify(error)); } }; diff --git a/src/account/DevicesPage.vue b/src/account/DevicesPage.vue index e4ed7c7..ce83ec8 100644 --- a/src/account/DevicesPage.vue +++ b/src/account/DevicesPage.vue @@ -34,7 +34,7 @@
- +
{{ errors.first('deviceVpnConf') }}

@@ -225,14 +225,6 @@ }, hideDeviceHelp () { this.displayDeviceHelp = {}; }, - downloadURI(uri, name) { // adapted from https://stackoverflow.com/a/15832662/1251543 - let link = document.createElement("a"); - link.download = name; - link.href = uri; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }, mitmOn () { this.mitmLoading = true; this.errors.clear(); diff --git a/src/account/profile/PolicyPage.vue b/src/account/profile/PolicyPage.vue index f7cbb57..33b4a73 100644 --- a/src/account/profile/PolicyPage.vue +++ b/src/account/profile/PolicyPage.vue @@ -1,6 +1,14 @@