1
0
Fork 0
mirror of https://github.com/classchartsapi/classcharts-api-js.git synced 2026-05-14 11:58:13 +00:00

Merge branch 'main' into feat/getCode

This commit is contained in:
James 2023-06-02 22:34:48 +01:00 committed by GitHub
commit 7e53992dbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 427 additions and 196 deletions

View file

@ -1,4 +1,3 @@
import ky, { type Options as KyOptions } from "ky-universal";
import type {
ActivityResponse,
AnnouncementsResponse,
@ -44,13 +43,13 @@ export class BaseClient {
*/
public lastPing = 0;
/**
* @property API_BASE Base API URL, this is different depending if its called as a parent or student
* @property API_BASE Base API URL, this is different depending on if its called as a parent or student
* @internal
*/
protected API_BASE = "";
/**
*
* @param API_BASE Base API URL, this is different depending if its called as a parent or student
* @param API_BASE Base API URL, this is different depending on if its called as a parent or student
*/
constructor(API_BASE: string) {
this.authCookies = [];
@ -59,7 +58,7 @@ export class BaseClient {
/**
* Revalidates the session ID.
*
* This is called automatically when the session ID is older than 3 minutes or when intially using the .login() method
* This is called automatically when the session ID is older than 3 minutes or when initially using the .login() method
* @internal
*/
public async getNewSessionId() {
@ -77,7 +76,7 @@ export class BaseClient {
this.lastPing = Date.now();
}
/**
* Makes a request to the Classcharts API with the required authentication headers
* Makes a request to the ClassCharts API with the required authentication headers
*
* @param path Path to the API endpoint
* @param kyOptions Ky (fetch library) request options
@ -89,7 +88,7 @@ export class BaseClient {
*/
public async makeAuthedRequest(
path: string,
kyOptions: KyOptions,
fetchOptions: RequestInit,
options?: { revalidateToken?: boolean }
) {
if (!this.sessionId) throw new Error("No session ID");
@ -100,24 +99,27 @@ export class BaseClient {
options.revalidateToken = true;
}
const requestOptions = {
...kyOptions,
...fetchOptions,
headers: {
Cookie: this?.authCookies?.join(";") ?? [],
Authorization: "Basic " + this.sessionId,
...kyOptions.headers,
...fetchOptions.headers,
},
credentials: undefined,
} satisfies KyOptions;
} satisfies RequestInit;
if (options?.revalidateToken === true && this.lastPing) {
if (Date.now() - this.lastPing + 5000 > PING_INTERVAL) {
await this.getNewSessionId();
}
}
const request = await ky(path, requestOptions);
const responseJSON = (await request.json()) as ClassChartsResponse<
unknown,
unknown
>;
const request = await fetch(path, requestOptions);
let responseJSON: ClassChartsResponse<unknown, unknown>;
try {
responseJSON = await request.json();
} catch (err) {
throw new Error(
"Error parsing JSON. Returned response: " + (await request.text())
);
}
if (responseJSON.success == 0) {
throw new Error(responseJSON.error);
}

View file

@ -1,4 +1,3 @@
import ky from "ky-universal";
import type { GetPupilsResponse } from "../types.js";
import { BaseClient } from "./baseClient.js";
@ -24,7 +23,7 @@ export class ParentClient extends BaseClient {
}
/**
* Authenticates with classcharts
* Authenticates with ClassCharts
*/
async login(): Promise<void> {
if (!this.email) throw new Error("Email not inputted");
@ -33,11 +32,11 @@ export class ParentClient extends BaseClient {
formData.append("email", this.email);
formData.append("logintype", "existing");
formData.append("password", this.password);
formData.append("recaptcha-token", "no-token-avaliable");
formData.append("recaptcha-token", "no-token-available");
const headers = new Headers({
"Content-Type": "application/x-www-form-urlencoded",
});
const response = await ky(BASE_URL + "/parent/login", {
const response = await fetch(BASE_URL + "/parent/login", {
method: "POST",
body: formData,
headers: headers,
@ -45,7 +44,7 @@ export class ParentClient extends BaseClient {
});
if (response.status != 302 || !response.headers.get("set-cookie"))
throw new Error(
"Unauthenticated: Classcharts returned an error: " +
"Unauthenticated: ClassCharts returned an error: " +
response.status +
" " +
response.statusText

View file

@ -1,14 +1,13 @@
import { API_BASE_STUDENT, BASE_URL } from "../utils/consts.js";
import { BaseClient } from "./baseClient.js";
import { parseCookies } from "../utils/utils.js";
import ky from "ky-universal";
/**
* Student Client
*/
export class StudentClient extends BaseClient {
/**
* @property studentCode Classcharts student code
* @property studentCode ClassCharts student code
* @internal
*/
private studentCode = "";
@ -20,7 +19,7 @@ export class StudentClient extends BaseClient {
/**
*
* @param studentCode Classcharts student code
* @param studentCode ClassCharts student code
* @param dateOfBirth Student's date of birth
*/
constructor(studentCode: string, dateOfBirth?: string) {
@ -30,7 +29,7 @@ export class StudentClient extends BaseClient {
}
/**
* Authenticates with classcharts
* Authenticates with ClassCharts
*/
async login(): Promise<void> {
if (!this.studentCode) throw new Error("Student Code not inputted");
@ -39,17 +38,16 @@ export class StudentClient extends BaseClient {
formData.append("code", this.studentCode.toUpperCase());
formData.append("dob", this.dateOfBirth);
formData.append("remember_me", "1");
formData.append("recaptcha-token", "no-token-avaliable");
const request = await ky(BASE_URL + "/student/login", {
formData.append("recaptcha-token", "no-token-available");
const request = await fetch(BASE_URL + "/student/login", {
method: "POST",
body: formData,
redirect: "manual",
throwHttpErrors: false,
credentials: undefined,
});
if (request.status != 302 || !request.headers.get("set-cookie")) {
throw new Error(
"Unauthenticated: Classcharts returned an error: " +
"Unauthenticated: ClassCharts returned an error: " +
request.status +
" " +
request.statusText

View file

@ -4,9 +4,9 @@
* Helper type to define response from ClassCharts
* @internal
*/
export type ClassChartsResponse<Data, Error> = {
export type ClassChartsResponse<Data, Meta> = {
data: Data;
meta: Error;
meta: Meta;
error?: string;
success: number;
};