Updated env + Added SignIn/SignUp
This commit is contained in:
parent
2218d2663b
commit
33c87b434c
25 changed files with 625 additions and 41 deletions
12
.babelrc
Normal file
12
.babelrc
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"esmodules": true
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
7
.editorconfig
Normal file
7
.editorconfig
Normal file
|
@ -0,0 +1,7 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
40
.eslintrc.js
40
.eslintrc.js
|
@ -1,22 +1,30 @@
|
|||
module.exports = {
|
||||
'env': {
|
||||
'es6': true,
|
||||
'node': true,
|
||||
env: {
|
||||
browser: true,
|
||||
es2020: true,
|
||||
node: true,
|
||||
jquery: true,
|
||||
},
|
||||
extends: ['airbnb-base', 'prettier'],
|
||||
plugins: ['prettier'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 11,
|
||||
sourceType: 'module',
|
||||
},
|
||||
rules: {
|
||||
'prettier/prettier': ['error'],
|
||||
'no-underscore-dangle': [
|
||||
'error',
|
||||
{
|
||||
allow: ['_id'],
|
||||
},
|
||||
'extends': [
|
||||
'google',
|
||||
],
|
||||
'globals': {
|
||||
'Atomics': 'readonly',
|
||||
'SharedArrayBuffer': 'readonly',
|
||||
},
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 2018,
|
||||
'sourceType': 'module',
|
||||
},
|
||||
'rules': {
|
||||
'max-len': ['error', {'code': 180}],
|
||||
'new-cap': ['error', {'capIsNewExceptions': ['ENUM', 'ARRAY', 'TEXT', 'STRING', 'ObjectId']}],
|
||||
ignorePatterns: ['public/libs/**/*.js', 'public/js/main.js', 'dist/**'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.js'],
|
||||
excludedFiles: '*.ejs',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
33
package.json
33
package.json
|
@ -5,12 +5,16 @@
|
|||
"scripts": {
|
||||
"start": "node ./dist/bin/www",
|
||||
"dev": "npm-run-all build start",
|
||||
"watch": "nodemon",
|
||||
"watch": "nodemon -e js,ejs",
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "babel ./src --out-dir dist",
|
||||
"build": "babel ./src --out-dir dist --copy-files",
|
||||
"test": "jest",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x",
|
||||
"yarn": "1.x"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@git.darkou.fr:dbroqua/nodecdtheque.git"
|
||||
|
@ -26,15 +30,31 @@
|
|||
"@babel/core": "^7.17.2",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"eslint": "^8.9.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "^12.3.3",
|
||||
"nodemon": "^2.0.15",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.5.1",
|
||||
"rimraf": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.17.2"
|
||||
"connect-ensure-login": "^0.1.1",
|
||||
"connect-flash": "^0.1.1",
|
||||
"connect-mongo": "^4.6.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"ejs": "^3.1.6",
|
||||
"express": "^4.17.2",
|
||||
"express-session": "^1.17.2",
|
||||
"jquery": "^3.6.0",
|
||||
"mdbootstrap": "^4.20.0",
|
||||
"mongoose": "^6.2.1",
|
||||
"mongoose-unique-validator": "^3.0.0",
|
||||
"passport": "^0.5.2",
|
||||
"passport-local": "^1.0.0"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"exec": "npm run dev",
|
||||
|
@ -47,11 +67,6 @@
|
|||
"*.spec.js"
|
||||
]
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/preset-env"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
},
|
||||
|
|
0
public/css/main.css
Normal file
0
public/css/main.css
Normal file
BIN
public/favicon.png
Normal file
BIN
public/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
1
public/img/404.svg
Normal file
1
public/img/404.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" ?><svg data-name="Layer 1" id="Layer_1" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:#515570;}.cls-2,.cls-3,.cls-4,.cls-5{fill:none;stroke:#00adfe;stroke-miterlimit:10;}.cls-2,.cls-3,.cls-4,.cls-5,.cls-6{stroke-linecap:round;}.cls-2,.cls-5{stroke-width:4px;}.cls-3,.cls-4{stroke-width:3px;}.cls-4{stroke-dasharray:0.09 8.71;}.cls-5{stroke-dasharray:0.09 8.92;}.cls-6{fill:#fff;stroke:#393c54;stroke-linejoin:round;stroke-width:6px;}.cls-7{fill:#f8dc25;}</style></defs><title/><path class="cls-1" d="M41.48,93.8l-1.25,0-.6,14.28a2.07,2.07,0,0,1-1.89,2l-12.65,1.12A2.07,2.07,0,0,1,22.83,109L23.6,94.2,6.21,94.6a2.07,2.07,0,0,1-2.09-2.42L8.93,63.66a2.07,2.07,0,0,1,2-1.73h9.85a2.07,2.07,0,0,1,2,2.44L19.21,84.74l4.92-.15,1.32-26.28a2.07,2.07,0,0,1,2.07-2h12a2.07,2.07,0,0,1,2.07,2.16L40.59,84l.73,0A2.07,2.07,0,0,1,43.5,86v5.71A2.07,2.07,0,0,1,41.48,93.8Z"/><path class="cls-1" d="M121.48,50.8l-1.25,0-.6,14.28a2.07,2.07,0,0,1-1.89,2l-12.65,1.12A2.07,2.07,0,0,1,102.83,66l.77-14.83-17.39.39a2.07,2.07,0,0,1-2.09-2.42l4.81-28.51a2.07,2.07,0,0,1,2-1.73h9.85a2.07,2.07,0,0,1,2,2.44L99.21,41.74l4.92-.15,1.32-26.28a2.07,2.07,0,0,1,2.07-2h12a2.07,2.07,0,0,1,2.07,2.16l-1,25.49.73,0A2.07,2.07,0,0,1,123.5,43v5.71A2.07,2.07,0,0,1,121.48,50.8Z"/><path class="cls-2" d="M75.83,54.64l.69.48a14.84,14.84,0,0,1,4.26,19,11.87,11.87,0,0,1-16.07,4.85,9.5,9.5,0,0,1-3.88-12.86A7.6,7.6,0,0,1,71.12,63a6.08,6.08,0,0,1,2.48,8.23,4.86,4.86,0,0,1-6.58,2,3.89,3.89,0,0,1-1.59-5.27,3.11,3.11,0,0,1,4.21-1.27,2.49,2.49,0,0,1,1,3.37,2,2,0,0,1-2.7.81,1.59,1.59,0,0,1-.65-2.16A1.27,1.27,0,0,1,69,68.14a1,1,0,0,1,.42,1.38"/><path class="cls-3" d="M56,91a23.19,23.19,0,0,1-6.42-29.44,18.55,18.55,0,0,1,21.64-9"/><path class="cls-3" d="M87,92.64l0,0"/><path class="cls-4" d="M78.88,95.74a28.9,28.9,0,0,1-13.12-.21"/><path class="cls-3" d="M61.62,94.16l0,0"/><path class="cls-3" d="M98.32,81.11a28.9,28.9,0,0,1-6.83,8.44"/><path class="cls-2" d="M62.52,85.08A14.84,14.84,0,0,1,56.46,65a11.87,11.87,0,0,1,16.07-4.85A9.5,9.5,0,0,1,76.41,73a7.6,7.6,0,0,1-10.29,3.1,6.08,6.08,0,0,1-2.48-8.23,4.86,4.86,0,0,1,6.58-2,3.89,3.89,0,0,1,1.59,5.27,3.11,3.11,0,0,1-4.21,1.27,2.49,2.49,0,0,1-1-3.37,2,2,0,0,1,2.7-.81,1.59,1.59,0,0,1,.65,2.16,1.27,1.27,0,0,1-1.73.52,1,1,0,0,1-.42-1.38"/><path class="cls-3" d="M61,42.87a28.85,28.85,0,0,1,17.13,3.24A23.18,23.18,0,0,1,87.63,77.5,18.55,18.55,0,0,1,68.4,87.06"/><path class="cls-2" d="M41.49,54l0,0"/><path class="cls-5" d="M48,47.81a29,29,0,0,1,3.93-2.28"/><path class="cls-2" d="M56,43.92h0"/><ellipse class="cls-6" cx="68.42" cy="69.5" rx="7.58" ry="7.43"/><circle class="cls-7" cx="55.22" cy="55.5" r="4"/><path class="cls-7" d="M39.64,81.33l.47-1.2a.4.4,0,0,1,.75,0l.47,1.2a3.63,3.63,0,0,0,2,2l1.2.47a.4.4,0,0,1,0,.75l-1.2.47a3.63,3.63,0,0,0-2,2l-.47,1.2a.4.4,0,0,1-.75,0l-.47-1.2a3.63,3.63,0,0,0-2-2l-1.2-.47a.4.4,0,0,1,0-.75l1.2-.47A3.63,3.63,0,0,0,39.64,81.33Z"/><path class="cls-7" d="M94,48.27l.47-1.2a.4.4,0,0,1,.75,0l.47,1.2a3.63,3.63,0,0,0,2,2l1.2.47a.4.4,0,0,1,0,.75l-1.2.47a3.63,3.63,0,0,0-2,2l-.47,1.2a.4.4,0,0,1-.75,0L94,54.07a3.63,3.63,0,0,0-2-2l-1.2-.47a.4.4,0,0,1,0-.75l1.2-.47A3.63,3.63,0,0,0,94,48.27Z"/><circle class="cls-7" cx="95.61" cy="95.63" r="1.6"/><circle class="cls-7" cx="42.02" cy="63.64" r="1.6"/><circle class="cls-7" cx="85.48" cy="42.04" r="1.6"/></svg>
|
After Width: | Height: | Size: 3.3 KiB |
BIN
public/img/logo.png
Normal file
BIN
public/img/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
0
public/js/main.js
Normal file
0
public/js/main.js
Normal file
115
src/app.js
115
src/app.js
|
@ -1,14 +1,119 @@
|
|||
import express from 'express';
|
||||
import path from 'path';
|
||||
import path from "path";
|
||||
import express from "express";
|
||||
import cookieParser from "cookie-parser";
|
||||
import passport from "passport";
|
||||
import mongoose from "mongoose";
|
||||
import flash from "connect-flash";
|
||||
import session from "express-session";
|
||||
import MongoStore from "connect-mongo";
|
||||
|
||||
import indexRouter from './routes/index';
|
||||
import config, { env, mongoDbUri, secret } from "./config";
|
||||
|
||||
import indexRouter from "./routes/index";
|
||||
|
||||
// Mongoose schema init
|
||||
require("./models/users");
|
||||
|
||||
require("./libs/passport")(passport);
|
||||
|
||||
mongoose
|
||||
.connect(mongoDbUri, { useNewUrlParser: true, useUnifiedTopology: true })
|
||||
.catch(() => {
|
||||
process.exit();
|
||||
});
|
||||
|
||||
const sess = {
|
||||
cookie: {
|
||||
maxAge: 86400000,
|
||||
},
|
||||
secret,
|
||||
saveUninitialized: false,
|
||||
resave: false,
|
||||
store: MongoStore.create({
|
||||
mongoUrl: mongoDbUri,
|
||||
mongoOptions: { useNewUrlParser: true, useUnifiedTopology: true },
|
||||
}),
|
||||
};
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(express.static(path.join(__dirname, '../public')));
|
||||
app.use(cookieParser());
|
||||
app.use(flash());
|
||||
|
||||
app.use('/', indexRouter);
|
||||
app.use(session(sess));
|
||||
|
||||
if (["production"].indexOf(env) !== -1) {
|
||||
app.enable("trust proxy", 1);
|
||||
sess.cookie.secure = true;
|
||||
/* eslint-disable func-names */
|
||||
app.use((req, res, next) => {
|
||||
if (req.secure) {
|
||||
// request was via https, so do no special handling
|
||||
next();
|
||||
} else {
|
||||
// request was via http, so redirect to https
|
||||
res.redirect(`https://${req.headers.host}${req.url}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
|
||||
app.set("views", path.join(__dirname, "views"));
|
||||
app.set("view engine", "ejs");
|
||||
|
||||
app.use(express.static(path.join(__dirname, "../public")));
|
||||
app.use(
|
||||
"/libs/jquery",
|
||||
express.static(path.join(__dirname, "../node_modules/jquery/dist/"))
|
||||
);
|
||||
app.use(
|
||||
"/libs/mdbootstrap",
|
||||
express.static(path.join(__dirname, "../node_modules/mdbootstrap"))
|
||||
);
|
||||
|
||||
app.use("/", indexRouter);
|
||||
|
||||
// Handle 404
|
||||
app.use((req, res) => {
|
||||
if (req.xhr) {
|
||||
res.status(404).send({ message: "404: Not found" });
|
||||
} else {
|
||||
res.status(404).render("error", {
|
||||
page: { title: `404: Cette page n'existe pas.` },
|
||||
errorCode: 404,
|
||||
user: req.user || null,
|
||||
config,
|
||||
session: req.session || null,
|
||||
flashInfo: null,
|
||||
query: null,
|
||||
params: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Handle 500
|
||||
app.use((error, req, res, next) => {
|
||||
if (req.xhr) {
|
||||
res.status(error.errorCode || 500).send({ message: error.message });
|
||||
} else {
|
||||
res.status(500);
|
||||
res.render("error", {
|
||||
page: { title: "500: Oups… le serveur a crashé !", error },
|
||||
errorCode: error.errorCode || 500,
|
||||
user: req.user || null,
|
||||
config,
|
||||
session: req.session || null,
|
||||
flashInfo: null,
|
||||
query: null,
|
||||
params: null,
|
||||
});
|
||||
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
export default app;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
module.exports = {
|
||||
nodeEnv: process.env.NODE_ENV || 'development',
|
||||
port: parseInt(process.env.PORT || '3001', 10),
|
||||
nodeEnv: process.env.NODE_ENV || "development",
|
||||
port: parseInt(process.env.PORT || "3001", 10),
|
||||
mongoDbUri: process.env.MONGODB_URI || "mongodb://nodecdtheque-db/cdtheque",
|
||||
secret: process.env.SECRET || "waemaeMe5ahc6ce1chaeKohKa6Io8Eik",
|
||||
};
|
||||
|
|
3
src/helpers/index.js
Normal file
3
src/helpers/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
export const getBaseUrl = (req) => `${req.protocol}://${req.get("host")}`;
|
3
src/libs/format.js
Normal file
3
src/libs/format.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export default (res, page) => {
|
||||
res.status(200).render("index", page.render());
|
||||
};
|
39
src/libs/passport.js
Normal file
39
src/libs/passport.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* eslint-disable func-names */
|
||||
const mongoose = require("mongoose");
|
||||
const LocalStrategy = require("passport-local").Strategy;
|
||||
|
||||
const Users = mongoose.model("Users");
|
||||
|
||||
module.exports = function (passport) {
|
||||
passport.serializeUser((user, done) => {
|
||||
done(null, user);
|
||||
});
|
||||
|
||||
passport.deserializeUser((user, done) => {
|
||||
done(null, user);
|
||||
});
|
||||
passport.use(
|
||||
"user",
|
||||
new LocalStrategy(
|
||||
{
|
||||
usernameField: "email",
|
||||
passwordField: "password",
|
||||
},
|
||||
(email, password, done) => {
|
||||
Users.findOne({ email })
|
||||
.then((user) => {
|
||||
if (!user || !user.validPassword(password)) {
|
||||
return done(
|
||||
null,
|
||||
false,
|
||||
"Oops! Identifiants incorrects"
|
||||
);
|
||||
}
|
||||
|
||||
return done(null, user);
|
||||
})
|
||||
.catch(done);
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
44
src/middleware/Auth.js
Normal file
44
src/middleware/Auth.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
import Pages from "./Pages";
|
||||
|
||||
import Users from "../models/users";
|
||||
|
||||
/**
|
||||
* Classe permettant la gestion des utilisateurs
|
||||
*/
|
||||
class Auth extends Pages {
|
||||
/**
|
||||
* Méthode permettant de créer un nouvel utilisateur
|
||||
* @param {Req} req
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
static async register(req) {
|
||||
try {
|
||||
const { username, email, password } = req.body;
|
||||
const user = new Users({
|
||||
username,
|
||||
email,
|
||||
salt: password,
|
||||
});
|
||||
|
||||
const resUser = await user.save();
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
req.login(resUser, (errLogin) => {
|
||||
if (errLogin) {
|
||||
return reject(errLogin);
|
||||
}
|
||||
|
||||
return resolve(null);
|
||||
});
|
||||
});
|
||||
|
||||
return resUser;
|
||||
} catch (err) {
|
||||
req.flash("error", err.toString());
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Auth;
|
62
src/middleware/Pages.js
Normal file
62
src/middleware/Pages.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
import config from "../config";
|
||||
import { getBaseUrl } from "../helpers";
|
||||
|
||||
/**
|
||||
* Classe permettant de gérer les page du back office
|
||||
*/
|
||||
class Pages {
|
||||
/**
|
||||
* @param {Object} req
|
||||
* @param {String} viewname
|
||||
*/
|
||||
constructor(req, viewname) {
|
||||
this.req = req;
|
||||
this.pageContent = {
|
||||
page: {
|
||||
title: null,
|
||||
user: null,
|
||||
},
|
||||
viewname: `pages/${viewname}`,
|
||||
};
|
||||
|
||||
this.user = null;
|
||||
this.pagename = viewname;
|
||||
|
||||
if (req.session && req.session.passport && req.session.passport.user) {
|
||||
this.user = req.session.passport.user;
|
||||
}
|
||||
|
||||
if (!req.query.page) {
|
||||
req.query.page = 1;
|
||||
}
|
||||
if (!req.query.limit) {
|
||||
req.query.limit = config.pagination;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendu de la page
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
this.pageContent.session = this.req.session;
|
||||
this.pageContent.flashInfo = this.req.flash("info");
|
||||
this.pageContent.error = this.req.flash("error") || null;
|
||||
this.pageContent.query = this.req.query;
|
||||
this.pageContent.params = this.req.params;
|
||||
this.pageContent.user = this.user;
|
||||
this.pageContent.config = config;
|
||||
this.pageContent.getBaseUrl = getBaseUrl();
|
||||
|
||||
if (this.req.session.flash && this.req.session.flash.error) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
this.pageContent.page.failureFlash =
|
||||
this.req.session.flash.error[0];
|
||||
this.req.session.flash = null;
|
||||
}
|
||||
|
||||
return this.pageContent;
|
||||
}
|
||||
}
|
||||
|
||||
export default Pages;
|
58
src/models/users.js
Normal file
58
src/models/users.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* eslint-disable func-names */
|
||||
/* eslint-disable no-invalid-this */
|
||||
import mongoose from "mongoose";
|
||||
import uniqueValidator from "mongoose-unique-validator";
|
||||
import crypto from "crypto";
|
||||
|
||||
const UserSchema = new mongoose.Schema(
|
||||
{
|
||||
username: {
|
||||
type: String,
|
||||
unique: true,
|
||||
required: [true, "est requis"],
|
||||
match: [/^[a-zA-Z0-9]+$/, "est invalide"],
|
||||
index: true,
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
lowercase: true,
|
||||
unique: true,
|
||||
required: [true, "est requis"],
|
||||
match: [/\S+@\S+\.\S+/, "est invalide"],
|
||||
index: true,
|
||||
},
|
||||
hash: String,
|
||||
salt: String,
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
UserSchema.plugin(uniqueValidator, { message: "est déjà utilisé" });
|
||||
|
||||
UserSchema.methods.validPassword = function (password) {
|
||||
const [salt, key] = this.hash.split(":");
|
||||
|
||||
return key === crypto.scryptSync(password, salt, 64).toString("hex");
|
||||
};
|
||||
|
||||
UserSchema.pre("save", function (next) {
|
||||
const user = this;
|
||||
|
||||
if (!user.isModified("salt")) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const salt = crypto.randomBytes(16).toString("hex");
|
||||
|
||||
return crypto.scrypt(user.salt, salt, 64, (err, derivedKey) => {
|
||||
if (err) {
|
||||
next(err);
|
||||
}
|
||||
this.salt = salt;
|
||||
this.hash = `${salt}:${derivedKey.toString("hex")}`;
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
export default mongoose.model("Users", UserSchema);
|
|
@ -1,11 +1,82 @@
|
|||
import express from 'express';
|
||||
import express from "express";
|
||||
import passport from "passport";
|
||||
import { ensureLoggedIn } from "connect-ensure-login";
|
||||
|
||||
import Pages from "../middleware/Pages";
|
||||
import Auth from "../middleware/Auth";
|
||||
|
||||
import render from "../libs/format";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const router = express.Router();
|
||||
|
||||
/* GET home page. */
|
||||
router.get('/', function(req, res, next) {
|
||||
res.render('index', {title: 'World'});
|
||||
router
|
||||
.route("/")
|
||||
.get(ensureLoggedIn("/connexion"), (req, res) =>
|
||||
res.redirect("/ma-collection")
|
||||
);
|
||||
|
||||
router
|
||||
.route("/connexion")
|
||||
.get((req, res, next) => {
|
||||
try {
|
||||
const page = new Pages(req, "connexion");
|
||||
|
||||
render(res, page);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
})
|
||||
.post(
|
||||
passport.authenticate("user", {
|
||||
failureRedirect: "/connexion",
|
||||
failureFlash: true,
|
||||
}),
|
||||
(req, res) => {
|
||||
const { next, query } = req.body;
|
||||
let url = `/${next}`;
|
||||
|
||||
if (next) {
|
||||
if (query) {
|
||||
const params = JSON.parse(query);
|
||||
Object.keys(params).forEach((key) => {
|
||||
url += `${url.indexOf("?") === -1 ? "?" : "&"}${key}=${
|
||||
params[key]
|
||||
}`;
|
||||
});
|
||||
}
|
||||
return res.redirect(url);
|
||||
}
|
||||
return res.redirect("/");
|
||||
}
|
||||
);
|
||||
|
||||
router
|
||||
.route("/inscription")
|
||||
.get((req, res, next) => {
|
||||
try {
|
||||
const page = new Pages(req, "inscription");
|
||||
|
||||
render(res, page);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
})
|
||||
.post(async (req, res) => {
|
||||
try {
|
||||
await Auth.register(req);
|
||||
|
||||
res.redirect("/");
|
||||
} catch (err) {
|
||||
res.redirect("/inscription");
|
||||
}
|
||||
});
|
||||
|
||||
router.route("/se-deconnecter").get((req, res) => {
|
||||
req.logout();
|
||||
req.session.destroy(() => {
|
||||
res.redirect("/");
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
|
23
src/views/error.ejs
Normal file
23
src/views/error.ejs
Normal file
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<%- include('partials/head', {page: page, user: user}); %>
|
||||
|
||||
<body class="error">
|
||||
<%- include('partials/header'); %>
|
||||
<main class="mt-4">
|
||||
<div class="container">
|
||||
<section class="px-md-5 mx-md-5 dark-grey-text mb-4">
|
||||
<h1><%= page.title %></h1>
|
||||
<% if ( errorCode && errorCode === 404 ) { %>
|
||||
<img src="/img/404.svg" alt="Erreur 404" style="max-height: 400px;" />
|
||||
<% } %>
|
||||
<p class="lead">
|
||||
<%= page.error %>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<%- include('partials/footer', {page: page, user: user, blog: null}); %>
|
||||
</body>
|
||||
|
||||
</html>
|
26
src/views/index.ejs
Normal file
26
src/views/index.ejs
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<%- include('partials/head'); %>
|
||||
<body>
|
||||
<%- include('partials/header'); %>
|
||||
|
||||
<% if ( page.failureFlash ) {%>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<%= page.failureFlash %>
|
||||
</div>
|
||||
<% } %>
|
||||
<%
|
||||
if (error && error.length > 0) {
|
||||
for( let i = 0 ; i < error.length ; i += 1 ) {
|
||||
%>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<%= error %>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
}
|
||||
%>
|
||||
<%- include(viewname) %>
|
||||
<%- include('partials/footer'); %>
|
||||
</body>
|
||||
</html>
|
26
src/views/pages/connexion.ejs
Normal file
26
src/views/pages/connexion.ejs
Normal file
|
@ -0,0 +1,26 @@
|
|||
<div class="container">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="p-2">
|
||||
<form class="text-center border border-light p-5" method="POST">
|
||||
<img class="mb-4" src="/img/logo.png" alt="DarKou">
|
||||
<p class="h4 mb-4">Connexion</p>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="email" id="email" name="email" class="form-control" required>
|
||||
<label for="email">Adresse e-mail</label>
|
||||
</div>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="password" id="password" name="password" class="form-control" required>
|
||||
<label for="password">Mot de passe</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary btn-block my-4" type="submit">Connexion</button>
|
||||
|
||||
<p>Pas encore inscrit ?
|
||||
<a href="/inscription">Inscrivez-vous</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
31
src/views/pages/inscription.ejs
Normal file
31
src/views/pages/inscription.ejs
Normal file
|
@ -0,0 +1,31 @@
|
|||
<div class="container">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="p-2">
|
||||
<form class="text-center border border-light p-5" method="POST">
|
||||
<img class="mb-4" src="/img/logo.png" alt="DarKou">
|
||||
<p class="h4 mb-4">Inscription</p>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="text" id="username" name="username" class="form-control" required>
|
||||
<label for="username">Nom d'utilisateur</label>
|
||||
</div>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="email" id="email" name="email" class="form-control" required>
|
||||
<label for="email">Adresse e-mail</label>
|
||||
</div>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="password" id="password" name="password" class="form-control" required>
|
||||
<label for="password">Mot de passe</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary btn-block my-4" type="submit">Inscription</button>
|
||||
|
||||
<p>Déjà inscrit ?
|
||||
<a href="/connexion">Connectez-vous</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
5
src/views/partials/footer.ejs
Normal file
5
src/views/partials/footer.ejs
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script type="text/javascript" src="/libs/mdbootstrap/js/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/libs/mdbootstrap/js/popper.min.js"></script>
|
||||
<script type="text/javascript" src="/libs/mdbootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="/libs/mdbootstrap/js/mdb.min.js"></script>
|
||||
<script type="text/javascript" src="/js/main.js"></script>
|
18
src/views/partials/head.ejs
Normal file
18
src/views/partials/head.ejs
Normal file
|
@ -0,0 +1,18 @@
|
|||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title><% if (page.title) { %><%= page.title %> <% } else { %> DarKou - Ma CDThèque <% } %></title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.11.2/css/all.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/libs/mdbootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/libs/mdbootstrap/css/mdb.min.css">
|
||||
<link rel="stylesheet" href="/libs/mdbootstrap/css/style.css">
|
||||
|
||||
<link rel="stylesheet" href="/css/main.css" />
|
||||
</head>
|
25
src/views/partials/header.ejs
Normal file
25
src/views/partials/header.ejs
Normal file
|
@ -0,0 +1,25 @@
|
|||
<nav class="navbar navbar-expand-md navbar-dark primary-color sticky-top">
|
||||
<a class="navbar-brand" href="/">CDThèque</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<% if ( user ) { %>
|
||||
<div class="navbar-collapse collapse w-100 order-1 dual-collapse2">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/upload">Ajouter une image</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true"
|
||||
aria-expanded="false">Mon compte</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="/gallery">Mes images</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/se-deconnecter">Déconnexion</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
</nav>
|
Loading…
Reference in a new issue