diff --git a/package.json b/package.json index 28ecac6..2841919 100644 --- a/package.json +++ b/package.json @@ -19,5 +19,5 @@ "@types/node": "^16.11.6", "typescript": "^4.4.4" }, - "types": "./types/index.d.ts" + "types": "./index.d.ts" } \ No newline at end of file diff --git a/src/client.ts b/src/client.ts index ba07461..0eb52cc 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,7 +1,18 @@ import Undici from 'undici' -import { DisplayDate, Homework, User } from '../types' +import { RequestOptions } from 'undici/types/dispatcher' +import { + ActivityResponse, + BehaviourResponse, + GetActivityOptions, + GetBehaviourOptions, + GetHomeworkOptions, + GetLessonsOptions, + Homework, + HomeworksResponse, + LessonsResponse, + Student, +} from '../types' import { API_BASE, BASE_URL } from './consts' - export class ClasschartsClient { public studentCode = '' public dateOfBirth = '' @@ -13,9 +24,34 @@ export class ClasschartsClient { this.studentCode = String(studentCode) this.dateOfBirth = String(dateOfBirth) } + private async makeAuthedRequest( + path: string, + options: Omit + ) { + if (!this.authCookies) throw new Error('Not authenticated') + const requestOptions: Omit = { + ...options, + headers: { + Cookie: this.authCookies.join(';'), + authorization: 'Basic ' + this.sessionId, + }, + } + const request = await Undici.request(path, requestOptions) + let responseJSON + try { + responseJSON = await request.body.json() + } catch (err) { + throw new Error('Invalid JSON response, check your dates') + } + if (responseJSON.success == 0) { + throw new Error(responseJSON.error) + } + return responseJSON.data + } + async init() { - const formData = new URLSearchParams() if (!this.studentCode) throw new Error('Student Code not inputted') + const formData = new URLSearchParams() formData.append('_method', 'POST') formData.append('code', this.studentCode.toUpperCase()) formData.append('dob', this.dateOfBirth) @@ -49,60 +85,64 @@ export class ClasschartsClient { /** * - * @returns {User} + * @returns {Promise} */ - async getStudentInfo(): Promise { + async getStudentInfo(): Promise { if (!this.authCookies) throw new Error('Not authenticated') - const request = await Undici.request(API_BASE + '/ping', { + const data = await this.makeAuthedRequest(API_BASE + '/ping', { method: 'POST', body: 'include_date=true', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - Cookie: this.authCookies.join(';'), - authorization: 'Basic ' + this.sessionId, - }, }) - const data = await request.body.json() - return data.data?.user + return data?.user + } + async getActivity( + options: GetActivityOptions | null + ): Promise { + const params = new URLSearchParams() + options?.from && params.append('form', options?.from) + options?.to && params.append('to', options?.to) + return this.makeAuthedRequest( + API_BASE + '/activity/' + this.sessionId + '?' + params.toString(), + { + method: 'GET', + } + ) + } + async getBehaviour( + options: GetBehaviourOptions | null + ): Promise { + const params = new URLSearchParams() + options?.from && params.append('form', options?.from) + options?.to && params.append('to', options?.to) + options?.last_id && params.append('last_id', options?.last_id) + return await this.makeAuthedRequest( + API_BASE + '/behaviour/' + this.studentId + '?' + params.toString(), + { + method: 'GET', + } + ) } /** * Gets all the homework from * @param displayDate {DisplayDate} * @param fromDate * @param toDate - * @returns {Array} + * @returns {Promise>} */ async listHomeworks( - displayDate: DisplayDate, - fromDate: string, - toDate: string - ): Promise> { + options: GetHomeworkOptions | null + ): Promise { if (!this.authCookies) throw new Error('Not authenticated') const params = new URLSearchParams() - params.append('display_date', String(displayDate)) - fromDate && params.append('from', String(fromDate)) - toDate && params.append('to', String(toDate)) - const request = await Undici.request( + params.append('display_date', String(options?.displayDate)) + options?.fromDate && params.append('from', String(options?.fromDate)) + options?.toDate && params.append('to', String(options?.toDate)) + let data: Array = await this.makeAuthedRequest( API_BASE + '/homeworks/' + this.studentId + '?' + params.toString(), { method: 'GET', - headers: { - Cookie: this.authCookies.join(';'), - authorization: 'Basic ' + this.sessionId, - }, } ) - let responseJSON - try { - responseJSON = await request.body.json() - } catch (err) { - throw new Error('Invalid JSON response, check your dates') - } - - if (responseJSON.success == 0) { - throw new Error(responseJSON.error) - } - let data: Array = responseJSON?.data for (let i = 0; i < data.length; i++) { // homework.lesson.replace(/\\/g, '') data[i].description = data[i].description.replace( @@ -114,4 +154,21 @@ export class ClasschartsClient { } return data } + /** + * + * @param date + * @returns {Promise} + */ + async getLessons(options: GetLessonsOptions): Promise { + if (!this.authCookies) throw new Error('Not authenticated') + if (!options?.date) throw new Error('No date specified') + const params = new URLSearchParams() + params.append('date', String(options?.date)) + return await this.makeAuthedRequest( + API_BASE + '/timetable/' + this.studentId + '?' + params.toString(), + { + method: 'GET', + } + ) + } } diff --git a/src/index.ts b/src/index.ts index b0847b4..83dae76 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1 @@ -import { ClasschartsClient } from './client' - -exports.ClasschartsClient = ClasschartsClient +export * from './client' diff --git a/src/tests/test.ts b/src/tests/test.ts index 1886896..031a71d 100644 --- a/src/tests/test.ts +++ b/src/tests/test.ts @@ -3,9 +3,8 @@ const { code, dob } = require('../../src/tests/config.json') async function main() { const client = new ClasschartsClient(code, dob) await client.init() - console.log( - await client.listHomeworks('due_date', '2021-10-21', '2021-11-27') - ) + console.log(await client.getBehaviour(null)) + console.log(await client.getActivity(null)) } main() diff --git a/tsconfig.json b/tsconfig.json index ed2a143..313538b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -37,7 +37,7 @@ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ diff --git a/types/index.d.ts b/types/index.d.ts index e243fcc..7a8d8f3 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,4 +1,4 @@ -export interface User { +export interface Student { id: number name: string first_name: string @@ -36,6 +36,61 @@ export interface User { survey_id: number | null detention_alias_plural_uc: string } +export interface GetActivityOptions { + from: string | undefined + to: string | undefined +} +export interface ActivityTimelinePoint { + positive: number + negative: number + name: string + start: string + end: string +} +export interface ActivityResponse { + timeline: Array + positiveReasons: Record + negative_reasons: Record + other_positive: Array + other_negative: Array + other_positive_count: Array + other_negative_count: Array +} +export interface GetBehaviourOptions { + from: string | undefined + to: string | undefined + last_id: string | undefined +} +export interface BehaviourPoint { + id: number + type: string + polarity: string + reason: string + score: number + timestamp: string + timestamp_custom_time: string | null + style: { + border_color: string | null + custom_class: string | null + } + pupil_name: string + lesson_name: string + teacher_name: string + room_name: string | null + note: string + _can_delete: string + detention_date: string | null + detention_time: string | null + detention_location: string | null + detention_type: string | null +} +export type BehaviourResponse = Array +export type DisplayDate = 'due_date' | 'issue_date' +export interface GetHomeworkOptions { + displayDate: DisplayDate + fromDate: string + toDate: string +} export interface Homework { lesson: string subject: string @@ -65,4 +120,26 @@ export interface Homework { validated_links: Array validated_attachments: Array } -export type DisplayDate = 'due_date' | 'issue_date' +export type HomeworksResponse = Array +export interface GetLessonsOptions { + date: string +} +export interface Lesson { + teacher_name: string + lesson_name: string + subject_name: string + is_alternative_lesson: boolean + period_name: string + period_number: string + room_name: string + date: string + start_time: string + end_time: string + key: number + note_abstract: string + note: string + pupil_note_abstract: string + pupil_note: string + pupil_note_raw: string +} +export type LessonsResponse = Array