const https = require("https"); const config = require("worker_threads").workerData; const models = require("../models"); const reg_event = /(?:(?:BEGIN:VEVENT\nDTSTAMP:(?:[A-Z0-9]*?)\nDTSTART:([A-Z0-9]*?)\nDTEND:([A-Z0-9]*?)\nSUMMARY: {0,}([a-zéèàA-Z0-9-. \, \\/ô]*?)\nLOCATION:([a-zA-Zéèà0-9-. \,\\]*?)\nDESCRIPTION:(?:\\n){0,}(LP(?:[ a-zA-Z0-9]*))\\n((?:(?:[A-Z]*) (?:[A-Z]*)(?: (?:[A-Z]*)){0,}\\n){0,})(?:.*?)\nEND:VEVENT)|(?:BEGIN:VEVENT\nDTSTAMP:(?:[A-Z0-9]*?)\nDTSTART:([A-Z0-9]*?)\nDTEND:([A-Z0-9]*?)\nSUMMARY: {0,}((?:S(?:[A-Z0-9-]*)|M(?:[A-Z0-9-]*)(?:\/M(?:[A-Z0-9-]*)){0,}|Conférence)[a-zéèàA-Z0-9-. \, \\/]*?)\nLOCATION:([a-zA-Zéèà0-9-. \,\\]*?)\nDESCRIPTION:(?:\\n){0,}((?:(?:G[0-9]S[0-9]|S[0-9]|ASPE)\\n){0,})((?:(?:[A-Z]*) (?:[A-Z]*)(?: (?:[A-Z]*)){0,}\\n){0,})(?:.*?)\nEND:VEVENT))/gs; const reg_location = /((?:[SH0-9][0-9]{2})|(?:(?:Préfa |Amphi)[0-9]))/g; const reg_teachers = /^(?:((?:[a-zA-Z]*[ -]{0,}){0,}) ([a-zA-Z]*))$/m; const reg_date = /([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})Z/; const reg_classe = /(?:(LP)[ -]{0,}(.*)|(?:(G[0-9])(S[0-9])))/; const base_url = config["edt"]; function fetchEvents(days = 1, TS_Start = new Date()) { return new Promise((resolve, reject) => { let start = new Date(TS_Start); if (start == "Invalid Date") start = new Date(); let end = new Date(start); end.setDate(end.getDate() + days); let url = base_url + start.getFullYear() + "-" + start.getMonth() + "-" + start.getDate() + "&lastDate=" + end.getFullYear() + "-" + end.getMonth() + "-" + end.getDate(); https.get(url, (resp) => { let data = ""; resp.on("data", (chunk) => { data += chunk; }); resp.on("end", () => { let output = []; data = data.replace(/\r/g, ""); let m; while ((m = reg_event.exec(data)) !== null) { if (m.index === reg_event.lastIndex) { reg_event.lastIndex++; } let event = []; let promotion = []; let classe = []; /* m = [ FullMatch, StartTime, EndTime, EventDescription ( SubjectID,Name,Class?) , Location, ClassGroup, Teacher(s) ] */ if (m[1] !== undefined) { // LPXXXX classe.push(m[5]); } else { m.splice(1, 6); // GXSX | SX | ASPE let csplit = m[5].split("\\n"); csplit.pop(); csplit.forEach(e => { if (e === "ASPE") promotion.push(e); if (/^S[0-9]$/.test(e)) promotion.push(e); if (/^G[0-9]S[0-9]$/.test(e)) classe.push(e); }); } event["title"] = m[3]; event["promotion"] = promotion; event["class"] = classe; /* Date */ let d1 = reg_date.exec(m[1]); let d2 = reg_date.exec(m[2]); event["startDate"] = new Date(d1[1] + "-" + d1[2] + "-" + d1[3] + "T" + d1[4] + ":" + d1[5] + ":" + d1[6] + ".00Z"); event["endDate"] = new Date(d2[1] + "-" + d2[2] + "-" + d2[3] + "T" + d2[4] + ":" + d2[5] + ":" + d2[6] + ".00Z"); /* Location */ event["locations"] = []; let loc; while ((loc = reg_location.exec(m[4])) !== null) { if (loc.index === reg_location.lastIndex) { reg_location.lastIndex++; } event["locations"].push(loc[1]); } /* Teachers */ event['teachers'] = [] let fullTeachers = m[6].split('\\n'); fullTeachers.forEach(e => { if(e !== ""){ let splittedTeachers = reg_teachers.exec(e); event['teachers'].push([splittedTeachers[1],splittedTeachers[2]]); } }); output.push(event); } resolve(output); }); }).on("error", (err) => { reject(err); }); }); } function compare(a, b) { if (a.length !== b.length) { return false; } let set = {}; a.forEach((i) => { if (set[i] !== undefined) { set[i]++; } else { set[i] = 1; } }); let difference = b.every((i) => { if (set[i] === undefined) { return false; } else { set[i]--; if (set[i] === 0) { delete set[i]; } return true; } }); return Object.keys(set) == 0 && difference; } function compareGroups(list1, list2) { return compare(list1, list2.map(g => [g.number, g.Semester.name, g.Semester.year])); } function compareTeachers(list1, list2) { return compare(list1, list2.map(t => t.lastName.toUpperCase() + " " + t.firstName.toUpperCase())); } function compareSemesters(list1, list2) { return compare(list1, list2.map(s => s.name)); } async function updateDatabase() { let events = await fetchEvents(365, new Date(2020, 9, 1)); for (let event of await models.Event.findAll({ include: [{ model: models.Group, include: {model: models.Semester, required: true} }, models.User, models.Semester] })) { if (!events.find(e => (e.title === event.name && e.startDate.getTime() === event.startDate.getTime() && e.endDate.getTime() === event.endDate.getTime() && e.locations.join(", ") === event.locations && compareGroups(e.class, event.Groups) && compareTeachers(e.teachers, event.Users) && compareSemesters(e.semesters, event.Semesters)))) await event.destroy(); else delete events[events.indexOf(event)]; } for (let event of events) { let e = await models.Event.create({ name: event.title, startDate: event.startDate, endDate: event.endDate, locations: event.locations.join(", ") }); let teachers = []; for (let teacher of event.teachers) { let t = await models.User.findOne({where: {permissions: 2, lastName: teacher[0], firstName: teacher[1]}}); if (!t) t = await models.User.create({ email: teacher[1].toLowerCase().replace(" ", "-") + "." + teacher[0].toLowerCase().replace(" ", "-") + "@univ-lyon1.fr", firstName: teacher[1], lastName: teacher[0], permissions: 2, passwordHash: Math.round((Math.pow(36, 12 + 1) - Math.random() * Math.pow(36, 12))).toString(36).slice(1) }); teachers.push(t); } await e.addUsers(teachers); let semesters = []; for (let semester of event.promotion) { let s = await models.Semester.findOne({where: {name: semester, year: event.startDate.getFullYear()}}); if (!s) s = await models.Semester.create({ name: semester, year: event.startDate.getFullYear() }); semesters.push(s); } await e.addSemesters(semesters); let groups = []; for (let group of event.class) { let rGroup = reg_classe.exec(group); let semesterName; let groupName; if (rGroup[1] !== undefined) { // LP semesterName = 'LP'; groupName = rGroup[2]; } else { // GXSX semesterName = rGroup[4]; groupName = rGroup[3]; } let s = await models.Semester.findOne({where: {name: semesterName, year: event.startDate.getFullYear()}}); if (!s) s = await models.Semester.create({ name: semesterName, year: event.startDate.getFullYear() }); let g = await models.Group.findOne({where: {number: groupName, SemesterId: s.id}}); if (!g) g = await models.Group.create({ number: groupName, SemesterId: s.id }); groups.push(g); } await e.addGroups(groups); } } updateDatabase().then(() => setInterval(updateDatabase, 30000));