diff --git a/src/_helpers/router.js b/src/_helpers/router.js index 35617d0..3335028 100644 --- a/src/_helpers/router.js +++ b/src/_helpers/router.js @@ -15,6 +15,7 @@ import LogoutPage from '../auth/LogoutPage' import ForgotPasswordPage from '../auth/ForgotPasswordPage' import MultifactorAuthPage from '../auth/MultifactorAuthPage' import AppLoginPage from '../auth/AppLoginPage' +import RestorePage from "../auth/RestorePage" import DashboardPage from '../account/DashboardPage' import ProfilePage from '../account/profile/ProfilePage' import ActionPage from '../account/profile/ActionPage' @@ -111,6 +112,7 @@ export const router = new Router({ { path: '/logout', component: LogoutPage }, { path: '/forgotPassword', component: ForgotPasswordPage }, { path: '/appLogin', component: AppLoginPage }, + { path: '/restore', component: RestorePage }, { path: '/admin/accounts', component: AccountsPage }, { path: '/admin/new_account', component: ProfilePage }, @@ -128,7 +130,7 @@ export const router = new Router({ }); const publicPages = [ - '/login', '/logout', '/register', '/appLogin', + '/login', '/logout', '/register', '/appLogin', '/restore', '/forgotPassword', '/resetPassword', '/action', '/auth', '/activate', '/legal' diff --git a/src/_services/network.service.js b/src/_services/network.service.js index 07b76a3..579c6df 100644 --- a/src/_services/network.service.js +++ b/src/_services/network.service.js @@ -10,13 +10,16 @@ export const networkService = { getNetworkById, getNearestRegions, startNetwork, + queueBackup, forkNetwork, getStatusesByNetworkId, getNodesByNetworkId, stopNetwork, + restoreNetwork, deleteNetwork, requestNetworkKeys, - retrieveNetworkKeys + retrieveNetworkKeys, + getNetworkBackups }; function getAllNetworks(userId, messages, errors) { @@ -58,6 +61,16 @@ function stopNetwork(userId, networkId, messages, errors) { return fetch(`${config.apiUrl}/users/${userId}/networks/${networkId}/actions/stop`, util.postWithAuth()).then(util.handleCrudResponse(messages, errors)); } +function queueBackup(userId, networkId, messages, errors) { + return fetch(`${config.apiUrl}/users/${userId}/networks/${networkId}/backups/user_requested`, util.putWithAuth()) + .then(util.handleCrudResponse(messages, errors)); +} + +function restoreNetwork(userId, networkId, messages, errors) { + return fetch(`${config.apiUrl}/users/${userId}/networks/${networkId}/actions/restore`, + util.postWithAuth()).then(util.handleCrudResponse(messages, errors)); +} + // deleting network is not allowed via API, instead we delete the AccountPlan, which in turn deletes the network function deleteNetwork(userId, networkId, messages, errors) { return fetch(`${config.apiUrl}/users/${userId}/plans/${networkId}`, util.deleteWithAuth()).then(util.handleCrudResponse(messages, errors)); @@ -69,4 +82,9 @@ function requestNetworkKeys(userId, networkId, messages, errors) { function retrieveNetworkKeys(userId, networkId, code, password, messages, errors) { return fetch(`${config.apiUrl}/users/${userId}/networks/${networkId}/actions/keys/${code}`, util.postWithAuth({name: 'password', value: password})).then(util.handleCrudResponse(messages, errors)); -} \ No newline at end of file +} + +function getNetworkBackups(userId, networkId, messages, errors) { + return fetch(`${config.apiUrl}/users/${userId}/networks/${networkId}/backups`, util.getWithAuth()) + .then(util.handleCrudResponse(messages, errors)); +} diff --git a/src/_services/user.service.js b/src/_services/user.service.js index b241fa1..5ff4307 100644 --- a/src/_services/user.service.js +++ b/src/_services/user.service.js @@ -9,6 +9,7 @@ export const userService = { login, appLogin, logout, + restore, forgotPassword, register, searchAccounts, @@ -66,6 +67,16 @@ function appLogin(session, messages, errors) { .then(setSessionUser); } +function restore(shortKey, longKey, password, messages, errors) { + const requestOptions = { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ 'data': longKey, 'password': password }) + }; + return fetch(`${config.apiUrl}/auth/restore/${shortKey}`, requestOptions) + .then(handleAuthResponse(messages, errors)); +} + function logout(messages, errors) { if (util.currentUser() === null) { console.log('userService.logout: already logged out'); diff --git a/src/_store/account.module.js b/src/_store/account.module.js index 919cc6d..6cb997a 100644 --- a/src/_store/account.module.js +++ b/src/_store/account.module.js @@ -10,6 +10,7 @@ const user = util.currentUser(); const defaultStatus = { loggingIn: false, loggedIn: false, + restoring: false, registering: false, updating: false, settingLocale: false, @@ -111,6 +112,17 @@ const actions = { error => commit('logoutFailure', error) ); }, + restore({ dispatch, commit }, { shortKey, longKey, password, systemConfigs, messages, errors }) { + commit('restoreRequest'); + userService.restore(shortKey, longKey, password, messages, errors) + .then( + ok => { + commit('restoreSuccess'); + systemConfigs.isWaitingRestoring = false; + }, + error => commit('restoreFailure', error) + ); + }, forgotPassword({ commit }, {username, messages, errors}) { commit('forgotPasswordRequest'); userService.forgotPassword(username, messages, errors) @@ -293,6 +305,17 @@ const mutations = { console.log('logout failed: '+JSON.stringify(error)); }, + restoreRequest(state) { + state.status = Object.assign({}, state.status, {restoring: true}); + }, + restoreSuccess(state) { + state.status = Object.assign({}, state.status, {restoring: false}); + }, + restoreFailure(state, error) { + state.status = Object.assign({}, state.status, {restoring: false}); + console.log('restore failed: ' + JSON.stringify(error)); + }, + forgotPasswordRequest(state) { state.status = Object.assign({}, {sendingResetPasswordMessage: true}); state.resetPasswordMessageSent = false; diff --git a/src/_store/networks.module.js b/src/_store/networks.module.js index c8c76e1..a6df403 100644 --- a/src/_store/networks.module.js +++ b/src/_store/networks.module.js @@ -8,9 +8,9 @@ import { util } from '../_helpers'; const state = { loading: { - networks: false, network: false, deleting: false, + networks: false, network: false, stopping: false, restoring: false, deleting: false, nearestRegions: false, startingNetwork: false, networkStatuses: false, networkNodes: false, - requestNetworkKeys: false, retrieveNetworkKeys: false + requestNetworkKeys: false, retrieveNetworkKeys: false, queueBackup: false }, creating: null, error: null, @@ -22,7 +22,9 @@ const state = { networkNodes: null, deletedNetworkUuid: null, networkKeysRequested: null, - networkKeys: null + networkKeys: null, + restoreKey: null, + backups: null, }; const actions = { @@ -35,13 +37,18 @@ const actions = { ); }, + getBackups({ commit }, { userId, networkId, messages, errors }) { + commit('getNetworkBackupsRequest'); + networkService.getNetworkBackups(userId, networkId, messages, errors) + .then(backups => commit('getNetworkBackupsSuccess', backups), + error => commit('getNetworkBackupsFailure', error)); + }, + getNetworkById({ commit }, {userId, networkId, messages, errors}) { commit('getNetworkByIdRequest'); networkService.getNetworkById(userId, networkId, messages, errors) - .then( - network => commit('getNetworkByIdSuccess', network), - error => commit('getNetworkByIdFailure', error) - ); + .then(network => commit('getNetworkByIdSuccess', network), + error => commit('getNetworkByIdFailure', error)); }, addPlanAndStartNetwork({ commit }, {userId, accountPlan, cloud, region, messages, errors}) { @@ -95,6 +102,25 @@ const actions = { ); }, + queueBackup({ commit, dispatch }, { userId, networkId, messages, errors }) { + commit('queueBackupRequest', networkId); + networkService.queueBackup(userId, networkId, messages, errors) + .then(backup => commit('queueBackupSuccess', backup), + error => commit('queueBackupFailure', { networkId, error: error.toString() })) + .then(r => dispatch('getBackups', + { userId: userId, networkId: networkId, + messages: messages, errors: errors })); +}, + + restoreNetwork({ commit }, { userId, networkId, messages, errors }) { + commit('restoreNetworkRequest', networkId); + networkService.restoreNetwork(userId, networkId, messages, errors) + .then( + network => commit('restoreNetworkSuccess', network), + error => commit('restoreNetworkFailure', { networkId, error: error.toString() }) + ); + }, + deleteNetwork({ commit }, {userId, networkId, messages, errors}) { commit('deleteNetworkRequest', networkId); networkService.deleteNetwork(userId, networkId, messages, errors) @@ -215,6 +241,31 @@ const mutations = { state.error = error; }, + queueBackupRequest(state, id) { + state.loading.queueBackup = true; + }, + queueBackupSuccess(state, id) { + // noop - state.loading.queueBackup will be set to false only after backup info is loaded to prevent allowing + // another backup in queue before this one i really processed. + }, + queueBackupFailure(state, { id, error }) { + state.loading.queueBackup = false; + state.error = error; + }, + + restoreNetworkRequest(state, networkId) { + state.loading.restoring = true; + state.restoreKey = null; + }, + restoreNetworkSuccess(state, restoreNodeNotification) { + state.restoreKey = restoreNodeNotification.restoreKey; + state.loading.restoring = false; + }, + restoreNetworkFailure(state, { restoreNodeNotification, error }) { + state.loading.restoring = false; + state.error = error; + }, + deleteNetworkRequest(state, id) { state.loading.deleting = true; }, @@ -271,6 +322,18 @@ const mutations = { retrieveNetworkKeysFailure(state, error) { state.loading.retrieveNetworkKeys = false; state.error = { error }; + }, + getNetworkBackupsRequest(state, backups) { + state.backups = null; + }, + getNetworkBackupsSuccess(state, backups) { + state.backups = backups; + state.loading.queueBackup = false; + }, + getNetworkBackupsFailure(state, error) { + state.backups = null; + state.loading.queueBackup = false; + state.error = { error }; } }; diff --git a/src/_store/system.module.js b/src/_store/system.module.js index 7a20261..dad227f 100644 --- a/src/_store/system.module.js +++ b/src/_store/system.module.js @@ -21,6 +21,7 @@ const state = { launchLock: null, promoCodePolicy: null, requireSendMetrics: null, + isWaitingRestoring: false, support: {}, securityLevels: null }, @@ -177,6 +178,14 @@ const getters = { index: 1 }); } else { + if (isAdmin) { + dashApps.push({ + href: '/bubble/' + configs.networkUuid, + title: messages.label_menu_network, + icon: messages.label_menu_networks_icon, + index: 1 + }); + } dashApps.push({ href: '/devices', title: messages.label_menu_devices, diff --git a/src/account/NetworkPage.vue b/src/account/NetworkPage.vue index 66e9613..d777487 100644 --- a/src/account/NetworkPage.vue +++ b/src/account/NetworkPage.vue @@ -1,11 +1,17 @@