Compare commits
4 Commits
651f870415
...
1cf5b5a089
Author | SHA1 | Date | |
---|---|---|---|
1cf5b5a089 | |||
dd6d7fc552 | |||
dcb50849aa | |||
be62b85c52 |
4
index.js
4
index.js
@ -9,7 +9,7 @@ loadDatabase();
|
||||
const submitEvent = new EventEmitter();
|
||||
await launchWeb(submitEvent);
|
||||
|
||||
submitEvent.on("call", async (call) => {
|
||||
submitEvent.on("contacts/call", async (call) => {
|
||||
let vote;
|
||||
if (call.vote) {
|
||||
console.log(`${call.phone} va voter`);
|
||||
@ -23,7 +23,7 @@ submitEvent.on("call", async (call) => {
|
||||
{ where: { phone: call.phone } },
|
||||
);
|
||||
});
|
||||
submitEvent.on("add", (request) => {
|
||||
submitEvent.on("contacts/add", (request) => {
|
||||
console.log(request);
|
||||
});
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
export default {
|
||||
path: "/api/contacts/add",
|
||||
requiresLogin: true,
|
||||
type: "post",
|
||||
async execute(request, response) {
|
||||
global.events.submitEvent.emit("add", request.body);
|
||||
},
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { permissionBits } from '../../../../utils/permissions.js';
|
||||
|
||||
export default {
|
||||
path: "/api/contacts/call",
|
||||
requiresLogin: true,
|
||||
permissions: permissionBits.CALL,
|
||||
type: "post",
|
||||
async execute(request, response) {
|
||||
global.events.submitEvent.emit("call", request.body);
|
||||
response.redirect("/calls");
|
||||
},
|
||||
}
|
22
src/html/pages/api/contacts.js
Normal file
22
src/html/pages/api/contacts.js
Normal file
@ -0,0 +1,22 @@
|
||||
import { permissionBits } from "../../../../utils/permissions.js";
|
||||
|
||||
export default {
|
||||
path: "/api/contacts(/*)?",
|
||||
requiresLogin: true,
|
||||
permissions: permissionBits.CALL,
|
||||
type: "post",
|
||||
async execute(request, response) {
|
||||
const phone = request.originalUrl.split("/")[3];
|
||||
const operation = request.originalUrl.split("/")[4];
|
||||
switch(operation) {
|
||||
case 'call':
|
||||
global.events.submitEvent.emit("contacts/call", request.body);
|
||||
response.redirect("/calls");
|
||||
break
|
||||
case 'add':
|
||||
global.events.submitEvent.emit("contacts/add", request.body);
|
||||
//response.redirect("/");
|
||||
break
|
||||
}
|
||||
},
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
import { permissionBits } from "../../../../utils/permissions.js";
|
||||
|
||||
export default {
|
||||
path: "/api/users(/*)?",
|
||||
requiresLogin: true,
|
||||
permissions: permissionBits.ADMIN,
|
||||
type: "post",
|
||||
async execute(request, response) {
|
||||
const username = request.originalUrl.split("/")[3];
|
||||
const operation = request.originalUrl.split("/")[4];
|
||||
const args = request.body;
|
||||
switch (operation) {
|
||||
case "create":
|
||||
if (
|
||||
await global.database.users.findOne({
|
||||
where: { username: username },
|
||||
})
|
||||
) return response.redirect("/dashboard/users/create?error=User already exists");
|
||||
console.log(`Creating user ${username}`);
|
||||
|
||||
let permissions = Number(args.permissions);
|
||||
if (isNaN(permissions)) {
|
||||
permissions = 0;
|
||||
for (const permissionBit of args.permissions) {
|
||||
permissions += Number(permissionBit);
|
||||
}
|
||||
}
|
||||
if(!(permissions & permissionBits.DEFAULT)) permissions ^= permissionBits.DEFAULT;
|
||||
await global.database.users.create({
|
||||
username: username,
|
||||
password: args.password,
|
||||
permissions: permissions,
|
||||
});
|
||||
break;
|
||||
case "delete":
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
19
src/html/pages/api/users_get.js
Normal file
19
src/html/pages/api/users_get.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { permissionBits } from "../../../../utils/permissions.js";
|
||||
|
||||
export default {
|
||||
path: "/api/users/:username",
|
||||
requiresLogin: true,
|
||||
permissions: permissionBits.ADMIN,
|
||||
type: "get",
|
||||
async execute(request, response) {
|
||||
const { username } = request.params;
|
||||
const user = await global.database.users.findOne({
|
||||
where: { username: username },
|
||||
});
|
||||
if(!user || user == 0) return response.status(404).send({ message: "User does not exist" });
|
||||
response.send({
|
||||
username: user.username,
|
||||
permissions: user.permissions,
|
||||
});
|
||||
},
|
||||
};
|
32
src/html/pages/api/users_post.js
Normal file
32
src/html/pages/api/users_post.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { permissionBits } from "../../../../utils/permissions.js";
|
||||
|
||||
export default {
|
||||
path: "/api/users/:username",
|
||||
requiresLogin: true,
|
||||
permissions: permissionBits.ADMIN,
|
||||
type: "post",
|
||||
async execute(request, response) {
|
||||
const { username } = request.params;
|
||||
let { permissions, password } = request.body;
|
||||
if (
|
||||
await global.database.users.findOne({
|
||||
where: { username: username },
|
||||
})
|
||||
) return response.status(412).send({ message: "User already exists" });
|
||||
|
||||
if (!(permissions & permissionBits.DEFAULT))
|
||||
permissions ^= permissionBits.DEFAULT;
|
||||
|
||||
const userParams = {
|
||||
username: username,
|
||||
password: password,
|
||||
permissions: permissions,
|
||||
}
|
||||
console.log(`Creating user ${username}`);
|
||||
await global.database.users.create(userParams);
|
||||
response.status(201).send({
|
||||
username: username,
|
||||
permissions: permissions,
|
||||
});
|
||||
},
|
||||
};
|
@ -1,4 +1,6 @@
|
||||
import { permissionBits } from '../../../../utils/permissions.js';
|
||||
import { readFile } from 'fs/promises';
|
||||
import { navbar } from '../../../../utils/navbar.js';
|
||||
|
||||
export default {
|
||||
path: "/dashboard/users",
|
||||
@ -6,6 +8,9 @@ export default {
|
||||
permissions: permissionBits.ADMIN,
|
||||
type: "get",
|
||||
async execute(request, response) {
|
||||
response.redirect("/dashboard/users/list");
|
||||
const html = await readFile(`${process.env.WWW}/dashboard/users/index.html`);
|
||||
return await response.send(html.toString()
|
||||
.replace('<NAVBAR>', navbar(request.session))
|
||||
);
|
||||
},
|
||||
}
|
||||
|
44
src/html/pages/dashboard/users_list.js
Normal file
44
src/html/pages/dashboard/users_list.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { navbar } from '../../../../utils/navbar.js';
|
||||
import { readFile } from 'fs/promises';
|
||||
import { permissionBits, checkPermissions } from '../../../../utils/permissions.js';
|
||||
|
||||
export default {
|
||||
path: "/dashboard/users/list",
|
||||
requiresLogin: true,
|
||||
permissions: permissionBits.ADMIN,
|
||||
type: "get",
|
||||
async execute(request, response) {
|
||||
const userList = await global.database.users.findAll();
|
||||
const userTable = genUserTable(userList);
|
||||
const html = await readFile(`${process.env.WWW}/dashboard/users/list.html`);
|
||||
return await response.send(html.toString()
|
||||
.replace('<NAVBAR>', navbar(request.session))
|
||||
.replace('<USERTABLE>', userTable)
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
function genUserTable(users) {
|
||||
let res = `
|
||||
<table>
|
||||
<tr>
|
||||
<th>Identifiant</th>
|
||||
<th>Permissions</th>
|
||||
<th>Action</th>
|
||||
</tr>`;
|
||||
for(const user of users) {
|
||||
const userPermDict = checkPermissions(user.permissions);
|
||||
let userPerms = [];
|
||||
for (const [key, value] of Object.entries(userPermDict)) {
|
||||
if(value && key != "default") userPerms.push(key);
|
||||
};
|
||||
res += `
|
||||
<tr>
|
||||
<td><a href='./${user.username}'>${user.username}</a></td>
|
||||
<td>${userPerms.join(", ")}</td>
|
||||
<!--<td><button>Supprimer</button></td>-->
|
||||
</tr>`;
|
||||
}
|
||||
res += `</table>`;
|
||||
return res
|
||||
}
|
42
src/html/pages/dashboard/users_show.js
Normal file
42
src/html/pages/dashboard/users_show.js
Normal file
@ -0,0 +1,42 @@
|
||||
import { permissionBits, checkPermissions } from '../../../../utils/permissions.js';
|
||||
import { readFile } from 'fs/promises';
|
||||
import { navbar } from '../../../../utils/navbar.js';
|
||||
|
||||
export default {
|
||||
path: "/dashboard/users/:username",
|
||||
requiresLogin: true,
|
||||
permissions: permissionBits.ADMIN,
|
||||
type: "get",
|
||||
async execute(request, response) {
|
||||
const { username } = request.params;
|
||||
const user = await global.database.users.findOne({ where: { username: username } });
|
||||
if(!user) return response.redirect('/dashboard/users');
|
||||
const html = await readFile(`${process.env.WWW}/dashboard/users/info.html`);
|
||||
response.send(html.toString()
|
||||
.replace('<NAVBAR>', navbar(request.session))
|
||||
.replace('<USERINFO>', getUserHTML(user))
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
function getUserHTML(user) {
|
||||
const userPermDict = checkPermissions(user.permissions);
|
||||
let userPerms = [];
|
||||
for (const [key, value] of Object.entries(userPermDict)) {
|
||||
if(value && key != "default") userPerms.push(key);
|
||||
};
|
||||
let res = `
|
||||
<table>
|
||||
<tr>
|
||||
<th>Identifiant</th>
|
||||
<th>Permissions</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>${user.username}</td>
|
||||
<td>${userPerms.join(", ")}</td>
|
||||
<td><button>Supprimer</button></td>
|
||||
</tr>
|
||||
</table>`;
|
||||
return res;
|
||||
}
|
@ -4,10 +4,10 @@ export default {
|
||||
async execute(request, response) {
|
||||
const { username, password } = request.body;
|
||||
console.log(request.body);
|
||||
global.database.users.findOne({ where: { username: username } }).then(function (user) {
|
||||
global.database.users.findOne({ where: { username: username } }).then(async function (user) {
|
||||
if (!user) {
|
||||
response.redirect('/login');
|
||||
} else if (!user.validPassword(password)) {
|
||||
} else if (!await user.validPassword(password)) {
|
||||
response.redirect('/login');
|
||||
} else {
|
||||
request.session.user = user.dataValues;
|
||||
|
@ -1,29 +1,89 @@
|
||||
import fs from 'fs';
|
||||
const pagesPath = "./src/html/pages/";
|
||||
|
||||
async function deployHandler() {
|
||||
global.handler = {
|
||||
get: {},
|
||||
post: {},
|
||||
async function genHandler() {
|
||||
const handler = {
|
||||
get: [],
|
||||
post: [],
|
||||
path: [],
|
||||
delete: [],
|
||||
};
|
||||
let numberOfPages = 0;
|
||||
const PagesCategories = fs
|
||||
const endpointCategories = fs
|
||||
.readdirSync(pagesPath)
|
||||
.filter((file) => !file.includes("."));
|
||||
for (const category of PagesCategories) {
|
||||
const pageFiles = fs
|
||||
for (const category of endpointCategories) {
|
||||
const endpointFiles = fs
|
||||
.readdirSync(`${pagesPath}${category}`)
|
||||
.filter((file) => file.endsWith(".js"));
|
||||
for (const file of pageFiles) {
|
||||
const { default: page } = await import(`.${pagesPath}${category}/${file}`);
|
||||
global.handler[page.type][page.path] = page;
|
||||
for (const file of endpointFiles) {
|
||||
const { default: endpoint } = await import(`.${pagesPath}${category}/${file}`);
|
||||
handler[endpoint.type].push(endpoint);
|
||||
console.log(
|
||||
`\x1b[32mChargement de POST: ${page.path} !\x1b[0m`,
|
||||
`\x1b[32mChargement de POST: ${endpoint.path} !\x1b[0m`,
|
||||
);
|
||||
numberOfPages++;
|
||||
console.log(numberOfPages + " pages chargées ! ");
|
||||
console.log(numberOfPages + " endpoints chargés ! ");
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
async function deployHandler(app) {
|
||||
const handler = await genHandler();
|
||||
|
||||
for(const endpoint of handler.get) {
|
||||
app.get(endpoint.path, async (request, response) => {
|
||||
const [path, args] = parseURL(request.originalUrl);
|
||||
console.log("GET: " + path);
|
||||
|
||||
if (endpoint.requiresLogin && !request.session.user) {
|
||||
return response.redirect("/login");
|
||||
}
|
||||
if (endpoint.permissions) {
|
||||
if((endpoint.permissions & request.session.user.permissions) == 0) {
|
||||
return response.status(403).send("Vous n'avez pas la permission d'effectuer cette action !");
|
||||
}
|
||||
}
|
||||
return await endpoint.execute(
|
||||
request,
|
||||
response,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
for(const endpoint of handler.post) {
|
||||
app.post(endpoint.path, async (request, response) => {
|
||||
console.log("POST: " + request.originalUrl);
|
||||
|
||||
if (endpoint.requiresLogin && !request.session.user) {
|
||||
return response.redirect("/login");
|
||||
}
|
||||
if (endpoint.permissions) {
|
||||
if((endpoint.permissions & request.session.user.permissions) == 0) {
|
||||
return response.status(403).send("Vous n'avez pas la permission d'effectuer cette action !");
|
||||
}
|
||||
}
|
||||
return await endpoint.execute(
|
||||
request,
|
||||
response,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function parseURL(URL) {
|
||||
const spURL = URL.split("?");
|
||||
const path = spURL[0];
|
||||
if(!spURL[1]) return [path, {}];
|
||||
|
||||
const args = {};
|
||||
for (let i = 0; i < spURL[1].split("=").length; i+=2) {
|
||||
const key = spURL[1].split("=")[i];
|
||||
const val = spURL[1].split("=")[i+1];
|
||||
args[key] = val;
|
||||
}
|
||||
return [path, args];
|
||||
}
|
||||
|
||||
export { deployHandler };
|
||||
|
@ -26,6 +26,7 @@ function checkPermissions(userPermissionBits) {
|
||||
if(userPermissionBits & permissionBits.ADMIN) {
|
||||
permissions.admin = true;
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
/*
|
||||
let userPermissionBits = permissionBits.DEFAULT;
|
||||
|
57
web.js
57
web.js
@ -19,48 +19,7 @@ async function launchWeb() {
|
||||
app.use("/assets", express.static(`${process.env.WWW}/assets`));
|
||||
app.use(favicon(`${process.env.WWW}/assets/images/favicon.ico`));
|
||||
|
||||
await deployHandler();
|
||||
|
||||
app.post("*", async (request, response) => {
|
||||
console.log("POST: " + request.originalUrl);
|
||||
let handled = global.handler.post[request.originalUrl];
|
||||
|
||||
if(!handled) for(const path of Object.keys(global.handler.post)) {
|
||||
if(new RegExp(path).test(request.originalUrl)) handled = global.handler.post[path];
|
||||
}
|
||||
|
||||
if (!handled) return console.log(request.originalUrl);
|
||||
if (handled.requiresLogin && !request.session.user) {
|
||||
return response.redirect("/login");
|
||||
}
|
||||
if (handled.permissions) {
|
||||
if((handled.permissions & request.session.user.permissions) == 0) return response.status(403).send("Vous n'avez pas la permission d'effectuer cette action !");
|
||||
}
|
||||
return await handled.execute(
|
||||
request,
|
||||
response,
|
||||
);
|
||||
});
|
||||
|
||||
app.get("*", async (request, response) => {
|
||||
const [path, args] = parseURL(request.originalUrl);
|
||||
//console.log(parseURL(request.originalUrl));
|
||||
console.log(`GET: ${path}${args ? "?" + args : ""}`);
|
||||
let handled = global.handler.get[path];
|
||||
|
||||
if(!handled) for(const path of Object.keys(global.handler.get)) {
|
||||
if(new RegExp(path).test(request.originalUrl)) handled = global.handler.get[path];
|
||||
}
|
||||
|
||||
if (!handled) return;
|
||||
if (handled.requiresLogin && !request.session.user) {
|
||||
return response.redirect("/login");
|
||||
}
|
||||
if (handled.permissions) {
|
||||
if((handled.permissions & request.session.user.permissions) == 0) return response.status(403).send("Vous n'avez pas la permission d'accéder cette page !");
|
||||
}
|
||||
return await handled.execute(request, response, args);
|
||||
});
|
||||
await deployHandler(app);
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
app.listen(PORT, () => {
|
||||
@ -68,18 +27,4 @@ async function launchWeb() {
|
||||
});
|
||||
}
|
||||
|
||||
function parseURL(URL) {
|
||||
const spURL = URL.split("?");
|
||||
const path = spURL[0];
|
||||
if(!spURL[1]) return [path, {}];
|
||||
|
||||
const args = {};
|
||||
for (let i = 0; i < spURL[1].split("=").length; i+=2) {
|
||||
const key = spURL[1].split("=")[i];
|
||||
const val = spURL[1].split("=")[i+1];
|
||||
args[key] = val;
|
||||
}
|
||||
return [path, args];
|
||||
}
|
||||
|
||||
export { launchWeb };
|
||||
|
@ -1,3 +1,5 @@
|
||||
body {font-family: Arial, Helvetica, sans-serif;}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
|
@ -9,7 +9,7 @@
|
||||
<NAVBAR>
|
||||
<h1>Dashboard</h1>
|
||||
<p><a href='/calls'>Phoning</a></p>
|
||||
<p><a href='/dashboard/users/create'>Ajouter un utilisateur</a></p>
|
||||
<p><a href='/dashboard/users'>Gestion des utilisateurs</a></p>
|
||||
<p><a href='/logout'>Déconnexion</a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Utilisateurs</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
@ -77,15 +78,36 @@ a {
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function setAction(form) {
|
||||
form.action = `/api/users/${form.username.value}/create`;
|
||||
return true;
|
||||
function createUserFromForm() {
|
||||
const form = document.getElementById("userCreateForm");
|
||||
let perms = 1;
|
||||
for(const node of form.querySelectorAll('input[name="permissions"]')) {
|
||||
perms += node.checked ? Number(node.value) : 0;
|
||||
}
|
||||
console.log(perms)
|
||||
fetch(`/api/users/${form.username.value}`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username: form.username.value,
|
||||
permissions: perms,
|
||||
password: form.password.value,
|
||||
}),
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then(async (response) => {
|
||||
const res = await response.json();
|
||||
console.log(res);
|
||||
if(!response.ok) return alert(res.message);
|
||||
window.location = `/dashboard/users/${res.username}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<NAVBAR>
|
||||
<form action="/api/users/:username/create" method="post" onsubmit="return setAction(this)">
|
||||
<form action="javascript:createUserFromForm()" id="userCreateForm">
|
||||
<div class="container">
|
||||
<h1>Création de compte</h1>
|
||||
<p>Formulaire de création de compte.</p>
|
||||
|
15
www/dashboard/users/index.html
Normal file
15
www/dashboard/users/index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>Utilisateurs</title>
|
||||
</head>
|
||||
<body>
|
||||
<NAVBAR>
|
||||
<h1>Gestion des utilisateurs</h1>
|
||||
<p><a href='/dashboard/users/list'>Liste des utilisateurs</a></p>
|
||||
<p><a href='/dashboard/users/create'>Ajouter un utilisateur</a></p>
|
||||
<p><a href='/dashboard'>Retour</a></p>
|
||||
</body>
|
||||
</html>
|
18
www/dashboard/users/info.html
Normal file
18
www/dashboard/users/info.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Utilisateurs</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
table, th, td {
|
||||
border:1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<NAVBAR>
|
||||
<USERINFO>
|
||||
<a href='./'><p>Retour</p></a>
|
||||
</body>
|
||||
</html>
|
18
www/dashboard/users/list.html
Normal file
18
www/dashboard/users/list.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Utilisateurs</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
table, th, td {
|
||||
border:1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<NAVBAR>
|
||||
<USERTABLE>
|
||||
<a href='./'><p>Retour</p></a>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user