user module + translations
This commit is contained in:
@@ -69,12 +69,7 @@ class UsersController {
|
||||
await user.update(req, req.body);
|
||||
res.json({ status: 'OK' });
|
||||
} catch (err) {
|
||||
if (err.message == 'unauthorized') {
|
||||
res.status(401).json({ status: 'error', message: 'Unauthorized' })
|
||||
} else {
|
||||
console.error(err);
|
||||
res.status(500).json({ status: 'error' })
|
||||
}
|
||||
res.json({ status: 'error', message: err.message});
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<router-view :key="$route.fullPath" />
|
||||
<v-snackbar v-model="store.snackbar.show" :color="store.snackbar.color" :timeout="store.snackbar.timeout">
|
||||
{{ store.snackbar.text }}
|
||||
<template v-slot:actions>
|
||||
<v-btn variant="text" @click="store.snackbar.show = false"> Close </v-btn>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
<template>
|
||||
<v-app-bar color="blue" scroll-behavior="elevate" scroll-threshold="20">
|
||||
<!-- <v-app-bar-nav-icon variant="text" @click.stop="drawer = !drawer"></v-app-bar-nav-icon> -->
|
||||
<v-app-bar-title>ProNature Playground</v-app-bar-title>
|
||||
<v-btn to="/manage" icon="mdi-wrench-cog-outline" v-if="roles.editor"></v-btn>
|
||||
<v-dialog max-width="400">
|
||||
<v-app-bar-title>{{ l.playground }}</v-app-bar-title>
|
||||
<v-btn to="/manage" icon="mdi-wrench-cog-outline" v-if="roles.editor" v-tooltip="l.workshop"></v-btn>
|
||||
<v-dialog max-width="480">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn icon="mdi-account" variant="text" v-bind="props"></v-btn>
|
||||
</template>
|
||||
<v-card class="pa-3" :title="user? 'Profile' : 'Sign in' ">
|
||||
<Auth v-if="!user"></Auth>
|
||||
<Profile v-else></Profile>
|
||||
</v-card>
|
||||
<template v-slot:default="{ isActive }">
|
||||
<v-card class="pa-3" :title="user? l.profile : l.signin ">
|
||||
<v-card-text>
|
||||
<Profile v-if="user"></Profile>
|
||||
<Auth v-show="!user" @login-success="isActive.value = false"></Auth>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
</v-dialog >
|
||||
</v-app-bar>
|
||||
</template>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<v-app-bar color="primary" scroll-behavior="elevate" scroll-threshold="20">
|
||||
<!-- <v-app-bar-nav-icon variant="text" @click.stop="drawer = !drawer"></v-app-bar-nav-icon> -->
|
||||
<v-app-bar-title>ProNature Games Workshop</v-app-bar-title>
|
||||
<v-btn to="/" icon="mdi-seesaw" v-tooltip="'To playground'"></v-btn>
|
||||
<v-app-bar-title>{{ l.workshop }}</v-app-bar-title>
|
||||
<v-btn to="/" icon="mdi-seesaw" v-tooltip="l.playground"></v-btn>
|
||||
<v-menu>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn icon="mdi-plus" variant="text" v-bind="props"></v-btn>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<v-form>
|
||||
<v-text-field label="Email" v-model="form.email" type="email" required></v-text-field>
|
||||
<v-text-field label="Password" v-model="form.password" type="password" required></v-text-field>
|
||||
<v-text-field :label="l.email" v-model="form.email" type="email" required></v-text-field>
|
||||
<v-text-field :label="l.password" v-model="form.password" type="password" required></v-text-field>
|
||||
<template v-if="mode==='register'">
|
||||
<v-text-field label="Confirm Password" v-model="form.passConfirm" type="password" required></v-text-field>
|
||||
<v-text-field :label="l.passwordRetype" v-model="form.passConfirm" type="password" required></v-text-field>
|
||||
<v-img :src="`/api/user/captcha?${captchaIter}`" class="my-2" height="100px"></v-img>
|
||||
<v-text-field label="Enter Captcha" v-model="form.captcha" required></v-text-field>
|
||||
<v-text-field :label="l.confirmCaptcha" v-model="form.captcha" required></v-text-field>
|
||||
</template>
|
||||
<v-btn @click="login" :color="mode==='login' ? 'green' : 'grey'">Sign in</v-btn>
|
||||
<v-btn @click="register" :color="mode==='register' ? 'green' : 'grey'" class="float-right">Sign up</v-btn>
|
||||
<v-btn @click="login" :color="mode==='login' ? 'green' : 'grey'">{{l.signin}}</v-btn>
|
||||
<v-btn @click="register" :color="mode==='register' ? 'green' : 'grey'" class="float-right">{{l.signup}}</v-btn>
|
||||
</v-form>
|
||||
</template>
|
||||
|
||||
@@ -30,8 +30,13 @@ export default {
|
||||
// Implement login logic here
|
||||
if (this.mode == 'login') {
|
||||
// Perform login
|
||||
await this.$api.user.signin(this.form);
|
||||
await this.loadUser();
|
||||
let response = await this.$api.user.signin(this.form);
|
||||
if(response.data?.status === 'OK') {
|
||||
await this.loadUser();
|
||||
this.$emit('login-success');
|
||||
} else {
|
||||
this.toast(this.getErrorText(response.data), 'red');
|
||||
}
|
||||
} else {
|
||||
this.mode = 'login';
|
||||
}
|
||||
@@ -39,8 +44,13 @@ export default {
|
||||
async register() {
|
||||
if (this.mode == 'register') {
|
||||
// Implement registration logic here
|
||||
await this.$api.user.signup(this.form);
|
||||
await this.loadUser();
|
||||
let response = await this.$api.user.signup(this.form);
|
||||
if(response.data?.status === 'OK') {
|
||||
this.toast(this.l.signupSuccess, 'green');
|
||||
await this.loadUser();
|
||||
} else {
|
||||
this.toast(this.getErrorText(response.data), 'red');
|
||||
}
|
||||
} else {
|
||||
this.mode = 'register';
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<template>
|
||||
<v-form>
|
||||
<v-text-field label="Email" disabled v-model="user.email" type="email" required></v-text-field>
|
||||
<v-text-field label="Change Password" v-model="form.password" type="password" required></v-text-field>
|
||||
<v-text-field label="Confirm Password" v-model="form.passConfirm" type="password" required></v-text-field>
|
||||
<v-btn @click="update" color="green">Update Profile</v-btn>
|
||||
<v-btn @click="signout" color="grey" class="float-right">Sign out</v-btn>
|
||||
<v-text-field :label="l.email" disabled v-model="user.email" type="email" required></v-text-field>
|
||||
<v-text-field :label="l.passwordChange" v-model="form.password" type="password" required></v-text-field>
|
||||
<v-text-field :label="l.passwordRetype" v-model="form.passConfirm" type="password" required></v-text-field>
|
||||
<v-btn @click="update" color="green">{{ l.update }}</v-btn>
|
||||
<v-btn @click="signout" color="grey" class="float-right">{{ l.signout }}</v-btn>
|
||||
</v-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -24,7 +25,12 @@ export default {
|
||||
await this.loadUser();
|
||||
},
|
||||
async update() {
|
||||
await this.$api.user.update({...this.form, _id: this.user._id});
|
||||
let response = await this.$api.user.update({...this.form, _id: this.user._id});
|
||||
if(response.data.status === 'OK') {
|
||||
this.toast('Profile updated successfully', 'green');
|
||||
} else {
|
||||
this.toast(this.getErrorText(response.data), 'red');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useAppStore } from '@/stores/app';
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
store: null
|
||||
store: null,
|
||||
}
|
||||
},
|
||||
created(){
|
||||
@@ -32,5 +32,25 @@ export default {
|
||||
this.user = response.data.user;
|
||||
return this.user;
|
||||
},
|
||||
getErrorText(error){
|
||||
let msg = error?.response?.data?.error || error?.message;
|
||||
if (msg){
|
||||
if (typeof msg == 'object'){
|
||||
return JSON.stringify(msg);
|
||||
}else if (this.l.errors[msg]) {
|
||||
return this.l.errors[msg]
|
||||
}else {
|
||||
return msg;
|
||||
}
|
||||
}else{
|
||||
return error;
|
||||
}
|
||||
},
|
||||
toast(text, color, timeout=3000){
|
||||
this.store.snackbar.text = text;
|
||||
this.store.snackbar.color = color;
|
||||
this.store.snackbar.timeout = timeout;
|
||||
this.store.snackbar.show = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+104
-2
@@ -1,6 +1,8 @@
|
||||
const lang = {
|
||||
en: {
|
||||
_code: 'en',
|
||||
playground: 'ProNature Playground',
|
||||
workshop: 'ProNature Workshop',
|
||||
createGameObject: 'Add game object',
|
||||
editGameObject: 'Edit game object',
|
||||
createGame: 'Add game',
|
||||
@@ -38,10 +40,61 @@ const lang = {
|
||||
editScenario: 'Edit scenario',
|
||||
editScenes: 'Edit scenes',
|
||||
addScene: 'Add scene',
|
||||
addTask: 'Add task'
|
||||
addTask: 'Add task',
|
||||
date: 'Date modified',
|
||||
update: 'Update',
|
||||
signin: 'Sign in',
|
||||
signup: 'Sign up',
|
||||
signupSuccess: 'Successful sign-up',
|
||||
profile: 'Profile',
|
||||
'reset-password': 'Reset password',
|
||||
'change-password': 'Change password',
|
||||
signout: 'Sign out',
|
||||
faq: 'Help',
|
||||
email:'E-mail',
|
||||
passwordChange: 'Change password',
|
||||
password:'Password',
|
||||
passwordRetype: 'Password (confirm)',
|
||||
passwordCurrent: 'Your current password',
|
||||
passwordForgotten: 'Forgotten password',
|
||||
recoveryMailSent: 'Password reset mail was sent. Please check your e-mail.',
|
||||
confirmCaptcha: 'Enter the text you see',
|
||||
'validate-email': 'E-mail validation',
|
||||
emailValidated: 'Your e-mail address was successfully validated.',
|
||||
validationMailContent: v1 => `Activation link: <a href="${v1}">${v1}</a>`,
|
||||
validationMailSent: 'Activation link was sent.',
|
||||
forgottenPassMailContent: v1 => `Recover your account by following this link: <a href="${v1}">${v1}</a>`,
|
||||
emailNotValidated: 'This email is not validated',
|
||||
resendValidationMail: 'Resend verification e-mail',
|
||||
displayName:'Display Name',
|
||||
firstName:'First Name',
|
||||
lastName:'Last Name',
|
||||
errors:{
|
||||
unauthorized: 'Unauthorized',
|
||||
notFound: 'Object not found',
|
||||
noReadPermissions: 'You don\'t have access to this content',
|
||||
noEditPermissions:'Missing edit permissions',
|
||||
noCreatePermissions:'Missing create permissions',
|
||||
noDeletePermissions:'Missing delete permissions',
|
||||
noPermissions: 'No permissions',
|
||||
ftsUnavailable: 'Full text search service is not available',
|
||||
systemReadOnly: 'Request rejected. The system is in read-only mode.',
|
||||
invalidEmail: 'Invalid email',
|
||||
emailExists: 'This email is already registered',
|
||||
invalidPassword: 'Invalid password',
|
||||
invalidUsername: 'Invalid username',
|
||||
passwordMismatch: 'Password mismatch',
|
||||
invalidCaptcha: 'Invalid captcha',
|
||||
invalidValidationLink: 'Invalid/inactive validation link',
|
||||
activationLinkExpired: 'Activation link has expired',
|
||||
invalidActivationLink: 'Invalid activation link',
|
||||
objectUpdateCollision: 'Save failed. Object was altered by another user. Please refresh the page.'
|
||||
},
|
||||
},
|
||||
bg: {
|
||||
_code: 'bg',
|
||||
playground: 'ProNature игрище',
|
||||
workshop: 'ProNature работилница',
|
||||
createGameObject: 'Добавяне на игрови обект',
|
||||
editGameObject: 'Редактиране на игрови обект',
|
||||
createGame: 'Добавяне на игра',
|
||||
@@ -79,7 +132,56 @@ const lang = {
|
||||
editScenario: 'Редактиране на сценарий',
|
||||
editScenes: 'Редактиране на сцени',
|
||||
addScene: 'Добавяне на сцена',
|
||||
addTask: 'Добавяне на задача'
|
||||
addTask: 'Добавяне на задача',
|
||||
date: 'Промяна',
|
||||
update: 'Обнови',
|
||||
signin: 'Вход',
|
||||
signup: 'Регистрация',
|
||||
signupSuccess: 'Успешна регистрация',
|
||||
profile: 'Профил',
|
||||
'reset-password': 'Възстановяване на парола',
|
||||
'change-password': 'Промяна на парола',
|
||||
signout: 'Изход',
|
||||
faq: 'Помощ',
|
||||
email:'Имейл',
|
||||
passwordChange: 'Смяна на парола',
|
||||
password:'Парола',
|
||||
passwordRetype:'Парола (отново)',
|
||||
passwordCurrent: 'Текуща парола',
|
||||
passwordForgotten: 'Забравена парола',
|
||||
recoveryMailSent: 'На посочения от Вас адрес е изпратен мейл за възстановяване на парола',
|
||||
confirmCaptcha: 'Въведете текста от картинката',
|
||||
'validate-email': 'Валидиране на имейл',
|
||||
emailValidated: 'Вашият имейл е валидиран.',
|
||||
validationMailContent: v1 => `Линк за активиране: <a href="${v1}">${v1}</a>`,
|
||||
validationMailSent: 'На посочената поща е изпратен линк за активиране',
|
||||
forgottenPassMailContent: v1 => `Линк за възстановяване на парола: <a href="${v1}">${v1}</a>`,
|
||||
emailNotValidated: 'Този имейл не е валидиран',
|
||||
resendValidationMail: 'Повторно изпращане на имейл за верификация',
|
||||
displayName:'Псевдоним',
|
||||
firstName:'Име',
|
||||
lastName:'Фамилия',
|
||||
errors:{
|
||||
unauthorized: 'Отказан достъп',
|
||||
notFound: 'Обектът не е намерен',
|
||||
noReadPermissions: 'Нямате достъп до това съдържание',
|
||||
noEditPermissions:'Нямате права за редакция на този обект',
|
||||
noCreatePermissions:'Нямате права за създаване на обект',
|
||||
noDeletePermissions:'Нямате права за изтриване на този обект',
|
||||
noPermissions: 'Нямате права',
|
||||
ftsUnavailable: 'Услугата за пълнотекстово търсене не е налична',
|
||||
systemReadOnly: 'Записът е отказан. Системата работи в read-only режим.',
|
||||
invalidEmail: 'Невалиден имейл',
|
||||
emailExists: 'Този имейл вече е регистриран',
|
||||
invalidPassword: 'Грешна парола',
|
||||
invalidUsername: 'Грешно потребителско име',
|
||||
passwordMismatch: 'Паролите не съвпадат',
|
||||
invalidCaptcha: 'Невалиден текст от картинката',
|
||||
invalidValidationLink: 'Невалиден линк за валидация',
|
||||
activationLinkExpired: 'Изтекъл линк за активация',
|
||||
invalidActivationLink: 'Невалиден линк за активация',
|
||||
objectUpdateCollision: 'Неуспешен запис. Обектът е бил редактиран от друг потребител. Моля опресенете страницата.'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -9,10 +9,17 @@ prefs = reactive(prefs ? JSON.parse(prefs) : {
|
||||
}
|
||||
})
|
||||
|
||||
let snackbar = reactive({
|
||||
show: false,
|
||||
text: '',
|
||||
color: 'info',
|
||||
timeout: 3000,
|
||||
})
|
||||
|
||||
watch(prefs, (newPrefs) => {
|
||||
localStorage.setItem('prefs', JSON.stringify(newPrefs))
|
||||
}, { deep: true })
|
||||
|
||||
export const useAppStore = defineStore('app', {
|
||||
state: () => ({ prefs }),
|
||||
state: () => ({ prefs, snackbar }),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user