@heknon/node-webtop
Version:
A Backend for an unofficial WebTop (SmartSchool - Israel) API.
83 lines (75 loc) • 3.79 kB
text/typescript
import { AxiosInstance } from "axios";
import { defaultApiRoutes } from "../apiConfig";
import cheerio from 'cheerio';
import moment from 'moment';
import { Grade, Grades, GradeYear, GradeSemester } from "./DataObjects";
import { Lesson } from "../DataObjects";
export const constructGradeSemester = async (axios: AxiosInstance, studentYear: number, semester: number, onlyFilledGrades: boolean): Promise<GradeSemester> => {
const req = await axios.post(defaultApiRoutes.grades(studentYear, semester === 1));
const $ = cheerio.load(req.data);
if ($($('div .center')[3]).text() === 'לא נמצאו נתונים') throw new Error("Couldn't find grade data for this year.");
const grades = constructGradesFromHTML($, onlyFilledGrades);
return {
semester,
latest: grades[0],
oldest: grades[grades.length - 1],
grades
} as GradeSemester;
}
export const constructGradeYear = async (axios: AxiosInstance, studentYear: number, onlyFilledGrades: boolean): Promise<GradeYear> => {
const sem1 = await constructGradeSemester(axios, studentYear, 1, onlyFilledGrades);
const sem2 = await constructGradeSemester(axios, studentYear, 2, onlyFilledGrades);
const grades = [sem1, sem2] as GradeSemester[];
return {
studentYear,
latest: grades[1].latest,
oldest: grades[0].oldest,
grades
} as GradeYear;
}
export const constructGrades = async (axios: AxiosInstance, onlyFilledGrades: boolean): Promise<Grades> => {
const grades = [] as GradeYear[];
try {
await constructGradeYear(axios, 0, onlyFilledGrades).then(yr => grades.push(yr))
await constructGradeYear(axios, 1, onlyFilledGrades).then(yr => grades.push(yr))
await constructGradeYear(axios, 2, onlyFilledGrades).then(yr => grades.push(yr))
} catch(e) {
return {
latest: grades[grades.length - 1].latest,
oldest: grades[0].oldest,
grades
} as Grades;
}
return {
latest: grades[grades.length - 1].latest,
oldest: grades[0].oldest,
grades
} as Grades;
}
const constructGradesFromHTML = ($: CheerioStatic, onlyFilledGrades: boolean): Grade[] => {
const grades = [] as Grade[];
const gradeCards = $('.pupil-card-item');
gradeCards.each((i, gradeCard) => {
if (gradeCard.children[0].children.length === 1 && onlyFilledGrades) return;
const grade = {} as Grade;
const gradeNum = gradeCard.children[0].children.length === 1 ? -1 : Number.parseInt($(gradeCard.children[0].children[1]).text().match(/\d+/)![0]);
const gradeDate = $(gradeCard.parent.prev).text().match(/\d+/g);
const gradeDetails = $(gradeCard.children[1].children[0]).text().match(/^[^ \(]+|\(([^)]+)\)/g)!;
grade.title = $(gradeCard.children[0].children[0]).text();
grade.grade = gradeNum;
grade.date = moment({
year: Number.parseInt(gradeDate![2]),
month: Number.parseInt(gradeDate![1]),
day: Number.parseInt(gradeDate![0]),
});
const gradeDetailsLengthBiggerThan2 = gradeDetails.length > 2;
grade.lesson = {
subjectName: gradeDetails[0],
teacherName: gradeDetailsLengthBiggerThan2 ? gradeDetails[2].replace(/\(|\)/g, '') : gradeDetails[1].replace(/\(|\)/g, '')
} as Lesson;
if (gradeDetailsLengthBiggerThan2) grade.lesson.level = Number.parseInt(/\d+/.exec(gradeDetails[1])![0]);
if (gradeCard.children[1].children.length > 1) grade.weight = Number.parseInt(/\d+/.exec($(gradeCard.children[1].children[1]).text())![0]);
grades.push(grade)
});
return grades;
}