Setup login/register/logout in layout, move more from index to layout, add more columns to user model, use logged user to fill oder form
This commit is contained in:
parent
ffe31c6af9
commit
2ca80e5300
15 changed files with 210 additions and 78 deletions
2
app.js
2
app.js
|
@ -6,6 +6,7 @@ let logger = require("morgan");
|
||||||
let config = require("./config/config.json");
|
let config = require("./config/config.json");
|
||||||
|
|
||||||
let indexRouter = require("./routes/index");
|
let indexRouter = require("./routes/index");
|
||||||
|
let registerRouter = require("./routes/register");
|
||||||
let loginRouter = require("./routes/login");
|
let loginRouter = require("./routes/login");
|
||||||
let logoutRouter = require("./routes/logout");
|
let logoutRouter = require("./routes/logout");
|
||||||
let commandRouter = require("./routes/command");
|
let commandRouter = require("./routes/command");
|
||||||
|
@ -36,6 +37,7 @@ app.use(session(sess));
|
||||||
app.use(express.static(path.join(__dirname, "public")));
|
app.use(express.static(path.join(__dirname, "public")));
|
||||||
|
|
||||||
app.use("/", indexRouter);
|
app.use("/", indexRouter);
|
||||||
|
app.use("/register", registerRouter);
|
||||||
app.use("/login", loginRouter);
|
app.use("/login", loginRouter);
|
||||||
app.use("/logout", logoutRouter);
|
app.use("/logout", logoutRouter);
|
||||||
app.use("/command", commandRouter);
|
app.use("/command", commandRouter);
|
||||||
|
|
|
@ -6,6 +6,7 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
class Department extends Model {
|
class Department extends Model {
|
||||||
static associate(models) {
|
static associate(models) {
|
||||||
Department.hasMany(models.Command);
|
Department.hasMany(models.Command);
|
||||||
|
Department.hasMany(models.User);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Department.init({
|
Department.init({
|
||||||
|
|
|
@ -5,6 +5,7 @@ const {
|
||||||
module.exports = (sequelize, DataTypes) => {
|
module.exports = (sequelize, DataTypes) => {
|
||||||
class User extends Model {
|
class User extends Model {
|
||||||
static associate(models) {
|
static associate(models) {
|
||||||
|
User.belongsTo(models.Department);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPassword(password) {
|
checkPassword(password) {
|
||||||
|
@ -19,6 +20,23 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
primaryKey: true
|
primaryKey: true
|
||||||
},
|
},
|
||||||
|
email: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
validate: {
|
||||||
|
isEmail: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
firstName: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
unique: "userFullName"
|
||||||
|
},
|
||||||
|
lastName: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
unique: "userFullName"
|
||||||
|
},
|
||||||
passwordHash: {
|
passwordHash: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
const commandAction = document.getElementById("command-action");
|
const commandAction = document.getElementById("command-action");
|
||||||
const rmButton = document.getElementById("remove-command");
|
const rmButton = document.getElementById("remove-command");
|
||||||
const more = document.getElementById("more");
|
|
||||||
const dark = document.getElementById("dark");
|
|
||||||
const about = document.getElementById("about");
|
|
||||||
const contact = document.getElementById("contact");
|
|
||||||
|
|
||||||
function lastCommandId() {
|
function lastCommandId() {
|
||||||
let list = document.querySelectorAll("div.command h2");
|
let list = document.querySelectorAll("div.command h2");
|
||||||
|
@ -33,21 +29,3 @@ rmButton.addEventListener("click", () => {
|
||||||
if (id === 2)
|
if (id === 2)
|
||||||
rmButton.classList.add("hide");
|
rmButton.classList.add("hide");
|
||||||
});
|
});
|
||||||
|
|
||||||
more.firstChild.addEventListener("click", () => {
|
|
||||||
dark.classList.remove("hide");
|
|
||||||
about.classList.remove("hide");
|
|
||||||
});
|
|
||||||
|
|
||||||
more.lastChild.addEventListener("click", () => {
|
|
||||||
dark.classList.remove("hide");
|
|
||||||
contact.classList.remove("hide")
|
|
||||||
});
|
|
||||||
|
|
||||||
dark.addEventListener("click", () => {
|
|
||||||
dark.classList.add("hide");
|
|
||||||
if (! about.classList.contains("hide"))
|
|
||||||
about.classList.add("hide");
|
|
||||||
else
|
|
||||||
contact.classList.add("hide");
|
|
||||||
});
|
|
||||||
|
|
23
public/javascripts/layout.js
Normal file
23
public/javascripts/layout.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
const more = document.getElementById("more");
|
||||||
|
const dark = document.getElementById("dark");
|
||||||
|
const about = document.getElementById("about");
|
||||||
|
const contact = document.getElementById("contact");
|
||||||
|
|
||||||
|
|
||||||
|
more.firstChild.addEventListener("click", () => {
|
||||||
|
dark.classList.remove("hide");
|
||||||
|
about.classList.remove("hide");
|
||||||
|
});
|
||||||
|
|
||||||
|
more.lastChild.addEventListener("click", () => {
|
||||||
|
dark.classList.remove("hide");
|
||||||
|
contact.classList.remove("hide")
|
||||||
|
});
|
||||||
|
|
||||||
|
dark.addEventListener("click", () => {
|
||||||
|
dark.classList.add("hide");
|
||||||
|
if (! about.classList.contains("hide"))
|
||||||
|
about.classList.add("hide");
|
||||||
|
else
|
||||||
|
contact.classList.add("hide");
|
||||||
|
});
|
|
@ -56,8 +56,8 @@ a {
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field input[type="text"], .field input[type="list"], .field input[type="date"], .field input[type="number"],
|
.field input[type="text"], .field input[type="list"], .field input[type="date"], .field input[type="password"],
|
||||||
.field input[type="checkbox"] {
|
.field input[type="number"], .field input[type="checkbox"], .field input[type="email"] {
|
||||||
height: 2.5vh;
|
height: 2.5vh;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
|
@ -165,6 +165,26 @@ p.before-link a::before {
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#user {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.3em;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 0 0 0.3em 0.3em;
|
||||||
|
box-shadow: 0.5em 0.5em 0.5em rgba(0, 0, 255, .2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#user>p, #user>a {
|
||||||
|
margin: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user>a {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
@media (hover: none) and (pointer: coarse) {
|
@media (hover: none) and (pointer: coarse) {
|
||||||
body {
|
body {
|
||||||
font-size: xx-large;
|
font-size: xx-large;
|
||||||
|
|
|
@ -5,7 +5,7 @@ let models = require("../models");
|
||||||
|
|
||||||
|
|
||||||
router.get("/", sessionCheck(3), async (req, res) => {
|
router.get("/", sessionCheck(3), async (req, res) => {
|
||||||
res.render("admin", {title: "SOD", sandwiches: await models.Sandwich.findAll(), users: await models.User.findAll()});
|
res.render("admin", {title: "SOD", user: req.session.user, sandwiches: await models.Sandwich.findAll(), users: await models.User.findAll()});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
@ -5,7 +5,7 @@ let models = require("../models");
|
||||||
router.get("/", async (req, res) => {
|
router.get("/", async (req, res) => {
|
||||||
let departments = await models.Department.findAll();
|
let departments = await models.Department.findAll();
|
||||||
let sandwiches = await models.Sandwich.findAll();
|
let sandwiches = await models.Sandwich.findAll();
|
||||||
res.render("index", { title: "SOD", departments: departments, sandwiches: sandwiches });
|
res.render("index", { title: "SOD", user: req.session.user, departments: departments, sandwiches: sandwiches });
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
@ -23,7 +23,7 @@ router.get("/", sessionCheck(2), async (req, res) => {
|
||||||
commands[i.Command.DepartmentName][name][i.Command.id] = []
|
commands[i.Command.DepartmentName][name][i.Command.id] = []
|
||||||
commands[i.Command.DepartmentName][name][i.Command.id].push(i);
|
commands[i.Command.DepartmentName][name][i.Command.id].push(i);
|
||||||
}
|
}
|
||||||
res.render("orders", {title: "SOD", commands: commands, date: date});
|
res.render("orders", {title: "SOD", user: req.session.user, commands: commands, date: date});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
50
routes/register.js
Normal file
50
routes/register.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
let express = require("express");
|
||||||
|
let router = express.Router();
|
||||||
|
let models = require("../models");
|
||||||
|
|
||||||
|
|
||||||
|
router.get("/", async (req, res) => {
|
||||||
|
if (req.session.user)
|
||||||
|
res.redirect("/");
|
||||||
|
else
|
||||||
|
res.render("register", {title: "SOD", departments: await models.Department.findAll()});
|
||||||
|
})
|
||||||
|
.post("/", async (req, res) => {
|
||||||
|
if (!req.body.username || !req.body.email || !req.body.firstName || !req.body.lastName ||
|
||||||
|
!req.body.department || !req.body.password)
|
||||||
|
res.render("error", {message: "Invalid register !", error: {status: "Missing args"}});
|
||||||
|
else if (await models.User.findByPk(req.body.username))
|
||||||
|
res.render("error", {message: "Invalid register !",
|
||||||
|
error: {status: "Username already taken"}});
|
||||||
|
else if (await models.User.findOne({where: {firstName: req.body.firstName,
|
||||||
|
lastName: req.body.lastName}}))
|
||||||
|
res.render("error", {message: "Invalid register !",
|
||||||
|
error: {status: "First & last name already register"}});
|
||||||
|
else if (await models.User.findOne({where: {email: req.body.email}}))
|
||||||
|
res.render("error", {message: "Invalid register !", error: {status: "Email already used"}});
|
||||||
|
else {
|
||||||
|
let department = await models.Department.findByPk(req.body.department);
|
||||||
|
if (!department)
|
||||||
|
res.render("error", {message: "Invalid register !",
|
||||||
|
error: {status: "Invalid department"}});
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
let user = await models.User.create({
|
||||||
|
username: req.body.username,
|
||||||
|
email: req.body.email,
|
||||||
|
firstName: req.body.firstName,
|
||||||
|
lastName: req.body.lastName,
|
||||||
|
passwordHash: req.body.password
|
||||||
|
});
|
||||||
|
await user.setDepartment(department);
|
||||||
|
req.session.user = user;
|
||||||
|
res.redirect("/");
|
||||||
|
} catch (e) {
|
||||||
|
res.render("error", {message: "Registration fail !", error: {}});
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -10,6 +10,7 @@ router.get("/", sessionCheck(1), async (req, res) => {
|
||||||
|
|
||||||
res.render("sandwiches", {
|
res.render("sandwiches", {
|
||||||
title: "SOD",
|
title: "SOD",
|
||||||
|
user: req.session.user,
|
||||||
sandwiches: await models.SandwichCommand.findAll({
|
sandwiches: await models.SandwichCommand.findAll({
|
||||||
attributes: ["SandwichName", [sequelize.fn("COUNT", sequelize.col("SandwichName")), "number"]],
|
attributes: ["SandwichName", [sequelize.fn("COUNT", sequelize.col("SandwichName")), "number"]],
|
||||||
where: {date: date},
|
where: {date: date},
|
||||||
|
|
|
@ -7,17 +7,17 @@ block content
|
||||||
form#command(action="/command" method="POST")
|
form#command(action="/command" method="POST")
|
||||||
div.field
|
div.field
|
||||||
label(for="department") Department:
|
label(for="department") Department:
|
||||||
input#department(type="list" list="department-list" name="department" autocomplete="off" required)
|
input#department(type="list" list="department-list" name="department" value=user ? user.DepartmentName : "" autocomplete="off" required)
|
||||||
datalist#department-list
|
datalist#department-list
|
||||||
each department in departments
|
each department in departments
|
||||||
option(value=department.name)
|
option(value=department.name)
|
||||||
|
|
||||||
div.field
|
div.field
|
||||||
label(for="firstname") First name:
|
label(for="firstname") First name:
|
||||||
input#firstname(type="text" name="firstName" required)
|
input#firstname(type="text" name="firstName" value=user ? user.firstName : "" required)
|
||||||
div.field
|
div.field
|
||||||
label(for="lastname") Last name:
|
label(for="lastname") Last name:
|
||||||
input#lastname(type="text" name="lastName" required)
|
input#lastname(type="text" name="lastName" value=user ? user.lastName : "" required)
|
||||||
|
|
||||||
div#command1.command
|
div#command1.command
|
||||||
h2 Command 1
|
h2 Command 1
|
||||||
|
@ -39,50 +39,4 @@ block content
|
||||||
each sandwich in sandwiches
|
each sandwich in sandwiches
|
||||||
option(value=sandwich.name)
|
option(value=sandwich.name)
|
||||||
|
|
||||||
div#more
|
|
||||||
a About
|
|
||||||
a Contact
|
|
||||||
|
|
||||||
div#dark.hide
|
|
||||||
div#about.popup.card.hide
|
|
||||||
h1 About
|
|
||||||
p This software respond to the COVID-19 health crisis for the following students' offices food supply
|
|
||||||
div.images
|
|
||||||
div
|
|
||||||
img(src="images/logoBio.png")
|
|
||||||
p Bio student office
|
|
||||||
div
|
|
||||||
img(src="images/logoChimie.png")
|
|
||||||
p Chemical student office
|
|
||||||
div
|
|
||||||
img(src="images/logoGC.png")
|
|
||||||
p Civil engineering student office
|
|
||||||
div
|
|
||||||
img(src="images/logoGCGP.png")
|
|
||||||
p Chemical and process engineering student office
|
|
||||||
div
|
|
||||||
img(src="images/logoGEA.png")
|
|
||||||
p Management of companies and administrations student office
|
|
||||||
div
|
|
||||||
img(src="images/logoInfo.png")
|
|
||||||
p IT student office
|
|
||||||
p.before-link Made with ❤️ by
|
|
||||||
a(href="https://www.linkedin.com/in/florian-charlaix" target="_blank") Florian Charlaix
|
|
||||||
div#contact.popup.card.hide
|
|
||||||
h1 Contact
|
|
||||||
p.before-link Order issue:
|
|
||||||
a(href="mailto: ") test@test.fr
|
|
||||||
p.before-link Bio student office:
|
|
||||||
a(href="mailto: ")
|
|
||||||
p.before-link Chemical student office:
|
|
||||||
a(href="mailto: ")
|
|
||||||
p.before-link Civil engineering student office:
|
|
||||||
a(href="mailto: ")
|
|
||||||
p.before-link Chemical and process engineering student office:
|
|
||||||
a(href="mailto: bde.gcgp.lyon1@gmail.com") bde.gcgp.lyon1@gmail.com
|
|
||||||
p.before-link Management of companies and administrations student office:
|
|
||||||
a(href="mailto: ")
|
|
||||||
p.before-link IT student office:
|
|
||||||
a(href="mailto: contact@bde-info.org") contact@bde-info.org
|
|
||||||
|
|
||||||
script(src="javascripts/index.js")
|
script(src="javascripts/index.js")
|
||||||
|
|
|
@ -5,3 +5,59 @@ html
|
||||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||||
body
|
body
|
||||||
block content
|
block content
|
||||||
|
|
||||||
|
div#user
|
||||||
|
if user
|
||||||
|
p=user.username
|
||||||
|
a(href="/logout") Logout
|
||||||
|
else
|
||||||
|
a(href="/login") Login
|
||||||
|
a(href="/register") Register
|
||||||
|
|
||||||
|
div#more
|
||||||
|
a About
|
||||||
|
a Contact
|
||||||
|
|
||||||
|
div#dark.hide
|
||||||
|
div#about.popup.card.hide
|
||||||
|
h1 About
|
||||||
|
p This software respond to the COVID-19 health crisis for the following students' offices food supply
|
||||||
|
div.images
|
||||||
|
div
|
||||||
|
img(src="images/logoBio.png")
|
||||||
|
p Bio student office
|
||||||
|
div
|
||||||
|
img(src="images/logoChimie.png")
|
||||||
|
p Chemical student office
|
||||||
|
div
|
||||||
|
img(src="images/logoGC.png")
|
||||||
|
p Civil engineering student office
|
||||||
|
div
|
||||||
|
img(src="images/logoGCGP.png")
|
||||||
|
p Chemical and process engineering student office
|
||||||
|
div
|
||||||
|
img(src="images/logoGEA.png")
|
||||||
|
p Management of companies and administrations student office
|
||||||
|
div
|
||||||
|
img(src="images/logoInfo.png")
|
||||||
|
p IT student office
|
||||||
|
p.before-link Made with ❤️ by
|
||||||
|
a(href="https://www.linkedin.com/in/florian-charlaix" target="_blank") Florian Charlaix
|
||||||
|
div#contact.popup.card.hide
|
||||||
|
h1 Contact
|
||||||
|
p.before-link Order issue:
|
||||||
|
a(href="mailto: ") test@test.fr
|
||||||
|
p.before-link Bio student office:
|
||||||
|
a(href="mailto: ")
|
||||||
|
p.before-link Chemical student office:
|
||||||
|
a(href="mailto: ")
|
||||||
|
p.before-link Civil engineering student office:
|
||||||
|
a(href="mailto: ")
|
||||||
|
p.before-link Chemical and process engineering student office:
|
||||||
|
a(href="mailto: bde.gcgp.lyon1@gmail.com") bde.gcgp.lyon1@gmail.com
|
||||||
|
p.before-link Management of companies and administrations student office:
|
||||||
|
a(href="mailto: ")
|
||||||
|
p.before-link IT student office:
|
||||||
|
a(href="mailto: contact@bde-info.org") contact@bde-info.org
|
||||||
|
|
||||||
|
script(src="javascripts/layout.js")
|
||||||
|
|
|
@ -6,8 +6,8 @@ block content
|
||||||
div.field
|
div.field
|
||||||
label(for="username") Username:
|
label(for="username") Username:
|
||||||
input#username(type="text" name="username" required)
|
input#username(type="text" name="username" required)
|
||||||
dov.field
|
div.field
|
||||||
label(for="password") Username:
|
label(for="password") Password:
|
||||||
input#password(type="password" name="password" required)
|
input#password(type="password" name="password" required)
|
||||||
div.field
|
div.field
|
||||||
input(type="submit" value="Login")
|
input(type="submit" value="Login")
|
||||||
|
|
29
views/register.pug
Normal file
29
views/register.pug
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
extends layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
form.card(action="/register" method="POST")
|
||||||
|
h1 Register
|
||||||
|
div.field
|
||||||
|
label(for="username") Username:
|
||||||
|
input#username(type="text" name="username" required)
|
||||||
|
div.field
|
||||||
|
label(for="email") Email:
|
||||||
|
input#email(type="email" name="email" required)
|
||||||
|
div.field
|
||||||
|
label(for="firstName") First name:
|
||||||
|
input#firstName(type="text" name="firstName" required)
|
||||||
|
div.field
|
||||||
|
label(for="lastName") Last name:
|
||||||
|
input#lastName(type="text" name="lastName" required)
|
||||||
|
div.field
|
||||||
|
label(for="department") Department:
|
||||||
|
input#department(type="list" list="department-list" name="department" required=)
|
||||||
|
div.field
|
||||||
|
label(for="password") Password:
|
||||||
|
input#password(type="password" name="password" required)
|
||||||
|
div.field
|
||||||
|
input(type="submit" value="Register")
|
||||||
|
|
||||||
|
datalist#department-list
|
||||||
|
each department in departments
|
||||||
|
option(value=department.name)
|
Reference in a new issue