From 2c4ae43e688a9873e86211ea0e7aeb9ba770dd77 Mon Sep 17 00:00:00 2001 From: Minteck Date: Tue, 18 Oct 2022 08:59:09 +0200 Subject: Update --- .../node_modules/pronote-api/src/fetch/absences.js | 114 +++++++++++++ .../node_modules/pronote-api/src/fetch/contents.js | 51 ++++++ .../pronote-api/src/fetch/evaluations.js | 65 ++++++++ alarm/node_modules/pronote-api/src/fetch/files.js | 32 ++++ .../pronote-api/src/fetch/homeworks.js | 45 +++++ alarm/node_modules/pronote-api/src/fetch/infos.js | 33 ++++ alarm/node_modules/pronote-api/src/fetch/marks.js | 73 ++++++++ alarm/node_modules/pronote-api/src/fetch/menu.js | 41 +++++ .../pronote-api/src/fetch/pronote/absences.js | 164 ++++++++++++++++++ .../pronote-api/src/fetch/pronote/auth.js | 43 +++++ .../pronote-api/src/fetch/pronote/contents.js | 60 +++++++ .../pronote-api/src/fetch/pronote/evaluations.js | 49 ++++++ .../pronote-api/src/fetch/pronote/files.js | 16 ++ .../pronote-api/src/fetch/pronote/homeworks.js | 43 +++++ .../pronote-api/src/fetch/pronote/infos.js | 33 ++++ .../pronote-api/src/fetch/pronote/keepAlive.js | 8 + .../pronote-api/src/fetch/pronote/logout.js | 8 + .../pronote-api/src/fetch/pronote/marks.js | 71 ++++++++ .../pronote-api/src/fetch/pronote/menu.js | 42 +++++ .../pronote-api/src/fetch/pronote/navigate.js | 23 +++ .../pronote-api/src/fetch/pronote/params.js | 141 ++++++++++++++++ .../pronote-api/src/fetch/pronote/timetable.js | 81 +++++++++ .../pronote-api/src/fetch/pronote/user.js | 183 +++++++++++++++++++++ .../pronote-api/src/fetch/timetable.js | 95 +++++++++++ 24 files changed, 1514 insertions(+) create mode 100644 alarm/node_modules/pronote-api/src/fetch/absences.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/contents.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/evaluations.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/files.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/homeworks.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/infos.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/marks.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/menu.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/absences.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/auth.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/contents.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/evaluations.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/files.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/homeworks.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/infos.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/keepAlive.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/logout.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/marks.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/menu.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/navigate.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/params.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/timetable.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/pronote/user.js create mode 100644 alarm/node_modules/pronote-api/src/fetch/timetable.js (limited to 'alarm/node_modules/pronote-api/src/fetch') diff --git a/alarm/node_modules/pronote-api/src/fetch/absences.js b/alarm/node_modules/pronote-api/src/fetch/absences.js new file mode 100644 index 0000000..9c1ac02 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/absences.js @@ -0,0 +1,114 @@ +const { getPeriodBy } = require('../data/periods'); +const { withId, checkDuplicates } = require('../data/id'); + +const getAbsences = require('./pronote/absences'); + +// eslint-disable-next-line complexity +async function absences(session, user, period = null, from = null, to = null, type = null) +{ + const result = { + absences: [], + delays: [], + punishments: [], + other: [], + totals: [] + }; + + const p = getPeriodBy(session, !period && !type && from && to ? 'Trimestre 1' : period, type); + const absences = await getAbsences(session, user, p, from || p.from, to || p.to); + if (!absences) { + return null; + } + + for (const event of absences.events) { + // eslint-disable-next-line default-case + switch (event.type) { + case 'absence': + result.absences.push(withId({ + from: event.from, + to: event.to, + justified: event.justified, + solved: event.solved, + hours: event.hours, + reason: event.reasons.length && event.reasons[0].name || '' + }, ['from', 'to'])); + break; + case 'delay': + result.delays.push(withId({ + date: event.date, + justified: event.justified, + solved: event.solved, + justification: event.justification, + minutesMissed: event.duration, + reason: event.reasons.length && event.reasons[0].name || '' + }, ['data', 'minutesMissed'])); + break; + case 'punishment': + // eslint-disable-next-line no-case-declarations + let detention = null; + if (event.nature.type === 1) { + const schedule = event.schedule[0]; + const hour = session.params.firstHour.getHours() + schedule.position / session.params.ticksPerHour; + + const from = new Date(schedule.date.getTime()); + const to = new Date(schedule.date.getTime()); + + from.setHours(from.getHours() + hour); + to.setHours(to.getHours() + hour); + to.setMinutes(to.getMinutes() + schedule.duration); + + detention = { from, to }; + } + + result.punishments.push(withId({ + date: event.date, + isExclusion: event.isExclusion, + isDuringLesson: !event.isNotDuringLesson, + homework: event.homework, + circumstances: event.circumstances, + giver: event.giver.name, + reason: event.reasons.length && event.reasons[0].name || '', + detention + }, ['data'])); + break; + case 'other': + result.other.push(withId({ + kind: event.name, + date: event.date, + giver: event.giver.name, + comment: event.comment, + subject: event.subject && event.subject.name || null + }, ['kind', 'date'])); + break; + } + } + + Object.values(result).forEach(checkDuplicates); + + if (absences.subjects) { + for (const subject of absences.subjects) { + if (subject.inGroup) { + continue; + } + + const res = parseSubject(subject); + if (subject.group) { + res.subs = absences.subjects.filter(s => s.inGroup === subject.group).map(s => parseSubject(s)); + } + + result.totals.push(res); + } + } + + return result; +} + +function parseSubject(subject) { + return { + subject: subject.name, + hoursAssisted: subject.hoursAssisted, + hoursMissed: subject.hoursMissed + }; +} + +module.exports = absences; diff --git a/alarm/node_modules/pronote-api/src/fetch/contents.js b/alarm/node_modules/pronote-api/src/fetch/contents.js new file mode 100644 index 0000000..62e85df --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/contents.js @@ -0,0 +1,51 @@ +const { toPronoteWeek } = require('../data/dates'); +const { getFileURL } = require('../data/files'); +const fromHTML = require('../data/html'); +const { withId, checkDuplicates } = require('../data/id'); + +const getContents = require('./pronote/contents'); + +async function contents(session, user, from = new Date(), to = null) +{ + if (!to || to < from) { + to = new Date(from.getTime()); + to.setDate(to.getDate() + 1); + } + + const fromWeek = toPronoteWeek(session, from); + const toWeek = toPronoteWeek(session, to); + + const contents = await getContents(session, user, fromWeek, toWeek); + if (!contents) { + return null; + } + + const result = []; + + for (const lesson of contents.lessons) { + if (lesson.from < from || lesson.to > to) { + continue; + } + + const content = lesson.content[0]; // Maybe on some instances there will be multiple entries ? Check this + if (typeof content === 'undefined') { + continue; + } + result.push(withId({ + subject: lesson.subject.name, + teachers: lesson.teachers.map(t => t.name), + from: lesson.from, + to: lesson.to, + color: lesson.color, + title: content.name, + description: fromHTML(content.description), + htmlDescription: content.htmlDescription, + files: content.files.map(f => withId({ name: f.name, url: getFileURL(session, f) }, ['name'])), + category: content.category.name + }, ['subject', 'from', 'to'])); + } + + return checkDuplicates(result).sort((a, b) => a.from - b.from); +} + +module.exports = contents; diff --git a/alarm/node_modules/pronote-api/src/fetch/evaluations.js b/alarm/node_modules/pronote-api/src/fetch/evaluations.js new file mode 100644 index 0000000..dca1b9f --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/evaluations.js @@ -0,0 +1,65 @@ +const { getPeriodBy } = require('../data/periods'); +const { withId, checkDuplicates } = require('../data/id'); + +const getEvaluations = require('./pronote/evaluations'); + +async function evaluations(session, user, period = null, type = null) +{ + const evaluations = await getEvaluations(session, user, getPeriodBy(session, period, type)); + if (!evaluations) { + return null; + } + + const result = []; + + if (!evaluations) { + return null; + } + + for (const evaluation of evaluations) { + let subject = result.find(s => s.name === evaluation.subject.name); + if (!subject) { + const { position, name, color } = evaluation.subject; + subject = { + position, + name, + teacher: evaluation.teacher.name, + color, + evaluations: [] + }; + + result.push(subject); + } + + subject.evaluations.push(withId({ + name: evaluation.name, + date: evaluation.date, + coefficient: evaluation.coefficient, + levels: evaluation.acquisitionLevels.map(({ name, position, value, item, domain, pillar }) => ({ + name: item && item.name || domain.name, + position, + value: { + short: value, + long: name + }, + prefixes: !pillar.prefixes[0] ? [] : pillar.prefixes + })) + }, ['name', 'date'], subject.name)); + } + + result.forEach(s => checkDuplicates(s.evaluations)); + + result.sort((a, b) => a.position - b.position); + result.forEach(s => { + s.evaluations.forEach(e => { + e.levels.sort((a, b) => a.position - b.position); + e.levels.forEach(l => delete l.position); + }); + + return delete s.position; + }); + + return result; +} + +module.exports = evaluations; diff --git a/alarm/node_modules/pronote-api/src/fetch/files.js b/alarm/node_modules/pronote-api/src/fetch/files.js new file mode 100644 index 0000000..7703ee4 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/files.js @@ -0,0 +1,32 @@ +const { parseDate } = require('../data/dates'); +const { getFileURL } = require('../data/files'); +const { withId, checkDuplicates } = require('../data/id'); + +const getFiles = require('./pronote/files'); + +async function files(session, user) { + const files = await getFiles(session, user); + if (!files) { + return null; + } + + const result = []; + + const subjects = {}; + for (const subject of files.listeMatieres.V) { + subjects[subject.N] = subject.L; + } + + for (const file of files.listeRessources.V) { + result.push(withId({ + time: parseDate(file.date.V), + subject: subjects[file.matiere.V.N], + name: file.ressource.V.L, + url: getFileURL(session, { id: file.ressource.V.N, name: file.ressource.V.L, type: file.ressource.V.G }) + }, 'subject', 'name')); + } + + return checkDuplicates(result); +} + +module.exports = files; diff --git a/alarm/node_modules/pronote-api/src/fetch/homeworks.js b/alarm/node_modules/pronote-api/src/fetch/homeworks.js new file mode 100644 index 0000000..7f2146b --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/homeworks.js @@ -0,0 +1,45 @@ +const { toPronoteWeek } = require('../data/dates'); +const { getFileURL } = require('../data/files'); +const fromHTML = require('../data/html'); +const { withId, checkDuplicates } = require('../data/id'); + +const getHomeworks = require('./pronote/homeworks'); + +async function homeworks(session, user, from = new Date(), to = null) +{ + if (!to || to < from) { + to = new Date(from.getTime()); + to.setDate(to.getDate() + 1); + } + + const fromWeek = toPronoteWeek(session, from); + const toWeek = toPronoteWeek(session, to); + + const homeworks = await getHomeworks(session, user, fromWeek, toWeek); + if (!homeworks) { + return null; + } + + const result = []; + + for (const homework of homeworks) { + if (homework.for < from || homework.for > to) { + continue; + } + + result.push(withId({ + description: fromHTML(homework.description), + htmlDescription: homework.description, + subject: homework.subject.name, + givenAt: homework.givenAt, + for: homework.for, + done: homework.done, + color: homework.color, + files: homework.files.map(f => withId({ name: f.name, url: getFileURL(session, f) }, ['name'])) + }, 'subject', 'givenAt')); + } + + return checkDuplicates(result).sort((a, b) => a.for - b.for); +} + +module.exports = homeworks; diff --git a/alarm/node_modules/pronote-api/src/fetch/infos.js b/alarm/node_modules/pronote-api/src/fetch/infos.js new file mode 100644 index 0000000..0ec03a7 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/infos.js @@ -0,0 +1,33 @@ +const { getFileURL } = require('../data/files'); +const fromHTML = require('../data/html'); +const { withId, checkDuplicates } = require('../data/id'); + +const getInfos = require('./pronote/infos'); + +async function infos(session, user) +{ + const infos = await getInfos(session, user); + if (!infos) { + return null; + } + + const result = []; + + for (const info of infos.infos) + { + result.push(withId({ + date: info.date, + title: info.name, + author: info.author.name, + content: fromHTML(info.content[0].text), + htmlContent: info.content[0].text, + files: info.content[0].files.map(f => withId({ name: f.name, url: getFileURL(session, f) }, ['name'])) + }, ['date', 'title'])); + } + + checkDuplicates(result).sort((a, b) => a.date - b.date); + + return result; +} + +module.exports = infos; diff --git a/alarm/node_modules/pronote-api/src/fetch/marks.js b/alarm/node_modules/pronote-api/src/fetch/marks.js new file mode 100644 index 0000000..1e57e85 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/marks.js @@ -0,0 +1,73 @@ +const { getPeriodBy } = require('../data/periods'); +const { withId, checkDuplicates } = require('../data/id'); + +const getMarks = require('./pronote/marks'); + +async function marks(session, user, period = null, type = null) +{ + const marks = await getMarks(session, user, getPeriodBy(session, period, type)); + if (!marks) { + return null; + } + + const result = { + subjects: [], + averages: {} + }; + + if (marks.studentAverage) { + result.averages.student = Number((marks.studentAverage / marks.studentAverageScale * 20).toFixed(2)); + } + if (marks.studentClassAverage) { + result.averages.studentClass = Number(marks.studentClassAverage.toFixed(2)); + } + + for (const subject of marks.subjects.sort((a, b) => a.order - b.order)) { + result.subjects.push({ + name: subject.name, + averages: { + student: subject.studentAverage / subject.studentAverageScale * 20, + studentClass: subject.studentClassAverage, + max: subject.maxAverage, + min: subject.minAverage + }, + color: subject.color, + marks: [] + }); + } + + for (const mark of marks.marks) { + const subject = result.subjects.find(s => s.name === mark.subject.name); + if (!subject) { + continue; + } + + const res = { + isAway: mark.value < 0 + }; + + if (!res.isAway) { + res.value = mark.value; + } + + if (mark.average >= 0) { + res.min = mark.min; + res.max = mark.max; + res.average = mark.average; + } + + subject.marks.push(withId({ + title: mark.title, + ...res, + scale: mark.scale, + coefficient: mark.coefficient, + date: mark.date + }, ['title', 'date'], subject.name)); + } + + result.subjects.forEach(s => checkDuplicates(s.marks)); + + return result; +} + +module.exports = marks; diff --git a/alarm/node_modules/pronote-api/src/fetch/menu.js b/alarm/node_modules/pronote-api/src/fetch/menu.js new file mode 100644 index 0000000..6f2872c --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/menu.js @@ -0,0 +1,41 @@ +const getMenu = require('./pronote/menu'); + +async function menu(session, user, from = new Date(), to = null) +{ + if (!to || to < from) { + to = new Date(from.getTime()); + to.setDate(to.getDate() + 1); + to.setHours(to.getHours() - 1); + } + + const result = []; + const date = new Date(from.getTime()); + + // eslint-disable-next-line no-unmodified-loop-condition + while (date < to) { + const menus = await getMenu(session, user, date); + if (!menus) { + return null; + } + + for (const menu of menus.menus) { + if (menu.date < from || menu.date > to) { + continue; + } + + result.push({ + date: menu.date, + meals: menu.meals.map(m => m.content.map(c => c.lines.map(({ name, labels }) => ({ + name, + labels: labels.map(({ name, color }) => ({ name, color })) + })))) + }); + } + + date.setDate(date.getDate() + 7); + } + + return result; +} + +module.exports = menu; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/absences.js b/alarm/node_modules/pronote-api/src/fetch/pronote/absences.js new file mode 100644 index 0000000..19bf2dc --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/absences.js @@ -0,0 +1,164 @@ +const parse = require('../../data/types'); +const { toPronote } = require('../../data/objects'); +const { toPronoteDate } = require('../../data/dates'); +const { fromPronoteHours } = require('../../data/dates'); + +const navigate = require('./navigate'); + +const PAGE_NAME = 'PagePresence'; +const TAB_ID = 19; +const ACCOUNTS = ['student', 'parent']; + +async function getAbsences(session, user, period, from, to) +{ + const absences = await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + DateDebut: { + _T: 7, + V: toPronoteDate(from) + }, + DateFin: { + _T: 7, + V: toPronoteDate(to) + }, + periode: period.name ? toPronote(period) : period + }); + + if (!absences) { + return null; + } + + return { + authorizations: (a => ({ + absences: a.absence, + fillAbsenceReason: a.saisieMotifAbsence, + delays: a.retard, + fillDelayReason: a.saisieMotifRetard, + punishments: a.punition, + exclusions: a.exclusion, + sanctions: a.sanction, + conservatoryMesures: a.mesureConservatoire, + infirmary: a.infirmerie, + mealAbsences: a.absenceRepas, + internshipAbsences: a.absenceInternat, + observations: a.observation, + incidents: a.incident, + totalHoursMissed: a.totalHeuresManquees + }))(absences.autorisations), + events: parse(absences.listeAbsences, a => parseEvent(a), false), + subjects: parse(absences.Matieres, ({ + P, regroupement, dansRegroupement, suivi, absence, excluCours, excluEtab + }) => ({ + position: P, + group: regroupement, + inGroup: dansRegroupement, + hoursAssisted: suivi / 3600, + hoursMissed: absence / 3600, + lessonExclusions: excluCours, + establishmentExclusions: excluEtab + })), + recaps: parse(absences.listeRecapitulatifs, ({ NombreTotal, NbrHeures, NombreNonJustifie }) => ({ + count: NombreTotal, + unjustifiedCount: NombreNonJustifie, + hours: fromPronoteHours(NbrHeures) + })), + sanctions: parse(absences.listeSanctionUtilisateur) // TODO: Check values + }; +} + +function parseEvent(a) +{ + switch (a.page.Absence) { + case 13: + return { + type: 'absence', + ...parseAbsence(a) + }; + case 14: + return { + type: 'delay', + ...parseDelay(a) + }; + case 41: + return { + type: 'punishment', + ...parsePunishment(a) + }; + case 45: + return { + type: 'other', + ...parseOther(a) + }; + default: + return { + type: 'unknown', + ...a + }; + } +} + +function parseAbsence(a) +{ + return { + from: parse(a.dateDebut), + to: parse(a.dateFin), + opened: a.ouverte, + solved: a.reglee, + justified: a.justifie, + hours: fromPronoteHours(a.NbrHeures), + days: a.NbrJours, + reasons: parse(a.listeMotifs) + } +} + +function parseDelay(a) +{ + return { + date: parse(a.date), + solved: a.reglee, + justified: a.justifie, + justification: a.justification, + duration: a.duree, + reasons: parse(a.listeMotifs) + }; +} + +function parsePunishment(a) +{ + return { + date: parse(a.dateDemande), + isExclusion: a.estUneExclusion, + isNotDuringLesson: a.horsCours, + homework: a.travailAFaire, + isBoundToIncident: a.estLieAUnIncident, + circumstances: a.circonstances, + duration: a.duree, + giver: parse(a.demandeur), + isSchedulable: a.estProgrammable, + reasons: parse(a.listeMotifs), + schedule: parse(a.programmation, ({ date, placeExecution, duree }) => ({ + date: parse(date), + position: placeExecution, + duration: duree + })), + nature: a.nature && parse(a.nature, ({ estProgrammable, estAvecARParent }) => ({ + isSchedulable: estProgrammable, + requiresParentsMeeting: estAvecARParent + })) + } +} + +function parseOther(a) +{ + return { + date: parse(a.date), + giver: parse(a.demandeur, ({ estProfPrincipal, mail }) => ({ + isHeadTeacher: estProfPrincipal, + mail + })), + comment: a.commentaire, + read: a.estLue, + subject: parse(a.matiere) + }; +} + +module.exports = getAbsences; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/auth.js b/alarm/node_modules/pronote-api/src/fetch/pronote/auth.js new file mode 100644 index 0000000..9c1d566 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/auth.js @@ -0,0 +1,43 @@ +const request = require('../../request'); +const { cipher } = require('../../cipher'); + +async function getId(session, username, fromCas) +{ + const { donnees: id } = await request(session, 'Identification', { + donnees: { + genreConnexion: 0, + genreEspace: session.type.id, + identifiant: username, + pourENT: fromCas, + enConnexionAuto: false, + demandeConnexionAuto: false, + demandeConnexionAppliMobile: false, + demandeConnexionAppliMobileJeton: false, + uuidAppliMobile: '', + loginTokenSAV: '' + } + }); + + return { + scramble: id.alea, + challenge: id.challenge + }; +} + +async function getAuthKey(session, challenge, key) +{ + const { donnees: auth } = await request(session, 'Authentification', { + donnees: { + connexion: 0, + challenge: cipher(session, challenge, { key }), + espace: session.type.id + } + }); + + return auth.cle; +} + +module.exports = { + getId, + getAuthKey +}; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/contents.js b/alarm/node_modules/pronote-api/src/fetch/pronote/contents.js new file mode 100644 index 0000000..7525e3d --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/contents.js @@ -0,0 +1,60 @@ +const parse = require('../../data/types'); +const { fromPronote } = require('../../data/objects'); + +const navigate = require('./navigate'); + +const PAGE_NAME = 'PageCahierDeTexte'; +const TAB_ID = 89; +const ACCOUNTS = ['student', 'parent']; + +async function getContents(session, user, fromWeek = 1, toWeek = null) +{ + if (!toWeek || toWeek < fromWeek) { + toWeek = fromWeek; + } + + const contents = await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + domaine: { + _T: 8, + V: `[${fromWeek}..${toWeek}]` + } + }); + + if (!contents) { + return null; + } + + return { + lessons: parse(contents.ListeCahierDeTextes, ({ + cours, verrouille, listeGroupes, Matiere, CouleurFond, listeProfesseurs, Date, DateFin, + listeContenus, listeElementsProgrammeCDT + }) => ({ + lesson: parse(cours), + locked: verrouille, + groups: parse(listeGroupes), // TODO: Check values + subject: parse(Matiere), + color: CouleurFond, + teachers: parse(listeProfesseurs), + from: parse(Date), + to: parse(DateFin), + content: parse(listeContenus, ({ + descriptif, categorie, parcoursEducatif, ListePieceJointe, training + }) => ({ + description: parse(descriptif), + category: parse(categorie), + path: parcoursEducatif, + files: parse(ListePieceJointe), + training: parse(training).ListeExecutionsQCM.map(o => fromPronote(o)) // TODO: Check values + })), + skills: parse(listeElementsProgrammeCDT) + })), + resources: (({ listeRessources, listeMatieres }) => ({ + resources: parse(listeRessources), // TODO: Check values + subjects: parse(listeMatieres) // TODO: Check values + }))(parse(contents.ListeRessourcesPedagogiques)), + // TODO: Check values + numericalResources: parse(parse(contents.ListeRessourcesNumeriques).listeRessources) + }; +} + +module.exports = getContents; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/evaluations.js b/alarm/node_modules/pronote-api/src/fetch/pronote/evaluations.js new file mode 100644 index 0000000..c9065fd --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/evaluations.js @@ -0,0 +1,49 @@ +const parse = require('../../data/types'); +const { toPronote } = require('../../data/objects'); + +const navigate = require('./navigate'); + +const PAGE_NAME = 'DernieresEvaluations'; +const TAB_ID = 201; +const ACCOUNTS = ['student', 'parent']; + +async function getEvaluations(session, user, period) +{ + const evaluations = await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + periode: period.name ? toPronote(period) : period + }); + + if (!evaluations) { + return null; + } + + return parse(evaluations.listeEvaluations, ({ + listeNiveauxDAcquisitions, listePaliers, matiere, individu, coefficient, descriptif, date, periode + }) => ({ + title: descriptif, + acquisitionLevels: parse(listeNiveauxDAcquisitions, ({ + abbreviation, ordre, pilier, coefficient, domaine, item + }) => ({ + position: ordre, + value: abbreviation, + pillar: parse(pilier, ({ strPrefixes }) => ({ + prefixes: strPrefixes.split(', ') + })), + coefficient, + domain: parse(domaine), + item: item && parse(item) || null + })), + levels: parse(listePaliers), + subject: parse(matiere, ({ couleur, ordre, serviceConcerne }) => ({ + position: ordre, + service: parse(serviceConcerne), + color: couleur + })), + teacher: parse(individu), + coefficient, + date: parse(date), + period: parse(periode) + })); +} + +module.exports = getEvaluations; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/files.js b/alarm/node_modules/pronote-api/src/fetch/pronote/files.js new file mode 100644 index 0000000..2871fbe --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/files.js @@ -0,0 +1,16 @@ +const navigate = require('./navigate'); + +const PAGE_NAME = 'RessourcePedagogique'; +const TAB_ID = 99; +const ACCOUNTS = ['student']; + +async function getFiles(session, user) +{ + return await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + avecRessourcesPronote: true, + avecRessourcesEditeur: false + }); +} + + +module.exports = getFiles; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/homeworks.js b/alarm/node_modules/pronote-api/src/fetch/pronote/homeworks.js new file mode 100644 index 0000000..7d13c48 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/homeworks.js @@ -0,0 +1,43 @@ +const parse = require('../../data/types'); + +const navigate = require('./navigate'); + +const PAGE_NAME = 'PageCahierDeTexte'; +const TAB_ID = 88; +const ACCOUNTS = ['student', 'parent']; + +async function getHomeworks(session, user, fromWeek = 1, toWeek = null) +{ + if (!toWeek || toWeek < fromWeek) { + toWeek = fromWeek; + } + + const homeworks = await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + domaine: { + _T: 8, + V: `[${fromWeek}..${toWeek}]` + } + }); + + if (!homeworks) { + return null; + } + + return parse(homeworks.ListeTravauxAFaire, ({ + descriptif, PourLe, TAFFait, niveauDifficulte, duree, cours, DonneLe, + Matiere, CouleurFond, ListePieceJointe + }) => ({ + description: parse(descriptif), + lesson: parse(cours), + subject: parse(Matiere), + givenAt: parse(DonneLe), + for: parse(PourLe), + done: TAFFait, + difficultyLevel: niveauDifficulte, + duration: duree, + color: CouleurFond, + files: parse(ListePieceJointe) + })); +} + +module.exports = getHomeworks; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/infos.js b/alarm/node_modules/pronote-api/src/fetch/pronote/infos.js new file mode 100644 index 0000000..6e05ce1 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/infos.js @@ -0,0 +1,33 @@ +const parse = require('../../data/types'); +const navigate = require('./navigate'); + +const PAGE_NAME = 'PageActualites'; +const TAB_ID = 8; +const ACCOUNTS = ['student', 'parent']; + +async function getInfos(session, user) +{ + const infos = await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + estAuteur: false + }); + + if (!infos) { + return null; + } + + return { + categories: parse(infos.listeCategories, ({ estDefaut }) => ({ + isDefault: estDefaut + })), + infos: parse(infos.listeActualites, ({ dateDebut, elmauteur, listeQuestions }) => ({ + date: parse(dateDebut), + author: parse(elmauteur), + content: parse(listeQuestions, ({ texte, listePiecesJointes }) => ({ + text: parse(texte), + files: parse(listePiecesJointes) + })) + })) + }; +} + +module.exports = getInfos; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/keepAlive.js b/alarm/node_modules/pronote-api/src/fetch/pronote/keepAlive.js new file mode 100644 index 0000000..89705ec --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/keepAlive.js @@ -0,0 +1,8 @@ +const request = require('../../request'); + +async function keepAlive(session) +{ + await request(session, 'Presence'); +} + +module.exports = keepAlive; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/logout.js b/alarm/node_modules/pronote-api/src/fetch/pronote/logout.js new file mode 100644 index 0000000..ede23e7 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/logout.js @@ -0,0 +1,8 @@ +const request = require('../../request'); + +async function logout(session) +{ + await request(session, 'SaisieDeconnexion'); +} + +module.exports = logout; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/marks.js b/alarm/node_modules/pronote-api/src/fetch/pronote/marks.js new file mode 100644 index 0000000..dcb7644 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/marks.js @@ -0,0 +1,71 @@ +const parse = require('../../data/types'); +const { toPronote } = require('../../data/objects'); + +const navigate = require('./navigate'); + +const PAGE_NAME = 'DernieresNotes'; +const TAB_ID = 198; +const ACCOUNTS = ['student', 'parent']; + +async function getMarks(session, user, period) +{ + const marks = await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + Periode: period.name ? toPronote(period) : period + }); + + if (!marks) { + return null; + } + + const result = {}; + + if (marks.moyGenerale) { + result.studentAverage = parse(marks.moyGenerale); + result.studentAverageScale = parse(marks.baremeMoyGenerale); + result.defaultStudentAverageScale = parse(marks.baremeMoyGeneraleParDefaut); + } + + if (marks.moyGeneraleClasse) { + result.studentClassAverage = parse(marks.moyGeneraleClasse); + } + + return { + ...result, + subjects: marks.avecDetailService && parse(marks.listeServices, ({ + ordre, estServiceEnGroupe, + moyEleve, baremeMoyEleve, baremeMoyEleveParDefaut, moyClasse, moyMax, moyMin, + couleur + }) => ({ + position: ordre, + isGroupSubject: estServiceEnGroupe, + studentAverage: parse(moyEleve), + studentAverageScale: parse(baremeMoyEleve), + defaultStudentAverageScale: parse(baremeMoyEleveParDefaut), + studentClassAverage: parse(moyClasse), + maxAverage: parse(moyMax), + minAverage: parse(moyMin), + color: couleur + })) || [], + marks: marks.avecDetailDevoir && parse(marks.listeDevoirs, ({ + note, bareme, baremeParDefaut, date, service, periode, moyenne, estEnGroupe, noteMax, noteMin, + commentaire, coefficient + }) => ({ + subject: parse(service, ({ couleur }) => ({ + color: couleur + })), + title: commentaire, + value: parse(note), + scale: parse(bareme), + average: parse(moyenne), + defaultScale: parse(baremeParDefaut), + coefficient, + min: parse(noteMin) || -1, + max: parse(noteMax) || -1, + date: parse(date), + period: parse(periode), + isGroupMark: estEnGroupe + })) || [] + }; +} + +module.exports = getMarks; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/menu.js b/alarm/node_modules/pronote-api/src/fetch/pronote/menu.js new file mode 100644 index 0000000..988c168 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/menu.js @@ -0,0 +1,42 @@ +const { toPronoteDate } = require('../../data/dates'); +const parse = require('../../data/types'); + +const navigate = require('./navigate'); + +const PAGE_NAME = 'PageMenus'; +const TAB_ID = 10; +const ACCOUNTS = ['student', 'parent']; + +async function getMenu(session, user, day = new Date()) +{ + const menu = await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + date: { + _T: 7, + V: toPronoteDate(day) + } + }); + + if (!menu) { + return null; + } + + return { + hasLunch: menu.AvecRepasMidi, + hasDiner: menu.AvecRepasSoir, + filledWeeks: parse(menu.DomaineDePresence), + menus: parse(menu.ListeJours, false).map(({ Date, ListeRepas }) => ({ + date: parse(Date), + meals: parse(ListeRepas, ({ ListePlats }) => ({ + content: parse(ListePlats, ({ ListeAliments }) => ({ + lines: parse(ListeAliments, ({ listeLabelsAlimentaires }) => ({ + labels: parse(listeLabelsAlimentaires, ({ couleur }) => ({ + color: couleur + })) + })) + })) + })) + })) + }; +} + +module.exports = getMenu; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/navigate.js b/alarm/node_modules/pronote-api/src/fetch/pronote/navigate.js new file mode 100644 index 0000000..edaa3d4 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/navigate.js @@ -0,0 +1,23 @@ +const { toPronote } = require('../../data/objects'); +const request = require('../../request'); + +async function navigate(session, user, page, tab, accounts, data) +{ + if (session.user.hiddenTabs.includes(tab) || !accounts.includes(session.type.name)) { + return null; + } + + const content = { + _Signature_: { + membre: toPronote(user), + onglet: tab + } + }; + if (data) { + content.donnees = data; + } + + return (await request(session, page, content)).donnees; +} + +module.exports = navigate; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/params.js b/alarm/node_modules/pronote-api/src/fetch/pronote/params.js new file mode 100644 index 0000000..12fc2e9 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/params.js @@ -0,0 +1,141 @@ +const parse = require('../../data/types'); +const { fromPronote } = require('../../data/objects'); + +const request = require('../../request'); + +const { getUUID } = require('../../cipher'); + +async function getParams(session) +{ + const { donnees: params } = await request(session, 'FonctionParametres', { + donnees: { Uuid: getUUID(session, session.aesIV) } + }); + + const general = params.General; + if (!general) { + return; + } + return { + navigatorId: params.identifiantNav, + fonts: parse(params.listePolices, false).map(o => o.L), + withMember: params.avecMembre, + forNewCaledonia: params.pourNouvelleCaledonie, + loginImageId: params.genreImageConnexion, + loginImageUrl: params.urlImageConnexion, + cssLogo: params.logoProduitCss, + theme: params.Theme, + serverTime: parse(params.DateServeurHttp), + mobileURL: params.URLMobile, + mobileSupport: params.AvecEspaceMobile, + title: params.Nom, + indexEducationWebsite: parse(general.urlSiteIndexEducation), + version: general.versionPN, + versionFull: general.version, + year: ~~general.millesime, + language: { id: general.langID, name: general.langue }, + supportedLanguages: parse(general.listeLangues, false).map(({ langID, description }) => ({ + id: langID, + name: description + })), + infoPage: general.lienMentions, + hasForum: general.avecForum, + helpURL: parse(general.UrlAide), + videosURL: parse(general.urlAccesVideos), + twitterURL: parse(general.urlAccesTwitter), + withLoginOptions: general.AvecChoixConnexion, + establishment: general.NomEtablissement, + displayWeeks: general.afficherSemainesCalendaires, + schoolYear: general.AnneeScolaire, + firstCycle: parse(general.dateDebutPremierCycle), + firstDay: parse(general.PremiereDate), + firstMonday: parse(general.PremierLundi), + lastDay: parse(general.DerniereDate), + ticksPerDay: general.PlacesParJour, + ticksPerHour: general.PlacesParHeure, + sequenceDuration: general.DureeSequence, + ticksForHalfDayAbsence: general.PlaceDemiJourneeAbsence, + hasLunch: general.activationDemiPension, + lunchStart: general.debutDemiPension, + lunchEnd: general.finDemiPension, + withPlainAfternoonHours: general.AvecHeuresPleinesApresMidi, + firstOrLastWorkingDay: parse(general.JourOuvre), + workingDays: parse(general.JoursOuvres), + lunchDays: parse(general.JoursDemiPension), + parentsChat: general.ActivationMessagerieEntreParents, + workingDaysPerCycle: general.joursOuvresParCycle, + firstDayOfWeek: general.premierJourSemaine, + timetableGridsInCycle: general.grillesEDTEnCycle, + workingDaysCycle: parse(general.setOfJoursCycleOuvre), + halfWorkingDays: general.DemiJourneesOuvrees.map(parse), + frequenciesRanges: general.DomainesFrequences.map(parse), + frequenciesLabels: general.LibellesFrequences, + defaultMarkMax: parse(general.BaremeNotation), + allowedAnnotations: parse(general.listeAnnotationsAutorisees), + acquisitionLevels: parse(general.ListeNiveauxDAcquisitions, ({ + listePositionnements, positionJauge, actifPour, abbreviation, raccourci, + couleur, ponderation, nombrePointsBrevet, estAcqui, estNotantPourTxReussite + }) => ({ + positions: parse(listePositionnements, ({ abbreviation, abbreviationAvecPrefixe }) => ({ + shortName: abbreviation, + shortNameWithPrefix: abbreviationAvecPrefixe + }), 'count'), + triggerPosition: positionJauge, + activeFor: parse(actifPour), + shortName: abbreviation, + shortPath: raccourci, + color: couleur, + weighting: parse(ponderation), + brevetPoints: parse(nombrePointsBrevet), + acquired: estAcqui, + countsForSuccess: estNotantPourTxReussite + }), 'count'), + displayAcquisitionShortLabel: general.AfficherAbbreviationNiveauDAcquisition, + withEvaluationHistory: general.AvecEvaluationHistorique, + withoutIntermediaryLevelAutoValidation: general.SansValidationNivIntermediairesDsValidAuto, + onlySchoolYearEvaluationsInAutoValidation: general.NeComptabiliserQueEvalsAnneeScoDsValidAuto, + CECRLLevelsSupport: general.AvecGestionNiveauxCECRL, + langActivityColor: general.couleurActiviteLangagiere, + minMarkMCQ: general.minBaremeQuestionQCM, + maxMarkMCQ: general.maxBaremeQuestionQCM, + maxPointsMCQ: general.maxNbPointQCM, + skillsGridLabelSize: general.tailleLibelleElementGrilleCompetence, + homeworkCommentSize: general.tailleCommentaireDevoir, + officeEnabled: general.O365_Actif, + officeFederatedMode: general.O365_ModeFederated, + officeTutorial: parse(general.O365_UrlTuto_Office), + oneDriveTutorial: parse(general.O365_UrlTuto_OneDrive), + connexionInfoRetrieval: general.AvecRecuperationInfosConnexion, + font: general.Police, + fontSize: general.TaillePolice, + attachedStudents: general.AvecElevesRattaches, + phoneMask: general.maskTelephone, + maxECTS: general.maxECTS, + maxAppreciationSizes: general.TailleMaxAppreciation, + publicHolidays: parse(general.listeJoursFeries, ({ dateDebut, dateFin }) => ({ + from: parse(dateDebut), + to: parse(dateFin) + })), + displaySequences: general.afficherSequences, + firstHour: parse(general.PremiereHeure), + hours: parse(general.ListeHeures, ({ A }) => ({ + round: A === undefined + }), 'count'), + endHours: parse(general.ListeHeuresFin, ({ A }) => ({ + round: A === undefined + }), 'count'), + sequences: general.sequences, + periods: general.ListePeriodes.map(p => fromPronote(p, ({ G, periodeNotation, dateDebut, dateFin }) => ({ + kind: G === 1 ? 'trimester' : (G === 2 ? 'semester' : (G === 3 ? 'year' : 'other')), + notationPeriod: periodeNotation, + from: parse(dateDebut), + to: parse(dateFin) + }), false)), + logo: parse(general.logo), + breaks: parse(general.recreations, ({ place }) => ({ + position: place + })), + appCookieName: general.nomCookieAppli + }; +} + +module.exports = getParams; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/timetable.js b/alarm/node_modules/pronote-api/src/fetch/pronote/timetable.js new file mode 100644 index 0000000..a98b9ce --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/timetable.js @@ -0,0 +1,81 @@ +const parse = require('../../data/types'); +const { toPronote, fromPronote } = require('../../data/objects'); + +const navigate = require('./navigate'); + +const PAGE_NAME = 'PageEmploiDuTemps'; +const TAB_ID = 16; +const ACCOUNTS = ['student', 'parent']; + +async function getTimetable(session, user, week) +{ + const student = toPronote(session.user); + const timetable = await navigate(session, user, PAGE_NAME, TAB_ID, ACCOUNTS, { + avecAbsencesEleve: false, // TODO: Test what those parameters do + avecAbsencesRessource: true, + avecConseilDeClasse: true, + avecDisponibilites: true, + avecInfosPrefsGrille: true, + avecRessourceLibrePiedHoraire: false, + estEDTPermanence: false, + numeroSemaine: week, // *Clown emoji* + NumeroSemaine: week, + ressource: student, + Ressource: student + }); + + if (!timetable || !timetable.ListeCours) { + return null; + } + + let iCalURL = null; + if (timetable.avecExportICal) { + const id = timetable.ParametreExportiCal; + iCalURL = `${session.server}ical/Edt.ics?icalsecurise=${id}&version=${session.params.version}`; + } + + return { + hasCancelledLessons: timetable.avecCoursAnnule, + iCalURL, + lessons: timetable.ListeCours.map(o => fromPronote(o, ({ + place, duree, DateDuCours, CouleurFond, ListeContenus, AvecTafPublie, Statut, estAnnule, estRetenue, + dispenseEleve + }) => ({ + position: place, + duration: duree, + date: parse(DateDuCours), + status: Statut, + color: CouleurFond, + content: parse(ListeContenus), + hasHomework: AvecTafPublie, + isCancelled: !!estAnnule, + isDetention: !!estRetenue, + remoteLesson: !!dispenseEleve && dispenseEleve.V.maison + }))), + // I was unable to witness a filled "absences.joursCycle", so didn't include it + breaks: parse(timetable.recreations, ({ place }) => ({ + position: place + })) + }; +} + +async function getFilledDaysAndWeeks(session, user) +{ + const daysData = await navigate(session, user, PAGE_NAME + '_DomainePresence', TAB_ID, ACCOUNTS, { + Ressource: toPronote(session.user) + }); + + if (!daysData) { + return null; + } + + return { + filledWeeks: parse(daysData.Domaine), + filledDays: parse(daysData.joursPresence) + } +} + +module.exports = { + getTimetable, + getFilledDaysAndWeeks +}; diff --git a/alarm/node_modules/pronote-api/src/fetch/pronote/user.js b/alarm/node_modules/pronote-api/src/fetch/pronote/user.js new file mode 100644 index 0000000..54f62be --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/pronote/user.js @@ -0,0 +1,183 @@ +const request = require('../../request'); + +const parse = require('../../data/types'); +const { getFileURL } = require('../../data/files'); +const { fromPronote } = require('../../data/objects'); + +async function getUser(session) +{ + const { donnees: user } = await request(session, 'ParametresUtilisateur'); + const { data, authorizations } = getSpecificData(session, user); + + const res = user.ressource; + const aut = user.autorisations; + + return { + ...fromPronote(res), + ...data, + establishmentsInfo: parse(user.listeInformationsEtablissements, ({ Logo, Coordonnees }) => ({ + logoID: parse(Logo), + address: [Coordonnees.Adresse1, Coordonnees.Adresse2], + postalCode: Coordonnees.CodePostal, + postalLabel: Coordonnees.LibellePostal, + city: Coordonnees.LibelleVille, + province: Coordonnees.Province, + country: Coordonnees.Pays, + website: Coordonnees.SiteInternet + })), + userSettings: (({ version, EDT, theme, Communication }) => ({ + version, + timetable: { + displayCanceledLessons: EDT.afficherCoursAnnules, + invertAxis: EDT.axeInverseEDT, + invertWeeklyPlanAxis: EDT.axeInversePlanningHebdo, + invertDayPlanAxis: EDT.axeInversePlanningJour, + invertDay2PlanAxis: EDT.axeInversePlanningJour2, + dayCount: EDT.nbJours, + resourceCount: EDT.nbRessources, + daysInTimetable: EDT.nbJoursEDT, + sequenceCount: EDT.nbSequences + }, + theme: theme.theme, + unreadDiscussions: Communication.DiscussionNonLues + }))(user.parametresUtilisateur), + sessionAuthorizations: { + twitterManagement: user.autorisationsSession.fonctionnalites.gestionTwitter, + expandedAttestation: user.autorisationsSession.fonctionnalites.attestationEtendue + }, + authorizations: { + discussions: aut.AvecDiscussion, + teachersDiscussions: aut.AvecDiscussionProfesseurs, + timetableVisibleWeeks: parse(aut.cours.domaineConsultationEDT), + canEditLessons: parse(aut.cours.domaineModificationCours), + hideClassParts: aut.cours.masquerPartiesDeClasse, + maxEstablishmentFileSize: aut.tailleMaxDocJointEtablissement, + editPassword: aut.compte.avecSaisieMotDePasse, + editPersonalInfo: aut.compte.avecInformationsPersonnelles, + canPrint: aut.autoriserImpression, + ...authorizations + }, + minPasswordSize: user.reglesSaisieMDP.min, + maxPasswordSize: user.reglesSaisieMDP.max, + passwordRules: parse(user.reglesSaisieMDP.regles), + kioskAccess: user.autorisationKiosque, + tabs: user.listeOnglets.map(parseTab), + hiddenTabs: user.listeOngletsInvisibles, + notifiedTabs: user.listeOngletsNotification + }; +} + +function parseTab({ G: id, Onglet: subs }) +{ + return { id, subs: (subs || []).map(parseTab) }; +} + +function getSpecificData(session, data) +{ + switch (session.type.name) + { + case 'student': + return getStudentData(session, data); + case 'parent': + return getParentData(session, data); + case 'teacher': + + break; + case 'administration': + + break; + default: + return {}; + } +} + +function getStudentData(session, data) +{ + return { + data: getStudent(session, data.ressource), + authorizations: { + maxUserWorkFileSize: data.autorisations.tailleMaxRenduTafEleve + } + }; +} + +function getStudent(session, res) +{ + const avatar = {}; + if (res.avecPhoto) { + avatar.avatar = getFileURL(session, { + id: res.N, + name: 'photo.jpg' + }); + } + + return { + ...fromPronote(res), + establishment: parse(res.Etablissement), + ...avatar, + studentClass: fromPronote(res.classeDEleve), + classHistory: parse(res.listeClassesHistoriques, ({ AvecNote, AvecFiliere }) => ({ + hadMarks: AvecNote, + hadOptions: AvecFiliere + })), + groups: parse(res.listeGroupes), + tabsPillars: parse(res.listeOngletsPourPiliers, ({ listePaliers }) => ({ + levels: parse(listePaliers, ({ listePiliers }) => ({ + pillars: parse(listePiliers, ({ estPilierLVE, estSocleCommun, Service }) => ({ + isForeignLanguage: estPilierLVE, + isCoreSkill: estSocleCommun, + subject: Service && parse(Service) + })) + })) + }), 'tab'), + tabsPeriods: parse(res.listeOngletsPourPeriodes, ({ listePeriodes, periodeParDefaut }) => ({ + periods: parse(listePeriodes, ({ GenreNotation }) => ({ + isCorePeriod: GenreNotation === 1 + })), + defaultPeriod: parse(periodeParDefaut) + }), 'tab') + }; +} + +function getParentData(session, data) +{ + const res = data.ressource; + const aut = data.autorisations; + + return { + data: { + isDelegate: res.estDelegue, + isBDMember: res.estMembreCA, + canDiscussWithManagers: res.avecDiscussionResponsables, + absencesReasons: parse(data.listeMotifsAbsences), + delaysReasons: parse(data.listeMotifsRetards), + classDelegates: parse(res.listeClassesDelegue), + students: res.listeRessources.map(r => fromPronote(r, ({ listeSessions }) => ({ + ...getStudent(session, r), + sessions: parse(listeSessions, ({ date, strHeureDebut, strHeureFin }) => ({ + from: getDateWithHours(parse(date), strHeureDebut), + to: getDateWithHours(parse(date), strHeureFin) + })) + }))) + }, + authorizations: { + staffDiscussion: aut.AvecDiscussionPersonnels, + parentsDiscussion: aut.AvecDiscussionParents, + editStudentPassword: aut.compte.avecSaisieMotDePasseEleve, + editCoordinates: aut.compte.avecSaisieInfosPersoCoordonnees, + editAuthorizations: aut.compte.avecSaisieInfosPersoAutorisations + } + }; +} + +function getDateWithHours(date, hours) +{ + const h = hours.indexOf('h'); + + date.setHours(date.getHours() + ~~hours.substring(0, h)); + date.setMinutes(date.getMinutes() + ~~hours.substring(h)); + + return date; +} + +module.exports = getUser; diff --git a/alarm/node_modules/pronote-api/src/fetch/timetable.js b/alarm/node_modules/pronote-api/src/fetch/timetable.js new file mode 100644 index 0000000..059b849 --- /dev/null +++ b/alarm/node_modules/pronote-api/src/fetch/timetable.js @@ -0,0 +1,95 @@ +const { toPronoteWeek } = require('../data/dates'); +const { withId, checkDuplicates } = require('../data/id'); + +const { getFilledDaysAndWeeks, getTimetable } = require('./pronote/timetable'); + +async function timetable(session, user, from = new Date(), to = null) +{ + if (!to || to < from) { + to = new Date(from.getTime()); + to.setDate(to.getDate() + 1); + } + + const filled = await getFilledDaysAndWeeks(session, user); + if (!filled) { + return null; + } + + const fromWeek = toPronoteWeek(session, from); + const toWeek = toPronoteWeek(session, to); + + const weeks = []; + for (let i = fromWeek; i <= toWeek; i++) { + weeks.push(i); + } + + const result = []; + for (const week of weeks) { + const timetable = await getTimetable(session, user, week); + const lessons = getTimetableWeek(session, timetable); + + if (lessons) { + lessons.filter(l => l.from >= from && l.from <= to).forEach(lesson => { + if (!filled.filledWeeks.includes(week)) { + lesson.isCancelled = true; + } + + result.push(lesson); + }); + } + } + + return result.sort((a, b) => a.from - b.from); +} + +function getTimetableWeek(session, table) { + const result = []; + if (!table || !table.lessons) { + return + } + + for (const lesson of table.lessons) { + const from = lesson.date; + const to = new Date(from.getTime() + (lesson.duration / session.params.ticksPerHour * 3600000)); + + const res = { + from, + to, + isDetention: lesson.isDetention, + remoteLesson: lesson.remoteLesson, + status: lesson.status, + hasDuplicate: !!table.lessons.find(l => l.date.getTime() === from.getTime() && l !== lesson) + }; + + let room, subject, teacher; + if (lesson.isDetention) { + subject = lesson.content[0]; + teacher = lesson.content[1]; + room = lesson.content[2]; + } else { + if (lesson.content) { + subject = lesson.content.find(o => o.type === 16); + teacher = lesson.content.find(o => o.type === 3); + room = lesson.content.find(o => o.type === 17); + } else { + subject = 'Non défini'; + room = 'Non défini'; + teacher = 'Non défini'; + } + + res.isAway = (lesson.status || false) && !!lesson.status.match(/(.+)?prof(.+)?absent(.+)?/giu); + res.isCancelled = !res.isAway && lesson.isCancelled; + res.color = lesson.color; + } + + res.subject = subject && subject.name || null; + res.teacher = teacher && teacher.name || null; + res.room = room && room.name || null; + + result.push(withId(res, ['from', 'to', 'subject'])); + } + + return checkDuplicates(result); +} + +module.exports = timetable; -- cgit