소스 검색

Add support for restoring bubble on running instance

pull/8/head
Kristijan Mitrovic 4 년 전
부모
커밋
9a82e342b5
4개의 변경된 파일121개의 추가작업 그리고 37개의 파일을 삭제
  1. +11
    -0
      src/_services/user.service.js
  2. +22
    -0
      src/_store/account.module.js
  3. +2
    -1
      src/_store/system.module.js
  4. +86
    -36
      src/auth/LoginPage.vue

+ 11
- 0
src/_services/user.service.js 파일 보기

@@ -8,6 +8,7 @@ import { util } from '../_helpers';
export const userService = {
login,
logout,
restore,
forgotPassword,
register,
searchAccounts,
@@ -55,6 +56,16 @@ function login(name, password, totpToken, unlockKey, 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');


+ 22
- 0
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,
@@ -93,6 +94,16 @@ 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.isInRestoringStatus = false;
},
error => commit('restoreFailure', error)
);
},
forgotPassword({ commit }, {username, messages, errors}) {
commit('forgotPasswordRequest');
userService.forgotPassword(username, messages, errors)
@@ -251,6 +262,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;


+ 2
- 1
src/_store/system.module.js 파일 보기

@@ -18,7 +18,8 @@ const state = {
cloudConfigs: {},
sslPort: null,
promoCodePolicy: null,
requireSendMetrics: null
requireSendMetrics: null,
isInRestoringStatus: false
},
entityConfigs: {},
searchResults: [],


+ 86
- 36
src/auth/LoginPage.vue 파일 보기

@@ -1,43 +1,85 @@
<!-- Copyright (c) 2020 Bubble, Inc. All rights reserved. For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ -->
<template>
<div>
<h2>{{messages.form_title_login}}</h2>
<h2 v-if="configs && configs.isInRestoringStatus">{{ messages.form_title_restore }}</h2>
<h2 v-else>{{ messages.form_title_login }}</h2>

<h4 v-if="resetPasswordMessageSent === true" class="alert-success">{{messages.message_resetPassword_sent}}</h4>
<h4 v-if="submitted && errors.has('approvalToken')" class="invalid-feedback d-block">{{ errors.first('approvalToken') }}</h4>

<form @submit.prevent="handleSubmit">
<div class="form-group">
<label for="name">{{messages.field_label_username}}</label>
<input type="text" v-model="name" name="name" class="form-control" :class="{ 'is-invalid': submitted && !name }" />
<div v-show="submitted && !name" class="invalid-feedback">Name is required</div>
<div v-if="submitted && errors.has('account')" class="invalid-feedback d-block">{{ errors.first('account') }}</div>
<div v-if="submitted && errors.has('name')" class="invalid-feedback d-block">{{ errors.first('name') }}</div>
</div>
<div class="form-group">
<label htmlFor="password">{{messages.field_label_password}}</label>
<input type="password" v-model="password" name="password" class="form-control" :class="{ 'is-invalid': submitted && !password }" />
<div v-if="submitted && errors.has('password')" class="invalid-feedback d-block">{{ errors.first('password') }}</div>
</div>
<div v-if="showTotp" class="form-group">
<p>{{messages.message_login_authenticator_auth}}</p>
<label htmlFor="totpToken">{{messages.field_label_totp_code}}</label>
<input v-validate="'required'" v-model="totpToken" name="totpToken" class="form-control"/>
<div v-if="submitted && errors.has('totpToken')" class="invalid-feedback d-block">{{ errors.first('totpToken') }}</div>
</div>
<div v-if="configs && configs.locked === true" class="form-group">
<label htmlFor="unlockKey">{{messages.field_label_unlock_key}}</label>
<input type="password" v-model="unlockKey" name="unlockKey" class="form-control" :class="{ 'is-invalid': submitted && !unlockKey }" />
<div v-show="submitted && !unlockKey" class="invalid-feedback">Unlock Key is required</div>
<div v-if="submitted && errors.has('unlockKey')" class="invalid-feedback d-block">{{ errors.first('unlockKey') }}</div>
</div>
<div class="form-group">
<div><small v-html="messages.message_login_agreeToTerms"></small><hr/></div>
<button class="btn btn-primary" :disabled="status.loggingIn">{{messages.button_label_login}}</button>
<img v-show="status.loggingIn" :src="loadingImgSrc" />
<router-link v-if="configs && configs.allowRegistration" to="/register" class="btn btn-link">{{messages.button_label_register}}</router-link>
</div>
<div class="form-group">
<router-link to="/forgotPassword" class="btn btn-link">{{messages.button_label_forgotPassword}}</router-link>
</div>
<span v-if="configs && configs.isInRestoringStatus">
<div class="form-group">
<label htmlFor="restoreShortKey">{{messages.field_label_restore_short_key}}</label>
<input type="text" v-model="restoreShortKey" name="restoreShortKey" class="form-control"
:class="{ 'is-invalid': submitted && !restoreShortKey }" />
<div v-show="submitted && !restoreShortKey" class="invalid-feedback">Required</div>
<div v-if="submitted && errors.has('restoreShortKey')" class="invalid-feedback d-block">
{{ errors.first('restoreShortKey') }}
</div>
</div>

<div class="form-group">
<label htmlFor="restoreLongNetworkKey">{{messages.field_label_restore_long_key}}</label>
<textarea v-model="restoreLongNetworkKey" name="restoreLongNetworkKey" class="form-control"
:class="{ 'is-invalid': submitted && !restoreLongNetworkKey }" />
<div v-show="submitted && !restoreLongNetworkKey" class="invalid-feedback">Required</div>
<div v-if="submitted && errors.has('restoreLongNetworkKey')" class="invalid-feedback d-block">
{{ errors.first('restoreLongNetworkKey') }}
</div>
</div>

<div class="form-group">
<label htmlFor="password">{{messages.field_label_password}}</label>
<input type="password" v-model="password" name="password" class="form-control"
:class="{ 'is-invalid': submitted && !password }" />
<div v-if="submitted && errors.has('password')" class="invalid-feedback d-block">
{{ errors.first('password') }}
</div>
</div>

<div class="form-group">
<button class="btn btn-primary" :disabled="status.restoring">
{{ messages.button_label_restore }}
</button>
<img v-show="status.restoring" :src="loadingImgSrc" />
</div>
</span>
<span v-else>
<div class="form-group">
<label for="name">{{messages.field_label_username}}</label>
<input type="text" v-model="name" name="name" class="form-control" :class="{ 'is-invalid': submitted && !name }" />
<div v-show="submitted && !name" class="invalid-feedback">Name is required</div>
<div v-if="submitted && errors.has('account')" class="invalid-feedback d-block">{{ errors.first('account') }}</div>
<div v-if="submitted && errors.has('name')" class="invalid-feedback d-block">{{ errors.first('name') }}</div>
</div>
<div class="form-group">
<label htmlFor="password">{{messages.field_label_password}}</label>
<input type="password" v-model="password" name="password" class="form-control" :class="{ 'is-invalid': submitted && !password }" />
<div v-if="submitted && errors.has('password')" class="invalid-feedback d-block">{{ errors.first('password') }}</div>
</div>
<div v-if="showTotp" class="form-group">
<p>{{messages.message_login_authenticator_auth}}</p>
<label htmlFor="totpToken">{{messages.field_label_totp_code}}</label>
<input v-validate="'required'" v-model="totpToken" name="totpToken" class="form-control"/>
<div v-if="submitted && errors.has('totpToken')" class="invalid-feedback d-block">{{ errors.first('totpToken') }}</div>
</div>
<div v-if="configs && configs.locked === true" class="form-group">
<label htmlFor="unlockKey">{{messages.field_label_unlock_key}}</label>
<input type="password" v-model="unlockKey" name="unlockKey" class="form-control" :class="{ 'is-invalid': submitted && !unlockKey }" />
<div v-show="submitted && !unlockKey" class="invalid-feedback">Unlock Key is required</div>
<div v-if="submitted && errors.has('unlockKey')" class="invalid-feedback d-block">{{ errors.first('unlockKey') }}</div>
</div>
<div class="form-group">
<div><small v-html="messages.message_login_agreeToTerms"></small><hr/></div>
<button class="btn btn-primary" :disabled="status.loggingIn">{{messages.button_label_login}}</button>
<img v-show="status.loggingIn" :src="loadingImgSrc" />
<router-link v-if="configs && configs.allowRegistration" to="/register" class="btn btn-link">{{messages.button_label_register}}</router-link>
</div>
<div class="form-group">
<router-link to="/forgotPassword" class="btn btn-link">{{messages.button_label_forgotPassword}}</router-link>
</div>
</span>
</form>
</div>
</template>
@@ -53,6 +95,9 @@ export default {
password: '',
totpToken: null,
unlockKey: (this.$route.query && this.$route.query.k) ? this.$route.query.k : null,
restoreShortKey: (this.$route.query && this.$route.query.k) ? this.$route.query.k : null,
restoreLongNetworkKey: null,
// reuse password for this restoreLongNetworkKey's password
showTotp: false,
submitted: false,
loadingImgSrc: loadingImgSrc
@@ -66,13 +111,18 @@ export default {
...mapState('system', ['configs', 'messages'])
},
methods: {
...mapActions('account', ['login', 'logout']),
...mapActions('account', ['login', 'logout', 'restore']),
...mapActions('system', ['loadSystemConfigs']),
handleSubmit (e) {
this.errors.clear();
this.submitted = true;
const { name, password, totpToken, unlockKey } = this;
if (name && password) {
if (configs && configs.isInRestoringStatus) {
this.restore({
shortKey: restoreShortKey, longKey: restoreLongNetworkKey, password: password,
systemConfigs: this.configs, messages: this.messages, errors: this.errors
});
} else if (name && password) {
this.login({
user: {name, password, totpToken, unlockKey},
systemConfigs: this.configs,


불러오는 중...
취소
저장