mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Cleanup and fixes
This commit is contained in:
@@ -151,9 +151,9 @@ function fetchAlarms({ page, itemsPerPage, sortBy }) {
|
||||
page: page || 1,
|
||||
page_size: itemsPerPage || 10,
|
||||
}
|
||||
if (sortBy) {
|
||||
if (sortBy && sortBy.length) {
|
||||
params.ordering = sortBy
|
||||
.map((item) => (this.options.sortDesc[0] ? `-${item}` : item))
|
||||
.map((item) => (item.order !== 'asc' ? `-${item.key}` : item.key))
|
||||
.join(',')
|
||||
}
|
||||
if (search.value !== '') {
|
||||
@@ -177,7 +177,7 @@ async function deleteAlarm(alarm, single = true) {
|
||||
}
|
||||
async function deleteAlarms() {
|
||||
await alarmsApi.bulkDelete(selected.value.map((alarm) => alarm.id))
|
||||
busStore.displayNotification({ msg: this.$gettext('Alarms deleted') })
|
||||
busStore.displayNotification({ msg: $gettext('Alarms deleted') })
|
||||
selected.value = []
|
||||
fetchAlarms({})
|
||||
}
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
<template>
|
||||
<v-container class="fill-height" fluid>
|
||||
<v-row align="center" justify="center">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
class="d-flex flex-column justify-center pa-10"
|
||||
@keyup.enter="changePassword"
|
||||
>
|
||||
<h4 class="text-primary mb-6 text-h4">
|
||||
{{ $gettext('Forgot password?') }}
|
||||
</h4>
|
||||
<v-form ref="observer">
|
||||
<p id="password_validation">
|
||||
{{ password_validation_error }}
|
||||
</p>
|
||||
<label class="m-label">{{ $gettext('Change password') }}</label>
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
type="password"
|
||||
variant="outlined"
|
||||
:rules="[rules.required]"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="password_confirmed"
|
||||
type="password"
|
||||
variant="outlined"
|
||||
:rules="[
|
||||
rules.required,
|
||||
(value) => rules.samePassword(value, password),
|
||||
]"
|
||||
/>
|
||||
</v-form>
|
||||
<div class="d-flex justify-center">
|
||||
<v-btn
|
||||
class="flex-grow-1"
|
||||
color="primary"
|
||||
size="large"
|
||||
:loading="loading"
|
||||
@click="changePassword"
|
||||
>
|
||||
{{ $gettext('Submit') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
<div>
|
||||
<router-link :to="{ name: 'Login' }" class="float-right text-primary">
|
||||
{{ $gettext('Return to login') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import auth from '@/api/auth'
|
||||
import rules from '@/plugins/rules.js'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const loading = ref(false)
|
||||
const password = ref('')
|
||||
const password_confirmed = ref('')
|
||||
const password_validation_error = ref('')
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const observer = ref(null)
|
||||
|
||||
let token
|
||||
let id
|
||||
|
||||
function checkUrl() {
|
||||
if (route.params.token === undefined) {
|
||||
if (token === '' || id === '') {
|
||||
router.push({ name: 'PasswordRecovery' })
|
||||
}
|
||||
} else {
|
||||
const decodedId = atob(route.params.id)
|
||||
if (!/^\d+$/.test(decodedId)) {
|
||||
router.push({ name: 'PasswordRecovery' })
|
||||
} else {
|
||||
id = route.params.id
|
||||
token = route.params.token
|
||||
router.push({ name: 'PasswordRecoveryChangeForm' })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function changePassword() {
|
||||
const { valid } = await observer.value.validate()
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const payload = {
|
||||
new_password1: password.value,
|
||||
new_password2: password_confirmed.value,
|
||||
token: token,
|
||||
id: id,
|
||||
}
|
||||
loading.value = true
|
||||
password_validation_error.value = ''
|
||||
auth
|
||||
.changePassword(payload)
|
||||
.then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
loading.value = false
|
||||
router.push({ name: 'Login' })
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
let message = ''
|
||||
loading.value = false
|
||||
if (err.response.status === 403) {
|
||||
message = $gettext('Invalid reset token.')
|
||||
} else if (err.response.status === 404) {
|
||||
message = $gettext('User unknown.')
|
||||
} else if (
|
||||
err.response.status === 400 &&
|
||||
err.response.data.type === 'password_requirement'
|
||||
) {
|
||||
err.response.data.errors.forEach((element) => {
|
||||
message += $gettext(element) + '<br>'
|
||||
})
|
||||
} else if (err.response.status === 429) {
|
||||
message = $gettext('Too many unsuccessful attempts, please try later.')
|
||||
}
|
||||
password_validation_error.value = message
|
||||
})
|
||||
}
|
||||
|
||||
checkUrl()
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#password_validation {
|
||||
color: crimson;
|
||||
}
|
||||
</style>
|
||||
@@ -1,130 +0,0 @@
|
||||
<template>
|
||||
<v-container class="fill-height" fluid>
|
||||
<v-row align="center" justify="center">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="10"
|
||||
md="8"
|
||||
class="text-center"
|
||||
@keyup.enter="recoverPassword"
|
||||
>
|
||||
<h4 class="text-primary mb-10 text-h4">
|
||||
{{ $gettext('Forgot password?') }}
|
||||
</h4>
|
||||
<v-form ref="observer" class="my-4">
|
||||
<label class="m-label">{{
|
||||
$gettext('Please fill-in your primary email address')
|
||||
}}</label>
|
||||
<v-text-field
|
||||
v-model="email"
|
||||
variant="outlined"
|
||||
:rules="[rules.required, rules.email]"
|
||||
:error-messages="errors"
|
||||
/>
|
||||
</v-form>
|
||||
<div class="d-flex justify-center">
|
||||
<v-btn
|
||||
class="flex-grow-1"
|
||||
color="primary"
|
||||
size="large"
|
||||
:loading="loading"
|
||||
@click="recoverPassword"
|
||||
>
|
||||
{{ $gettext('Submit') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
<div>
|
||||
<a class="float-right text-primary" @click="returnToLogin">{{
|
||||
$gettext('Return to login')
|
||||
}}</a>
|
||||
</div>
|
||||
</v-col>
|
||||
<ConfirmDialog ref="dialog" />
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import ConfirmDialog from '@/components/tools/ConfirmDialog.vue'
|
||||
|
||||
import auth from '@/api/auth'
|
||||
import rules from '@/plugins/rules.js'
|
||||
|
||||
const router = useRouter()
|
||||
const { $gettext } = useGettext()
|
||||
const loading = ref(false)
|
||||
const email = ref('')
|
||||
const dialog = ref(null)
|
||||
const observer = ref(null)
|
||||
const errors = ref([])
|
||||
|
||||
function returnToLogin() {
|
||||
router.push({ name: 'Login' })
|
||||
}
|
||||
|
||||
async function showDialog(title, body, error = false) {
|
||||
let color = 'info'
|
||||
if (error) {
|
||||
color = 'error'
|
||||
}
|
||||
const confirm = await dialog.value.open(title, body, {
|
||||
color: color,
|
||||
cancelLabel: $gettext('Ok'),
|
||||
agreeLabel: $gettext('Return to login'),
|
||||
})
|
||||
if (!confirm) {
|
||||
return
|
||||
}
|
||||
returnToLogin()
|
||||
}
|
||||
|
||||
async function recoverPassword() {
|
||||
const { valid } = await observer.value.validate()
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const payload = {
|
||||
email: email.value,
|
||||
}
|
||||
loading.value = true
|
||||
auth
|
||||
.recoverPassword(payload)
|
||||
.then(async (resp) => {
|
||||
loading.value = false
|
||||
if (resp.status === 200) {
|
||||
if (resp.data.type === 'sms') {
|
||||
router.push({ name: 'PasswordRecoverySmsTotpForm' })
|
||||
} else if (resp.data.type === 'email') {
|
||||
await showDialog(
|
||||
'Info',
|
||||
$gettext('Email sent, please check your inbox')
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
loading.value = false
|
||||
if (err.response.status === 404) {
|
||||
if (
|
||||
err.response.data.type === 'sms' ||
|
||||
err.response.data.type === 'email'
|
||||
) {
|
||||
errors.value = [$gettext(err.response.data.reason)]
|
||||
}
|
||||
} else if (
|
||||
err.response.status === 503 &&
|
||||
err.response.data.type === 'email'
|
||||
) {
|
||||
showDialog('Error', err.response.data.reason, true)
|
||||
} else if (err.response.status === 429) {
|
||||
errors.value = [
|
||||
$gettext('Too many unsuccessful attempts, please try later.'),
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,140 +0,0 @@
|
||||
<template>
|
||||
<v-container class="fill-height" fluid>
|
||||
<v-row align="center" justify="center">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
class="d-flex flex-column justify-center pa-10"
|
||||
@keyup.enter="changePassword"
|
||||
>
|
||||
<ConfirmDialog ref="confirm" />
|
||||
<h4 class="text-primary mb-6 text-h4">
|
||||
{{ $gettext('Password recovery') }}
|
||||
</h4>
|
||||
<v-form ref="observer">
|
||||
<label class="m-label"
|
||||
>{{ $gettext("Enter the code you've just received by SMS") }}
|
||||
</label>
|
||||
<v-text-field
|
||||
v-model="sms_totp"
|
||||
type="totp"
|
||||
variant="outlined"
|
||||
:rules="[rules.required, (value) => rules.length(value, 6)]"
|
||||
:error-messages="errors"
|
||||
/>
|
||||
</v-form>
|
||||
<div class="d-flex justify-center">
|
||||
<v-btn
|
||||
class="flex-grow-1"
|
||||
color="primary"
|
||||
size="large"
|
||||
:loading="loading"
|
||||
@click="checkSmsTotp"
|
||||
>
|
||||
{{ $gettext('Submit') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
<div>
|
||||
<a class="float-left text-primary" @click="resendSms">{{
|
||||
$gettext('Resend SMS.')
|
||||
}}</a>
|
||||
<router-link
|
||||
:to="{ name: 'Login' }"
|
||||
class="float-right text-primary"
|
||||
>{{ $gettext('Return to login') }}</router-link
|
||||
>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { ref } from 'vue'
|
||||
import auth from '@/api/auth'
|
||||
import rules from '@/plugins/rules.js'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import ConfirmDialog from '@/components/tools/ConfirmDialog.vue'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const router = useRouter()
|
||||
const confirm = ref(null)
|
||||
const loading = ref(false)
|
||||
const observer = ref(null)
|
||||
const sms_totp = ref('')
|
||||
const errors = ref([])
|
||||
|
||||
async function showErrorDialog(body) {
|
||||
const confirm = await confirm.value.open($gettext('Error'), body, {
|
||||
color: 'error',
|
||||
cancelLabel: $gettext('Return to login'),
|
||||
agreeLabel: $gettext('Retry reset'),
|
||||
})
|
||||
if (!confirm) {
|
||||
router.push({ name: 'Login' })
|
||||
} else {
|
||||
router.push({ name: 'PasswordRecoveryForm' })
|
||||
}
|
||||
}
|
||||
|
||||
async function resendSms() {
|
||||
auth
|
||||
.checkSmsTotp({ type: 'resend' })
|
||||
.then((resp) => {
|
||||
loading.value = false
|
||||
if (resp.status === 200) {
|
||||
observer.value.setErrors({
|
||||
sms_totp: this.$gettext('TOTP resent.'),
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(async (err) => {
|
||||
if (err.response.status === 400) {
|
||||
this.loading = false
|
||||
await showErrorDialog(
|
||||
$gettext(
|
||||
'User seems wrong, return to login or restart reset the process?'
|
||||
)
|
||||
)
|
||||
} else if (err.response.status === 429) {
|
||||
errors.value = [
|
||||
$gettext('Too many unsuccessful attempts, please try later.'),
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function checkSmsTotp() {
|
||||
const { valid } = await observer.value.validate()
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const payload = {
|
||||
type: 'confirm',
|
||||
sms_totp: this.sms_totp,
|
||||
}
|
||||
loading.value = true
|
||||
auth
|
||||
.checkSmsTotp(payload)
|
||||
.then((resp) => {
|
||||
loading.value = false
|
||||
if (resp.status === 200) {
|
||||
// Code is good, redirecting to change password form.
|
||||
router.push({
|
||||
name: 'PasswordRecoveryChangeForm',
|
||||
data: resp.response.data,
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(async (err) => {
|
||||
loading.value = false
|
||||
if (err.response.status === 403 && 'reason' in err.response.data) {
|
||||
await showErrorDialog(err.response.data.reason)
|
||||
} else if (err.response.status === 400 && 'reason' in err.response.data) {
|
||||
errors.value = [$gettext(err.response.data.reason)]
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,78 +0,0 @@
|
||||
<template>
|
||||
<v-container class="fill-height" fuild>
|
||||
<v-row align="center" justify="center" dense>
|
||||
<v-col cols="12" sm="10" md="8" lg="8" class="text-center">
|
||||
<h4 class="text-primary mb-10 text-h4">
|
||||
{{ $gettext('Two-factor authentication') }}
|
||||
</h4>
|
||||
<v-form ref="loginForm" @submit.prevent="verifyCode">
|
||||
<div class="text-body-2">
|
||||
{{
|
||||
$gettext(
|
||||
'Enter the code from the two-factor app on your mobile device. If you have lost your device, you may enter one of your recovery codes.'
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
<v-otp-input
|
||||
ref="otpInput"
|
||||
v-model="code"
|
||||
length="6"
|
||||
:rules="[rules.required]"
|
||||
@finish="verifyCode"
|
||||
/>
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
size="large"
|
||||
type="submit"
|
||||
:loading="loading"
|
||||
class="mb-5"
|
||||
>
|
||||
{{ $gettext('Verify code') }}
|
||||
</v-btn>
|
||||
</v-form>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import account from '@/api/account'
|
||||
import Cookies from 'js-cookie'
|
||||
import rules from '@/plugins/rules.js'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const router = useRouter()
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const loading = ref(false)
|
||||
const code = ref('')
|
||||
const loginForm = ref()
|
||||
|
||||
async function verifyCode() {
|
||||
const { valid } = await loginForm.value.validate()
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
account
|
||||
.verifyTFACode(code.value)
|
||||
.then((resp) => {
|
||||
Cookies.set('token', resp.data.access, { sameSite: 'strict' })
|
||||
Cookies.set('refreshToken', resp.data.refresh, {
|
||||
sameSite: 'strict',
|
||||
})
|
||||
authStore.initialize().then(() => {
|
||||
// bus.$emit('loggedIn')
|
||||
router.push({ name: 'DomainList' })
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -12,33 +12,11 @@ const routes = [
|
||||
name: 'Login',
|
||||
component: () => import('@/views/login/LoginView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'twofa',
|
||||
name: 'TwoFA',
|
||||
component: () => import('@/views/login/TwoFA.vue'),
|
||||
},
|
||||
{
|
||||
path: 'logged',
|
||||
name: 'LoginCallback',
|
||||
component: () => import('@/views/login/LoginCallbackView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'password_recovery',
|
||||
name: 'PasswordRecovery',
|
||||
component: () => import('../views/login/PasswordRecoveryView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'password_recovery/confirm/:id?/:token?/',
|
||||
name: 'PasswordRecoveryChangeForm',
|
||||
component: () =>
|
||||
import('../views/login/PasswordRecoveryChangeView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'password_recovery/sms_confirm',
|
||||
name: 'PasswordRecoverySms',
|
||||
component: () =>
|
||||
import('../views/login/PasswordRecoverySmsTotpView.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -65,3 +65,9 @@ const tab = ref()
|
||||
background-color: #f7f8fa !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.v-window__container {
|
||||
width: 100% !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -195,3 +195,9 @@ loadParams(route.params.app)
|
||||
color: #ff5252 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.v-window__container {
|
||||
width: 100% !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<template v-if="smAndDown">
|
||||
<PasswordRecoveryChangeForm />
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-row class="fill-height ma-0">
|
||||
<v-col class="bg-primary">
|
||||
<v-img
|
||||
src="@/assets/Modoboa_RVB-BLANC-SANS.png"
|
||||
max-width="300"
|
||||
class="mt-10 ml-8"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col class="text-center">
|
||||
<PasswordRecoveryChangeForm />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import PasswordRecoveryChangeForm from '@/components/login/PasswordRecoveryChangeForm.vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
const { smAndDown } = useDisplay()
|
||||
</script>
|
||||
@@ -1,129 +0,0 @@
|
||||
<template>
|
||||
<v-row style="height: 100%; margin: 0 auto">
|
||||
<v-col cols="0" sm="6" class="primary" style="height: 100%">
|
||||
<v-img
|
||||
src="@/assets/Modoboa_RVB-BLANC-SANS.png"
|
||||
max-width="300"
|
||||
class="mt-10 ml-8"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
class="d-flex flex-column justify-center pa-10"
|
||||
@keyup.enter="recoverPassword"
|
||||
>
|
||||
<span class="text-primary mb-6 text-h4">{{
|
||||
$gettext('Forgot password?')
|
||||
}}</span>
|
||||
<v-form ref="observer">
|
||||
<label class="m-label">{{
|
||||
$gettext('Please fill-in your primary email address')
|
||||
}}</label>
|
||||
<v-text-field
|
||||
v-model="email"
|
||||
variant="outlined"
|
||||
:rules="[rules.required, rules.email]"
|
||||
:error-messages="errors"
|
||||
/>
|
||||
</v-form>
|
||||
<div class="d-flex justify-center">
|
||||
<v-btn
|
||||
class="flex-grow-1"
|
||||
color="primary"
|
||||
size="large"
|
||||
:loading="loading"
|
||||
@click="recoverPassword"
|
||||
>
|
||||
{{ $gettext('Submit') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
<div>
|
||||
<a :to="{ name: 'Login' }" class="float-right text-primary">{{
|
||||
$gettext('Return to login')
|
||||
}}</a>
|
||||
</div>
|
||||
</v-col>
|
||||
<ConfirmDialog ref="confirm" />
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import ConfirmDialog from '@/components/tools/ConfirmDialog.vue'
|
||||
|
||||
import auth from '@/api/auth'
|
||||
import rules from '@/plugins/rules.js'
|
||||
|
||||
const router = useRouter()
|
||||
const { $gettext } = useGettext()
|
||||
const loading = ref(false)
|
||||
const email = ref('')
|
||||
const confirm = ref(null)
|
||||
const errors = ref([])
|
||||
|
||||
async function showDialog(title, body, error = false) {
|
||||
let color = 'info'
|
||||
if (error) {
|
||||
color = 'error'
|
||||
}
|
||||
const result = await confirm.value.open(title, body, {
|
||||
color: color,
|
||||
cancelLabel: $gettext('Ok'),
|
||||
agreeLabel: $gettext('Return to login'),
|
||||
})
|
||||
if (!result) {
|
||||
return
|
||||
}
|
||||
router.push({ name: 'Login' })
|
||||
}
|
||||
|
||||
async function recoverPassword() {
|
||||
const { valid } = await this.$refs.observer.validate()
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const payload = {
|
||||
email: email.value,
|
||||
}
|
||||
loading.value = true
|
||||
auth
|
||||
.recoverPassword(payload)
|
||||
.then(async (resp) => {
|
||||
loading.value = false
|
||||
if (resp.status === 200) {
|
||||
if (resp.data.type === 'sms') {
|
||||
router.push({ name: 'PasswordRecoverySms' })
|
||||
} else if (resp.data.type === 'email') {
|
||||
await showDialog(
|
||||
$gettext('Info'),
|
||||
$gettext('Email sent, please check your inbox')
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(async (err) => {
|
||||
loading.value = false
|
||||
if (err.response.status === 404) {
|
||||
if (
|
||||
err.response.data.type === 'sms' ||
|
||||
err.response.data.type === 'email'
|
||||
) {
|
||||
errors.value = [err.response.data.reason]
|
||||
}
|
||||
} else if (
|
||||
err.response.status === 503 &&
|
||||
err.response.data.type === 'email'
|
||||
) {
|
||||
await showDialog($gettext('Error'), err.response.data.reason, true)
|
||||
} else if (err.response.status === 429) {
|
||||
errors.value = [
|
||||
$gettext('Too many unsuccessful attempts, please try later.'),
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<template v-if="smAndDown">
|
||||
<PasswordRecoverySmsTotpForm />
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-row class="fill-height ma-0">
|
||||
<v-col class="bg-primary">
|
||||
<v-img
|
||||
src="@/assets/Modoboa_RVB-BLANC-SANS.png"
|
||||
max-width="300"
|
||||
class="mt-10 ml-8"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col class="text-center">
|
||||
<PasswordRecoverySmsTotpForm />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import PasswordRecoverySmsTotpForm from '@/components/login/PasswordRecoverySmsTotpForm.vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
const { smAndDown } = useDisplay()
|
||||
</script>
|
||||
@@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<template v-if="smAndDown">
|
||||
<PasswordRecoveryForm />
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-row class="fill-height ma-0">
|
||||
<v-col class="bg-primary">
|
||||
<v-img
|
||||
src="@/assets/Modoboa_RVB-BLANC-SANS.png"
|
||||
max-width="300"
|
||||
class="mt-10 ml-8"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col class="text-center">
|
||||
<PasswordRecoveryForm />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import PasswordRecoveryForm from '@/components/login/PasswordRecoveryForm.vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
const { smAndDown } = useDisplay()
|
||||
</script>
|
||||
@@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<template v-if="smAndDown">
|
||||
<TwofaForm />
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-row class="fill-height ma-0">
|
||||
<v-col class="bg-primary">
|
||||
<v-img
|
||||
src="@/assets/Modoboa_RVB-BLANC-SANS.png"
|
||||
max-width="300"
|
||||
class="mt-10 ml-8"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col class="text-center">
|
||||
<TwofaForm />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import TwofaForm from '@/components/login/TwofaForm.vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
const { smAndDown } = useDisplay()
|
||||
</script>
|
||||
Reference in New Issue
Block a user