Needs to be done: copy link and setup window

This commit is contained in:
BinarySandia04 2024-09-29 18:05:11 +02:00
parent b04208106f
commit 546943d762
12 changed files with 154 additions and 84 deletions

View File

@ -1,6 +1,8 @@
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const crypto = require("crypto");
const CampaignSchema = new Schema({
name: {type: String, required: true},
description: {type: String},
@ -12,14 +14,7 @@ const CampaignSchema = new Schema({
});
CampaignSchema.statics.generateInvite = function() {
let possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTVWXYZ0123456789";
let cod = '';
for (let i = 0; i < 32; i++) {
cod += possible.charAt(Math.floor(Math.random() * possible.length));
}
return cod;
return crypto.randomBytes(8).toString('base64url');
}
module.exports = mongoose.model('Campaign', CampaignSchema);

View File

@ -9,6 +9,7 @@ const UserSchema = new Schema({
date: { type: Date, default: Date.now},
admin: {type: Boolean, default: false},
image: { type: String },
setupCode: { type: String },
settings: { type: Object }
});

View File

@ -11,21 +11,6 @@ const User = require("../models/User");
router.post('/register', rateLimitMiddleware, (req, res) => {
User.findOne({admin: true}).then((data) => {
if(!data) {
let {
name,
username,
email,
password
} = req.body;
if(!(name && username && email && password)){
res.json({
error: true,
msg: "params"
});
return;
}
User.findOne({username: username}).then((user) => {
if(user){
res.json({

View File

@ -7,6 +7,7 @@ const passport = require('passport');
const secret = require('../config/keys').secret;
const rateLimitMiddleware = require("../config/rate-limiter");
const { default: jwtDecode } = require('jwt-decode');
const crypto = require("crypto");
const { isAdmin } = require('../config/middleware');
@ -14,14 +15,47 @@ const User = require("../models/User");
const upload = require("../config/storage");
// Admin registers new user
router.post('/register', isAdmin, (req, res) => {
let setupCode = crypto.randomBytes(64).toString('base64url');
let user = new User({
admin: false,
name: crypto.randomBytes(16).toString('base64url'),
username: crypto.randomBytes(16).toString('base64url'),
email: crypto.randomBytes(16).toString('base64url'),
setupCode
});
user.save().then(user => {
res.json({
status: "ok",
code: setupCode,
});
}).catch({status: "err", msg: "internal"})
});
// User gets if setup account exists given the query code
router.get('/setup', (req, res) => {
User.findOne({setupCode: req.query.code}).then(user => {
if(user){
res.json({status: "ok", code: req.query.code});
}
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
router.post('/setup', rateLimitMiddleware, (req, res) => {
let {
name,
username,
email
email,
password
} = req.body;
let setupCode = req.query.code;
if(!(name && username && email)){
if(!(name && username && email && password && setupCode)){
res.json({
error: true,
msg: "params"
@ -29,39 +63,36 @@ router.post('/register', isAdmin, (req, res) => {
return;
}
User.findOne({username: username}).then((user) => {
if(user){
res.json({
error: true,
msg: "already-exists"
});
} else {
User.findOne({email: email}).then((user) => {
if(user){
User.findOne({setupCode}).then((user) => {
User.findOne({email: email}).then((sameUser) => {
if(sameUser){
res.json({
error: true,
msg: "already-email"
});
} else {
var user = new User({
name: name,
username: username,
email: email,
admin: true
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => {
if(err) throw err;
user.password = hash;
user.username = username;
user.email = email;
user.setupCode = undefined;
user.save().then(user => {
res.json({
status: "ok",
user
success: true
});
return;
}).catch((error) => { res.json({ error: true }); return; });
});
})
}
}).catch((error) => { res.json({ error: true, msg: "Hi ha hagut un error intern, prova-ho més tard" }); return; });
}
}).catch((error) => { res.json({ error: true, msg: "Hi ha hagut un error intern, prova-ho més tard" }); return; });
}).catch((error) => { res.json({ error: true, msg: "internal" }); return; });
}).catch((error) => { res.json({ error: true, msg: "internal" }); return; });
});
// Login post
router.post('/login', rateLimitMiddleware, (req, res) => {
const username = req.body.username;
const password = req.body.password;
@ -111,6 +142,7 @@ router.post('/login', rateLimitMiddleware, (req, res) => {
});
});
// Upload avatar post
router.post("/upload-avatar", upload.single("image"), passport.authenticate('jwt', {session: false}), (req, res) => {
const imageName = req.file.filename;

View File

@ -31,6 +31,7 @@ import PluginManagementWindow from '@/views/windows/settings/PluginManagementWin
import PluginWindow from '../views/windows/settings/PluginWindow.vue';
import FirstRegisterWindow from '../views/windows/FirstRegisterWindow.vue';
import RegisterUserWindow from '../views/windows/settings/RegisterUserWindow.vue';
import CopyPendingUserWindow from '../views/windows/settings/CopyPendingUserWindow.vue';
let windowMap = {
test: ExampleWindow,
@ -39,6 +40,7 @@ let windowMap = {
welcome: WelcomeWindow,
first_register: FirstRegisterWindow,
register_user: RegisterUserWindow,
copy_pending_user_window: CopyPendingUserWindow,
edit_profile: EditProfileWindow,
settings: SettingsWindow,
campaign_list: CampaignListWindow,

View File

@ -8,12 +8,14 @@ import Api from '@/services/Api'
import BigIconTemplate from '../partials/BigIconTemplate.vue';
import { SetMinSize, SetResizable } from '../../services/Windows';
import { backendUrl } from '../../services/BackendURL';
import { GetUser } from '../../services/User';
const props = defineProps(['data']);
const data = props.data;
const userIcon = ref("");
const handle = ref(null);
const isAdmin = ref(false);
let id = data.id;
console.log(data);
@ -26,6 +28,8 @@ onMounted(() => {
SetResizable(id, true);
SetMinSize(id, {width: 350, height: 280});
isAdmin.value = GetUser().admin;
Api().get('/user/retrieve-avatar?username=' + data.user.username).then((response) => {
if(response.data.image) userIcon.value = backendUrl + "public/" + response.data.image;
else userIcon.value = "public/img/def-avatar.jpg";
@ -39,7 +43,9 @@ onMounted(() => {
<WindowHandle :window="id" ref="handle"></WindowHandle>
<BigIconTemplate :title="data.user.username" :img="userIcon">
<div v-show="isAdmin">
Admin
</div>
</BigIconTemplate>
</div>
</template>

View File

@ -1,4 +1,8 @@
<script setup>
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
import { onMounted, ref, shallowRef, toRaw } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import Api from '@/services/Api'
@ -32,7 +36,17 @@ function RefreshUsers(){
let users = response.data.users;
elements.value = [];
users.forEach(user => {
console.log(user);
if(user.setupCode){
elements.value.push({
name: t('register-account.pending-account'),
_id: user._id,
info: {
name: t('register-account.pending-account')
},
user
})
} else elements.value.push({
name: user.username,
_id: user._id,
info: {
@ -51,10 +65,18 @@ async function ElementIcon(element){
}
function OpenAccount(data){
if(data.user.setupCode){
CreateChildWindow(id, 'copy_pending_user_window', {
code: data.user.setupCode,
id: 'copy_pending_user_window',
close: () => ClearWindow('copy_pending_user_window')
});
} else {
CreateChildWindow(id, 'edit_profile', {
user: toRaw(data.user),
close: () => {ClearWindow('edit_profile');}
close: () => ClearWindow('edit_profile')
});
}
}
function OpenCreateAccount(){

View File

@ -0,0 +1,42 @@
<script setup>
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
import { onMounted, ref, shallowRef, toRaw } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import WindowHandle from '@/views/partials/WindowHandle.vue';
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: 380});
ResetPosition(id, "center");
});
</script>
<template>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<h1>Hola</h1>
</div>
</template>
<style scoped>
.window-wrapper {
display: flex;
align-items: center;
}
</style>

View File

@ -32,18 +32,13 @@ let title = data.title;
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {width: 500, height: 430});
SetSize(id, {width: 400, height: 310});
ResetPosition(id, "center");
});
function register(){
Api().post('/user/register',
{
name: name.value,
username: username.value,
email: email.value,
}).then((response) => {
Api().post('/user/register').then((response) => {
const data = response.data;
console.log(data);
if(data.error){
@ -71,19 +66,6 @@ function register(){
<div class="document" v-html="t('register-account.welcome-message')">
</div>
<form v-on:submit.prevent="register">
<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">
<button class="btn-primary sound-click confirm-form-button">{{$t('general.register')}}</button>
</div>

View File

@ -37,7 +37,8 @@
},
"register-account": {
"title": "Create new user account",
"welcome-message": "<h1>Hola</h1>"
"welcome-message": "<h1>Hola</h1>",
"pending-account": "Pending account"
},
"main-menu": {
"title": "Dragonroll",

View File

@ -37,7 +37,8 @@
},
"register-account": {
"title": "Create new user account",
"welcome-message": "<p>Here you can create a new user account. The first time the user logs in will be prompted to set his password</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"
},
"main-menu": {
"title": "Dragonroll",

View File

@ -37,7 +37,8 @@
},
"register-account": {
"title": "Create new user account",
"welcome-message": "<h1>Hola</h1>"
"welcome-message": "<h1>Hola</h1>",
"pending-account": "Pending account"
},
"main-menu": {
"title": "Dragonroll",