Needs to be done: copy link and setup window
This commit is contained in:
parent
b04208106f
commit
546943d762
@ -1,6 +1,8 @@
|
|||||||
const mongoose = require("mongoose");
|
const mongoose = require("mongoose");
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const crypto = require("crypto");
|
||||||
|
|
||||||
const CampaignSchema = new Schema({
|
const CampaignSchema = new Schema({
|
||||||
name: {type: String, required: true},
|
name: {type: String, required: true},
|
||||||
description: {type: String},
|
description: {type: String},
|
||||||
@ -12,14 +14,7 @@ const CampaignSchema = new Schema({
|
|||||||
});
|
});
|
||||||
|
|
||||||
CampaignSchema.statics.generateInvite = function() {
|
CampaignSchema.statics.generateInvite = function() {
|
||||||
let possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTVWXYZ0123456789";
|
return crypto.randomBytes(8).toString('base64url');
|
||||||
let cod = '';
|
|
||||||
|
|
||||||
for (let i = 0; i < 32; i++) {
|
|
||||||
cod += possible.charAt(Math.floor(Math.random() * possible.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
return cod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = mongoose.model('Campaign', CampaignSchema);
|
module.exports = mongoose.model('Campaign', CampaignSchema);
|
@ -9,6 +9,7 @@ const UserSchema = new Schema({
|
|||||||
date: { type: Date, default: Date.now},
|
date: { type: Date, default: Date.now},
|
||||||
admin: {type: Boolean, default: false},
|
admin: {type: Boolean, default: false},
|
||||||
image: { type: String },
|
image: { type: String },
|
||||||
|
setupCode: { type: String },
|
||||||
settings: { type: Object }
|
settings: { type: Object }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,21 +11,6 @@ const User = require("../models/User");
|
|||||||
router.post('/register', rateLimitMiddleware, (req, res) => {
|
router.post('/register', rateLimitMiddleware, (req, res) => {
|
||||||
User.findOne({admin: true}).then((data) => {
|
User.findOne({admin: true}).then((data) => {
|
||||||
if(!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) => {
|
User.findOne({username: username}).then((user) => {
|
||||||
if(user){
|
if(user){
|
||||||
res.json({
|
res.json({
|
||||||
|
@ -7,6 +7,7 @@ const passport = require('passport');
|
|||||||
const secret = require('../config/keys').secret;
|
const secret = require('../config/keys').secret;
|
||||||
const rateLimitMiddleware = require("../config/rate-limiter");
|
const rateLimitMiddleware = require("../config/rate-limiter");
|
||||||
const { default: jwtDecode } = require('jwt-decode');
|
const { default: jwtDecode } = require('jwt-decode');
|
||||||
|
const crypto = require("crypto");
|
||||||
|
|
||||||
const { isAdmin } = require('../config/middleware');
|
const { isAdmin } = require('../config/middleware');
|
||||||
|
|
||||||
@ -14,14 +15,47 @@ const User = require("../models/User");
|
|||||||
|
|
||||||
const upload = require("../config/storage");
|
const upload = require("../config/storage");
|
||||||
|
|
||||||
|
// Admin registers new user
|
||||||
router.post('/register', isAdmin, (req, res) => {
|
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 {
|
let {
|
||||||
name,
|
name,
|
||||||
username,
|
username,
|
||||||
email
|
email,
|
||||||
|
password
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
let setupCode = req.query.code;
|
||||||
|
|
||||||
if(!(name && username && email)){
|
if(!(name && username && email && password && setupCode)){
|
||||||
res.json({
|
res.json({
|
||||||
error: true,
|
error: true,
|
||||||
msg: "params"
|
msg: "params"
|
||||||
@ -29,39 +63,36 @@ router.post('/register', isAdmin, (req, res) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
User.findOne({username: username}).then((user) => {
|
User.findOne({setupCode}).then((user) => {
|
||||||
if(user){
|
User.findOne({email: email}).then((sameUser) => {
|
||||||
res.json({
|
if(sameUser){
|
||||||
error: true,
|
res.json({
|
||||||
msg: "already-exists"
|
error: true,
|
||||||
});
|
msg: "already-email"
|
||||||
} else {
|
});
|
||||||
User.findOne({email: email}).then((user) => {
|
} else {
|
||||||
if(user){
|
bcrypt.genSalt(10, (err, salt) => {
|
||||||
res.json({
|
bcrypt.hash(user.password, salt, (err, hash) => {
|
||||||
error: true,
|
if(err) throw err;
|
||||||
msg: "already-email"
|
user.password = hash;
|
||||||
});
|
user.username = username;
|
||||||
} else {
|
user.email = email;
|
||||||
var user = new User({
|
user.setupCode = undefined;
|
||||||
name: name,
|
|
||||||
username: username,
|
|
||||||
email: email,
|
|
||||||
admin: true
|
|
||||||
});
|
|
||||||
|
|
||||||
user.save().then(user => {
|
user.save().then(user => {
|
||||||
res.json({
|
res.json({
|
||||||
status: "ok",
|
success: true
|
||||||
user
|
});
|
||||||
});
|
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) => {
|
router.post('/login', rateLimitMiddleware, (req, res) => {
|
||||||
const username = req.body.username;
|
const username = req.body.username;
|
||||||
const password = req.body.password;
|
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) => {
|
router.post("/upload-avatar", upload.single("image"), passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||||
const imageName = req.file.filename;
|
const imageName = req.file.filename;
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import PluginManagementWindow from '@/views/windows/settings/PluginManagementWin
|
|||||||
import PluginWindow from '../views/windows/settings/PluginWindow.vue';
|
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';
|
||||||
|
|
||||||
let windowMap = {
|
let windowMap = {
|
||||||
test: ExampleWindow,
|
test: ExampleWindow,
|
||||||
@ -39,6 +40,7 @@ let windowMap = {
|
|||||||
welcome: WelcomeWindow,
|
welcome: WelcomeWindow,
|
||||||
first_register: FirstRegisterWindow,
|
first_register: FirstRegisterWindow,
|
||||||
register_user: RegisterUserWindow,
|
register_user: RegisterUserWindow,
|
||||||
|
copy_pending_user_window: CopyPendingUserWindow,
|
||||||
edit_profile: EditProfileWindow,
|
edit_profile: EditProfileWindow,
|
||||||
settings: SettingsWindow,
|
settings: SettingsWindow,
|
||||||
campaign_list: CampaignListWindow,
|
campaign_list: CampaignListWindow,
|
||||||
|
@ -8,12 +8,14 @@ import Api from '@/services/Api'
|
|||||||
import BigIconTemplate from '../partials/BigIconTemplate.vue';
|
import BigIconTemplate from '../partials/BigIconTemplate.vue';
|
||||||
import { SetMinSize, SetResizable } from '../../services/Windows';
|
import { SetMinSize, SetResizable } from '../../services/Windows';
|
||||||
import { backendUrl } from '../../services/BackendURL';
|
import { backendUrl } from '../../services/BackendURL';
|
||||||
|
import { GetUser } from '../../services/User';
|
||||||
|
|
||||||
const props = defineProps(['data']);
|
const props = defineProps(['data']);
|
||||||
const data = props.data;
|
const data = props.data;
|
||||||
const userIcon = ref("");
|
const userIcon = ref("");
|
||||||
|
|
||||||
const handle = ref(null);
|
const handle = ref(null);
|
||||||
|
const isAdmin = ref(false);
|
||||||
|
|
||||||
let id = data.id;
|
let id = data.id;
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -26,6 +28,8 @@ onMounted(() => {
|
|||||||
SetResizable(id, true);
|
SetResizable(id, true);
|
||||||
SetMinSize(id, {width: 350, height: 280});
|
SetMinSize(id, {width: 350, height: 280});
|
||||||
|
|
||||||
|
isAdmin.value = GetUser().admin;
|
||||||
|
|
||||||
Api().get('/user/retrieve-avatar?username=' + data.user.username).then((response) => {
|
Api().get('/user/retrieve-avatar?username=' + data.user.username).then((response) => {
|
||||||
if(response.data.image) userIcon.value = backendUrl + "public/" + response.data.image;
|
if(response.data.image) userIcon.value = backendUrl + "public/" + response.data.image;
|
||||||
else userIcon.value = "public/img/def-avatar.jpg";
|
else userIcon.value = "public/img/def-avatar.jpg";
|
||||||
@ -39,7 +43,9 @@ onMounted(() => {
|
|||||||
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||||
|
|
||||||
<BigIconTemplate :title="data.user.username" :img="userIcon">
|
<BigIconTemplate :title="data.user.username" :img="userIcon">
|
||||||
|
<div v-show="isAdmin">
|
||||||
|
Admin
|
||||||
|
</div>
|
||||||
</BigIconTemplate>
|
</BigIconTemplate>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
|
||||||
import { onMounted, ref, shallowRef, toRaw } from 'vue';
|
import { onMounted, ref, shallowRef, toRaw } from 'vue';
|
||||||
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
|
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
|
||||||
import Api from '@/services/Api'
|
import Api from '@/services/Api'
|
||||||
@ -32,7 +36,17 @@ function RefreshUsers(){
|
|||||||
let users = response.data.users;
|
let users = response.data.users;
|
||||||
elements.value = [];
|
elements.value = [];
|
||||||
users.forEach(user => {
|
users.forEach(user => {
|
||||||
elements.value.push({
|
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,
|
name: user.username,
|
||||||
_id: user._id,
|
_id: user._id,
|
||||||
info: {
|
info: {
|
||||||
@ -51,10 +65,18 @@ async function ElementIcon(element){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function OpenAccount(data){
|
function OpenAccount(data){
|
||||||
CreateChildWindow(id, 'edit_profile', {
|
if(data.user.setupCode){
|
||||||
user: toRaw(data.user),
|
CreateChildWindow(id, 'copy_pending_user_window', {
|
||||||
close: () => {ClearWindow('edit_profile');}
|
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')
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function OpenCreateAccount(){
|
function OpenCreateAccount(){
|
||||||
|
42
client/src/views/windows/settings/CopyPendingUserWindow.vue
Normal file
42
client/src/views/windows/settings/CopyPendingUserWindow.vue
Normal 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>
|
||||||
|
|
||||||
|
|
@ -32,18 +32,13 @@ let title = data.title;
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
SetupHandle(id, handle);
|
SetupHandle(id, handle);
|
||||||
SetSize(id, {width: 500, height: 430});
|
SetSize(id, {width: 400, height: 310});
|
||||||
ResetPosition(id, "center");
|
ResetPosition(id, "center");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function register(){
|
function register(){
|
||||||
Api().post('/user/register',
|
Api().post('/user/register').then((response) => {
|
||||||
{
|
|
||||||
name: name.value,
|
|
||||||
username: username.value,
|
|
||||||
email: email.value,
|
|
||||||
}).then((response) => {
|
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
console.log(data);
|
console.log(data);
|
||||||
if(data.error){
|
if(data.error){
|
||||||
@ -71,19 +66,6 @@ function register(){
|
|||||||
<div class="document" v-html="t('register-account.welcome-message')">
|
<div class="document" v-html="t('register-account.welcome-message')">
|
||||||
</div>
|
</div>
|
||||||
<form v-on:submit.prevent="register">
|
<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">
|
<div class="form-field">
|
||||||
<button class="btn-primary sound-click confirm-form-button">{{$t('general.register')}}</button>
|
<button class="btn-primary sound-click confirm-form-button">{{$t('general.register')}}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,7 +37,8 @@
|
|||||||
},
|
},
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"main-menu": {
|
"main-menu": {
|
||||||
"title": "Dragonroll",
|
"title": "Dragonroll",
|
||||||
|
@ -37,7 +37,8 @@
|
|||||||
},
|
},
|
||||||
"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. 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": {
|
"main-menu": {
|
||||||
"title": "Dragonroll",
|
"title": "Dragonroll",
|
||||||
|
@ -37,7 +37,8 @@
|
|||||||
},
|
},
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"main-menu": {
|
"main-menu": {
|
||||||
"title": "Dragonroll",
|
"title": "Dragonroll",
|
||||||
|
Loading…
Reference in New Issue
Block a user