-
Notifications
You must be signed in to change notification settings - Fork 0
/
automaticActions.js
396 lines (309 loc) · 15.3 KB
/
automaticActions.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
const db = require('./Database/index');
const notify = require('./notify');
const aurionScrapper = require('./AurionScrapperCore/index');
const axios = require('axios');
const mongoose = require('mongoose');
const crypt = require('./crypt');
const { forEach } = require('lodash');
function getUTCDateNow(date) {
/**
* Converti une chaine au format 'jj/mm/aaaa' en UTC Date String.
* Si la chaine donnée en argument est vide, on renvoie
* la date du jour en UTC Date String initialisée à minuit.
*/
// Conversion de la date en Date Object
let jetlag = 2;
let dateNow = new Date()
let utcDateNow = Date.UTC(dateNow.getUTCFullYear(), dateNow.getUTCMonth(), dateNow.getUTCDate(), dateNow.getUTCHours() + jetlag, dateNow.getUTCMinutes(), dateNow.getUTCSeconds())
let utcDateObject = new Date(new Date(utcDateNow));
return utcDateObject;
}
function getMinutesBetweenDates(startDate, endDate) {
var diff = endDate.getTime() - startDate.getTime();
return (diff / 60000);
}
function keepHerokuAlive() {
/**
* A pour but de lancer une requête inutile sur l'API pour
* qu'elle ne se mette pas en veille sur Heroku.
*/
console.log("## Keep-Alive request ##");
axios
.get('https://juniapocketapi.herokuapp.com/')
.then(res => {
console.log(`KeepAlive statusCode: ${res.statusCode}`);
})
.catch(error => {
console.error(error);
return false;
})
}
async function updateMarks() {
console.log('## MAJ AUTO DES NOTES ##');
let listOfUserDoc;
try {
listOfUserDoc = await db.Models.User.find();
} catch (error) {
console.log(`updateMarks error --> ${error}`);
return false;
}
// console.log('LIST :', listOfUserDoc)
for (user of listOfUserDoc) {
let aurionID = user.aurionID;
let aurionPassword = crypt.decode(user.aurionPassword);
// On verifie que l'user a deja un document de notes
// Sinon on ne fait rien
let userMarkDoc = await db.manageMark.getStudentMarkDoc(aurionID)
if (userMarkDoc != null && userMarkDoc != 'ERROR') {
console.log(`Mise à jour des notes de ${userMarkDoc.aurionID}...`);
// On récupère notes sur Aurion
let updatedMarksOfUser;
try {
let marksPageContent = await aurionScrapper.fetch.marks(aurionID, aurionPassword);
if (marksPageContent == 'Username ou mot de passe invalide.') {
console.log(`updateMarks --> Les identifiants aurions de ${aurionID} ne sont plus valides.`)
}
updatedMarksOfUser = aurionScrapper.formatMarks.getFormatedMarks(marksPageContent);
} catch (error) {
console.log(`updateMarks error --> Echec de la récupération des notes Aurion de ${aurionID} --> ${error}`)
}
// On vérifie s'il y a au moins une nouvelle note
let oldMarksDoc = await db.search.findUserByAurionIDInCollection(aurionID, db.Models.Mark);
let listOfNewMarks = db.manageMark.getListOfNewMarks(oldMarksDoc.marks, updatedMarksOfUser);
let nbOfNewMarks = listOfNewMarks.length;
// Envoi notification si au moins une nouvelle note
if (nbOfNewMarks > 0) {
console.log(`Une nouvelle note pour ${aurionID} !`);
// On génère le contenu de la notif
let notifTitle = 'Nouvelle note !\n\n';
if (nbOfNewMarks > 1) notifTitle = 'Nouvelles notes !\n';
let notifContent = '';
for (mark of listOfNewMarks) {
let keys = Object.keys(mark);
for (k of keys) {
notifContent += k + ': ' + mark[k] + '\n'
}
notifContent += '\n';
}
// envoi
notify(aurionID, notifTitle, notifContent);
}
// On met a jour la database
// On pourrait sauter cette étape en utilisant la condition (nbOfNewMarks == 0)
try {
db.manageMark.updateMarksInDoc(aurionID, updatedMarksOfUser);
} catch (error) {
console.log(`updateMarks error --> Echec sauvegarde des notes de ${aurionID} dans Marks --> ${error}`)
return res.status(sCode.unauthorized).json({ error });
}
}
else {
console.log(`updateMarks --> ${aurionID} n'a pas notes déjà existantes. Pas de MAJ possible.`);
}
}
}
async function updatePlanning () {
console.log('## MAJ AUTO DES PLANNING ##');
let listOfUserDoc;
try {
listOfUserDoc = await db.Models.User.find();
} catch (error) {
console.log(`updatePlanning error --> ${error}`);
return false;
}
let date = ''
// console.log('LIST :', listOfUserDoc)
for (user of listOfUserDoc) {
let aurionID = user.aurionID;
let aurionPassword = crypt.decode(user.aurionPassword);
console.log(`Mise à jour planning semaine de ${aurionID}`);
// On verifie que l'user a deja un planning de sauvegardé pour la semaine actuelle
// Sinon on ne fait rien
let weekToUpdate = await db.managePlanning.findWeekPlanningFromDate(aurionID, date);
if (weekToUpdate != null && weekToUpdate != 'ERROR') {
// Récupération sur Aurion du Planning Semaine demandée
console.log(`Récupération du planning de ${aurionID} dans la semaine actuelle`);
let requestedWeek;
try {
let planningPage = await aurionScrapper.fetch.planning(aurionID, aurionPassword, date);
if (planningPage == 'Username ou mot de passe invalide.') {
console.log('IDENTIFIANTS_AURION_MODIFIES');
}
requestedWeek = await aurionScrapper.formatPlanning.responseWeekPlanning(planningPage);
} catch (error) {
console.log(`updatePlanning error --> Echec récupération planning aurion de ${aurionID} dans la semaine actuelle`);
}
// On vérifie s'il y a eu des modification d'emploi du temps
let listOfModifiedDays = db.managePlanning.getListOfModifiedDays(weekToUpdate, requestedWeek);
console.log('listOfModifiedDays:', listOfModifiedDays);
// S'il y a modification et que mise à jour automatique
// on envoie une notification à l'utilisateur
if (listOfModifiedDays.length > 0 ) {
// Génération contenu de la notif
let notifTitle = `Modifications Planning détectées : ${listOfModifiedDays[0]}`;
let notifContent = ``;
if (listOfModifiedDays.length > 1) {
notifTitle = `Modifications Planning détectées aux dates suivantes :`;
for (dateDay of listOfModifiedDays) {
notifContent += dateDay + '\n';
}
}
// Envoi de la notif
notify(aurionID, notifTitle, notifContent);
}
else {
console.log(`updatePlanning --> Pas de modifications de planning dans la semaine actuelle`);
}
// Mise à jour dans la BDD de la semaine demandée
try {
await db.managePlanning.updateWeek(aurionID, date, requestedWeek);
} catch (error) {
console.log(error);
}
}
}
}
async function updateUnavailableRooms() {
console.log('< updateUnavailableRooms >');
let listOfPlanningDoc;
try {
listOfPlanningDoc = await db.Models.Planning.find();
listOfRoomDoc = await db.Models.Room.find();
} catch (error) {
console.log(`updateMarks error --> ${error}`);
return false;
}
for (planningDoc of listOfPlanningDoc) {
for (Week of planningDoc.weeks) {
for (day of Object.keys(Week.days)) {
for (evenement of Week.days[day]) {
for (roomDoc of listOfRoomDoc) {
if (evenement.room.includes(roomDoc.label)) {
console.log(`${planningDoc.aurionID} / ${day} : ${roomDoc.label}`);
// On verif si date déjà existante dans la collection Unavailable Rooms
try {
let UnavailableRoomDoc = await db.Models.UnavailableRoom.findOne({ date: day });
// Si non existante
if (!UnavailableRoomDoc) {
// No data found / On créée et sauvegarde la date
var label = roomDoc.label;
let [startTime, endTime] = [evenement.startTime, evenement.endTime];
let obj = {};
obj[label] = [[startTime, endTime]];
const doc = db.Models.UnavailableRoom({
_id: new mongoose.Types.ObjectId(),
date: day,
rooms: obj
}, { collection: 'unavailableRoom' });
// sauvegarde mais empeche de passer à la suite tant que non fini
await doc.save().then(console.log('first save!'));
break;
}
// Si date existante dans la collection Unavailable Rooms
else {
// On verif si la salle est déjà existante ou non
let isRoomAlreadyThere = Object.keys(UnavailableRoomDoc.rooms).includes(roomDoc.label);
if (isRoomAlreadyThere) {
// On vérifie si le(s) créneau(x) renseingné(s) pour cette salle ne sont pas déjà inscrits comme non dispo
// On compare les heures de début uniquement (en supposant que les conflits ont déjà été traités par Aurion)
let isNew = true;
UnavailableRoomDoc.rooms[roomDoc.label].forEach((slot) => {
console.log('Already taken slot :', slot);
if (slot[0] == evenement.startTime) {
isNew = false;
}
});
// Si nouveau créneau, on l'ajoute et on save
if (isNew) {
let Slot = [evenement.startTime, evenement.endTime]
UnavailableRoomDoc.rooms[roomDoc.label].push(Slot);
// on trie les creneaux par horaires
UnavailableRoomDoc.rooms[roomDoc.label].sort((a, b) => {
let strStartTimeA = a[0].split(':')[0] + a[0].split(':')[1];
let strStartTimeB = b[0].split(':')[0] + b[0].split(':')[1];
return Number(strStartTimeA) - Number(strStartTimeB);
})
var pushObj = {};
pushObj['rooms.' + label] = [evenement.startTime, evenement.endTime];
db.Models.UnavailableRoom.updateOne({ date: day }, { $push: pushObj }).then(console.log('updated!'));
break;
}
}
else { // Si la salle n'existe pas encore à cette date on la rajoute
var label = roomDoc.label;
let [startTime, endTime] = [evenement.startTime, evenement.endTime];
let obj = {};
obj[label] = [[startTime, endTime]];
db.Models.UnavailableRoom.updateOne({ date: day }, { $push: obj }).then(console.log('room added to date!'));
}
}
} catch (error) {
console.log(`updateUnavailableRooms error --> ${error}`);
}
}
}
}
}
}
}
}
async function notifyNextCourse() {
/**
* NECESSITE QUE LE PLANNING SOIT DEJA ENREGISTRE DANS LA BDD
*
*/
console.log('## CHECK NOTIF PROCHAIN COURS ##');
// Si on est un dimanche, on ne fait rien.
let day = new Date().getDay()
if (day == 0) {
return true;
}
// Si on est entre 22h et 7h on ne fait rien
let hour = new Date().getHours()
if (hour > 22 && hour < 7) {
return true;
}
// Sinon, on récupère les planning des User ayant déjà sauv des planning
let listOfPlanningDoc;
try {
listOfPlanningDoc = await db.Models.Planning.find();
} catch (error) {
console.log(`getMinutesUntilNextCourse error --> ${error}`);
return false;
}
for (user of listOfPlanningDoc) {
// On récupère le planning de la semaine
let aurionID = user.aurionID;
let date = ''; // on prend la date du jour
let currentWeek = await db.managePlanning.findWeekPlanningFromDate(aurionID, date);
// si la semaine est enregistrée dans la BDD pour l'user
if (currentWeek != null) {
// On récupère dans la BDD les cours du jour puis on cherche le prochain horaire
let eventsOfTheDay = Object.values(currentWeek.days)[day - 1];
let beginDate;
for (e of eventsOfTheDay) {
// On calcule le nb de minutes restantes avant l'event (peut être négatif)
let [hour, min] = e.startTime.split(':');
let date = new Date(e.date);
beginDate = new Date(date.setTime(date.getTime() + hour * 60 * 60 * 1000 + min * 60 * 1000));
let dateNow = getUTCDateNow();
let diff = getMinutesBetweenDates(dateNow, beginDate)
// Si l'event n'est pas passé et qu'il se produit dans moins de 20 min
if (diff > 0 && diff <= 20) {
// On génère le contenu de la notif
let notifTitle = `Prochain cours dans ${Math.floor(diff)} minutes !`;
let notifContent = `Salle: ${e.room}\nIntitulé: ${e.eventName}\nIntervenant: ${e.teacher}`;
// envoi
notify(aurionID, notifTitle, notifContent);
}
}
}
}
}
module.exports = {
keepHerokuAlive,
updateMarks,
updatePlanning,
updateUnavailableRooms,
notifyNextCourse
}