Refactor password update functionality
This commit is contained in:
parent
e6381d30c4
commit
e4dc910865
|
@ -39,18 +39,18 @@ async function getUserDN(username: string): Promise<string> {
|
||||||
|
|
||||||
export async function updatePassword({
|
export async function updatePassword({
|
||||||
username,
|
username,
|
||||||
password,
|
currentPassword,
|
||||||
newPassword
|
newPassword
|
||||||
}: {
|
}: {
|
||||||
username: string
|
username: string
|
||||||
password: string
|
currentPassword: string
|
||||||
newPassword: string
|
newPassword: string
|
||||||
}): Promise<'SUCCESS' | 'FAIL'> {
|
}): Promise<'SUCCESS' | 'FAIL'> {
|
||||||
try {
|
try {
|
||||||
const userDN = await getUserDN(username)
|
const userDN = await getUserDN(username)
|
||||||
|
|
||||||
// Check if user can bind with current password
|
// Check if user can bind with current password
|
||||||
await ldapClient.bind(userDN, password)
|
await ldapClient.bind(userDN, currentPassword)
|
||||||
await ldapClient.unbind()
|
await ldapClient.unbind()
|
||||||
|
|
||||||
// Bind with admin user to change password
|
// Bind with admin user to change password
|
||||||
|
@ -68,7 +68,7 @@ export async function updatePassword({
|
||||||
// operation: 'delete',
|
// operation: 'delete',
|
||||||
// modification: new Attribute({
|
// modification: new Attribute({
|
||||||
// type: 'unicodePwd',
|
// type: 'unicodePwd',
|
||||||
// values: [encodePassword(password)]
|
// values: [encodePassword(currentPassword)]
|
||||||
// })
|
// })
|
||||||
// }),
|
// }),
|
||||||
|
|
||||||
|
|
|
@ -16,15 +16,16 @@ export const appRouter = router({
|
||||||
updatePassword: input(
|
updatePassword: input(
|
||||||
z.object({
|
z.object({
|
||||||
username: z.string(),
|
username: z.string(),
|
||||||
password: z.string(),
|
currentPassword: z.string(),
|
||||||
newPassword: z.string().min(8)
|
newPassword: z.string().min(8)
|
||||||
})
|
})
|
||||||
).mutation(async ({ input }) => {
|
).mutation(async ({ input }) => {
|
||||||
const { username, password, newPassword } = input
|
const { username, currentPassword, newPassword } = input
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updatePassword({
|
await updatePassword({
|
||||||
username,
|
username,
|
||||||
password,
|
currentPassword,
|
||||||
newPassword
|
newPassword
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<v-form @submit.prevent="submit">
|
<v-form ref="form" @submit.prevent="submit" validate-on="input">
|
||||||
<v-card :elevation="2">
|
<v-card :elevation="2" :loading="loading" :disabled="loading">
|
||||||
<v-card-title class="mb-6 pa-6 text-center">
|
<v-card-title class="mb-6 pa-6 text-center">
|
||||||
<span class="headline font-weight-light text-h4">Trocar senha</span>
|
<span class="headline font-weight-light text-h4">Trocar senha</span>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
autocomplete="username"
|
autocomplete="username"
|
||||||
hint="SIAPE para servidores, CPF para alunos."
|
hint="SIAPE para servidores, CPF para alunos."
|
||||||
prepend-inner-icon="mdi-account"
|
prepend-inner-icon="mdi-account"
|
||||||
:rules="[v => !!v || 'Campo obrigatório']"
|
:rules="[v => !!v || 'O usuário é obrigatório']"
|
||||||
required
|
required
|
||||||
density="compact"
|
density="compact"
|
||||||
/>
|
/>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
prepend-inner-icon="mdi-form-textbox-password"
|
prepend-inner-icon="mdi-form-textbox-password"
|
||||||
:append-inner-icon="showCurrent ? 'mdi-eye' : 'mdi-eye-off'"
|
:append-inner-icon="showCurrent ? 'mdi-eye' : 'mdi-eye-off'"
|
||||||
@click:append-inner="showCurrent = !showCurrent"
|
@click:append-inner="showCurrent = !showCurrent"
|
||||||
:rules="[v => !!v || 'Campo obrigatório']"
|
:rules="[v => !!v || 'A senha atual é obrigatória']"
|
||||||
required
|
required
|
||||||
density="compact"
|
density="compact"
|
||||||
/>
|
/>
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
prepend-inner-icon="mdi-lock-check"
|
prepend-inner-icon="mdi-lock-check"
|
||||||
:append-inner-icon="showNew ? 'mdi-eye' : 'mdi-eye-off'"
|
:append-inner-icon="showNew ? 'mdi-eye' : 'mdi-eye-off'"
|
||||||
@click:append-inner="showNew = !showNew"
|
@click:append-inner="showNew = !showNew"
|
||||||
:rules="[v => !!v || 'Campo obrigatório']"
|
:rules="newPasswordRules"
|
||||||
required
|
required
|
||||||
density="compact"
|
density="compact"
|
||||||
/>
|
/>
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
:append-inner-icon="showConfirm ? 'mdi-eye' : 'mdi-eye-off'"
|
:append-inner-icon="showConfirm ? 'mdi-eye' : 'mdi-eye-off'"
|
||||||
@click:append-inner="showConfirm = !showConfirm"
|
@click:append-inner="showConfirm = !showConfirm"
|
||||||
:rules="[
|
:rules="[
|
||||||
v => !!v || 'Campo obrigatório',
|
v => !!v || 'A confirmação da senha é obrigatória',
|
||||||
v => v === newPassword || 'As senhas não coincidem'
|
v => v === newPassword || 'As senhas não coincidem'
|
||||||
]"
|
]"
|
||||||
required
|
required
|
||||||
|
@ -66,19 +66,31 @@
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-btn type="submit" color="primary">Trocar senha</v-btn>
|
<v-btn
|
||||||
|
type="submit"
|
||||||
|
color="primary"
|
||||||
|
variant="flat"
|
||||||
|
size="large"
|
||||||
|
:disabled="!valid || loading"
|
||||||
|
>
|
||||||
|
Trocar senha
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-form>
|
</v-form>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import PasswordChecker from './PasswordChecker.vue'
|
import PasswordChecker from './PasswordChecker.vue'
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
submit: [{ username: string; currentPassword: string; newPassword: string }]
|
submit: [{ username: string; currentPassword: string; newPassword: string }]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
loading: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
const username = ref('')
|
const username = ref('')
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
const newPassword = ref('')
|
const newPassword = ref('')
|
||||||
|
@ -88,7 +100,28 @@ const showCurrent = ref(false)
|
||||||
const showNew = ref(false)
|
const showNew = ref(false)
|
||||||
const showConfirm = ref(false)
|
const showConfirm = ref(false)
|
||||||
|
|
||||||
const submit = () => {
|
// use form refs to validate
|
||||||
|
const form = ref<HTMLFormElement | null>(null)
|
||||||
|
|
||||||
|
const valid = computed(() => {
|
||||||
|
return form.value?.isValid || false
|
||||||
|
})
|
||||||
|
|
||||||
|
const newPasswordRules = [
|
||||||
|
(v: string) => !!v || 'A nova senha é obrigatória',
|
||||||
|
(v: string) =>
|
||||||
|
/[a-z]/.test(v) || 'A nova senha deve ter pelo menos uma letra minúscula',
|
||||||
|
(v: string) =>
|
||||||
|
/[A-Z]/.test(v) || 'A nova senha deve ter pelo menos uma letra maiúscula',
|
||||||
|
(v: string) =>
|
||||||
|
v.length >= 8 || 'A nova senha deve ter pelo menos 8 caracteres',
|
||||||
|
(v: string) =>
|
||||||
|
/[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]/.test(v) ||
|
||||||
|
'A nova senha deve ter pelo menos um caractere especial'
|
||||||
|
]
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
|
if (await form.value?.validate())
|
||||||
emit('submit', {
|
emit('submit', {
|
||||||
username: username.value,
|
username: username.value,
|
||||||
currentPassword: password.value,
|
currentPassword: password.value,
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<div class="font-weight-light mb-2">Regras para a nova senha:</div>
|
||||||
<v-alert
|
<v-alert
|
||||||
v-for="alert in alerts"
|
v-for="alert in alerts"
|
||||||
:key="alert.text"
|
:key="alert.text"
|
||||||
:type="alertType(password, alert.rule)"
|
:type="alertType(password, alert.rule)"
|
||||||
class="mb-1"
|
class="mb-2 rule"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
density="compact"
|
density="compact"
|
||||||
>
|
:text="alert.text"
|
||||||
{{ alert.text }}
|
/>
|
||||||
</v-alert>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -44,3 +44,9 @@ const alerts = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.rule {
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<v-container>
|
<v-container>
|
||||||
<v-row>
|
<v-row justify="center">
|
||||||
<v-col cols="8" offset="2">
|
<v-col xl="5" lg="6" md="7" sm="10">
|
||||||
<logo class="mx-auto my-3" :style="{ maxWidth: '128px' }" />
|
<logo class="mx-auto my-3" :style="{ maxWidth: '128px' }" />
|
||||||
<main-form @submit="submit" />
|
<main-form @submit="handleSubmit" :loading="loading" />
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
import Logo from '../components/Logo.vue'
|
import Logo from '../components/Logo.vue'
|
||||||
import MainForm from '../components/MainForm.vue'
|
import MainForm from '../components/MainForm.vue'
|
||||||
|
import { trpc } from '../trpc'
|
||||||
|
|
||||||
function submit({
|
const loading = ref(false)
|
||||||
|
|
||||||
|
async function handleSubmit({
|
||||||
username,
|
username,
|
||||||
currentPassword,
|
currentPassword,
|
||||||
newPassword
|
newPassword
|
||||||
|
@ -22,6 +26,19 @@ function submit({
|
||||||
currentPassword: string
|
currentPassword: string
|
||||||
newPassword: string
|
newPassword: string
|
||||||
}) {
|
}) {
|
||||||
console.log('submit', { username, currentPassword, newPassword })
|
try {
|
||||||
|
loading.value = true
|
||||||
|
await trpc.updatePassword.mutate({
|
||||||
|
username,
|
||||||
|
currentPassword,
|
||||||
|
newPassword
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user