|
|
@@ -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, |
|
|
|