Add reset password function and display current user on the page.
This commit is contained in:
@@ -39,6 +39,14 @@
|
||||
"copied": "Copied",
|
||||
"delete": "Delete",
|
||||
"signOut": "Sign out",
|
||||
"resetPassword": "Reset password",
|
||||
"submit": "Submit",
|
||||
"agree": "Agree",
|
||||
"newPassword": "New password",
|
||||
"currentPassword": "Current password",
|
||||
"confirmPassword": "Confirm password",
|
||||
"yourPasswordHasBeenReset": "Your password has been reset",
|
||||
"nowYouNeedToSignInAgain": "Now you need to sign in again",
|
||||
"webSearch": "Web Search",
|
||||
"webSearchDefaultPrompt": "Web search results:\n\n[web_results]\nCurrent date: [current_date]\n\nInstructions: Using the provided web search results, write a comprehensive reply to the given query. Make sure to cite results using [[number](URL)] notation after the reference. If the provided search results refer to multiple subjects with the same name, write separate answers for each subject.\nQuery: [query]",
|
||||
"genTitlePrompt": "Generate a short title for the following content, no more than 10 words. \n\nContent: ",
|
||||
|
||||
@@ -39,6 +39,14 @@
|
||||
"copied": "Скопировано",
|
||||
"delete": "Удалить",
|
||||
"signOut": "Выход",
|
||||
"resetPassword": "Сбросить пароль",
|
||||
"submit": "Отправить",
|
||||
"agree": "Согласен",
|
||||
"newPassword": "Новый пароль",
|
||||
"currentPassword": "Текущий пароль",
|
||||
"confirmPassword": "Подтвердите пароль",
|
||||
"yourPasswordHasBeenReset": "Ваш пароль был сброшен",
|
||||
"nowYouNeedToSignInAgain": "Теперь вам нужно снова войти в систему",
|
||||
"webSearch": "Поиск в интернете",
|
||||
"webSearchDefaultPrompt": "Результаты веб-поиска:\n\n[web_results]\nТекущая дата: [current_date]\n\nИнструкции: Используя предоставленные результаты веб-поиска, напишите развернутый ответ на заданный запрос. Обязательно цитируйте результаты, используя обозначение [[number](URL)] после ссылки. Если предоставленные результаты поиска относятся к нескольким темам с одинаковым названием, напишите отдельные ответы для каждой темы.\nЗапрос: [query]",
|
||||
"genTitlePrompt": "Придумайте короткий заголовок для следующего содержания, не более 10 слов. \n\nСодержание: ",
|
||||
|
||||
@@ -39,6 +39,14 @@
|
||||
"copied": "已复制",
|
||||
"delete": "删除",
|
||||
"signOut": "退出登录",
|
||||
"resetPassword": "重置密码",
|
||||
"submit": "提交",
|
||||
"agree": "同意",
|
||||
"newPassword": "新密码",
|
||||
"currentPassword": "当前密码",
|
||||
"confirmPassword": "确认密码",
|
||||
"yourPasswordHasBeenReset": "您的密码已重置",
|
||||
"nowYouNeedToSignInAgain": "现在您需要再次登录",
|
||||
"webSearch": "网页搜索",
|
||||
"webSearchDefaultPrompt": "网络搜索结果:\n\n[web_results]\n当前日期:[current_date]\n\n说明:使用提供的网络搜索结果,对给定的查询写出全面的回复。确保在引用参考文献后使用 [[number](URL)] 符号进行引用结果. 如果提供的搜索结果涉及到多个具有相同名称的主题,请针对每个主题编写单独的答案。\n查询:[query]",
|
||||
"genTitlePrompt": "为以下内容生成一个不超过10个字的简短标题。 \n\n内容: ",
|
||||
|
||||
@@ -124,19 +124,48 @@ onMounted(async () => {
|
||||
:permanent="drawerPermanent"
|
||||
width="300"
|
||||
>
|
||||
<div class="px-2 py-2">
|
||||
<template
|
||||
v-slot:prepend
|
||||
>
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-btn
|
||||
block
|
||||
variant="outlined"
|
||||
prepend-icon="add"
|
||||
class="text-none"
|
||||
@click="createNewConversation"
|
||||
>
|
||||
{{ $t('newConversation') }}
|
||||
</v-btn>
|
||||
<v-list-item
|
||||
prepend-icon="face"
|
||||
:title="$auth.user.username"
|
||||
:subtitle="$auth.user.email"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-menu>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn
|
||||
v-bind="props"
|
||||
size="small"
|
||||
variant="text"
|
||||
icon="expand_more"
|
||||
></v-btn>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item
|
||||
:title="$t('resetPassword')"
|
||||
to="/account/resetPassword"
|
||||
>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
:title="$t('signOut')"
|
||||
@click="signOut"
|
||||
>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<v-divider></v-divider>
|
||||
</template>
|
||||
|
||||
<div class="px-2">
|
||||
<v-list>
|
||||
<v-list-item v-show="loadingConversations">
|
||||
<v-list-item-title class="d-flex justify-center">
|
||||
<v-progress-circular indeterminate></v-progress-circular>
|
||||
@@ -287,24 +316,17 @@ onMounted(async () => {
|
||||
@click="feedback"
|
||||
></v-list-item>
|
||||
|
||||
<v-list-item
|
||||
rounded="xl"
|
||||
prepend-icon="logout"
|
||||
:title="$t('signOut')"
|
||||
@click="signOut"
|
||||
></v-list-item>
|
||||
|
||||
</v-list>
|
||||
</div>
|
||||
</template>
|
||||
</v-navigation-drawer>
|
||||
|
||||
<v-app-bar
|
||||
class="d-md-none"
|
||||
class=""
|
||||
>
|
||||
<v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>
|
||||
|
||||
<v-toolbar-title>{{ runtimeConfig.public.appName }}</v-toolbar-title>
|
||||
<v-toolbar-title>{{ currentConversation.topic ?? runtimeConfig.public.appName }}</v-toolbar-title>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
@@ -312,7 +334,15 @@ onMounted(async () => {
|
||||
:title="$t('newConversation')"
|
||||
icon="add"
|
||||
@click="createNewConversation()"
|
||||
class="d-md-none"
|
||||
></v-btn>
|
||||
<v-btn
|
||||
variant="outlined"
|
||||
class="text-none d-none d-md-block"
|
||||
@click="createNewConversation"
|
||||
>
|
||||
{{ $t('newConversation') }}
|
||||
</v-btn>
|
||||
|
||||
</v-app-bar>
|
||||
|
||||
|
||||
176
pages/account/resetPassword.vue
Normal file
176
pages/account/resetPassword.vue
Normal file
@@ -0,0 +1,176 @@
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
middleware: ["auth"]
|
||||
})
|
||||
const formData = ref({
|
||||
old_password: '',
|
||||
new_password1: '',
|
||||
new_password2: ''
|
||||
})
|
||||
const formRules = ref({
|
||||
old_password: [
|
||||
v => !!v || 'Current password is required'
|
||||
],
|
||||
new_password1: [
|
||||
v => !!v || 'New password is required'
|
||||
],
|
||||
new_password2: [
|
||||
v => !!v || 'Confirm password is required',
|
||||
v => v === formData.value.new_password1 || 'Passwords do not match'
|
||||
]
|
||||
})
|
||||
const fieldErrors = ref({
|
||||
old_password: '',
|
||||
new_password1: '',
|
||||
new_password2: '',
|
||||
})
|
||||
const { $auth } = useNuxtApp()
|
||||
const errorMsg = ref(null)
|
||||
const resetForm = ref(null)
|
||||
const valid = ref(true)
|
||||
const submitting = ref(false)
|
||||
const route = useRoute()
|
||||
const passwordInputType = ref('password')
|
||||
|
||||
const signOut = async () => {
|
||||
const { data, error } = await useFetch('/api/account/logout/', {
|
||||
method: 'POST'
|
||||
})
|
||||
if (!error.value) {
|
||||
await $auth.logout()
|
||||
}
|
||||
}
|
||||
|
||||
const submit = async () => {
|
||||
errorMsg.value = null
|
||||
const { valid } = await resetForm.value.validate()
|
||||
if (valid) {
|
||||
submitting.value = true
|
||||
const { data, error } = await useFetch('/api/account/password/change/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(formData.value)
|
||||
})
|
||||
submitting.value = false
|
||||
if (error.value) {
|
||||
if (error.value.status === 400) {
|
||||
for (const key in formData.value) {
|
||||
if (error.value.data[key]) {
|
||||
fieldErrors.value[key] = error.value.data[key][0]
|
||||
}
|
||||
}
|
||||
if (error.value.data.non_field_errors) {
|
||||
errorMsg.value = error.value.data.non_field_errors[0]
|
||||
}
|
||||
} else {
|
||||
if (error.value.data.detail) {
|
||||
errorMsg.value = error.value.data.detail
|
||||
} else {
|
||||
errorMsg.value = 'Something went wrong. Please try again.'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
successDialog.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleFieldUpdate = (field) => {
|
||||
fieldErrors.value[field] = ''
|
||||
}
|
||||
|
||||
const successDialog = ref(false)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card
|
||||
style="height: 100vh"
|
||||
>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col
|
||||
sm="9"
|
||||
offset-sm="1"
|
||||
md="6"
|
||||
offset-md="3"
|
||||
>
|
||||
<v-card
|
||||
class="mt-15"
|
||||
elevation="0"
|
||||
>
|
||||
<div class="text-center text-h4">{{ $t('resetPassword') }}</div>
|
||||
<v-card-text>
|
||||
<v-form ref="resetForm">
|
||||
<v-text-field
|
||||
v-model="formData.old_password"
|
||||
:rules="formRules.old_password"
|
||||
:error-messages="fieldErrors.old_password"
|
||||
@update:modelValue="handleFieldUpdate('old_password')"
|
||||
:label="$t('currentPassword')"
|
||||
variant="underlined"
|
||||
clearable
|
||||
></v-text-field>
|
||||
<v-text-field
|
||||
v-model="formData.new_password1"
|
||||
:rules="formRules.new_password1"
|
||||
:error-messages="fieldErrors.new_password1"
|
||||
@update:modelValue="handleFieldUpdate('new_password1')"
|
||||
:label="$t('newPassword')"
|
||||
variant="underlined"
|
||||
clearable
|
||||
></v-text-field>
|
||||
<v-text-field
|
||||
v-model="formData.new_password2"
|
||||
:rules="formRules.new_password2"
|
||||
:error-messages="fieldErrors.new_password2"
|
||||
@update:modelValue="handleFieldUpdate('new_password2')"
|
||||
:label="$t('confirmPassword')"
|
||||
variant="underlined"
|
||||
clearable
|
||||
></v-text-field>
|
||||
</v-form>
|
||||
|
||||
<div v-if="errorMsg" class="text-red">{{ errorMsg }}</div>
|
||||
|
||||
<div
|
||||
class="mt-5 d-flex justify-space-between"
|
||||
>
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
:loading="submitting"
|
||||
@click="submit"
|
||||
size="large"
|
||||
>{{ $t('submit') }}</v-btn>
|
||||
</div>
|
||||
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card>
|
||||
|
||||
<v-dialog
|
||||
v-model="successDialog"
|
||||
persistent
|
||||
width="auto"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="text-h5">
|
||||
{{ $t('yourPasswordHasBeenReset') }}
|
||||
</v-card-title>
|
||||
<v-card-text>{{ $t('nowYouNeedToSignInAgain') }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
color="green-darken-1"
|
||||
variant="text"
|
||||
@click="signOut"
|
||||
>
|
||||
{{ $t('agree') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
@@ -83,7 +83,7 @@ const submit = async () => {
|
||||
}
|
||||
|
||||
const handleFieldUpdate = (field) => {
|
||||
// fieldErrors.value[field] = ''
|
||||
fieldErrors.value[field] = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -122,7 +122,7 @@ const handleFieldUpdate = (field) => {
|
||||
:error-messages="fieldErrors.email"
|
||||
label="Email"
|
||||
variant="underlined"
|
||||
@@update:modelValue="handleFieldUpdate('email')"
|
||||
@update:modelValue="handleFieldUpdate('email')"
|
||||
clearable
|
||||
></v-text-field>
|
||||
|
||||
|
||||
@@ -7,25 +7,33 @@ definePageMeta({
|
||||
const route = useRoute()
|
||||
const currentConversation = useConversation()
|
||||
const conversation = ref(getDefaultConversationData())
|
||||
watchEffect(() => {
|
||||
if (!route.params.id) {
|
||||
conversation.value = getDefaultConversationData()
|
||||
|
||||
const loadConversation = async () => {
|
||||
const { data, error } = await useAuthFetch('/api/chat/conversations/' + route.params.id)
|
||||
if (!error.value) {
|
||||
conversation.value = data.value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const loadMessage = async () => {
|
||||
conversation.value.loadingMessages = true
|
||||
const { data, error } = await useAuthFetch('/api/chat/messages/?conversationId=' + route.params.id)
|
||||
if (!error.value) {
|
||||
conversation.value.messages = data.value
|
||||
}
|
||||
conversation.value.loadingMessages = false
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
onActivated(async () => {
|
||||
console.log('activated')
|
||||
console.log(conversation.value)
|
||||
if (route.params.id) {
|
||||
conversation.value.id = parseInt(route.params.id)
|
||||
conversation.value.loadingMessages = true
|
||||
await loadConversation()
|
||||
await loadMessage()
|
||||
conversation.value.loadingMessages = false
|
||||
} else {
|
||||
conversation.value = getDefaultConversationData()
|
||||
}
|
||||
console.log(conversation.value)
|
||||
currentConversation.value = Object.assign({}, conversation.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user