Account creation now works

This commit is contained in:
BinarySandia04 2024-09-30 15:28:04 +02:00
parent 546943d762
commit 0b4b0fefb2
11 changed files with 288 additions and 124 deletions

View File

@ -36,13 +36,14 @@ router.post('/register', isAdmin, (req, res) => {
}); });
// User gets if setup account exists given the query code // User gets if setup account exists given the query code
router.get('/setup', (req, res) => { router.get('/verify-setup', (req, res) => {
User.findOne({setupCode: req.query.code}).then(user => { User.findOne({setupCode: req.query.code}).then(user => {
if(user){ if(user){
res.json({status: "ok", code: req.query.code}); res.json({status: "ok", code: req.query.code});
} else {
res.json({status: "err", msg: "not-exists"})
} }
res.json({status: "err", msg: "not-exists"}); });
}).catch(res.json({status: "err", msg: "internal"}));
}); });
// User posts the parameters of his new account given by admin // User posts the parameters of his new account given by admin
@ -72,7 +73,7 @@ router.post('/setup', rateLimitMiddleware, (req, res) => {
}); });
} else { } else {
bcrypt.genSalt(10, (err, salt) => { bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => { bcrypt.hash(password, salt, (err, hash) => {
if(err) throw err; if(err) throw err;
user.password = hash; user.password = hash;
user.username = username; user.username = username;

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,112 +1,12 @@
<script setup>
import { onMounted } from 'vue'
import { RouterLink, RouterView } from 'vue-router'
import { GetUser, HasAdmin, UserStatus, LoadUser } from '@/services/User.js'
import { IsAdmin } from './services/User'
import useEmitter from '@/services/Emitter';
const emitter = useEmitter();
import { DisplayToast, SetEmitter } from './services/Dragonroll'
import { CreateWindow } from './services/Windows';
import { FetchResources } from './services/Resources';
import { ImportModule } from './services/Modules';
import { FetchPlugins } from './services/Plugins';
LoadUser();
SetEmitter(emitter);
async function start(){
if(GetUser()){
CreateWindow('main_menu');
// DisplayToast('green', 'Logged in successfully as ' + GetUser().username + '!', 3000)
} else {
if(await HasAdmin()){
CreateWindow('login');
} else {
CreateWindow('register');
}
}
await FetchResources();
await FetchPlugins();
await ImportModule('dnd-5e')
DisplayToast('aqua', 'All plugins loaded successfully');
}
onMounted(() => {
start();
})
</script>
<template> <template>
<div class="wrapper" id="container"> <div class="wrapper" id="container">
<RouterView /> <RouterView />
</div> </div>
</template> </template>
<style scoped> <style scoped>
.web-title {
font-size: 22px;
font-weight: bolder;
padding-bottom: 12px;
color: var(--color-heading)
}
.sidebar-link {
font-weight: bold;
}
.sidebar-separator {
margin-top: 10px;
margin-left: 8px;
margin-bottom: 10px;
}
.top-nav {
display: flex;
width: 100%;
flex-direction: column;
}
a {
width: 100%;
}
.sidebar {
flex-grow: 0;
flex-shrink: 0;
position: sticky;
top: 0;
display: flex;
max-height: 100vh;
min-height: 100vh;
overflow-y: auto;
background-color: var(--color-background-soft);
}
.wrapper { .wrapper {
flex-grow: 1; flex-grow: 1;
flex-shrink: 0; flex-shrink: 0;
} }
@media (min-width: 1024px) {
.sidebar {
min-width: 240px;
padding: 16px;
height: 100%;
}
}
</style> </style>

View File

@ -8,10 +8,10 @@ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [ routes: [
{path: '/', name: 'home', component: HomeView}, {path: '/', name: 'home', component: HomeView},
{path: '/setup/:setupCode', redirect: to => {
{path: '/:pathMatch(.*)*', name: "NotFound", component: NotFoundView }, return {path: '/', query: {setupCode: to.params.setupCode}}
}},
{path: '/:pathMatch(.*)*', redirect: {name: 'home'} },
] ]
}) })

View File

@ -32,6 +32,7 @@ import PluginWindow from '../views/windows/settings/PluginWindow.vue';
import FirstRegisterWindow from '../views/windows/FirstRegisterWindow.vue'; import FirstRegisterWindow from '../views/windows/FirstRegisterWindow.vue';
import RegisterUserWindow from '../views/windows/settings/RegisterUserWindow.vue'; import RegisterUserWindow from '../views/windows/settings/RegisterUserWindow.vue';
import CopyPendingUserWindow from '../views/windows/settings/CopyPendingUserWindow.vue'; import CopyPendingUserWindow from '../views/windows/settings/CopyPendingUserWindow.vue';
import SetupAccountWindow from '../views/windows/SetupAccountWindow.vue';
let windowMap = { let windowMap = {
test: ExampleWindow, test: ExampleWindow,
@ -41,6 +42,7 @@ let windowMap = {
first_register: FirstRegisterWindow, first_register: FirstRegisterWindow,
register_user: RegisterUserWindow, register_user: RegisterUserWindow,
copy_pending_user_window: CopyPendingUserWindow, copy_pending_user_window: CopyPendingUserWindow,
setup_account: SetupAccountWindow,
edit_profile: EditProfileWindow, edit_profile: EditProfileWindow,
settings: SettingsWindow, settings: SettingsWindow,
campaign_list: CampaignListWindow, campaign_list: CampaignListWindow,

View File

@ -1,18 +1,80 @@
<script setup> <script setup>
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
import { onMounted } from 'vue'; import { onMounted } from 'vue';
import { RouterLink, RouterView } from 'vue-router'
import WindowManager from '@/views/managers/WindowManager.vue' import WindowManager from '@/views/managers/WindowManager.vue'
import { GetUser } from '@/services/User'
import Api from '@/services/Api'
import { CreateWindow } from '@/services/Windows' import { CreateWindow } from '@/services/Windows'
import Toast from './partials/Toast.vue'; import { GetUser, HasAdmin, LoadUser } from '@/services/User.js'
import { DisplayToast, SetEmitter } from '../services/Dragonroll'; import { DisplayToast, SetEmitter } from '@/services/Dragonroll';
import GameManager from './managers/GameManager.vue'; import { FetchResources } from '@/services/Resources';
import TooltipManager from './managers/TooltipManager.vue'; import { ImportModule } from '@/services/Modules';
import ContextMenuManager from './managers/ContextMenuManager.vue'; import { FetchPlugins } from '@/services/Plugins';
import useEmitter from '@/services/Emitter';
const emitter = useEmitter();
import Toast from '@/views/partials/Toast.vue';
import GameManager from '@/views/managers/GameManager.vue';
import TooltipManager from '@/views/managers/TooltipManager.vue';
import ContextMenuManager from '@/views/managers/ContextMenuManager.vue';
import { useRoute } from 'vue-router'
LoadUser();
SetEmitter(emitter);
async function DisplayFirstWindow(){
if(GetUser()){
CreateWindow('main_menu');
return;
}
// Check if we have a link
if(route.query.setupCode){
// Let's try to activate it
Api().get('/user/verify-setup?code=' + route.query.setupCode).then(res => {
if(res.data.code){
// Yep exists
CreateWindow('setup_account', {
title: "register-account.setup.title",
id: 'setup_account',
setupCode: res.data.code,
})
return;
}
DisplayToast("red", t('register-account.setup.invalid-link'));
CreateWindow('login');
});
} else {
if(await HasAdmin()){
CreateWindow('login');
} else {
CreateWindow('register');
}
}
}
async function start(){
DisplayFirstWindow();
await FetchResources();
await FetchPlugins();
await ImportModule('dnd-5e')
DisplayToast('aqua', 'All plugins loaded successfully');
}
onMounted(() => {
start();
})
const route = useRoute()
</script> </script>
<template> <template>

View File

@ -0,0 +1,149 @@
<script setup>
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
import ErrorMessage from '@/views/others/ErrorMessage.vue'
import WindowHandle from '@/views/partials/WindowHandle.vue';
import { onMounted, ref } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import Api from '@/services/Api.js'
import { ClearWindow, CreateWindow } from '@/services/Windows';
import { DisplayToast } from '@/services/Dragonroll';
const email = ref("");
const name = ref("");
const username = ref("");
const password = ref("");
const confirmPassword = ref("");
const errorMessage = ref("");
const handle = ref(null);
const props = defineProps(['data']);
const data = props.data;
let id = data.id;
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {width: 500, height: 620});
ResetPosition(id, "center");
});
function setup(){
if(password.value != confirmPassword.value){
errorMessage.value = t('general.password-mismatch');
return;
}
Api().post('/user/setup?code=' + data.setupCode,
{
name: name.value,
username: username.value,
email: email.value,
password: password.value,
}).then((response) => {
const data = response.data;
if(data.error){
console.log(data);
errorMessage.value = data.msg;
} else {
errorMessage.value = "";
console.log("Logged successfully");
DisplayToast('green', 'Account setup successfull, now log in!', 3000);
ClearWindow(id);
CreateWindow('login');
}
}).catch((error) => {
console.log(error);
});
}
</script>
<template>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<div class="window-content">
<div class="document" v-html="t('register-account.setup.welcome-message')">
</div>
<form v-on:submit.prevent="setup">
<div class="form-field">
<label for="name">{{$t('general.name')}}</label>
<input id="name-field" type="text" :placeholder="t('placeholders.name')" name="name" v-model="name" autocomplete="off" >
</div>
<div class="form-field">
<label for="email">{{$t('general.email')}}</label>
<input id="email-field" type="email" :placeholder="t('placeholders.email')" name="email" v-model="email" autocomplete="off" >
</div>
<div class="form-field">
<label for="username">{{$t('general.username')}}</label>
<input id="username-field" type="text" :placeholder="t('placeholders.username')" name="username" v-model="username" autocomplete="off" >
</div>
<div class="form-field">
<label for="password">{{$t('general.password')}}</label>
<input id="password-field" type="password" :placeholder="t('placeholders.password')" name="password" v-model="password" autocomplete="off" >
</div>
<div class="form-field">
<label for="confirm-password">{{$t('general.password-confirm')}}</label>
<input id="confirm-password-field" type="password" :placeholder="t('placeholders.password-confirm')" name="confirm-password" v-model="confirmPassword" autocomplete="off" >
</div>
<div class="form-field">
<button class="btn-primary sound-click confirm-form-button">{{$t('register-account.setup.confirm')}}</button>
</div>
</form>
<ErrorMessage v-if="errorMessage">{{ errorMessage }}</ErrorMessage>
</div>
<!-- <VersionRender></VersionRender> -->
</div>
</template>
<style scoped>
p {
user-select: none;
}
.window-wrapper {
display: flex;
align-items: center;
}
.window-content {
flex-direction: column;
display: flex;
align-items: center;
padding-bottom: 50px;
width: 100%;
padding: 20px;
}
.splash-image {
width: 450px;
user-select: none;
}
form {
width: 100%;
}
label {
text-align: left;
}
</style>

View File

@ -6,6 +6,7 @@ import { onMounted, ref, shallowRef, toRaw } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows'; import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import WindowHandle from '@/views/partials/WindowHandle.vue'; import WindowHandle from '@/views/partials/WindowHandle.vue';
import { DisplayToast } from '../../../services/Dragonroll';
const handle = ref(null); const handle = ref(null);
@ -16,18 +17,26 @@ let id = data.id;
onMounted(() => { onMounted(() => {
SetupHandle(id, handle); SetupHandle(id, handle);
SetSize(id, {width: 500, height: 380}); SetSize(id, {width: 300, height: 170});
ResetPosition(id, "center"); ResetPosition(id, "center");
}); });
function CopyLink(){
let root = location.protocol + '//' + location.host;
navigator.clipboard.writeText(`${root}/setup/${data.code}`)
DisplayToast('aqua', t('settings.pending-account.copy-success'));
}
</script> </script>
<template> <template>
<div class="window-wrapper" :id="'window-wrapper-' + id"> <div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle> <WindowHandle :window="id" ref="handle"></WindowHandle>
<div class="document centered">
<h1>Hola</h1> <h1>{{$t('settings.pending-account.title')}}</h1>
<p>{{$t('settings.pending-account.content')}}</p>
</div>
<button v-on:click.prevent="CopyLink">{{$t('settings.pending-account.copy-link')}}</button>
</div> </div>
</template> </template>

View File

@ -12,6 +12,7 @@
"username": "Username", "username": "Username",
"password": "Password", "password": "Password",
"password-confirm": "Confirm your password", "password-confirm": "Confirm your password",
"password-mismatch": "Password mismatch",
"register": "Register", "register": "Register",
"quantity": "Quantity", "quantity": "Quantity",
"weight": "Weight", "weight": "Weight",
@ -38,7 +39,14 @@
"register-account": { "register-account": {
"title": "Create new user account", "title": "Create new user account",
"welcome-message": "<h1>Hola</h1>", "welcome-message": "<h1>Hola</h1>",
"pending-account": "Pending account" "pending-account": "Pending account",
"setup": {
"title": "Setup Account",
"invalid-link": "Invalid setup code link",
"welcome-message": "<p>Here you can create a new user account.</p><br><p>Once you have registered a new account, you will recieve a link that you must give to the owner of the new account. From there, the owner will be able to setup his new account</p><hr>",
"confirm": "Setup Account"
},
"invalid-link": "Invalid setup code link"
}, },
"main-menu": { "main-menu": {
"title": "Dragonroll", "title": "Dragonroll",
@ -65,6 +73,12 @@
"manage-plugins-button": "Manage plugins", "manage-plugins-button": "Manage plugins",
"manage-accounts": "Manage site accounts", "manage-accounts": "Manage site accounts",
"manage-plugins": "Manage plugins" "manage-plugins": "Manage plugins"
},
"pending-account": {
"title": "Pending account",
"content": "This account is pending for confirmation",
"copy-link": "Copy link",
"copy-success": "Copied account setup link successfully!"
} }
}, },
"campaigns": { "campaigns": {

View File

@ -12,6 +12,7 @@
"username": "Username", "username": "Username",
"password": "Password", "password": "Password",
"password-confirm": "Confirm your password", "password-confirm": "Confirm your password",
"password-mismatch": "Password mismatch",
"register": "Register", "register": "Register",
"quantity": "Quantity", "quantity": "Quantity",
"weight": "Weight", "weight": "Weight",
@ -38,7 +39,13 @@
"register-account": { "register-account": {
"title": "Create new user account", "title": "Create new user account",
"welcome-message": "<p>Here you can create a new user account.</p><br><p>Once you have registered a new account, you will recieve a link that you must give to the owner of the new account. From there, the owner will be able to setup his new account</p><hr>", "welcome-message": "<p>Here you can create a new user account.</p><br><p>Once you have registered a new account, you will recieve a link that you must give to the owner of the new account. From there, the owner will be able to setup his new account</p><hr>",
"pending-account": "Pending account" "pending-account": "Pending account",
"setup": {
"title": "Setup Account",
"invalid-link": "Invalid setup code link",
"welcome-message": "<h1>Welcome!</h1><b>You have been invited to a Dragonroll server!</b><p>Create your account by filling the following fields:</p><hr>",
"confirm": "Setup Account"
}
}, },
"main-menu": { "main-menu": {
"title": "Dragonroll", "title": "Dragonroll",
@ -68,6 +75,12 @@
"manage-plugins": { "manage-plugins": {
"title": "Manage Plugins" "title": "Manage Plugins"
} }
},
"pending-account": {
"title": "Pending account",
"content": "This account is pending for confirmation",
"copy-link": "Copy link",
"copy-success": "Copied account setup link successfully!"
} }
}, },
"campaigns": { "campaigns": {

View File

@ -12,6 +12,7 @@
"username": "Nombre de usuario", "username": "Nombre de usuario",
"password": "Contraseña", "password": "Contraseña",
"password-confirm": "Confirma tu contraseña", "password-confirm": "Confirma tu contraseña",
"password-mismatch": "Password mismatch",
"register": "Registrar-se", "register": "Registrar-se",
"quantity": "Quantity", "quantity": "Quantity",
"weight": "Weight", "weight": "Weight",
@ -26,7 +27,7 @@
}, },
"placeholders": { "placeholders": {
"name": "John Doe", "name": "John Doe",
"email": "john@doe.com", "email": "john{'@'}doe.com",
"username": "Introduce tu nombre de usuario...", "username": "Introduce tu nombre de usuario...",
"password": "Introduce tu contraseña...", "password": "Introduce tu contraseña...",
"password-confirm": "Vuelve a introducir tu contraseña..." "password-confirm": "Vuelve a introducir tu contraseña..."
@ -38,7 +39,14 @@
"register-account": { "register-account": {
"title": "Create new user account", "title": "Create new user account",
"welcome-message": "<h1>Hola</h1>", "welcome-message": "<h1>Hola</h1>",
"pending-account": "Pending account" "pending-account": "Pending account",
"setup": {
"title": "Setup Account",
"invalid-link": "Invalid setup code link",
"welcome-message": "<h1>Welcome!</h1><b>You have been invited to a Dragonroll server!</b><p>Create your account by filling the following fields:</p><hr>",
"confirm": "Setup Account"
},
"invalid-link": "Invalid setup code link"
}, },
"main-menu": { "main-menu": {
"title": "Dragonroll", "title": "Dragonroll",
@ -65,6 +73,12 @@
"manage-plugins-button": "Manage plugins", "manage-plugins-button": "Manage plugins",
"manage-accounts": "Manage site accounts", "manage-accounts": "Manage site accounts",
"manage-plugins": "Manage plugins" "manage-plugins": "Manage plugins"
},
"pending-account": {
"title": "Pending account",
"content": "This account is pending for confirmation",
"copy-link": "Copy link",
"copy-success": "Copied account setup link successfully!"
} }
}, },
"campaigns": { "campaigns": {