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 indexRouter = require("./routes/index");
|
||||
let registerRouter = require("./routes/register");
|
||||
let loginRouter = require("./routes/login");
|
||||
let logoutRouter = require("./routes/logout");
|
||||
let commandRouter = require("./routes/command");
|
||||
|
@ -36,6 +37,7 @@ app.use(session(sess));
|
|||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
app.use("/", indexRouter);
|
||||
app.use("/register", registerRouter);
|
||||
app.use("/login", loginRouter);
|
||||
app.use("/logout", logoutRouter);
|
||||
app.use("/command", commandRouter);
|
||||
|
|
|
@ -6,6 +6,7 @@ module.exports = (sequelize, DataTypes) => {
|
|||
class Department extends Model {
|
||||
static associate(models) {
|
||||
Department.hasMany(models.Command);
|
||||
Department.hasMany(models.User);
|
||||
}
|
||||
}
|
||||
Department.init({
|
||||
|
|
|
@ -5,6 +5,7 @@ const {
|
|||
module.exports = (sequelize, DataTypes) => {
|
||||
class User extends Model {
|
||||
static associate(models) {
|
||||
User.belongsTo(models.Department);
|
||||
}
|
||||
|
||||
checkPassword(password) {
|
||||
|
@ -19,6 +20,23 @@ module.exports = (sequelize, DataTypes) => {
|
|||
type: DataTypes.STRING,
|
||||
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: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
const commandAction = document.getElementById("command-action");
|
||||
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() {
|
||||
let list = document.querySelectorAll("div.command h2");
|
||||
|
@ -33,21 +29,3 @@ rmButton.addEventListener("click", () => {
|
|||
if (id === 2)
|
||||
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%;
|
||||
}
|
||||
|
||||
.field input[type="text"], .field input[type="list"], .field input[type="date"], .field input[type="number"],
|
||||
.field input[type="checkbox"] {
|
||||
.field input[type="text"], .field input[type="list"], .field input[type="date"], .field input[type="password"],
|
||||
.field input[type="number"], .field input[type="checkbox"], .field input[type="email"] {
|
||||
height: 2.5vh;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
|
@ -165,6 +165,26 @@ p.before-link a::before {
|
|||
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) {
|
||||
body {
|
||||
font-size: xx-large;
|
||||
|
|
|
@ -5,7 +5,7 @@ let models = require("../models");
|
|||
|
||||
|
||||
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;
|
||||
|
|
|
@ -5,7 +5,7 @@ let models = require("../models");
|
|||
router.get("/", async (req, res) => {
|
||||
let departments = await models.Department.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;
|
||||
|
|
|
@ -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].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;
|
||||
|
|
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", {
|
||||
title: "SOD",
|
||||
user: req.session.user,
|
||||
sandwiches: await models.SandwichCommand.findAll({
|
||||
attributes: ["SandwichName", [sequelize.fn("COUNT", sequelize.col("SandwichName")), "number"]],
|
||||
where: {date: date},
|
||||
|
|
|
@ -7,17 +7,17 @@ block content
|
|||
form#command(action="/command" method="POST")
|
||||
div.field
|
||||
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
|
||||
each department in departments
|
||||
option(value=department.name)
|
||||
|
||||
div.field
|
||||
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
|
||||
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
|
||||
h2 Command 1
|
||||
|
@ -39,50 +39,4 @@ block content
|
|||
each sandwich in sandwiches
|
||||
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")
|
||||
|
|
|
@ -5,3 +5,59 @@ html
|
|||
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||
body
|
||||
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
|
||||
label(for="username") Username:
|
||||
input#username(type="text" name="username" required)
|
||||
dov.field
|
||||
label(for="password") Username:
|
||||
div.field
|
||||
label(for="password") Password:
|
||||
input#password(type="password" name="password" required)
|
||||
div.field
|
||||
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