UNPKG

@heknon/node-webtop

Version:

A Backend for an unofficial WebTop (SmartSchool - Israel) API.

203 lines (173 loc) 8.15 kB
import axios, { AxiosInstance } from 'axios'; import { stringify as queryStringify } from 'query-string'; import axiosCookieJarSupport from 'axios-cookiejar-support'; import { CookieJar } from 'tough-cookie'; import { defaultApiRoutes, baseUrl, baseApiUrl, routes } from './apiConfig'; import { load as cheerioLoad } from 'cheerio'; import { constructTimeTable } from './TimeTable/TimeTable'; import { constructGrades, constructGradeSemester, constructGradeYear } from './Grades/Grades' import { constructInbox } from './Inbox/Inbox'; import { constructMessage } from './Inbox/Message'; import { constructTestsLeft } from './TestsLeft/TestsLeft'; import { TimeTable } from './TimeTable/DataObjects'; import { constructTimeTableChanges } from './TimeTableChanges/TimeTableChanges'; import { WebtopSecurityData, LessonResponse, EventResponse, HomeworkResponse, WebTopUsersResponse, WebTopUserData, PersonalDetails, PushNotifications } from './DataObjects'; export default class Client { id: string; password: string; _axiosInstance: AxiosInstance | null; _cookieJar: CookieJar | null; platform: string | null; constructor(id: string, password: string) { this.id = id; this.password = password; this._axiosInstance = null; this._cookieJar = null; this.platform = null; } /** * get the security necessary for logging in * @param {CheerioStatic} $ parsed html * @returns {WebtopSecurityData} */ _getSecurityData($: CheerioStatic): WebtopSecurityData { const keys = $("#captchaWrapper").children('input[type="hidden"]')[0]; return { securityId: keys.attribs.id, securityValue: keys.attribs.value, }; }; /** * gets platform in use * @param {CheerioStatic} $ parsed html * @returns platform axios is using */ _getPlatform($: CheerioStatic) { const platform = $('#platform').val(); return platform; } async login() { this._cookieJar = new CookieJar(); this._axiosInstance = axios.create({ jar: this._cookieJar, withCredentials: true, headers: { 'User-Agent': 'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 5 Build/LMY48B; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/43.0.2357.65 Mobile Safari/537.36' }, });; axiosCookieJarSupport(this._axiosInstance); this._axiosInstance.defaults.jar = this._cookieJar; const html = (await this._axiosInstance.get(baseUrl)).data; const $ = cheerioLoad(html); const { securityId, securityValue } = this._getSecurityData($); const data = { 'action': 'login', 'rememberMe': 1, 'captcha': '', 'secondsToLogin': 23, 'username': this.id, 'password': this.password, [securityId]: securityValue }; this.platform = this._getPlatform($); const loginReq = await this._axiosInstance.post(baseApiUrl(this.platform), queryStringify(data)); if (loginReq.data.error !== undefined) throw new Error(loginReq.data.error); return loginReq; } async logout() { const res = await this._axiosInstance!.post(baseApiUrl(this.platform), queryStringify({action: 'logout'})); if (res.status === 200) { this.platform = ''; this._axiosInstance = null; this._cookieJar = null; return res; } throw new Error('Failed to logout') } /** * get all the grades of all 3 years of school * @param onlyFilledGrades if only to show grades that have been filled by a teacher. if false grades that haven't been filled will be set to -1 */ async getGrades(onlyFilledGrades: boolean = true) { return constructGrades(this._axiosInstance!, onlyFilledGrades); } /** * get the grades of a semester * @param semester the semester. 1 or 2. * @param studentYear the study year * @param onlyFilledGrades if only to show grades that have been filled by a teacher. if false grades that haven't been filled will be set to -1 */ async getSemesterGrades(studentYear = 0, semester = 0, onlyFilledGrades: boolean = true) { return constructGradeSemester(this._axiosInstance!, studentYear - 1, semester, onlyFilledGrades); } /** * get the grades of a year * @param studentYear the study year * @param onlyFilledGrades if only to show grades that have been filled by a teacher. if false grades that haven't been filled will be set to -1 */ async getYearGrades(studentYear = 0, onlyFilledGrades: boolean = true) { return constructGradeYear(this._axiosInstance!, studentYear - 1, onlyFilledGrades); } async getTodayLessons(): Promise<LessonResponse[]> { return (await this._axiosInstance!.get(defaultApiRoutes.todayTimetable)).data; } async getTodayEvents(): Promise<EventResponse[]> { return (await this._axiosInstance!.get(defaultApiRoutes.todayEvents)).data; } async getHomework(): Promise<HomeworkResponse[]> { return (await this._axiosInstance!.get(defaultApiRoutes.homework)).data; } /** * @param removeEmptyHours Remove hours which there are no lessons on from the response */ async getTimeTable(removeEmptyHours: boolean = false): Promise<TimeTable> { const timetable = await this._axiosInstance!.get(routes.timetable); return constructTimeTable(timetable.data, removeEmptyHours); } async getTestLeftToDo() { const testsLeft = await this._axiosInstance!.get(routes.changesAndExams); return constructTestsLeft(testsLeft.data); } async getTimeTableChanges() { const changes = await this._axiosInstance!.get(routes.changesAndExams); return constructTimeTableChanges(changes.data); } async getMainPage() { return (await this._axiosInstance!.get(baseUrl)).data; } async getUsers(query: string): WebTopUsersResponse { return (await this._axiosInstance!.post(defaultApiRoutes.searchUsers, queryStringify({ value: query }))).data; } async getInbox(page: number) { return constructInbox((await this._axiosInstance!.get(routes.inbox(page))).data); } async getMessage(id: number) { return constructMessage((await this._axiosInstance!.get(routes.message(id))).data, id, this._axiosInstance!); } async changePassword(newPassword: string) { return (await this._axiosInstance!.post(defaultApiRoutes.changePassword, queryStringify({ newPassword }))).data; } async changeUsername(currentPassword: string, newUsername: string) { return (await this._axiosInstance!.post(defaultApiRoutes.changeUsername, queryStringify({ currentPassword, newUsername }))).data; } async changePersonalDetails(personalDetails: PersonalDetails) { const data = personalDetails; data.emailUponUpdate = data.emailUponUpdate ? 1 : 0; data.showMyCellphone = data.showMyCellphone ? 1 : 0; data.showMyEmail = data.showMyEmail ? 1 : 0; return (await this._axiosInstance!.post(defaultApiRoutes.changeUsername, queryStringify(data))).data; } async changePushNotifications(pushNotifications: PushNotifications) { return (await this._axiosInstance!.post(defaultApiRoutes.changePushNotifications, queryStringify(pushNotifications))).data; } async getAllGradeUsers() { const gradeUsers = [] as WebTopUserData[]; for (let index = 1488; index < 1515; index++) { const users = await this.getUsers(String.fromCharCode(index)); for (const user of users) { if (!gradeUsers.includes(user)) gradeUsers.push(user); } } return gradeUsers; } }