Added login system and updated interface
This commit is contained in:
parent
dd32138229
commit
677d1d92d2
44
index.js
44
index.js
@ -1,43 +1,13 @@
|
|||||||
const { launchWeb } = require("./web.js");
|
import { launchWeb } from './web.js';
|
||||||
const { EventEmitter } = require("events");
|
import { EventEmitter } from 'events';
|
||||||
const Sequelize = require("sequelize");
|
import { loadDatabase } from './utils/database.js';
|
||||||
require('dotenv').config()
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
const sequelize = new Sequelize("database", "user", "password", {
|
loadDatabase();
|
||||||
host: "localhost",
|
|
||||||
dialect: "sqlite",
|
|
||||||
logging: false,
|
|
||||||
storage: "database.sqlite",
|
|
||||||
});
|
|
||||||
|
|
||||||
const contactsDB = sequelize.define("contacts", {
|
|
||||||
phone: {
|
|
||||||
type: Sequelize.STRING,
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
firstName: {
|
|
||||||
type: Sequelize.STRING,
|
|
||||||
},
|
|
||||||
lastName: {
|
|
||||||
type: Sequelize.STRING,
|
|
||||||
},
|
|
||||||
called: {
|
|
||||||
type: Sequelize.INTEGER, // 0: not called - 1: called - 2: ongoing call (- 3: no response ?)
|
|
||||||
defaultValue: false,
|
|
||||||
},
|
|
||||||
vote: {
|
|
||||||
type: Sequelize.BOOLEAN,
|
|
||||||
defaultValue: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
contactsDB.sync();
|
|
||||||
|
|
||||||
global.database = {};
|
|
||||||
global.database.contacts = contactsDB;
|
|
||||||
|
|
||||||
const submitEvent = new EventEmitter();
|
const submitEvent = new EventEmitter();
|
||||||
launchWeb(submitEvent);
|
await launchWeb(submitEvent);
|
||||||
|
|
||||||
submitEvent.on("call", async (call) => {
|
submitEvent.on("call", async (call) => {
|
||||||
let vote;
|
let vote;
|
||||||
|
@ -6,9 +6,14 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
|
"type": "module",
|
||||||
"author": "Ninjdai",
|
"author": "Ninjdai",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@adminjs/express": "^6.1.0",
|
||||||
|
"@adminjs/sequelize": "^4.1.1",
|
||||||
|
"adminjs": "^7.5.0",
|
||||||
|
"bcrypt": "^5.1.1",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
|
@ -10,4 +10,4 @@ async function getRandomUser() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { getRandomUser };
|
export { getRandomUser };
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
const { navbar } = require('../../utils/navbar.js');
|
import { navbar } from '../../utils/navbar.js';
|
||||||
|
|
||||||
function generateCallHTML(phoneNumber, name, callcount, session) {
|
function generateCallHTML(phoneNumber, name, callcount, session) {
|
||||||
const head = `<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"><link rel="stylesheet" type="text/css" href="/assets/css/form.css" /><title>AutoCallMenu</title></head>`;
|
const head = `<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"><link rel="stylesheet" type="text/css" href="/assets/css/form.css" /><title>AutoCallMenu</title></head>`;
|
||||||
const form = `
|
const form = `
|
||||||
<form action="/inputs/call" method="post">
|
<form action="/api/contacts/call" method="post">
|
||||||
<input type="hidden" name="phone" value="${phoneNumber}">
|
<input type="hidden" name="phone" value="${phoneNumber}">
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<input type="checkbox" name="vote">
|
<input type="checkbox" name="vote">
|
||||||
@ -18,4 +18,4 @@ function generateCallHTML(phoneNumber, name, callcount, session) {
|
|||||||
return `<!DOCTYPE html><html>${head}${body}</html>`;
|
return `<!DOCTYPE html><html>${head}${body}</html>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { generateCallHTML };
|
export { generateCallHTML };
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
export default {
|
||||||
path: "/inputs/add",
|
path: "/api/contacts/add",
|
||||||
requiresLogin: true,
|
requiresLogin: true,
|
||||||
type: "post",
|
type: "post",
|
||||||
async execute(request, response) {
|
async execute(request, response) {
|
@ -1,6 +1,9 @@
|
|||||||
module.exports = {
|
import { permissionBits } from '../../../../utils/permissions.js';
|
||||||
path: "/inputs/call",
|
|
||||||
|
export default {
|
||||||
|
path: "/api/contacts/call",
|
||||||
requiresLogin: true,
|
requiresLogin: true,
|
||||||
|
permissions: [permissionBits.CALL],
|
||||||
type: "post",
|
type: "post",
|
||||||
async execute(request, response) {
|
async execute(request, response) {
|
||||||
global.events.submitEvent.emit("call", request.body);
|
global.events.submitEvent.emit("call", request.body);
|
15
src/html/pages/api/users.js
Normal file
15
src/html/pages/api/users.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
path: "/api/users/*",
|
||||||
|
requiresLogin: true,
|
||||||
|
type: "post",
|
||||||
|
async execute(request, response) {
|
||||||
|
const path = request.originalUrl.split("/")[3];
|
||||||
|
const args = request.body;
|
||||||
|
switch(path) {
|
||||||
|
case 'create':
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
14
src/html/pages/dashboard/index.js
Normal file
14
src/html/pages/dashboard/index.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { readFile } from 'fs/promises';
|
||||||
|
import { navbar } from '../../../../utils/navbar.js';
|
||||||
|
import { permissionBits } from '../../../../utils/permissions.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
path: "/dashboard",
|
||||||
|
requiresLogin: true,
|
||||||
|
permissions: permissionBits.ADMIN,
|
||||||
|
type: "get",
|
||||||
|
async execute(request, response) {
|
||||||
|
const res = await readFile(`${process.env.WWW}/dashboard/index.html`, "utf8")
|
||||||
|
response.send(res.replaceAll("<NAVBAR>", navbar(request.session)));
|
||||||
|
},
|
||||||
|
}
|
11
src/html/pages/dashboard/users.js
Normal file
11
src/html/pages/dashboard/users.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { permissionBits } from '../../../../utils/permissions.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
path: "/dashboard/users",
|
||||||
|
requiresLogin: true,
|
||||||
|
permissions: permissionBits.ADMIN,
|
||||||
|
type: "get",
|
||||||
|
async execute(request, response) {
|
||||||
|
response.redirect("/dashboard/users/list");
|
||||||
|
},
|
||||||
|
}
|
14
src/html/pages/dashboard/users_create.js
Normal file
14
src/html/pages/dashboard/users_create.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { readFile } from 'fs/promises';
|
||||||
|
import { navbar } from '../../../../utils/navbar.js';
|
||||||
|
import { permissionBits } from '../../../../utils/permissions.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
path: "/dashboard/users/create",
|
||||||
|
requiresLogin: true,
|
||||||
|
permissions: permissionBits.ADMIN,
|
||||||
|
type: "get",
|
||||||
|
async execute(request, response) {
|
||||||
|
const res = await readFile(`${process.env.WWW}/dashboard/users/create.html`, "utf8")
|
||||||
|
response.send(res.replaceAll("<NAVBAR>", navbar(request.session)));
|
||||||
|
},
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
const { generateCallHTML } = require("../../../../src/html/callHTML.js");
|
import { generateCallHTML } from "../../../../src/html/callHTML.js";
|
||||||
const { getRandomUser } = require('../../../../src/database/getUser.js');
|
import { getRandomUser } from '../../../../src/database/getUser.js';
|
||||||
const { navbar } = require('../../../../utils/navbar.js');
|
import { navbar } from '../../../../utils/navbar.js';
|
||||||
|
import { permissionBits } from "../../../../utils/permissions.js";
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
path: "/calls",
|
path: "/calls",
|
||||||
requiresLogin: true,
|
requiresLogin: true,
|
||||||
|
permissions: [permissionBits.CALL],
|
||||||
type: "get",
|
type: "get",
|
||||||
async execute(request, response) {
|
async execute(request, response) {
|
||||||
const res = await generateCallResponse(request.session);
|
const res = await generateCallResponse(request.session);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const { readFile } = require('fs').promises;
|
import { readFile } from 'fs/promises';
|
||||||
const { navbar } = require('../../../../utils/navbar.js');
|
import { navbar } from '../../../../utils/navbar.js';
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
path: "/",
|
path: "/",
|
||||||
type: "get",
|
type: "get",
|
||||||
async execute(request, response) {
|
async execute(request, response) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const { readFile } = require('fs').promises;
|
import { readFile } from 'fs/promises';
|
||||||
const { navbar } = require('../../../../utils/navbar.js');
|
import { navbar } from '../../../../utils/navbar.js';
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
path: "/login",
|
path: "/login",
|
||||||
type: "get",
|
type: "get",
|
||||||
async execute(request, response, args) {
|
async execute(request, response, args) {
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
const { readFile } = require('fs').promises;
|
export default {
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
path: "/login",
|
path: "/login",
|
||||||
type: "post",
|
type: "post",
|
||||||
async execute(request, response) {
|
async execute(request, response) {
|
||||||
const { username, password } = request.body;
|
const { username, password } = request.body;
|
||||||
console.log(request.body);
|
console.log(request.body);
|
||||||
if (username == "ninjdai" && password == "azerty") {
|
global.database.users.findOne({ where: { username: username } }).then(function (user) {
|
||||||
request.session.user = { username };
|
if (!user) {
|
||||||
response.redirect("/");
|
response.redirect('/login');
|
||||||
|
} else if (!user.validPassword(password)) {
|
||||||
|
response.redirect('/login');
|
||||||
} else {
|
} else {
|
||||||
response.redirect("/login?fail=true");
|
request.session.user = user.dataValues;
|
||||||
|
response.redirect('/');
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
module.exports = {
|
export default {
|
||||||
path: "/logout",
|
path: "/logout",
|
||||||
type: "get",
|
type: "get",
|
||||||
async execute(request, response) {
|
async execute(request, response) {
|
||||||
|
69
utils/database.js
Normal file
69
utils/database.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import Sequelize from "sequelize";
|
||||||
|
import bcrypt from 'bcrypt';
|
||||||
|
import { permissionBits } from "./permissions.js";
|
||||||
|
|
||||||
|
function loadDatabase() {
|
||||||
|
const sequelize = new Sequelize("database", "user", "password", {
|
||||||
|
host: "localhost",
|
||||||
|
dialect: "sqlite",
|
||||||
|
logging: false,
|
||||||
|
storage: "database.sqlite",
|
||||||
|
});
|
||||||
|
|
||||||
|
const contactsDB = sequelize.define("contacts", {
|
||||||
|
phone: {
|
||||||
|
type: Sequelize.STRING,
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
firstName: {
|
||||||
|
type: Sequelize.STRING,
|
||||||
|
},
|
||||||
|
lastName: {
|
||||||
|
type: Sequelize.STRING,
|
||||||
|
},
|
||||||
|
called: {
|
||||||
|
type: Sequelize.INTEGER, // 0: not called - 1: called - 2: ongoing call (- 3: no response ?)
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
vote: {
|
||||||
|
type: Sequelize.BOOLEAN,
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const userDB = sequelize.define("users", {
|
||||||
|
username: {
|
||||||
|
type: Sequelize.STRING,
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: Sequelize.STRING,
|
||||||
|
},
|
||||||
|
permissions: {
|
||||||
|
type: Sequelize.INTEGER,
|
||||||
|
defaultValue: permissionBits.DEFAULT,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hooks: {
|
||||||
|
beforeCreate: async function(user) {
|
||||||
|
const salt = await bcrypt.genSalt(10);
|
||||||
|
user.password = await bcrypt.hash(user.password, salt);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
userDB.prototype.validPassword = async function(password) {
|
||||||
|
return await bcrypt.compare(password, this.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
contactsDB.sync();
|
||||||
|
userDB.sync();
|
||||||
|
|
||||||
|
global.database = {};
|
||||||
|
global.database.contacts = contactsDB;
|
||||||
|
global.database.users = userDB;
|
||||||
|
//global.database.users.create({username: "admin", password: "admin", permissions: permissionBits.DEFAULT | permissionBits.CALL | permissionBits.ADMIN})
|
||||||
|
//global.database.users.create({username: "test", password: "test", permissions: permissionBits.DEFAULT | permissionBits.CALL})
|
||||||
|
}
|
||||||
|
|
||||||
|
export { loadDatabase };
|
@ -1,7 +1,7 @@
|
|||||||
const fs = require('fs');
|
import fs from 'fs';
|
||||||
const pagesPath = "./src/html/pages/";
|
const pagesPath = "./src/html/pages/";
|
||||||
|
|
||||||
function deployHandler() {
|
async function deployHandler() {
|
||||||
global.handler = {
|
global.handler = {
|
||||||
get: {},
|
get: {},
|
||||||
post: {},
|
post: {},
|
||||||
@ -15,7 +15,7 @@ function deployHandler() {
|
|||||||
.readdirSync(`${pagesPath}${category}`)
|
.readdirSync(`${pagesPath}${category}`)
|
||||||
.filter((file) => file.endsWith(".js"));
|
.filter((file) => file.endsWith(".js"));
|
||||||
for (const file of pageFiles) {
|
for (const file of pageFiles) {
|
||||||
const page = require(`.${pagesPath}${category}/${file}`);
|
const { default: page } = await import(`.${pagesPath}${category}/${file}`);
|
||||||
global.handler[page.type][page.path] = page;
|
global.handler[page.type][page.path] = page;
|
||||||
console.log(
|
console.log(
|
||||||
`\x1b[32mChargement de POST: ${page.path} !\x1b[0m`,
|
`\x1b[32mChargement de POST: ${page.path} !\x1b[0m`,
|
||||||
@ -26,4 +26,4 @@ function deployHandler() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { deployHandler };
|
export { deployHandler };
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
module.exports = {
|
function navbar(session) {
|
||||||
navbar(session) {
|
|
||||||
let logField;
|
let logField;
|
||||||
if(session.user) {
|
if(session.user) {
|
||||||
logField = `<li style="float:right"><a class="active" href="/logout">${session.user.username} ✖ </a></li>`
|
logField = `<li style="float:right"><a class="active" href="/dashboard">${session.user.username}</a></li>`
|
||||||
} else {
|
} else {
|
||||||
logField = `<li style="float:right"><a class="active" href="/login">Login</a></li>`;
|
logField = `<li style="float:right"><a class="active" href="/login">Login</a></li>`;
|
||||||
}
|
}
|
||||||
@ -15,4 +14,4 @@ module.exports = {
|
|||||||
${logField}
|
${logField}
|
||||||
</ul>`;
|
</ul>`;
|
||||||
}
|
}
|
||||||
}
|
export { navbar };
|
||||||
|
37
utils/permissions.js
Normal file
37
utils/permissions.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
const permissionBits = {
|
||||||
|
DEFAULT: 1, // 0001
|
||||||
|
CALL: 2, // 0010
|
||||||
|
UNUSED: 4, // 0100
|
||||||
|
ADMIN: 8, // 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkPermissions(userPermissionBits) {
|
||||||
|
// Default if you have no permissions
|
||||||
|
let permissions = {
|
||||||
|
default: false,
|
||||||
|
call: false,
|
||||||
|
unused: false,
|
||||||
|
admin: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if(userPermissionBits & permissionBits.DEFAULT) {
|
||||||
|
permissions.default = true;
|
||||||
|
}
|
||||||
|
if(userPermissionBits & permissionBits.CALL) {
|
||||||
|
permissions.call = true;
|
||||||
|
}
|
||||||
|
if(userPermissionBits & permissionBits.UNUSED) {
|
||||||
|
permissions.unused = true;
|
||||||
|
}
|
||||||
|
if(userPermissionBits & permissionBits.ADMIN) {
|
||||||
|
permissions.admin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
let userPermissionBits = permissionBits.DEFAULT;
|
||||||
|
userPermissionBits |= permissionBits.CALL; // add permission
|
||||||
|
userPermissionBits ^= permissionBits.ADMIN; // toggle permission
|
||||||
|
userPermissionBits &= (~permissionBits.CALL); // remove permission
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { permissionBits, checkPermissions };
|
36
web.js
36
web.js
@ -1,10 +1,9 @@
|
|||||||
const express = require("express");
|
import express from "express";
|
||||||
const session = require("express-session");
|
import session from "express-session";
|
||||||
const { readFile } = require("fs").promises;
|
import { deployHandler } from "./utils/handler.js";
|
||||||
const { deployHandler } = require("./utils/handler.js");
|
import favicon from "serve-favicon";
|
||||||
const favicon = require("serve-favicon");
|
|
||||||
|
|
||||||
function launchWeb() {
|
async function launchWeb() {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use(express.json()); // Used to parse JSON bodies
|
app.use(express.json()); // Used to parse JSON bodies
|
||||||
@ -20,14 +19,26 @@ function launchWeb() {
|
|||||||
app.use("/assets", express.static(`${process.env.WWW}/assets`));
|
app.use("/assets", express.static(`${process.env.WWW}/assets`));
|
||||||
app.use(favicon(`${process.env.WWW}/assets/images/favicon.ico`));
|
app.use(favicon(`${process.env.WWW}/assets/images/favicon.ico`));
|
||||||
|
|
||||||
deployHandler();
|
await deployHandler();
|
||||||
|
|
||||||
app.post("*", async (request, response) => {
|
app.post("*", async (request, response) => {
|
||||||
console.log("POST: " + request.originalUrl);
|
console.log("POST: " + request.originalUrl);
|
||||||
if (!global.handler.post[request.originalUrl]) return;
|
if (!global.handler.post[request.originalUrl]) return;
|
||||||
if (global.handler.post[request.originalUrl].requiresLogin && !request.session.user) {
|
if (
|
||||||
|
global.handler.post[request.originalUrl].requiresLogin &&
|
||||||
|
!request.session.user
|
||||||
|
) {
|
||||||
return response.redirect("/login");
|
return response.redirect("/login");
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
global.handler.post[request.originalUrl].permissions &&
|
||||||
|
global.handler.post[request.originalUrl].permissions.reduce(
|
||||||
|
(a, b) => a + b,
|
||||||
|
) &
|
||||||
|
(request.session.user.permissions == 0)
|
||||||
|
) {
|
||||||
|
return response.status(403);
|
||||||
|
}
|
||||||
return await global.handler.post[request.originalUrl].execute(
|
return await global.handler.post[request.originalUrl].execute(
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
@ -35,7 +46,6 @@ function launchWeb() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.get("*", async (request, response) => {
|
app.get("*", async (request, response) => {
|
||||||
|
|
||||||
const [path, args] = parseURL(request.originalUrl);
|
const [path, args] = parseURL(request.originalUrl);
|
||||||
//console.log(parseURL(request.originalUrl));
|
//console.log(parseURL(request.originalUrl));
|
||||||
console.log(`GET: ${path}${args ? "?" + args : ""}`);
|
console.log(`GET: ${path}${args ? "?" + args : ""}`);
|
||||||
@ -44,11 +54,7 @@ function launchWeb() {
|
|||||||
if (global.handler.get[path].requiresLogin && !request.session.user) {
|
if (global.handler.get[path].requiresLogin && !request.session.user) {
|
||||||
return response.redirect("/login");
|
return response.redirect("/login");
|
||||||
}
|
}
|
||||||
return await global.handler.get[path].execute(
|
return await global.handler.get[path].execute(request, response, args);
|
||||||
request,
|
|
||||||
response,
|
|
||||||
args,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
@ -64,4 +70,4 @@ function parseURL(URL) {
|
|||||||
return [path, args];
|
return [path, args];
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { launchWeb };
|
export { launchWeb };
|
||||||
|
15
www/dashboard/index.html
Normal file
15
www/dashboard/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>AutoCallMenu</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<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='/logout'>Déconnexion</a></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
116
www/dashboard/users/create.html
Normal file
116
www/dashboard/users/create.html
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add padding to containers */
|
||||||
|
.container {
|
||||||
|
padding: 16px;
|
||||||
|
background-color: white;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
padding-left: 35px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 22px;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Full-width input fields */
|
||||||
|
input[type=text], input[type=password] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 5px 0 22px 0;
|
||||||
|
display: inline-block;
|
||||||
|
border: none;
|
||||||
|
background: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text]:focus, input[type=password]:focus {
|
||||||
|
background-color: #ddd;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overwrite default styles of hr */
|
||||||
|
hr {
|
||||||
|
border: 1px solid #f1f1f1;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a style for the submit button */
|
||||||
|
.registerbtn {
|
||||||
|
background-color: #04AA6D;
|
||||||
|
color: white;
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.registerbtn:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a blue text color to links */
|
||||||
|
a {
|
||||||
|
color: dodgerblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a grey background color and center the text of the "sign in" section */
|
||||||
|
.signin {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<NAVBAR>
|
||||||
|
<form action="/api/users/create" method="post">
|
||||||
|
<div class="container">
|
||||||
|
<h1>Création de compte</h1>
|
||||||
|
<p>Formulaire de création de compte.</p>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<label for="email"><b>Nom d'utilisateur</b></label>
|
||||||
|
<input type="text" placeholder="Entrez le nom d'utilisateur" name="email" id="email" required>
|
||||||
|
|
||||||
|
<label for="psw"><b>Mot de passe</b></label>
|
||||||
|
<input type="password" placeholder="Mot de passe" name="password" id="psw" required>
|
||||||
|
|
||||||
|
<label for="psw-repeat"><b>Mot de passe (confirmation)</b></label>
|
||||||
|
<input type="password" placeholder="Répétez le mot de passe" name="password-repeat" id="psw-repeat" required>
|
||||||
|
<h4>Permissions</h4>
|
||||||
|
<label class="container">Appels
|
||||||
|
<input type="checkbox" name="permissions_calls">
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
</label>
|
||||||
|
<!--<label class="container">Unused
|
||||||
|
<input type="checkbox">
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
</label>-->
|
||||||
|
<label class="container">Admin
|
||||||
|
<input type="checkbox" name="permissions_admin">
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
</label>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<button type="submit" class="registerbtn">Register</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -4,7 +4,7 @@
|
|||||||
<title></title>
|
<title></title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="/assets/css/login.css" rel="stylesheet">
|
<link href="/assets/css/forms/login.css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<NAVBAR>
|
<NAVBAR>
|
||||||
|
Loading…
Reference in New Issue
Block a user