Use a shared public view layout component
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
<script setup>
|
||||
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { Button, PasswordInput, TextInput, fetcher, FormGroup } from 'pankow';
|
||||
import { API_ORIGIN } from '../constants.js';
|
||||
import PublicPageLayout from '../components/PublicPageLayout.vue';
|
||||
|
||||
const ready = ref(false);
|
||||
const busy = ref(false);
|
||||
const passwordError = ref(null);
|
||||
const totpError = ref(null);
|
||||
const internalError = ref(null);
|
||||
const username = ref('');
|
||||
const password = ref('');
|
||||
const totpToken = ref('');
|
||||
const totpTokenRequired = ref(false);
|
||||
|
||||
// coming from login.html template
|
||||
const name = window.cloudron.name;
|
||||
const note = window.cloudron.note;
|
||||
const iconUrl = window.cloudron.iconUrl;
|
||||
const footer = window.cloudron.footer;
|
||||
const submitUrl = window.cloudron.submitUrl;
|
||||
|
||||
async function onSubmit() {
|
||||
busy.value = true;
|
||||
passwordError.value = false;
|
||||
totpError.value = false;
|
||||
internalError.value = false;
|
||||
|
||||
const body = {
|
||||
username: username.value,
|
||||
password: password.value,
|
||||
totpToken: totpToken.value
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await fetcher.post(submitUrl, body);
|
||||
if (res.status === 410) {
|
||||
// the oidc login session is old
|
||||
window.location.reload();
|
||||
} else if (res.status === 401) {
|
||||
if (res.body.message.indexOf('totpToken') !== -1) {
|
||||
totpError.value = totpTokenRequired.value; // only set on second try coming from login
|
||||
totpTokenRequired.value = true;
|
||||
totpToken.value = '';
|
||||
setTimeout(() => document.getElementById('inputTotpToken').focus(), 0);
|
||||
} else {
|
||||
password.value = '';
|
||||
passwordError.value = true;
|
||||
document.getElementById('inputPassword').focus();
|
||||
}
|
||||
} else if (res.status === 200 ) {
|
||||
if (res.body.redirectTo) return window.location.href = res.body.redirectTo;
|
||||
console.error('login success but missing redirectTo in data:', res.body);
|
||||
internalError.value = true;
|
||||
} else {
|
||||
internalError.value = true;
|
||||
}
|
||||
} catch (error) {
|
||||
internalError.value = true;
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
busy.value = false;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// placed optionally in local storage by setupaccount.js
|
||||
const autoLoginToken = localStorage.cloudronFirstTimeToken;
|
||||
if (autoLoginToken) {
|
||||
try {
|
||||
const res = await fetch.post(submitUrl, { autoLoginToken });
|
||||
localStorage.removeItem('cloudronFirstTimeToken');
|
||||
|
||||
if (res.body.redirectTo) window.location.href = res.body.redirectTo;
|
||||
else console.log('login success but missing redirectTo in data:', res.body);
|
||||
} catch (error) {
|
||||
console.error('Failed to use autologin token', error);
|
||||
}
|
||||
}
|
||||
|
||||
ready.value = true;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PublicPageLayout :footerHtml="footer">
|
||||
<div v-if="ready" style="max-width: 300px;">
|
||||
<small>{{ $t('login.loginTo') }}</small>
|
||||
<h1>{{ name }}</h1>
|
||||
<br/>
|
||||
<div :html="note"></div>
|
||||
|
||||
<div class="has-error" v-if="passwordError">{{ $t('login.errorIncorrectCredentials') }}</div>
|
||||
<div class="has-error" v-if="internalError">{{ $t('login.errorInternal') }}</div>
|
||||
|
||||
<form @submit.prevent="onSubmit" v-if="!totpTokenRequired">
|
||||
<input type="submit" style="display: none;"/>
|
||||
|
||||
<FormGroup>
|
||||
<label for="inputUsername">{{ $t('login.username') }}</label>
|
||||
<TextInput id="inputUsername" v-model="username" autofocus required/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup :has-error="passwordError">
|
||||
<label for="inputPassword">{{ $t('login.password') }}</label>
|
||||
<PasswordInput id="inputPassword" v-model="password" required/>
|
||||
</FormGroup>
|
||||
|
||||
<Button id="loginSubmitButton" style="margin-top: 12px" @click.prevent="onSubmit" :loading="busy">{{ $t('login.signInAction') }}</Button>
|
||||
<a href="/passwordreset.html" style="margin-left: 10px;">{{ $t('login.resetPasswordAction') }}</a>
|
||||
</form>
|
||||
|
||||
<form @submit.prevent="onSubmit" v-if="totpTokenRequired" autocomplete="off">
|
||||
<input type="submit" style="display: none;"/>
|
||||
|
||||
<FormGroup :has-error="totpError">
|
||||
<label for="inputTotpToken">{{ $t('login.2faToken') }}</label>
|
||||
<TextInput id="inputTotpToken" v-model="totpToken" required/>
|
||||
</FormGroup>
|
||||
|
||||
<Button id="totpTokenSubmitButton" style="margin-top: 12px" type="submit" @click.prevent="onSubmit" :loading="busy">{{ $t('login.signInAction') }}</Button>
|
||||
</form>
|
||||
</div>
|
||||
</PublicPageLayout>
|
||||
</template>
|
||||
Reference in New Issue
Block a user