Merge branch 'master' into 'vFront'
# Conflicts: # views/template/layout.pug
4
.gitignore
vendored
|
@ -112,3 +112,7 @@ config/config.json
|
||||||
|
|
||||||
# Sass output
|
# Sass output
|
||||||
public/stylesheets
|
public/stylesheets
|
||||||
|
|
||||||
|
# Floobits
|
||||||
|
.floo
|
||||||
|
.flooignore
|
||||||
|
|
18
agenda/index.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
const { Worker } = require("worker_threads");
|
||||||
|
let nb = 0;
|
||||||
|
|
||||||
|
|
||||||
|
function startWorker(workerArgs) {
|
||||||
|
let worker = new Worker(...workerArgs);
|
||||||
|
worker.on("error", (err) => {
|
||||||
|
console.error(err);
|
||||||
|
nb--;
|
||||||
|
if (nb > 0)
|
||||||
|
startWorker(workerArgs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const workerArgs = ["./agenda/worker.js", {workerData: app.get("config")}];
|
||||||
|
startWorker(workerArgs);
|
||||||
|
};
|
227
agenda/worker.js
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
const https = require("https");
|
||||||
|
const config = require("worker_threads").workerData;
|
||||||
|
const models = require("../models");
|
||||||
|
|
||||||
|
const reg_event = /(?:(?:BEGIN:VEVENT\nDTSTAMP:(?:[A-Z0-9]*?)\nDTSTART:([A-Z0-9]*?)\nDTEND:([A-Z0-9]*?)\nSUMMARY: {0,}([a-zéèàA-Z0-9-. \, \\/ô]*?)\nLOCATION:([a-zA-Zéèà0-9-. \,\\]*?)\nDESCRIPTION:(?:\\n){0,}((?:(?:LP(?:[ a-zA-Z0-9\\]*?))\\n){1,})((?:(?:[A-Z]*) (?:[A-Z]*)(?: (?:[A-Z]*)){0,}\\n){0,})(?:.*?)\nEND:VEVENT)|(?:BEGIN:VEVENT\nDTSTAMP:(?:[A-Z0-9]*?)\nDTSTART:([A-Z0-9]*?)\nDTEND:([A-Z0-9]*?)\nSUMMARY: {0,}((?:S(?:[A-Z0-9-]*)|M(?:[A-Z0-9-]*)(?:\/M(?:[A-Z0-9-]*)){0,}|Conférence)[a-zéèàA-Z0-9-. \, \\/]*?)\nLOCATION:([a-zA-Zéèà0-9-. \,\\]*?)\nDESCRIPTION:(?:\\n){0,}((?:(?:G[0-9]S[0-9]|S[0-9]|ASPE)\\n){0,})((?:(?:[A-Z]*) (?:[A-Z]*)(?: (?:[A-Z]*)){0,}\\n){0,})(?:.*?)\nEND:VEVENT))/gs;
|
||||||
|
const reg_location = /((?:[SH0-9][0-9]{2})|(?:(?:Préfa |Amphi)[0-9]))/g;
|
||||||
|
const reg_teachers = /^(?:((?:[a-zA-Z]*[ -]{0,}){0,}) ([a-zA-Z]*))$/m;
|
||||||
|
const reg_date = /([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})Z/;
|
||||||
|
const reg_group = /(?:(LP)[ -]{0,}(.*)|(?:(G[0-9])(S[0-9])))/;
|
||||||
|
const base_url = config["edt"];
|
||||||
|
const capitalizeFirstLetter = (string) => string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
|
||||||
|
|
||||||
|
|
||||||
|
function fetchEvents(days = 1, TS_Start = new Date()) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let start = new Date(TS_Start);
|
||||||
|
if (start == "Invalid Date")
|
||||||
|
start = new Date();
|
||||||
|
let end = new Date(start);
|
||||||
|
end.setDate(end.getDate() + days);
|
||||||
|
|
||||||
|
let url = base_url + start.getFullYear() + "-" + start.getMonth() + "-" + start.getDate() + "&lastDate=" + end.getFullYear() + "-" + end.getMonth() + "-" + end.getDate();
|
||||||
|
https.get(url, (resp) => {
|
||||||
|
let data = "";
|
||||||
|
resp.on("data", (chunk) => {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
resp.on("end", () => {
|
||||||
|
let output = [];
|
||||||
|
data = data.replace(/\r/g, "");
|
||||||
|
let m;
|
||||||
|
while ((m = reg_event.exec(data)) !== null) {
|
||||||
|
if (m.index === reg_event.lastIndex) {
|
||||||
|
reg_event.lastIndex++;
|
||||||
|
}
|
||||||
|
let event = [];
|
||||||
|
let semester = [];
|
||||||
|
let group = [];
|
||||||
|
/*
|
||||||
|
m = [
|
||||||
|
FullMatch,
|
||||||
|
StartTime,
|
||||||
|
EndTime,
|
||||||
|
EventDescription ( SubjectID,Name,Class?) ,
|
||||||
|
Location,
|
||||||
|
ClassGroup,
|
||||||
|
Teacher(s)
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
if (m[1] !== undefined) {
|
||||||
|
// LPXXXX
|
||||||
|
} else {
|
||||||
|
m.splice(1, 6);
|
||||||
|
// GXSX | SX | ASPE
|
||||||
|
}
|
||||||
|
let csplit = m[5].split("\\n");
|
||||||
|
csplit.pop();
|
||||||
|
csplit.forEach(e => {
|
||||||
|
if (e === "ASPE") {
|
||||||
|
semester.push(e);
|
||||||
|
}else if(/^S[0-9]$/.test(e)) {
|
||||||
|
semester.push(e);
|
||||||
|
}else{
|
||||||
|
let groupSplit = reg_group.exec(e);
|
||||||
|
if (groupSplit[1] === 'LP') {
|
||||||
|
group.push([groupSplit[2], groupSplit[1]]);
|
||||||
|
} else {
|
||||||
|
group.push([groupSplit[3], groupSplit[4]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
event["title"] = m[3];
|
||||||
|
event["semesters"] = semester;
|
||||||
|
event["groups"] = group;
|
||||||
|
/*
|
||||||
|
Date
|
||||||
|
*/
|
||||||
|
let d1 = reg_date.exec(m[1]);
|
||||||
|
let d2 = reg_date.exec(m[2]);
|
||||||
|
event["startDate"] = new Date(d1[1] + "-" + d1[2] + "-" + d1[3] + "T" + d1[4] + ":" + d1[5] + ":" + d1[6] + ".00Z");
|
||||||
|
event["endDate"] = new Date(d2[1] + "-" + d2[2] + "-" + d2[3] + "T" + d2[4] + ":" + d2[5] + ":" + d2[6] + ".00Z");
|
||||||
|
/*
|
||||||
|
Location
|
||||||
|
*/
|
||||||
|
event["locations"] = [];
|
||||||
|
let loc;
|
||||||
|
while ((loc = reg_location.exec(m[4])) !== null) {
|
||||||
|
if (loc.index === reg_location.lastIndex) {
|
||||||
|
reg_location.lastIndex++;
|
||||||
|
}
|
||||||
|
event["locations"].push(loc[1]);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Teachers
|
||||||
|
*/
|
||||||
|
event['teachers'] = [];
|
||||||
|
let fullTeachers = m[6].split('\\n');
|
||||||
|
fullTeachers.forEach(e => {
|
||||||
|
if(e !== ""){
|
||||||
|
let splittedTeachers = reg_teachers.exec(e);
|
||||||
|
event['teachers'].push([splittedTeachers[1],splittedTeachers[2]]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
output.push(event);
|
||||||
|
}
|
||||||
|
resolve(output);
|
||||||
|
});
|
||||||
|
}).on("error", (err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function compare(a, b) {
|
||||||
|
if (a.length !== b.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let set = {};
|
||||||
|
a.forEach((i) => {
|
||||||
|
if (set[i] !== undefined) {
|
||||||
|
set[i]++;
|
||||||
|
} else {
|
||||||
|
set[i] = 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let difference = b.every((i) => {
|
||||||
|
if (set[i] === undefined) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
set[i]--;
|
||||||
|
if (set[i] === 0) {
|
||||||
|
delete set[i];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Object.keys(set) == 0 && difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareGroups(list1, list2) {
|
||||||
|
return compare(list1.map(g => g[0] + " " + g[1]), list2.map(g => g.number + " " + g.Semester.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareTeachers(list1, list2) {
|
||||||
|
return compare(list1.map(t => t[0].toUpperCase() + " " + t[1].toUpperCase()), list2.map(t => t.lastName.toUpperCase() + " " + t.firstName.toUpperCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareSemesters(list1, list2) {
|
||||||
|
return compare(list1, list2.map(s => s.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateDatabase() {
|
||||||
|
let events = await fetchEvents(365, new Date(2020, 9, 1));
|
||||||
|
for (let event of await models.Event.findAll({
|
||||||
|
include: [{
|
||||||
|
model: models.Group,
|
||||||
|
include: {model: models.Semester, required: true}
|
||||||
|
}, models.User, models.Semester]
|
||||||
|
})) {
|
||||||
|
let ev = events.find(e => (e.title === event.name && e.startDate.getTime() === event.startDate.getTime() &&
|
||||||
|
e.endDate.getTime() === event.endDate.getTime() && e.locations.join(", ") === event.locations &&
|
||||||
|
compareGroups(e.groups, event.Groups) && compareTeachers(e.teachers, event.Users) &&
|
||||||
|
compareSemesters(e.semesters, event.Semesters)));
|
||||||
|
if (!ev)
|
||||||
|
await event.destroy();
|
||||||
|
else
|
||||||
|
events = events.filter(e => e !== ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let event of events) {
|
||||||
|
let e = await models.Event.create({
|
||||||
|
name: event.title,
|
||||||
|
startDate: event.startDate,
|
||||||
|
endDate: event.endDate,
|
||||||
|
locations: event.locations.join(", ")
|
||||||
|
});
|
||||||
|
|
||||||
|
let teachers = [];
|
||||||
|
for (let teacher of event.teachers) {
|
||||||
|
let t = await models.User.findOne({where: {permissions: 2, lastName: teacher[0].toUpperCase(), firstName: capitalizeFirstLetter(teacher[1])}});
|
||||||
|
if (!t)
|
||||||
|
t = await models.User.create({
|
||||||
|
email: teacher[1].toLowerCase().replaceAll(" ", "-") + "." + teacher[0].toLowerCase().replaceAll(" ", "-") + "@univ-lyon1.fr",
|
||||||
|
firstName: capitalizeFirstLetter(teacher[1]),
|
||||||
|
lastName: teacher[0].toUpperCase(),
|
||||||
|
permissions: 2,
|
||||||
|
passwordHash: Math.round((Math.pow(36, 12 + 1) - Math.random() * Math.pow(36, 12))).toString(36).slice(1)
|
||||||
|
});
|
||||||
|
teachers.push(t);
|
||||||
|
}
|
||||||
|
await e.addUsers(teachers);
|
||||||
|
|
||||||
|
let semesters = [];
|
||||||
|
for (let semester of event.semesters) {
|
||||||
|
let s = await models.Semester.findOne({where: {name: semester, year: event.startDate.getFullYear()}});
|
||||||
|
if (!s)
|
||||||
|
s = await models.Semester.create({
|
||||||
|
name: semester,
|
||||||
|
year: event.startDate.getFullYear()
|
||||||
|
});
|
||||||
|
semesters.push(s);
|
||||||
|
}
|
||||||
|
await e.addSemesters(semesters);
|
||||||
|
|
||||||
|
let groups = [];
|
||||||
|
for (let group of event.groups) {
|
||||||
|
let s = await models.Semester.findOne({where: {name: group[1], year: event.startDate.getFullYear()}});
|
||||||
|
if (!s)
|
||||||
|
s = await models.Semester.create({
|
||||||
|
name: group[1],
|
||||||
|
year: event.startDate.getFullYear()
|
||||||
|
});
|
||||||
|
|
||||||
|
let g = await models.Group.findOne({where: {number: group[0], SemesterId: s.id}});
|
||||||
|
if (!g)
|
||||||
|
g = await models.Group.create({
|
||||||
|
number: group[0],
|
||||||
|
SemesterId: s.id
|
||||||
|
});
|
||||||
|
groups.push(g);
|
||||||
|
}
|
||||||
|
await e.addGroups(groups);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDatabase().then(() => setInterval(updateDatabase, 30000));
|
6
app.js
|
@ -9,11 +9,10 @@ let config = process.env.NODE_ENV === "test" ? {} : require("./config/config.jso
|
||||||
let indexRouter = require("./routes/index");
|
let indexRouter = require("./routes/index");
|
||||||
const loginRouter = require("./routes/login");
|
const loginRouter = require("./routes/login");
|
||||||
const edtRouter = require("./routes/edt");
|
const edtRouter = require("./routes/edt");
|
||||||
const homeRouter = require("./routes/home");
|
|
||||||
const marksRouter = require("./routes/marks");
|
const marksRouter = require("./routes/marks");
|
||||||
const registerRouter = require("./routes/register");
|
const registerRouter = require("./routes/register");
|
||||||
const viescolRouter = require("./routes/viescol")
|
const viescolRouter = require("./routes/viescol");
|
||||||
const profilRouter = require("./routes/profil")
|
const profilRouter = require("./routes/profil");
|
||||||
|
|
||||||
let app = express();
|
let app = express();
|
||||||
const sessionMiddleware = session({
|
const sessionMiddleware = session({
|
||||||
|
@ -41,7 +40,6 @@ app.use("/", indexRouter);
|
||||||
app.use("/login", loginRouter);
|
app.use("/login", loginRouter);
|
||||||
app.use("/email", require("./routes/email"));
|
app.use("/email", require("./routes/email"));
|
||||||
app.use("/edt", edtRouter);
|
app.use("/edt", edtRouter);
|
||||||
app.use("/home", homeRouter);
|
|
||||||
app.use("/marks", marksRouter);
|
app.use("/marks", marksRouter);
|
||||||
app.use('/register', registerRouter);
|
app.use('/register', registerRouter);
|
||||||
app.use('/viescol', viescolRouter);
|
app.use('/viescol', viescolRouter);
|
||||||
|
|
15
bin/www
|
@ -17,7 +17,7 @@ const mailClient = new SMTPClient(process.env.NODE_ENV === "test" ? {} : require
|
||||||
/**
|
/**
|
||||||
* Render all Sass to css
|
* Render all Sass to css
|
||||||
*/
|
*/
|
||||||
css = sass.renderSync({
|
let css = sass.renderSync({
|
||||||
file: "sass/style.sass",
|
file: "sass/style.sass",
|
||||||
includePaths: ["sass/"],
|
includePaths: ["sass/"],
|
||||||
outputStyle: "compressed"
|
outputStyle: "compressed"
|
||||||
|
@ -30,7 +30,7 @@ fs.writeFileSync("public/stylesheets/style.css", css.css);
|
||||||
* Get port from environment and store in Express.
|
* Get port from environment and store in Express.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let port = normalizePort(process.env.PORT || "3000");
|
const port = normalizePort(process.env.PORT || "3000");
|
||||||
app.set("port", port);
|
app.set("port", port);
|
||||||
app.set("mailClient", mailClient);
|
app.set("mailClient", mailClient);
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ app.set("mailClient", mailClient);
|
||||||
* Create HTTP server.
|
* Create HTTP server.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create socket.io server
|
* Create socket.io server
|
||||||
|
@ -66,7 +66,7 @@ models.sequelize.sync().then(() => {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function normalizePort(val) {
|
function normalizePort(val) {
|
||||||
let port = parseInt(val, 10);
|
const port = parseInt(val, 10);
|
||||||
|
|
||||||
if (isNaN(port)) {
|
if (isNaN(port)) {
|
||||||
// named pipe
|
// named pipe
|
||||||
|
@ -90,7 +90,7 @@ function onError(error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bind = typeof port === "string"
|
const bind = typeof port === "string"
|
||||||
? "Pipe " + port
|
? "Pipe " + port
|
||||||
: "Port " + port;
|
: "Port " + port;
|
||||||
|
|
||||||
|
@ -114,9 +114,10 @@ function onError(error) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function onListening() {
|
function onListening() {
|
||||||
let addr = server.address();
|
const addr = server.address();
|
||||||
let bind = typeof addr === "string"
|
const bind = typeof addr === "string"
|
||||||
? "pipe " + addr
|
? "pipe " + addr
|
||||||
: "port " + addr.port;
|
: "port " + addr.port;
|
||||||
debug("Listening on " + bind);
|
debug("Listening on " + bind);
|
||||||
|
require("../agenda")(app);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"contact": "Your Contact <contact@your-email.fr>",
|
"contact": "Your Contact <contact@your-email.fr>",
|
||||||
"mailPath": "https://yourServer.com"
|
"mailPath": "https://yourServer.com"
|
||||||
},
|
},
|
||||||
|
"edt": "https://adelb.univ-lyon1.fr/jsp/custom/modules/plannings/anonymous_cal.jsp?resources=XXXX&projectId=XXXX&calType=ical&firstDate=",
|
||||||
"secret": "keyboard cat",
|
"secret": "keyboard cat",
|
||||||
"passwordPrivateKey": "ecc635295f200847b79299df48e15759"
|
"passwordPrivateKey": "ecc635295f200847b79299df48e15759"
|
||||||
}
|
}
|
||||||
|
|
23
models/UE.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Model } = require("sequelize");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
class UE extends Model {
|
||||||
|
static associate(models) {
|
||||||
|
UE.hasMany(models.Event);
|
||||||
|
UE.belongsToMany(models.User, {through: "UEUser"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UE.init({
|
||||||
|
name : {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
unique: true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: "UE",
|
||||||
|
});
|
||||||
|
return UE;
|
||||||
|
};
|
27
models/evaluation.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Model } = require("sequelize");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
class Evaluation extends Model {
|
||||||
|
static associate(models) {
|
||||||
|
Evaluation.belongsToMany(models.User, {through: "EvaluationTeacher"});
|
||||||
|
Evaluation.hasMany(models.Grade);
|
||||||
|
Evaluation.belongsTo(models.UE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Evaluation.init({
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: false
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: "Evaluation",
|
||||||
|
});
|
||||||
|
return Evaluation;
|
||||||
|
};
|
36
models/event.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Model } = require("sequelize");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
class Event extends Model {
|
||||||
|
static associate(models) {
|
||||||
|
Event.belongsToMany(models.Semester, {through: "EventSemester"});
|
||||||
|
Event.belongsToMany(models.Group, {through: "EventGroup"});
|
||||||
|
Event.belongsToMany(models.User, {through: "EventTeacher"});
|
||||||
|
Event.belongsTo(models.UE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event.init({
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
locations: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
startDate: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: false
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: "Event",
|
||||||
|
});
|
||||||
|
return Event;
|
||||||
|
};
|
30
models/grade.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Model } = require("sequelize");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
class Grade extends Model {
|
||||||
|
static associate(models) {
|
||||||
|
Grade.belongsTo(models.Evaluation);
|
||||||
|
Grade.belongsTo(models.User, {as: "TeacherGrade"});
|
||||||
|
Grade.belongsTo(models.User, {as: "StudentGrade"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Grade.init({
|
||||||
|
score: {
|
||||||
|
type: DataTypes.FLOAT,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
type: DataTypes.FLOAT,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
type: DataTypes.TEXT
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: "Grade",
|
||||||
|
});
|
||||||
|
return Grade;
|
||||||
|
};
|
23
models/group.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Model } = require("sequelize");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
class Group extends Model {
|
||||||
|
static associate(models) {
|
||||||
|
Group.belongsTo(models.Semester);
|
||||||
|
Group.belongsToMany(models.User, {through: "UserGroup"});
|
||||||
|
Group.belongsToMany(models.Event, {through: "EventGroup"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Group.init({
|
||||||
|
number: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: "Group",
|
||||||
|
});
|
||||||
|
return Group;
|
||||||
|
};
|
28
models/semester.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Model } = require("sequelize");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
class Semester extends Model {
|
||||||
|
static associate(models) {
|
||||||
|
Semester.hasMany(models.Group);
|
||||||
|
Semester.belongsToMany(models.Event, {through: "EventSemester"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Semester.init({
|
||||||
|
year: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
unique: "semester"
|
||||||
|
},
|
||||||
|
name : {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
unique: "semester"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
sequelize,
|
||||||
|
modelName: "Semester",
|
||||||
|
});
|
||||||
|
return Semester;
|
||||||
|
};
|
|
@ -8,7 +8,7 @@ const {
|
||||||
} = require("sequelize");
|
} = require("sequelize");
|
||||||
module.exports = (sequelize, DataTypes) => {
|
module.exports = (sequelize, DataTypes) => {
|
||||||
function hash(password, email) {
|
function hash(password, email) {
|
||||||
let cipher = crypto.createCipheriv(
|
const cipher = crypto.createCipheriv(
|
||||||
"aes-256-cbc",
|
"aes-256-cbc",
|
||||||
privateKey,
|
privateKey,
|
||||||
crypto.createHash("md5").update(email).digest("base64").slice(0, 16)
|
crypto.createHash("md5").update(email).digest("base64").slice(0, 16)
|
||||||
|
@ -18,6 +18,12 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
|
|
||||||
class User extends Model {
|
class User extends Model {
|
||||||
static associate(models) {
|
static associate(models) {
|
||||||
|
User.belongsToMany(models.Group, {through: "UserGroup"});
|
||||||
|
User.belongsToMany(models.Event, {through: "EventTeacher"});
|
||||||
|
User.belongsToMany(models.Evaluation, {through: "EvaluationTeacher"});
|
||||||
|
User.belongsToMany(models.UE, {through: "UEUser"});
|
||||||
|
//User.hasMany(models.Grade, {as : "TeacherGrade"});
|
||||||
|
//User.hasMany(models.Grade, {as: "StudentGrade"});
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPassword(password) {
|
checkPassword(password) {
|
||||||
|
|
9
public/browserconfig.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square150x150logo src="/images/mstile-150x150.png"/>
|
||||||
|
<TileColor>#da532c</TileColor>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
BIN
public/images/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
public/images/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
public/images/favicon-16x16.png
Normal file
After Width: | Height: | Size: 626 B |
BIN
public/images/favicon-32x32.png
Normal file
After Width: | Height: | Size: 1,005 B |
BIN
public/images/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
public/images/mstile-150x150.png
Normal file
After Width: | Height: | Size: 3 KiB |
169
public/images/safari-pinned-tab.svg
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="768.000000pt" height="768.000000pt" viewBox="0 0 768.000000 768.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
<metadata>
|
||||||
|
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||||
|
</metadata>
|
||||||
|
<g transform="translate(0.000000,768.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M0 3840 l0 -3440 3840 0 3840 0 0 234 c0 159 -4 237 -11 242 -14 8
|
||||||
|
-119 11 -119 3 0 -4 -15 -4 -32 -2 -18 3 -39 4 -45 4 -15 -1 -58 -1 -75 0 -7
|
||||||
|
0 -29 0 -48 0 -19 -1 -43 -1 -52 -1 -39 0 -54 0 -83 -1 -16 0 -39 0 -50 1 -11
|
||||||
|
1 -26 1 -32 1 -22 -1 -37 -2 -83 -1 -25 0 -61 -1 -80 -2 -19 -2 -45 0 -57 4
|
||||||
|
-12 4 -25 3 -28 -3 -4 -5 -11 -6 -17 -3 -14 9 -118 11 -118 2 0 -4 -13 -3 -29
|
||||||
|
2 -15 4 -33 5 -39 1 -13 -8 -87 -5 -101 4 -5 3 -12 1 -16 -5 -4 -6 -11 -8 -16
|
||||||
|
-4 -6 3 -32 6 -57 5 -46 -1 -85 -2 -137 -1 -14 0 -31 0 -37 -1 -7 0 -35 1 -63
|
||||||
|
1 -27 0 -66 -1 -85 -3 -19 -1 -45 1 -57 5 -12 4 -25 3 -28 -3 -4 -5 -11 -6
|
||||||
|
-17 -3 -13 8 -118 11 -118 3 0 -4 -15 -4 -32 -2 -18 3 -39 4 -45 4 -7 0 -24
|
||||||
|
-1 -38 -1 -14 0 -32 0 -40 0 -8 0 -27 0 -42 1 -16 0 -37 -1 -48 -1 -11 -1 -24
|
||||||
|
-1 -30 -1 -43 1 -116 1 -145 -2 -19 -1 -45 1 -57 5 -12 4 -25 3 -28 -3 -4 -5
|
||||||
|
-11 -6 -17 -3 -13 8 -118 11 -118 3 0 -4 -15 -4 -32 -2 -18 3 -39 4 -45 4 -7
|
||||||
|
0 -24 -1 -38 -1 -14 0 -32 0 -40 0 -8 0 -27 0 -42 1 -16 0 -37 -1 -48 -1 -11
|
||||||
|
-1 -24 -1 -30 -1 -43 1 -116 1 -145 -2 -19 -1 -45 1 -57 5 -12 4 -25 3 -28 -3
|
||||||
|
-4 -5 -11 -6 -17 -3 -13 8 -118 11 -118 3 0 -4 -15 -4 -32 -2 -18 3 -39 4 -45
|
||||||
|
4 -7 0 -24 -1 -38 -1 -14 0 -32 0 -40 0 -8 0 -27 0 -42 1 -16 0 -37 -1 -48 -1
|
||||||
|
-11 -1 -24 -1 -30 -1 -43 1 -116 1 -145 -2 -19 -1 -45 1 -57 5 -12 4 -25 3
|
||||||
|
-28 -3 -4 -5 -11 -6 -17 -3 -13 8 -118 11 -118 3 0 -4 -15 -4 -32 -2 -18 3
|
||||||
|
-42 4 -53 3 -11 -1 -24 -1 -30 -1 -43 1 -116 1 -145 -2 -19 -1 -45 1 -57 5
|
||||||
|
-12 4 -25 3 -28 -3 -4 -5 -11 -6 -17 -3 -14 9 -118 11 -118 2 0 -4 -13 -3 -29
|
||||||
|
2 -15 4 -33 5 -39 1 -13 -8 -87 -5 -101 4 -5 3 -12 1 -16 -5 -4 -6 -11 -8 -16
|
||||||
|
-4 -6 3 -34 6 -62 5 -29 -1 -72 -1 -97 -1 -25 0 -51 0 -57 0 -7 0 -21 0 -30 0
|
||||||
|
-10 0 -31 0 -48 -1 -16 0 -39 0 -50 1 -11 1 -27 1 -35 0 -8 0 -24 0 -35 0 -11
|
||||||
|
1 -26 1 -32 1 -16 -1 -35 -1 -68 -1 -14 0 -31 0 -37 -1 -7 0 -35 1 -63 1 -27
|
||||||
|
0 -66 -1 -85 -3 -19 -1 -45 1 -57 5 -12 4 -25 3 -28 -3 -4 -5 -11 -6 -17 -3
|
||||||
|
-13 8 -118 11 -118 3 0 -4 -15 -4 -32 -2 -18 3 -39 4 -45 4 -15 -1 -58 -1 -75
|
||||||
|
0 -7 0 -29 0 -48 0 -19 -1 -43 -1 -52 -1 -39 0 -54 0 -83 -1 -16 0 -39 0 -50
|
||||||
|
1 -11 1 -26 1 -32 1 -22 -1 -37 -2 -83 -1 -25 0 -61 -1 -80 -2 -19 -2 -45 0
|
||||||
|
-57 4 -12 4 -25 3 -28 -3 -4 -5 -11 -6 -17 -3 -14 9 -118 11 -118 2 0 -4 -13
|
||||||
|
-3 -29 2 -15 4 -33 5 -39 1 -13 -8 -87 -5 -101 4 -5 3 -12 1 -16 -5 -4 -6 -11
|
||||||
|
-8 -16 -4 -6 3 -32 6 -57 5 -46 -1 -85 -2 -137 -1 -14 0 -31 0 -37 -1 -7 0
|
||||||
|
-35 1 -63 1 -27 0 -66 -1 -85 -3 -19 -1 -45 1 -57 5 -12 4 -25 3 -28 -3 -4 -5
|
||||||
|
-11 -6 -17 -3 -13 8 -118 11 -118 3 0 -7 -60 -2 -68 5 -2 3 -14 1 -26 -3 -11
|
||||||
|
-5 -30 -5 -41 -1 -11 4 -29 4 -40 0 -11 -4 -29 -4 -40 0 -11 4 -30 4 -42 -1
|
||||||
|
-12 -5 -25 -5 -27 0 -3 4 -18 6 -34 3 -19 -2 -29 1 -30 10 -6 72 -6 108 -1
|
||||||
|
108 4 0 3 16 -1 35 -4 19 -5 35 -1 35 3 0 5 28 3 62 -1 35 -3 69 -2 76 0 6 0
|
||||||
|
20 0 30 0 9 0 26 0 37 1 11 1 26 1 33 -1 13 -1 34 -1 55 0 6 0 36 -1 65 -1 29
|
||||||
|
0 55 4 58 3 3 1 19 -3 35 -5 16 -6 29 -2 29 8 0 7 108 -1 117 -3 3 -2 16 3 29
|
||||||
|
6 14 6 26 -1 29 -5 4 -7 11 -3 16 7 12 9 138 2 145 -3 3 -2 19 2 37 4 18 4 41
|
||||||
|
0 52 -4 11 -4 32 1 47 4 15 4 30 -1 33 -5 3 -5 19 0 35 5 17 5 32 0 35 -5 3
|
||||||
|
-5 16 0 30 5 13 6 27 1 29 -4 3 -5 25 -1 49 3 24 3 52 0 63 -4 10 -4 31 1 46
|
||||||
|
4 15 4 30 -1 33 -5 3 -5 19 0 35 5 17 5 32 0 35 -5 3 -5 16 0 30 5 13 6 26 2
|
||||||
|
29 -5 3 -5 30 -2 61 3 31 3 58 -2 61 -4 3 -3 16 2 29 6 15 6 27 -1 30 -5 4 -7
|
||||||
|
11 -3 16 5 9 6 87 2 176 -1 24 1 45 4 49 4 3 2 19 -2 35 -5 16 -6 29 -2 29 4
|
||||||
|
0 6 28 4 62 -1 35 -3 69 -2 76 0 6 0 20 0 30 0 9 0 26 0 37 1 11 1 26 1 33 -1
|
||||||
|
13 -1 34 -1 55 0 6 0 36 -1 65 -1 29 0 55 4 58 3 3 1 19 -3 35 -5 16 -6 29 -2
|
||||||
|
29 8 0 7 108 -1 117 -3 3 -2 16 3 29 6 14 6 26 -1 29 -5 4 -7 11 -3 16 7 12 9
|
||||||
|
138 2 145 -3 3 -2 19 2 37 4 18 4 41 0 52 -4 11 -4 32 1 47 4 15 4 30 -1 33
|
||||||
|
-5 3 -5 19 0 35 5 17 5 32 0 35 -5 3 -5 16 0 30 5 13 6 27 1 29 -4 3 -5 25 -1
|
||||||
|
49 3 24 3 52 0 63 -4 10 -4 31 1 46 4 15 4 30 -1 33 -5 3 -5 19 0 35 5 17 5
|
||||||
|
32 0 35 -5 3 -5 16 0 30 5 13 6 26 2 29 -5 3 -5 30 -2 61 3 31 3 58 -2 61 -4
|
||||||
|
3 -3 16 2 29 6 15 6 27 -1 30 -5 4 -7 11 -3 16 5 9 6 87 2 176 -1 24 1 45 4
|
||||||
|
49 4 3 2 19 -2 35 -5 16 -6 29 -2 29 4 0 6 28 4 62 -1 35 -3 69 -2 76 0 6 0
|
||||||
|
20 0 30 0 9 0 26 0 37 1 11 1 26 1 33 -1 13 -1 34 -1 55 0 6 0 36 -1 65 -1 29
|
||||||
|
0 55 4 58 3 3 1 19 -3 35 -5 16 -6 29 -2 29 8 0 7 108 -1 117 -3 3 -2 16 3 29
|
||||||
|
6 14 6 26 -1 29 -5 4 -7 11 -3 16 7 12 9 138 2 145 -3 3 -2 19 2 37 4 18 4 41
|
||||||
|
0 52 -4 11 -4 32 1 47 4 15 4 30 -1 33 -5 3 -5 19 0 35 5 17 5 32 0 35 -5 3
|
||||||
|
-5 16 0 30 5 13 6 27 1 29 -4 3 -5 25 -1 49 3 24 3 52 0 63 -4 10 -4 31 1 46
|
||||||
|
4 15 4 30 -1 33 -5 3 -5 19 0 35 5 17 5 32 0 35 -5 3 -5 16 0 30 5 13 6 26 2
|
||||||
|
29 -5 3 -5 30 -2 61 3 31 3 58 -2 61 -4 3 -3 16 2 29 6 15 6 27 -1 30 -5 4 -7
|
||||||
|
11 -3 16 5 9 6 87 2 176 -1 24 1 45 4 49 4 3 2 19 -2 35 -5 16 -6 29 -2 29 4
|
||||||
|
0 6 28 4 62 -1 35 -3 69 -2 76 0 6 0 20 0 30 0 9 0 26 0 37 1 11 1 26 1 33 -1
|
||||||
|
12 -1 29 -1 57 0 8 0 36 -1 63 -1 26 0 52 1 57 8 34 3 35 -240 35 l-240 0 0
|
||||||
|
-3440z"/>
|
||||||
|
<path d="M4072 6781 c-34 -10 -65 -19 -67 -20 -3 0 -6 -1 -7 -2 -2 0 -10 -2
|
||||||
|
-18 -4 -8 -2 -58 -15 -110 -30 -52 -14 -120 -33 -150 -41 -30 -8 -103 -29
|
||||||
|
-162 -45 -60 -17 -114 -32 -120 -33 -7 -2 -20 -6 -28 -9 -12 -5 -96 -27 -155
|
||||||
|
-42 -5 -1 -17 -5 -25 -8 -14 -5 -59 -17 -87 -23 -6 -1 -27 -7 -45 -13 -32 -10
|
||||||
|
-464 -130 -598 -166 -8 -2 -121 -33 -250 -70 -129 -36 -242 -67 -250 -69 -8
|
||||||
|
-2 -22 -6 -30 -9 -12 -5 -207 -59 -260 -72 -8 -2 -73 -20 -145 -40 -71 -20
|
||||||
|
-137 -38 -145 -40 -55 -13 -76 -18 -85 -24 -5 -3 -12 -6 -15 -6 -86 -13 -168
|
||||||
|
-43 -196 -70 -19 -18 -44 -73 -46 -97 -2 -39 21 -103 44 -125 25 -23 69 -44
|
||||||
|
105 -48 12 -2 55 -13 95 -24 207 -60 595 -166 640 -176 9 -2 26 -9 37 -15 12
|
||||||
|
-6 21 -9 21 -6 0 3 15 0 33 -5 17 -6 39 -12 47 -14 8 -2 65 -18 125 -35 61
|
||||||
|
-18 118 -33 128 -35 9 -2 21 -7 27 -10 5 -3 22 -8 37 -10 23 -4 509 -137 688
|
||||||
|
-189 28 -9 70 -21 95 -27 25 -7 50 -14 55 -15 6 -2 21 -6 35 -9 34 -8 43 -11
|
||||||
|
60 -18 8 -4 27 -8 42 -11 14 -2 36 -9 47 -16 12 -6 21 -9 21 -6 0 2 30 -4 68
|
||||||
|
-15 37 -11 101 -29 142 -40 119 -33 129 -36 245 -69 61 -17 120 -33 132 -35
|
||||||
|
12 -3 33 -9 45 -14 13 -4 34 -6 48 -4 14 2 43 6 65 7 22 2 40 5 40 6 0 1 7 3
|
||||||
|
15 6 8 2 80 22 160 44 80 22 152 41 160 43 8 1 20 6 26 9 6 4 21 9 35 12 13 2
|
||||||
|
83 21 154 41 128 37 221 62 260 71 28 7 38 10 55 17 8 3 51 16 95 27 93 24 84
|
||||||
|
22 200 55 50 14 97 27 106 29 10 3 68 19 130 36 100 28 204 56 234 64 6 2 17
|
||||||
|
6 25 9 8 3 43 13 77 22 34 8 69 18 78 21 21 8 33 -30 25 -78 -4 -21 -4 -38 0
|
||||||
|
-38 4 0 4 -18 0 -40 -4 -22 -4 -40 0 -40 4 0 4 -18 0 -40 -4 -22 -4 -40 0 -40
|
||||||
|
4 0 4 -18 0 -40 -4 -22 -4 -40 0 -40 4 0 4 -18 0 -40 -4 -22 -4 -40 0 -40 4 0
|
||||||
|
4 -18 0 -40 -4 -22 -4 -40 0 -40 4 0 4 -19 0 -42 -5 -24 -6 -47 -3 -51 3 -5 5
|
||||||
|
-31 5 -59 -1 -39 -6 -55 -24 -72 -12 -11 -24 -20 -26 -18 -2 2 -16 -14 -33
|
||||||
|
-35 -16 -21 -33 -43 -37 -48 -23 -28 -40 -108 -37 -172 3 -81 34 -147 97 -206
|
||||||
|
l40 -38 -21 -132 c-11 -73 -23 -141 -25 -152 -3 -18 -7 -38 -22 -130 -1 -11
|
||||||
|
-19 -114 -38 -230 -37 -220 -37 -261 -4 -307 92 -130 365 -161 512 -58 91 63
|
||||||
|
103 101 81 237 -9 54 -18 110 -21 126 -6 42 -12 74 -29 177 -9 52 -18 109 -21
|
||||||
|
125 -2 17 -9 53 -14 80 -8 45 -15 83 -24 140 -20 127 -21 119 26 166 56 56 89
|
||||||
|
128 94 201 3 58 -21 168 -37 168 -5 0 -9 6 -9 14 0 8 -24 36 -54 63 -49 45
|
||||||
|
-54 53 -53 91 0 23 -2 44 -6 48 -3 3 -2 17 3 30 6 14 6 26 0 29 -6 3 -6 15 0
|
||||||
|
30 6 15 6 27 0 30 -6 3 -6 15 0 30 6 15 6 27 0 30 -6 3 -6 15 0 30 6 15 6 27
|
||||||
|
0 30 -6 3 -6 15 0 30 5 13 6 27 1 29 -4 3 -5 25 -1 49 3 25 3 54 -1 65 -5 12
|
||||||
|
-4 24 1 27 5 3 5 18 0 35 -5 17 -6 30 -2 30 6 0 7 98 2 160 -5 54 -2 58 68 79
|
||||||
|
126 38 607 169 645 175 47 9 102 56 117 102 32 96 -29 198 -125 209 -22 2 -83
|
||||||
|
16 -135 31 -52 14 -102 28 -110 30 -21 4 -472 130 -550 153 -109 32 -235 65
|
||||||
|
-240 64 -3 -1 -11 3 -17 9 -7 6 -13 8 -13 5 0 -3 -15 -1 -32 4 -32 10 -197 56
|
||||||
|
-228 64 -8 2 -40 11 -70 20 -30 9 -62 18 -70 20 -8 2 -49 13 -90 25 -87 24
|
||||||
|
-139 39 -160 44 -31 9 -130 36 -290 81 -91 25 -172 48 -180 50 -8 2 -15 4 -15
|
||||||
|
5 0 1 -11 4 -25 6 -14 3 -56 14 -95 26 -38 11 -74 21 -80 23 -32 7 -72 17 -85
|
||||||
|
22 -8 3 -24 8 -35 10 -11 2 -31 7 -45 13 -22 8 -78 23 -130 36 -8 2 -55 15
|
||||||
|
-105 29 -122 35 -159 38 -233 16z"/>
|
||||||
|
<path d="M2559 4994 c-1 -10 0 -135 2 -141 1 -5 1 -11 0 -15 -1 -7 -1 -107 0
|
||||||
|
-138 0 -8 0 -35 0 -60 0 -25 0 -52 0 -60 0 -8 0 -35 0 -60 0 -25 0 -52 0 -60
|
||||||
|
0 -8 0 -35 0 -60 0 -25 0 -52 0 -60 0 -8 0 -35 0 -60 0 -25 0 -52 0 -60 0 -8
|
||||||
|
0 -35 0 -60 0 -25 0 -52 0 -60 0 -8 0 -35 -1 -60 -3 -123 7 -195 34 -249 28
|
||||||
|
-55 148 -181 173 -181 7 0 13 -4 13 -9 0 -10 28 -26 160 -91 86 -43 260 -104
|
||||||
|
380 -135 3 0 23 -5 45 -10 22 -4 47 -10 55 -12 8 -2 24 -5 35 -7 11 -2 34 -6
|
||||||
|
50 -9 17 -4 50 -10 75 -13 25 -3 54 -7 65 -9 107 -16 203 -25 360 -31 114 -5
|
||||||
|
135 -5 213 -1 17 1 32 -1 32 -6 0 -4 5 -5 10 -2 6 4 48 8 93 11 157 8 223 14
|
||||||
|
317 28 19 3 51 8 70 10 76 12 106 17 120 21 8 2 27 6 43 9 15 3 35 7 45 10 9
|
||||||
|
3 28 7 42 10 54 11 148 38 210 61 105 39 115 43 122 44 12 3 159 81 198 104
|
||||||
|
68 42 156 126 192 183 37 59 64 181 45 200 -3 3 -1 19 3 35 5 16 5 29 1 29 -5
|
||||||
|
0 -5 15 -2 33 4 17 4 47 0 65 -4 17 -3 35 2 38 5 3 7 10 3 15 -8 13 -9 97 -2
|
||||||
|
105 4 3 3 16 -2 28 -4 12 -4 29 0 37 5 8 5 21 0 28 -4 8 -4 27 0 42 5 16 5 29
|
||||||
|
0 29 -5 0 -5 13 0 30 5 16 5 32 0 35 -5 3 -5 18 -1 33 5 15 5 36 1 47 -4 11
|
||||||
|
-4 30 1 41 4 12 5 25 2 28 -8 8 -9 76 -1 76 4 0 3 13 -2 30 -5 17 -5 32 0 35
|
||||||
|
5 3 6 16 1 28 -5 12 -5 31 -1 42 4 11 5 24 2 29 -3 5 -6 28 -6 50 -1 23 -6 40
|
||||||
|
-11 39 -10 -1 -240 -65 -395 -110 -47 -13 -92 -26 -100 -28 -8 -2 -55 -15
|
||||||
|
-105 -30 -49 -14 -101 -29 -115 -31 -24 -5 -51 -13 -172 -50 -29 -9 -63 -18
|
||||||
|
-76 -20 -13 -3 -44 -12 -69 -20 -25 -9 -54 -17 -65 -19 -11 -2 -28 -7 -38 -10
|
||||||
|
-10 -3 -27 -8 -37 -10 -25 -6 -205 -55 -223 -61 -8 -3 -15 -5 -15 -5 0 0 -29
|
||||||
|
-8 -65 -19 -36 -11 -83 -20 -105 -20 -43 0 -116 19 -400 100 -60 18 -132 38
|
||||||
|
-160 45 -27 7 -75 21 -105 30 -30 9 -66 18 -79 21 -14 3 -29 8 -34 11 -6 3
|
||||||
|
-20 7 -31 9 -12 1 -61 15 -111 29 -49 15 -94 28 -100 29 -5 2 -30 8 -55 15
|
||||||
|
-25 7 -52 15 -60 17 -8 2 -87 24 -175 49 -88 26 -167 48 -175 50 -8 2 -39 11
|
||||||
|
-67 19 -29 8 -53 12 -54 10z"/>
|
||||||
|
<path d="M1964 2708 c-3 -5 -5 -37 -4 -71 1 -34 1 -72 1 -84 0 -31 -1 -69 0
|
||||||
|
-90 0 -10 -1 -40 -1 -66 -1 -26 2 -57 5 -67 4 -12 2 -20 -5 -20 -6 0 -9 -4 -6
|
||||||
|
-8 6 -10 10 -112 5 -132 -3 -12 11 -15 79 -16 49 -1 85 3 89 9 7 12 11 546 3
|
||||||
|
548 -21 7 -162 3 -166 -3z"/>
|
||||||
|
<path d="M2666 2710 c-1 -3 -2 -342 -2 -755 l1 -750 55 -2 c88 -3 202 -5 355
|
||||||
|
-4 34 0 228 0 275 0 88 0 235 0 259 1 14 0 26 2 29 4 6 7 6 152 -1 162 -3 5
|
||||||
|
-171 9 -386 8 l-381 -1 0 274 c0 211 3 273 13 274 59 5 134 3 145 -4 6 -5 12
|
||||||
|
-6 12 -1 0 5 43 9 95 9 52 0 95 -4 95 -9 0 -5 6 -4 13 1 6 4 87 8 180 8 155
|
||||||
|
-1 167 0 168 17 0 10 0 38 0 63 0 25 0 55 0 68 l-1 22 -357 0 -358 0 0 225 0
|
||||||
|
225 370 -1 c325 0 371 2 376 16 3 8 5 47 4 85 l-1 70 -478 0 c-262 1 -478 -2
|
||||||
|
-480 -5z"/>
|
||||||
|
<path d="M3905 2711 c-4 -7 -7 -73 -6 -126 l1 -41 265 1 c168 0 266 -4 268
|
||||||
|
-10 2 -5 4 -302 3 -660 -1 -357 0 -655 2 -662 3 -8 35 -12 105 -12 l102 0 -1
|
||||||
|
669 c0 466 3 670 10 673 6 1 127 3 269 2 286 0 259 -8 259 70 0 19 -1 50 -1
|
||||||
|
68 l-1 33 -636 0 c-349 0 -637 -2 -639 -5z"/>
|
||||||
|
<path d="M5487 2706 c-7 -22 0 -1033 7 -1076 5 -25 10 -54 12 -65 5 -29 47
|
||||||
|
-139 54 -145 4 -3 14 -19 23 -36 20 -39 103 -115 156 -142 83 -43 172 -64 296
|
||||||
|
-68 339 -11 536 131 601 431 3 17 7 273 8 571 l2 540 -101 0 c-101 0 -101 0
|
||||||
|
-104 -25 -1 -14 -2 -32 -2 -38 1 -17 1 -36 1 -101 0 -30 2 -58 5 -62 3 -5 1
|
||||||
|
-12 -5 -15 -8 -5 -7 -11 1 -21 7 -9 8 -14 1 -14 -7 0 -8 -10 -3 -27 4 -16 5
|
||||||
|
-39 1 -53 -3 -13 -3 -46 0 -73 4 -26 3 -50 -2 -53 -5 -3 -4 -12 3 -20 7 -9 8
|
||||||
|
-14 1 -14 -7 0 -8 -10 -3 -27 4 -16 5 -39 1 -53 -3 -13 -3 -46 0 -73 4 -26 3
|
||||||
|
-50 -2 -53 -5 -3 -4 -12 3 -20 7 -9 8 -14 1 -14 -7 0 -8 -10 -2 -29 4 -16 6
|
||||||
|
-32 3 -34 -4 -4 -5 -71 -2 -127 1 -33 -10 -128 -22 -175 -28 -114 -78 -181
|
||||||
|
-164 -221 -108 -50 -291 -47 -394 6 -64 32 -133 127 -147 203 -2 12 -8 45 -13
|
||||||
|
72 -8 42 -10 214 -11 996 l0 65 -100 0 c-63 1 -100 -3 -103 -10z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
|
@ -11,7 +11,7 @@ document.getElementById("login").addEventListener("submit", e=>{
|
||||||
alert('Format d\'email incorrect.');
|
alert('Format d\'email incorrect.');
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
})
|
});
|
||||||
|
|
||||||
socket.on("login", data=>{
|
socket.on("login", data=>{
|
||||||
if(data.error){
|
if(data.error){
|
||||||
|
@ -19,4 +19,4 @@ socket.on("login", data=>{
|
||||||
}else{
|
}else{
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
}
|
}
|
||||||
})
|
});
|
|
@ -18,7 +18,7 @@ socket.on("logout", data=>{
|
||||||
}else{
|
}else{
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
function profilRedirect(){
|
function profilRedirect(){
|
||||||
|
|
|
@ -18,4 +18,4 @@ socket.on("profileEdit", data=>{
|
||||||
}else{
|
}else{
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
}
|
}
|
||||||
})
|
});
|
|
@ -20,4 +20,4 @@ socket.on("register", data=>{
|
||||||
}else{
|
}else{
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
19
public/site.webmanifest
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "Lyon's Exceptional Tool for University",
|
||||||
|
"short_name": "L'ETU",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/images/android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/images/android-chrome-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
let express = require("express");
|
const express = require("express");
|
||||||
let router = express.Router();
|
const sessionCheck = require("./utils/sessionCheck");
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/", (req, res) => {
|
router.get("/", sessionCheck(1), (req, res) => {
|
||||||
res.render("pages/edt", { title: "L'ETU" });
|
res.render("pages/edt", { title: "L'ETU" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ const sessionCheck = require("./utils/sessionCheck");
|
||||||
router.get("/check", async (req, res) => {
|
router.get("/check", async (req, res) => {
|
||||||
if (!req.query.token)
|
if (!req.query.token)
|
||||||
return error(req, res, "Missing argument", 400);
|
return error(req, res, "Missing argument", 400);
|
||||||
let user = await models.User.findOne({where: {emailToken: req.query.token}});
|
const user = await models.User.findOne({where: {emailToken: req.query.token}});
|
||||||
if (user) {
|
if (user) {
|
||||||
user.emailVerified = true;
|
user.emailVerified = true;
|
||||||
if (user.email.endsWith("@etu.univ-lyon1.fr"))
|
if (user.email.endsWith("@etu.univ-lyon1.fr"))
|
||||||
|
@ -25,7 +25,7 @@ router.get("/forget", sessionCheck(-1), async (req, res) => {
|
||||||
if (!req.query.token)
|
if (!req.query.token)
|
||||||
res.render("forget", {title: "L'ETU"});
|
res.render("forget", {title: "L'ETU"});
|
||||||
else {
|
else {
|
||||||
let user = await models.User.findOne({where: {passwordToken: data.token}});
|
const user = await models.User.findOne({where: {passwordToken: data.token}});
|
||||||
if (!user)
|
if (!user)
|
||||||
return error(req, res, "Invalid token", 400);
|
return error(req, res, "Invalid token", 400);
|
||||||
else if (user.passwordTokenDate && ((new Date().getTime() - user.passwordTokenDate.getTime()) / 1000 > 3600))
|
else if (user.passwordTokenDate && ((new Date().getTime() - user.passwordTokenDate.getTime()) / 1000 > 3600))
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
let express = require("express");
|
|
||||||
let router = express.Router();
|
|
||||||
|
|
||||||
/* GET home page. */
|
|
||||||
router.get("/", (req, res) => {
|
|
||||||
res.render("pages/home", { title: "L'ETU" });
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
|
|
@ -1,5 +1,5 @@
|
||||||
let express = require("express");
|
const express = require("express");
|
||||||
let router = express.Router();
|
const router = express.Router();
|
||||||
const sessionCheck = require("./utils/sessionCheck");
|
const sessionCheck = require("./utils/sessionCheck");
|
||||||
|
|
||||||
router.get("/", sessionCheck(1), (req, res) => {
|
router.get("/", sessionCheck(1), (req, res) => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
let express = require("express");
|
const express = require("express");
|
||||||
let router = express.Router();
|
const router = express.Router();
|
||||||
const sessionCheck = require("./utils/sessionCheck");
|
const sessionCheck = require("./utils/sessionCheck");
|
||||||
|
|
||||||
router.get("/",sessionCheck(-1), (req, res) => {
|
router.get("/",sessionCheck(-1), (req, res) => {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
let express = require("express");
|
const express = require("express");
|
||||||
let router = express.Router();
|
const sessionCheck = require("./utils/sessionCheck");
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/", (req, res) => {
|
router.get("/", sessionCheck(1), (req, res) => {
|
||||||
res.render("pages/marks", { title: "L'ETU" });
|
res.render("pages/marks", { title: "L'ETU" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
let express = require("express");
|
const express = require("express");
|
||||||
let router = express.Router();
|
const sessionCheck = require("./utils/sessionCheck");
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/", (req, res) => {
|
router.get("/", sessionCheck(1), (req, res) => {
|
||||||
res.render("pages/profil", { title: "L'ETU" });
|
res.render("pages/profil", { title: "L'ETU" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
let express = require("express");
|
const express = require("express");
|
||||||
let router = express.Router();
|
const router = express.Router();
|
||||||
const sessionCheck = require("./utils/sessionCheck");
|
const sessionCheck = require("./utils/sessionCheck");
|
||||||
|
|
||||||
router.get("/",sessionCheck(-1), (req, res) => {
|
router.get("/",sessionCheck(-1), (req, res) => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
let error = require("./error");
|
const error = require("./error");
|
||||||
|
|
||||||
function sessionCheck(permission) {
|
function sessionCheck(permission) {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
let express = require("express");
|
const express = require("express");
|
||||||
let router = express.Router();
|
const sessionCheck = require("./utils/sessionCheck");
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/", (req, res) => {
|
router.get("/", sessionCheck(1), (req, res) => {
|
||||||
res.render("pages/viescol", { title: "L'ETU" });
|
res.render("pages/viescol", { title: "L'ETU" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -71,16 +71,8 @@ h2
|
||||||
i
|
i
|
||||||
color: $primary
|
color: $primary
|
||||||
|
|
||||||
#panel
|
|
||||||
background-color: $dark2
|
|
||||||
height: 100vh
|
|
||||||
border-right: 2px solid $light3
|
|
||||||
padding: 0
|
|
||||||
position: fixed
|
|
||||||
|
|
||||||
#main
|
#main
|
||||||
background-color: $dark1
|
background-color: $dark1
|
||||||
margin-left: 16vw
|
|
||||||
|
|
||||||
#navtop
|
#navtop
|
||||||
font-size: 22px
|
font-size: 22px
|
||||||
|
@ -130,11 +122,11 @@ i
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
|
||||||
.student
|
.student
|
||||||
background: radial-gradient(circle, rgb(1, 79, 116) 20%, rgb(15, 15, 99) 100%)
|
background-image: linear-gradient(to top, #4481eb 0%, #04befe 100%)
|
||||||
.teacher
|
.teacher
|
||||||
background: radial-gradient(circle, rgb(5, 116, 1) 20%, rgb(11, 68, 10) 100%)
|
background-image: radial-gradient( circle farthest-corner at -1% 57.5%, rgba(19,170,82,1) 0%, rgba(0,102,43,1) 90% )
|
||||||
.admin
|
.admin
|
||||||
background: radial-gradient(circle, rgb(116, 74, 1) 20%, rgb(99, 42, 15) 100%)
|
background-image: radial-gradient( circle farthest-corner at 7.2% 19%, rgba(120,0,0,1) 0%, rgba(239,75,75,1) 100.2% )
|
||||||
|
|
||||||
#page
|
#page
|
||||||
margin: 0
|
margin: 0
|
||||||
|
@ -219,6 +211,7 @@ h3
|
||||||
.midi
|
.midi
|
||||||
td
|
td
|
||||||
height: 10vh
|
height: 10vh
|
||||||
|
cursor: auto
|
||||||
th
|
th
|
||||||
background-color: $secondary
|
background-color: $secondary
|
||||||
text-align: center
|
text-align: center
|
||||||
|
@ -234,6 +227,7 @@ h3
|
||||||
td
|
td
|
||||||
border-bottom: 1px solid white
|
border-bottom: 1px solid white
|
||||||
td
|
td
|
||||||
|
cursor: pointer
|
||||||
text-align: center
|
text-align: center
|
||||||
font-size: 15px
|
font-size: 15px
|
||||||
background-color: $medium
|
background-color: $medium
|
||||||
|
@ -489,6 +483,37 @@ div#visible + div
|
||||||
margin: auto
|
margin: auto
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
|
||||||
|
.detailsedt
|
||||||
|
z-index: 1
|
||||||
|
display: none
|
||||||
|
position: fixed
|
||||||
|
top: 20vh
|
||||||
|
left: 30%
|
||||||
|
background-color: $dark2
|
||||||
|
width: 40%
|
||||||
|
border-radius: 50px
|
||||||
|
border: 1px solid $light3
|
||||||
|
p
|
||||||
|
font-size: 20px
|
||||||
|
padding: 5px
|
||||||
|
color: white
|
||||||
|
margin: 0
|
||||||
|
text-align: center
|
||||||
|
p:first-child
|
||||||
|
font-size: 25px
|
||||||
|
background-color: $secondary
|
||||||
|
border-top-right-radius: 50px
|
||||||
|
border-top-left-radius: 50px
|
||||||
|
|
||||||
|
#slide-out
|
||||||
|
background-color: $dark2
|
||||||
|
a
|
||||||
|
color: white
|
||||||
|
font-size: 20px
|
||||||
|
|
||||||
|
#hamburger
|
||||||
|
position: fixed
|
||||||
|
|
||||||
#notvisible
|
#notvisible
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
|
|
|
@ -11,4 +11,4 @@ module.exports = socket => {
|
||||||
else
|
else
|
||||||
await emailCheck(socket, user, null);
|
await emailCheck(socket, user, null);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -10,4 +10,4 @@ module.exports = socket => {
|
||||||
else
|
else
|
||||||
await emailPassword(socket, user, null);
|
await emailPassword(socket, user, null);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ module.exports = socket => {
|
||||||
return async (data) => {
|
return async (data) => {
|
||||||
let user = await models.User.findOne({where: {passwordToken: data.token}});
|
let user = await models.User.findOne({where: {passwordToken: data.token}});
|
||||||
if (!user)
|
if (!user)
|
||||||
socket.emit("setPassword", {error: {message: "invalid_token"}})
|
socket.emit("setPassword", {error: {message: "invalid_token"}});
|
||||||
else if (user.passwordTokenDate && ((new Date().getTime() - user.passwordTokenDate.getTime()) / 1000 > 3600))
|
else if (user.passwordTokenDate && ((new Date().getTime() - user.passwordTokenDate.getTime()) / 1000 > 3600))
|
||||||
socket.emit("setPassword", {error: {message: "expired_token"}});
|
socket.emit("setPassword", {error: {message: "expired_token"}});
|
||||||
else {
|
else {
|
||||||
|
@ -16,4 +16,4 @@ module.exports = socket => {
|
||||||
socket.emit("setPassword", true);
|
socket.emit("setPassword", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
61
sockets/get/agendaGet.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
const models = require("../../models");
|
||||||
|
|
||||||
|
|
||||||
|
function addWhere(options, index, attr, value) {
|
||||||
|
if (!options.include[index].where)
|
||||||
|
options.include[index].where = {};
|
||||||
|
if (!options.include[index].where[attr])
|
||||||
|
options.include[index].where[attr] = {};
|
||||||
|
if (!options.include[index].where[attr][models.Sequelize.Op.or])
|
||||||
|
options.include[index].where[attr][models.Sequelize.Op.or] = [];
|
||||||
|
options.include[index].where[attr][models.Sequelize.Op.or].push(value);
|
||||||
|
options.include[index].require = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = socket => {
|
||||||
|
return async (data) => {
|
||||||
|
let options = {
|
||||||
|
where: {},
|
||||||
|
include: [
|
||||||
|
{model: models.User, attributes: ["email", "firstName", "lastName"]},
|
||||||
|
{model: models.Group, include: models.Semester},
|
||||||
|
{model: models.Semester, include: models.Group}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
if (data && data.startDate)
|
||||||
|
options.where.startDate = data.startDate;
|
||||||
|
if (data && data.endDate)
|
||||||
|
options.where.endDate = data.endDate;
|
||||||
|
if (data && data.semesters) {
|
||||||
|
for (let semester of data.semesters) {
|
||||||
|
let s = await models.Semester.findByPk(semester);
|
||||||
|
if (!s) {
|
||||||
|
socket.emit("agendaGet", {error: {message: "semester_not_found"}});
|
||||||
|
return
|
||||||
|
} else
|
||||||
|
addWhere(options, 2, "id", s.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data && data.groups) {
|
||||||
|
for (let group of data.groups) {
|
||||||
|
let g = await models.Group.findByPk(group);
|
||||||
|
if (!g) {
|
||||||
|
socket.emit("agendaGet", {error: {message: "group_not_found"}});
|
||||||
|
return
|
||||||
|
} else
|
||||||
|
addWhere(options, 1, "id", g.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data && data.teachers) {
|
||||||
|
for (let teacher of data.teachers) {
|
||||||
|
let t = await models.User.findByPk(teacher);
|
||||||
|
if (!t) {
|
||||||
|
socket.emit("agendaGet", {error: {message: "teacher_not_found"}});
|
||||||
|
return
|
||||||
|
} else
|
||||||
|
addWhere(options, 0, "email", t.email);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socket.emit("agendaGet", await models.Event.findAll(options));
|
||||||
|
}
|
||||||
|
};
|
22
sockets/get/evaluationGet.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
const models = require("../../models");
|
||||||
|
|
||||||
|
module.exports = socket => {
|
||||||
|
return async (data) => {
|
||||||
|
const options = {where: {},
|
||||||
|
include: [models.UE, {model: models.User},
|
||||||
|
{
|
||||||
|
model: models.Grade,
|
||||||
|
include: [{model: models.User, as: "TeacherGrade"}, {model: models.User, as: "StudentGrade"}]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data && data.id)
|
||||||
|
options.where.id = data.id;
|
||||||
|
|
||||||
|
if (socket.request.session.user.permissions === 2) {
|
||||||
|
options.include[1].where = {email: socket.request.session.user.email};
|
||||||
|
options.include[1].required = true;
|
||||||
|
}
|
||||||
|
socket.emit("evaluationGet", await models.Evaluation.findAll(options));
|
||||||
|
}
|
||||||
|
};
|
22
sockets/get/gradeGet.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
const models = require("../../models");
|
||||||
|
|
||||||
|
module.exports = socket => {
|
||||||
|
return async (data) => {
|
||||||
|
const options = {where: {}, include: [models.Evaluation,
|
||||||
|
{model: models.User, as: "TeacherGrade"},
|
||||||
|
{model: models.User, as: "StudentGrade"}]};
|
||||||
|
|
||||||
|
if (data && data.id)
|
||||||
|
options.where.id = data.id;
|
||||||
|
|
||||||
|
switch (socket.request.session.user.permissions) {
|
||||||
|
case 1:
|
||||||
|
options.where.StudentGradeEmail = socket.request.session.user.email;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
options.where.TeacherGradeEmail = socket.request.session.user.email;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
socket.emit("gradeGet", await models.Grade.findAll(options));
|
||||||
|
}
|
||||||
|
};
|
26
sockets/get/groupGet.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const models = require("../../models");
|
||||||
|
|
||||||
|
module.exports = socket => {
|
||||||
|
return async (data) => {
|
||||||
|
let options = {include: [{model: models.Semester}]};
|
||||||
|
if (data && (data.id || data.number || data.semester))
|
||||||
|
options.where = {};
|
||||||
|
if (data && data.id)
|
||||||
|
options.where.id = data.id;
|
||||||
|
if (data && data.number)
|
||||||
|
options.where.number = data.number;
|
||||||
|
if (data && data.semester) {
|
||||||
|
let s = await models.Semester.findByPk(data.semester);
|
||||||
|
if (!s) {
|
||||||
|
socket.emit("groupGet", {error: {message: "semester_not_found"}});
|
||||||
|
return
|
||||||
|
}
|
||||||
|
options.include[0].where = {id: s.id};
|
||||||
|
options.include[0].require = true;
|
||||||
|
}
|
||||||
|
if (data && data.users)
|
||||||
|
options.include.push({model: models.User, where: {email: {[models.Sequelize.Op.in]: data.users}}, require: true});
|
||||||
|
|
||||||
|
socket.emit("groupGet", await models.Group.findAll(options));
|
||||||
|
}
|
||||||
|
};
|
19
sockets/get/semesterGet.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
const models = require("../../models");
|
||||||
|
|
||||||
|
module.exports = socket => {
|
||||||
|
return async (data) => {
|
||||||
|
let options = {include: [{model: models.Group}]};
|
||||||
|
if (data && (data.id || data.name || data.year))
|
||||||
|
options.where = {};
|
||||||
|
if (data && data.id)
|
||||||
|
options.where.id = data.id;
|
||||||
|
if (data && data.name)
|
||||||
|
options.where.name = data.name;
|
||||||
|
if (data && data.year)
|
||||||
|
options.where.year = data.year;
|
||||||
|
if (data && data.groups)
|
||||||
|
options.include[0].where = {id: {[models.Sequelize.Op.or]: data.groups}};
|
||||||
|
|
||||||
|
socket.emit("semesterGet", await models.Semester.findAll(options));
|
||||||
|
}
|
||||||
|
};
|
17
sockets/get/userGet.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
const models = require("../../models");
|
||||||
|
|
||||||
|
module.exports = socket => {
|
||||||
|
return async (data) => {
|
||||||
|
let options = {where: {}};
|
||||||
|
if (data.email)
|
||||||
|
options.where.email = data.email;
|
||||||
|
if (data.firstName && data.lastName) {
|
||||||
|
options.where.firstName = data.firstName;
|
||||||
|
options.where.lastName = data.lastName;
|
||||||
|
}
|
||||||
|
if (data.permissions)
|
||||||
|
options.where.permissions = data.permissions;
|
||||||
|
|
||||||
|
socket.emit("userGet", await models.User.findAll(options));
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,6 +1,5 @@
|
||||||
module.exports = socket => {
|
module.exports = socket => {
|
||||||
console.log("New connection !");
|
console.log("New connection !");
|
||||||
console.log(socket.request.session.user);
|
|
||||||
if (!socket.request.session.user) {
|
if (!socket.request.session.user) {
|
||||||
socket.on("login", require("./login")(socket));
|
socket.on("login", require("./login")(socket));
|
||||||
socket.on("register", require("./register")(socket));
|
socket.on("register", require("./register")(socket));
|
||||||
|
@ -10,6 +9,15 @@ module.exports = socket => {
|
||||||
} else {
|
} else {
|
||||||
socket.on("profileEdit", require("./profile/edit")(socket));
|
socket.on("profileEdit", require("./profile/edit")(socket));
|
||||||
socket.on("logout", require("./logout")(socket));
|
socket.on("logout", require("./logout")(socket));
|
||||||
|
socket.on("agendaGet", require("./get/agendaGet")(socket));
|
||||||
|
socket.on("gradeGet", require("./get/gradeGet")(socket));
|
||||||
|
if (socket.request.session.user.permissions > 1)
|
||||||
|
socket.on("evaluationGet", require("./get/evaluationGet")(socket));
|
||||||
|
if (socket.request.session.user.permissions > 2) {
|
||||||
|
socket.on("groupGet", require("./get/groupGet")(socket));
|
||||||
|
socket.on("semesterGet", require("./get/semesterGet")(socket));
|
||||||
|
socket.on("userSet", require("./set/userSet")(socket));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
socket.emit("connected");
|
socket.emit("connected");
|
||||||
}
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ const models = require("../models");
|
||||||
|
|
||||||
module.exports = socket => {
|
module.exports = socket => {
|
||||||
return async (data) => {
|
return async (data) => {
|
||||||
let user = await models.User.findByPk(data.email);
|
let user = await models.User.findByPk(data.email, {include: {model: models.Group, include: models.Semester}});
|
||||||
if (!user)
|
if (!user)
|
||||||
socket.emit("login", {error: {message: "not_found"}});
|
socket.emit("login", {error: {message: "not_found"}});
|
||||||
else if (!user.checkPassword(data.password))
|
else if (!user.checkPassword(data.password))
|
||||||
|
@ -15,4 +15,4 @@ module.exports = socket => {
|
||||||
socket.emit("login", user)
|
socket.emit("login", user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -7,4 +7,4 @@ module.exports = socket => {
|
||||||
socket.emit("logout", {error: { message: "not_logged_in"}});
|
socket.emit("logout", {error: { message: "not_logged_in"}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
|
@ -6,7 +6,7 @@ module.exports = socket => {
|
||||||
if (!user)
|
if (!user)
|
||||||
socket.emit("profileEdit", {error: {message: "not_found"}});
|
socket.emit("profileEdit", {error: {message: "not_found"}});
|
||||||
else if (!user.checkPassword(data.oldPassword))
|
else if (!user.checkPassword(data.oldPassword))
|
||||||
socket.emit("profileEdit", {error: {message: "invalid_password"}})
|
socket.emit("profileEdit", {error: {message: "invalid_password"}});
|
||||||
else {
|
else {
|
||||||
if (data.firstName !== user.firstName)
|
if (data.firstName !== user.firstName)
|
||||||
user.firstName = data.firstName;
|
user.firstName = data.firstName;
|
||||||
|
@ -14,10 +14,10 @@ module.exports = socket => {
|
||||||
user.lastName = data.lastName;
|
user.lastName = data.lastName;
|
||||||
user.newPassword = data.newPassword;
|
user.newPassword = data.newPassword;
|
||||||
if (data.password && !user.checkPassword(data.password))
|
if (data.password && !user.checkPassword(data.password))
|
||||||
user.passwordHash = data.password
|
user.passwordHash = data.password;
|
||||||
socket.request.session.user = user;
|
socket.request.session.user = user;
|
||||||
socket.request.session.save();
|
socket.request.session.save();
|
||||||
socket.emit("profileEdit", user)
|
socket.emit("profileEdit", user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -18,4 +18,4 @@ module.exports = socket => {
|
||||||
await emailCheck(socket, user, null);
|
await emailCheck(socket, user, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
43
sockets/set/userSet.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
const models = require("../../models");
|
||||||
|
|
||||||
|
module.exports = socket => {
|
||||||
|
return async (data) => {
|
||||||
|
if (!data || !data.user) {
|
||||||
|
socket.emit("userSet", {error: {message: "missing_arguments"}});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let u = await models.User.findByPk(data.user);
|
||||||
|
if (!u) {
|
||||||
|
socket.emit("userSet", {error: {message: "user_not_found"}});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i in data)
|
||||||
|
switch (i) {
|
||||||
|
case "firstName":
|
||||||
|
u.firstName = data.firstName;
|
||||||
|
break;
|
||||||
|
case "lastName":
|
||||||
|
u.lastName = data.lastName;
|
||||||
|
break;
|
||||||
|
case "password":
|
||||||
|
u.passwordHash = data.password;
|
||||||
|
break;
|
||||||
|
case "permissions":
|
||||||
|
u.permissions = data.permissions;
|
||||||
|
break;
|
||||||
|
case "groups":
|
||||||
|
let groups = [];
|
||||||
|
for (let g of data.groups) {
|
||||||
|
let gp = await models.Group.findByPk(g);
|
||||||
|
if (!gp) {
|
||||||
|
socket.emit("userGet", {error: {message: "group_not_found"}});
|
||||||
|
return
|
||||||
|
}
|
||||||
|
groups.push(gp);
|
||||||
|
}
|
||||||
|
u.setGroups(groups);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await u.save();
|
||||||
|
}
|
||||||
|
};
|
|
@ -16,7 +16,7 @@ module.exports = async (socket, user, callBack) => {
|
||||||
subject: "forgot password"
|
subject: "forgot password"
|
||||||
}), async (err, message) => {
|
}), async (err, message) => {
|
||||||
if (err)
|
if (err)
|
||||||
socket.emit("forgotPassword", {error: {message: "fail_send_mail"}})
|
socket.emit("forgotPassword", {error: {message: "fail_send_mail"}});
|
||||||
else {
|
else {
|
||||||
user.passwordToken = token;
|
user.passwordToken = token;
|
||||||
user.passwordTokenDate = new Date();
|
user.passwordTokenDate = new Date();
|
||||||
|
|
|
@ -20,7 +20,7 @@ async function clean() {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
[app, models] = await setup();
|
[app, models] = await setup();
|
||||||
})
|
});
|
||||||
|
|
||||||
it("Main page content", async () => {
|
it("Main page content", async () => {
|
||||||
await request(app)
|
await request(app)
|
||||||
|
|
|
@ -1,87 +1,100 @@
|
||||||
extends ../template/navbar
|
extends ../template/navbar
|
||||||
|
|
||||||
block content
|
block content
|
||||||
table(id="edttable")
|
- let variable = [{name:"",ue:{id:0,name:""},teachers:[{id:0,firstName:"",lastName:""}],location:[""],dateStart:Date,dateEnd:Date,group:{id:0,number:0,promotion:{id:0,name:""}},promotion:{id:0,name:""}}];
|
||||||
tr
|
div.detailsedt#visibl
|
||||||
th Monday
|
p Maths
|
||||||
th Tuesday
|
p S26
|
||||||
th Wednesday
|
p Mr. Jaloux
|
||||||
th Thursday
|
p G4S3
|
||||||
th Friday
|
p 08h à 10h
|
||||||
tr
|
p UE------------
|
||||||
td
|
|
||||||
p Maths
|
div
|
||||||
p S26
|
table(id="edttable")
|
||||||
td
|
tr
|
||||||
p Maths
|
th Monday
|
||||||
p S26
|
th Tuesday
|
||||||
td
|
th Wednesday
|
||||||
p Maths
|
th Thursday
|
||||||
p S26
|
th Friday
|
||||||
td
|
tr
|
||||||
p Maths
|
td
|
||||||
p S26
|
p Maths
|
||||||
td
|
p S26
|
||||||
p Maths
|
td
|
||||||
p S26
|
p Maths
|
||||||
tr
|
p S26
|
||||||
td
|
td
|
||||||
p Maths
|
p Maths
|
||||||
p S26
|
p S26
|
||||||
td
|
td
|
||||||
p Maths
|
p Maths
|
||||||
p S26
|
p S26
|
||||||
td
|
td
|
||||||
p Maths
|
p Maths
|
||||||
p S26
|
p S26
|
||||||
td
|
tr
|
||||||
p Maths
|
td
|
||||||
p S26
|
p Maths
|
||||||
td
|
p S26
|
||||||
p Maths
|
td
|
||||||
p S26
|
p Maths
|
||||||
tr(class="midi")
|
p S26
|
||||||
td
|
td
|
||||||
td
|
p Maths
|
||||||
td
|
p S26
|
||||||
td
|
td
|
||||||
td
|
p Maths
|
||||||
tr
|
p S26
|
||||||
td
|
td
|
||||||
p Maths
|
p Maths
|
||||||
p S26
|
p S26
|
||||||
td
|
tr(class="midi")
|
||||||
p Maths
|
td
|
||||||
p S26
|
td
|
||||||
td
|
td
|
||||||
p Maths
|
td
|
||||||
p S26
|
td
|
||||||
td
|
tr
|
||||||
p Maths
|
td
|
||||||
p S26
|
p Maths
|
||||||
td
|
p S26
|
||||||
p Maths
|
td
|
||||||
p S26
|
p Maths
|
||||||
tr
|
p S26
|
||||||
td
|
td
|
||||||
p Maths
|
p Maths
|
||||||
p S26
|
p S26
|
||||||
td
|
td
|
||||||
p Maths
|
p Maths
|
||||||
p S26
|
p S26
|
||||||
td
|
td
|
||||||
p Maths
|
p Maths
|
||||||
p S26
|
p S26
|
||||||
td
|
tr
|
||||||
p Maths
|
td
|
||||||
p S26
|
p Maths
|
||||||
td
|
p S26
|
||||||
p Maths
|
td
|
||||||
p S26
|
p Maths
|
||||||
div(class="row" id="edtweek")
|
p S26
|
||||||
div(class="col s3 offset-s1")
|
td
|
||||||
i(class="large material-icons") fast_rewind
|
p Maths
|
||||||
div(class="col s4")
|
p S26
|
||||||
h3 Week of the 02/11/2020
|
td
|
||||||
div(class="col s3")
|
p Maths
|
||||||
i(class="large material-icons") fast_forward
|
p S26
|
||||||
|
td
|
||||||
|
p Maths
|
||||||
|
p S26
|
||||||
|
|
||||||
|
div(class="row" id="edtweek")
|
||||||
|
div(class="col s3 offset-s1")
|
||||||
|
i(class="large material-icons") fast_rewind
|
||||||
|
div(class="col s4")
|
||||||
|
h3 Week of the 02/11/2020
|
||||||
|
div(class="col s3")
|
||||||
|
i(class="large material-icons") fast_forward
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
extends ../template/navbar
|
extends ../template/navbar
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div.managesub#visible
|
div.managesub#visibl
|
||||||
p.topicname Tick the topics you would like to see in your news feed
|
p.topicname Tick the topics you would like to see in your news feed
|
||||||
form
|
form
|
||||||
p
|
p
|
||||||
|
|
|
@ -5,15 +5,24 @@ html
|
||||||
link(href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet")
|
link(href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet")
|
||||||
link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css")
|
link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css")
|
||||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||||
|
link(rel="icon" type="image/png" href="/images/favicon.ico")
|
||||||
|
link(rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png")
|
||||||
|
link(rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png")
|
||||||
|
link(rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png")
|
||||||
|
link(rel="manifest" href="/site.webmanifest")
|
||||||
|
link(rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5")
|
||||||
|
meta(name="msapplication-TileColor" content="#da532c")
|
||||||
|
meta(name="theme-color" content="#ffffff")
|
||||||
script(src="/socket.io/socket.io.js")
|
script(src="/socket.io/socket.io.js")
|
||||||
body
|
body
|
||||||
- var student = true
|
- var student = true
|
||||||
- var teacher = false
|
- var teacher = false
|
||||||
- var admin = false
|
- var admin = false
|
||||||
div(class="row" id="page")
|
div(class="row" id="page")
|
||||||
div(class="col s2" id="panel")
|
block navbar
|
||||||
block navbar
|
div(class="col s12" id="main")
|
||||||
div(class="col s10" id="main")
|
|
||||||
block content
|
block content
|
||||||
script(src="/javascripts/main.js")
|
script(src="/javascripts/main.js")
|
||||||
script(src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js")
|
script(src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js")
|
||||||
|
script.
|
||||||
|
M.AutoInit();
|
||||||
|
|
|
@ -1,54 +1,69 @@
|
||||||
extends layout
|
extends layout
|
||||||
|
|
||||||
block navbar
|
block navbar
|
||||||
if student === true
|
ul#slide-out.sidenav
|
||||||
div(id="navprofile" class="student" onclick="profilRedirect()")
|
if session.user.permissions === 1
|
||||||
p Kezel Benoit
|
li
|
||||||
p G4S3
|
.user-view.student
|
||||||
a(id="logout") Logout
|
p
|
||||||
if teacher === true
|
span.white-text.name=session.user.firstName + " " + session.user.lastName
|
||||||
div(id="navprofile" class="teacher" onclick="profilRedirect()")
|
p
|
||||||
p Kezel Benoit
|
if session.user.Groups[session.user.Groups.length-1]
|
||||||
a(id="logout") Logout
|
if session.user.Groups[session.user.Groups.length-1].number.startsWith("G")
|
||||||
if admin === true
|
span.white-text.name=session.user.Groups[session.user.Groups.length-1].number + session.user.Groups[session.user.Groups.length-1].Semester.name
|
||||||
div(id="navprofile" class="admin" onclick="profilRedirect()")
|
else
|
||||||
p Kezel Benoit
|
span.white-text.name=session.user.Groups[session.user.Groups.length-1].Semester.name + " " + session.user.Groups[session.user.Groups.length-1].number
|
||||||
a(id="logout") Logout
|
p
|
||||||
|
span.white-text.email=session.user.email
|
||||||
|
|
||||||
div(id="navtop")
|
li
|
||||||
ul
|
a(href="/" class="waves-effect") Home
|
||||||
if student === true
|
li
|
||||||
li(class="active")
|
a(href="/edt" class="waves-effect") Planning
|
||||||
a(href="/") Home
|
li(class="active")
|
||||||
li
|
a(href="/marks" class="waves-effect") Marks
|
||||||
a(href="/edt") Planning
|
li
|
||||||
li
|
a(href="https://mail.univ-lyon1.fr/owa/" class="waves-effect") Mail
|
||||||
a(href="/marks") Marks
|
li
|
||||||
li
|
a(href="https://clarolineconnect.univ-lyon1.fr/" class="waves-effect") Claroline
|
||||||
a(href="https://mail.univ-lyon1.fr/owa/") Mail
|
li
|
||||||
li
|
a(href="/viescol" class="waves-effect") School and student life
|
||||||
a(href="https://clarolineconnect.univ-lyon1.fr/") Claroline
|
|
||||||
li
|
if session.user.permissions === 2
|
||||||
a(href="/viescol") School and student life
|
li
|
||||||
if teacher === true
|
.user-view.teacher
|
||||||
li(class="active")
|
p(href='#name')
|
||||||
a(href="/") Home
|
span.white-text.name=session.user.firstName + " " + session.user.lastName
|
||||||
li
|
p(href='#email')
|
||||||
a(href="/edt") Planning
|
span.white-text.email=session.user.email
|
||||||
li
|
li
|
||||||
a(href="/marks") Marks
|
a(href="/" class="waves-effect") Home
|
||||||
li
|
li
|
||||||
a(href="https://mail.univ-lyon1.fr/owa/") Mail
|
a(href="/edt" class="waves-effect") Planning
|
||||||
li
|
li(class="active")
|
||||||
a(href="https://clarolineconnect.univ-lyon1.fr/") Claroline Connect
|
a(href="/marks" class="waves-effect") Marks
|
||||||
li
|
li
|
||||||
a(href="/viescol") School and student life
|
a(href="https://mail.univ-lyon1.fr/owa/" class="waves-effect") Mail
|
||||||
if admin === true
|
li
|
||||||
li(class="active")
|
a(href="https://clarolineconnect.univ-lyon1.fr/" class="waves-effect") Claroline
|
||||||
a Accueil
|
li
|
||||||
li
|
a(href="/viescol" class="waves-effect") School and student life
|
||||||
a Notes
|
|
||||||
li
|
if session.user.permissions === 3
|
||||||
a Vie scolaire et étudiante
|
li
|
||||||
li
|
.user-view.admin
|
||||||
a Gestion des profils
|
p(href='#name')
|
||||||
|
span.white-text.name=session.user.firstName + " " + session.user.lastName
|
||||||
|
p(href='#email')
|
||||||
|
span.white-text.email=session.user.email
|
||||||
|
li
|
||||||
|
a(href="/" class="waves-effect") Home
|
||||||
|
li(class="active")
|
||||||
|
a(href="/marks" class="waves-effect") Marks
|
||||||
|
li
|
||||||
|
a(href="/viescol" class="waves-effect") School and student life
|
||||||
|
li
|
||||||
|
a(href="/viescol" class="waves-effect") Profil Edition
|
||||||
|
|
||||||
|
a.sidenav-trigger(href='#' data-target='slide-out')#hamburger
|
||||||
|
i.material-icons.medium menu
|