summaryrefslogtreecommitdiff
path: root/school/node_modules/pronote-api/src/fetch
diff options
context:
space:
mode:
Diffstat (limited to 'school/node_modules/pronote-api/src/fetch')
-rw-r--r--school/node_modules/pronote-api/src/fetch/absences.js114
-rw-r--r--school/node_modules/pronote-api/src/fetch/contents.js51
-rw-r--r--school/node_modules/pronote-api/src/fetch/evaluations.js65
-rw-r--r--school/node_modules/pronote-api/src/fetch/files.js32
-rw-r--r--school/node_modules/pronote-api/src/fetch/homeworks.js45
-rw-r--r--school/node_modules/pronote-api/src/fetch/infos.js33
-rw-r--r--school/node_modules/pronote-api/src/fetch/marks.js73
-rw-r--r--school/node_modules/pronote-api/src/fetch/menu.js41
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/absences.js164
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/auth.js43
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/contents.js60
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/evaluations.js49
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/files.js16
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/homeworks.js43
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/infos.js33
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/keepAlive.js8
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/logout.js8
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/marks.js71
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/menu.js42
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/navigate.js23
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/params.js141
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/timetable.js81
-rw-r--r--school/node_modules/pronote-api/src/fetch/pronote/user.js183
-rw-r--r--school/node_modules/pronote-api/src/fetch/timetable.js95
24 files changed, 1514 insertions, 0 deletions
diff --git a/school/node_modules/pronote-api/src/fetch/absences.js b/school/node_modules/pronote-api/src/fetch/absences.js
new file mode 100644
index 0000000..9c1ac02
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/contents.js b/school/node_modules/pronote-api/src/fetch/contents.js
new file mode 100644
index 0000000..62e85df
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/evaluations.js b/school/node_modules/pronote-api/src/fetch/evaluations.js
new file mode 100644
index 0000000..dca1b9f
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/files.js b/school/node_modules/pronote-api/src/fetch/files.js
new file mode 100644
index 0000000..7703ee4
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/homeworks.js b/school/node_modules/pronote-api/src/fetch/homeworks.js
new file mode 100644
index 0000000..7f2146b
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/infos.js b/school/node_modules/pronote-api/src/fetch/infos.js
new file mode 100644
index 0000000..0ec03a7
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/marks.js b/school/node_modules/pronote-api/src/fetch/marks.js
new file mode 100644
index 0000000..1e57e85
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/menu.js b/school/node_modules/pronote-api/src/fetch/menu.js
new file mode 100644
index 0000000..6f2872c
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/absences.js b/school/node_modules/pronote-api/src/fetch/pronote/absences.js
new file mode 100644
index 0000000..19bf2dc
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/auth.js b/school/node_modules/pronote-api/src/fetch/pronote/auth.js
new file mode 100644
index 0000000..9c1d566
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/contents.js b/school/node_modules/pronote-api/src/fetch/pronote/contents.js
new file mode 100644
index 0000000..7525e3d
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/evaluations.js b/school/node_modules/pronote-api/src/fetch/pronote/evaluations.js
new file mode 100644
index 0000000..c9065fd
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/files.js b/school/node_modules/pronote-api/src/fetch/pronote/files.js
new file mode 100644
index 0000000..2871fbe
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/homeworks.js b/school/node_modules/pronote-api/src/fetch/pronote/homeworks.js
new file mode 100644
index 0000000..7d13c48
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/infos.js b/school/node_modules/pronote-api/src/fetch/pronote/infos.js
new file mode 100644
index 0000000..6e05ce1
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/keepAlive.js b/school/node_modules/pronote-api/src/fetch/pronote/keepAlive.js
new file mode 100644
index 0000000..89705ec
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/logout.js b/school/node_modules/pronote-api/src/fetch/pronote/logout.js
new file mode 100644
index 0000000..ede23e7
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/marks.js b/school/node_modules/pronote-api/src/fetch/pronote/marks.js
new file mode 100644
index 0000000..dcb7644
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/menu.js b/school/node_modules/pronote-api/src/fetch/pronote/menu.js
new file mode 100644
index 0000000..988c168
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/navigate.js b/school/node_modules/pronote-api/src/fetch/pronote/navigate.js
new file mode 100644
index 0000000..edaa3d4
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/params.js b/school/node_modules/pronote-api/src/fetch/pronote/params.js
new file mode 100644
index 0000000..12fc2e9
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/timetable.js b/school/node_modules/pronote-api/src/fetch/pronote/timetable.js
new file mode 100644
index 0000000..a98b9ce
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/pronote/user.js b/school/node_modules/pronote-api/src/fetch/pronote/user.js
new file mode 100644
index 0000000..54f62be
--- /dev/null
+++ b/school/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/school/node_modules/pronote-api/src/fetch/timetable.js b/school/node_modules/pronote-api/src/fetch/timetable.js
new file mode 100644
index 0000000..059b849
--- /dev/null
+++ b/school/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;