Add username-based login + mandatory first-time admin setup; push-ready
- User id/login = username (was email). Email is a separate settable field. - Default admin: username admin / password 1234, must_setup=True. - Login forces /setup on first login: set email + change password, then clears must_setup. - New /api/auth/setup endpoint; JWT sub = username; admin routes use username. - Frontend: Login uses username, router guard forces /setup, new Setup.vue (email + new password + confirm), i18n EN/TH. - Tests: test_setup.py added; all suites adapted (m0/m1/routes/security/setup/e2e) PASS.
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
<div class="card login-card">
|
||||
<h1>🎯 {{ i18n.t('app') }}</h1>
|
||||
<p class="muted" style="margin-top:-8px">Sales training simulator</p>
|
||||
<label>{{ i18n.t('email') }}</label>
|
||||
<input v-model="email" type="email" autocomplete="username" @keyup.enter="submit" />
|
||||
<label>{{ i18n.t('username') }}</label>
|
||||
<input v-model="username" type="text" autocomplete="username" @keyup.enter="submit" />
|
||||
<label>{{ i18n.t('password') }}</label>
|
||||
<div class="pw-wrap">
|
||||
<input v-model="password" :type="showPw ? 'text' : 'password'" autocomplete="current-password" @keyup.enter="submit" />
|
||||
@@ -13,7 +13,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="error" role="alert" v-if="error">{{ error }}</div>
|
||||
<button class="primary" style="width:100%;margin-top:16px" :disabled="loading || !email || !password" @click="submit">
|
||||
<button class="primary" style="width:100%;margin-top:16px" :disabled="loading || !username || !password" @click="submit">
|
||||
<span v-if="loading" class="spinner"></span>
|
||||
<span v-else>{{ i18n.t('login') }}</span>
|
||||
</button>
|
||||
@@ -29,7 +29,7 @@ import { i18n } from '../i18n'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const email = ref('')
|
||||
const username = ref('')
|
||||
const password = ref('')
|
||||
const showPw = ref(false)
|
||||
const error = ref('')
|
||||
@@ -39,8 +39,13 @@ async function submit() {
|
||||
error.value = ''
|
||||
loading.value = true
|
||||
try {
|
||||
await auth.login(email.value, password.value)
|
||||
router.push(route.query.redirect || '/')
|
||||
await auth.login(username.value.trim(), password.value)
|
||||
// First-time admin setup is mandatory before using the app.
|
||||
if (auth.mustSetup) {
|
||||
router.push({ path: '/setup' })
|
||||
} else {
|
||||
router.push(route.query.redirect || '/')
|
||||
}
|
||||
} catch (e) {
|
||||
error.value = i18n.t('loginError')
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user