2023-09-24 13:36:35 +01:00
|
|
|
import { API_BASE_STUDENT, BASE_URL } from "../utils/consts.ts";
|
|
|
|
|
import { BaseClient } from "../core/baseClient.ts";
|
|
|
|
|
import { parseCookies } from "../utils/utils.ts";
|
2024-05-28 14:07:34 +01:00
|
|
|
import type {
|
2023-11-29 00:03:56 +00:00
|
|
|
GetStudentCodeOptions,
|
|
|
|
|
GetStudentCodeResponse,
|
|
|
|
|
RewardPurchaseResponse,
|
|
|
|
|
RewardsResponse,
|
2023-09-24 21:17:15 +01:00
|
|
|
} from "../types.ts";
|
2022-03-12 11:30:03 +00:00
|
|
|
/**
|
2024-05-28 14:07:34 +01:00
|
|
|
* Student Client.
|
|
|
|
|
* See {@link BaseClient} for all shared methods.
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* ```ts
|
|
|
|
|
* import { StudentClient } from "classcharts-api";
|
|
|
|
|
* // Date of birth MUST in the format DD/MM/YYYY
|
|
|
|
|
* const client = new StudentClient("classchartsCode", "01/01/2000");
|
|
|
|
|
* await client.login();
|
|
|
|
|
* ```
|
2022-03-12 11:30:03 +00:00
|
|
|
*/
|
2023-04-16 20:47:40 +01:00
|
|
|
export class StudentClient extends BaseClient {
|
2023-11-29 00:03:56 +00:00
|
|
|
/**
|
2024-05-28 14:07:34 +01:00
|
|
|
* ClassCharts student code
|
2023-11-29 00:03:56 +00:00
|
|
|
*/
|
|
|
|
|
private studentCode = "";
|
|
|
|
|
/**
|
2024-05-28 14:07:34 +01:00
|
|
|
* Student's date of birth
|
2023-11-29 00:03:56 +00:00
|
|
|
*/
|
|
|
|
|
private dateOfBirth = "";
|
2022-03-12 11:30:03 +00:00
|
|
|
|
2023-11-29 00:03:56 +00:00
|
|
|
/**
|
|
|
|
|
* @param studentCode ClassCharts student code
|
|
|
|
|
* @param dateOfBirth Student's date of birth
|
|
|
|
|
*/
|
|
|
|
|
constructor(studentCode: string, dateOfBirth?: string) {
|
|
|
|
|
super(API_BASE_STUDENT);
|
|
|
|
|
this.studentCode = String(studentCode);
|
|
|
|
|
this.dateOfBirth = String(dateOfBirth);
|
|
|
|
|
}
|
2022-03-12 11:30:03 +00:00
|
|
|
|
2023-11-29 00:03:56 +00:00
|
|
|
/**
|
|
|
|
|
* Authenticates with ClassCharts
|
|
|
|
|
*/
|
|
|
|
|
async login(): Promise<void> {
|
2024-01-10 10:57:33 +00:00
|
|
|
if (!this.studentCode) {
|
|
|
|
|
throw new Error("Student Code not provided");
|
|
|
|
|
}
|
2023-11-29 00:03:56 +00:00
|
|
|
const formData = new URLSearchParams();
|
|
|
|
|
formData.append("_method", "POST");
|
|
|
|
|
formData.append("code", this.studentCode.toUpperCase());
|
|
|
|
|
formData.append("dob", this.dateOfBirth);
|
|
|
|
|
formData.append("remember_me", "1");
|
|
|
|
|
formData.append("recaptcha-token", "no-token-available");
|
|
|
|
|
const request = await fetch(`${BASE_URL}/student/login`, {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: formData,
|
|
|
|
|
redirect: "manual",
|
|
|
|
|
});
|
|
|
|
|
if (request.status !== 302 || !request.headers.has("set-cookie")) {
|
|
|
|
|
await request.body?.cancel(); // Make deno tests happy by closing the body, unsure whether this is needed for the actual library
|
|
|
|
|
throw new Error(
|
|
|
|
|
"Unauthenticated: ClassCharts didn't return authentication cookies",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const cookies = String(request.headers.get("set-cookie"));
|
|
|
|
|
this.authCookies = cookies.split(",");
|
|
|
|
|
const sessionCookies = parseCookies(cookies);
|
|
|
|
|
const sessionID = JSON.parse(
|
|
|
|
|
String(sessionCookies.student_session_credentials),
|
|
|
|
|
);
|
|
|
|
|
this.sessionId = sessionID.session_id;
|
|
|
|
|
await this.getNewSessionId();
|
|
|
|
|
const user = await this.getStudentInfo();
|
|
|
|
|
this.studentId = user.data.user.id;
|
|
|
|
|
}
|
2023-09-18 20:52:01 +01:00
|
|
|
|
2023-11-29 00:03:56 +00:00
|
|
|
/**
|
|
|
|
|
* Gets the available items in the current student's rewards shop
|
|
|
|
|
* @returns Array of purchasable items
|
|
|
|
|
*/
|
|
|
|
|
async getRewards(): Promise<RewardsResponse> {
|
|
|
|
|
return await this.makeAuthedRequest(
|
|
|
|
|
`${this.API_BASE}/rewards/${this.studentId}`,
|
|
|
|
|
{
|
|
|
|
|
method: "GET",
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-09-18 20:52:01 +01:00
|
|
|
|
2023-11-29 00:03:56 +00:00
|
|
|
/**
|
|
|
|
|
* Purchase a reward item from the current student's rewards shop
|
|
|
|
|
* @param itemId number
|
|
|
|
|
* @returns An object containing the current student's balance and item ID purchased
|
|
|
|
|
*/
|
|
|
|
|
async purchaseReward(itemId: number): Promise<RewardPurchaseResponse> {
|
|
|
|
|
return await this.makeAuthedRequest(`${this.API_BASE}/purchase/${itemId}`, {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: `pupil_id=${this.studentId}`,
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-09-24 21:17:15 +01:00
|
|
|
|
2023-11-29 00:03:56 +00:00
|
|
|
/**
|
|
|
|
|
* Gets the current student's student code
|
|
|
|
|
* @param options GetStudentCodeOptions
|
|
|
|
|
* @param options.dateOfBirth Date of birth in the format YYYY-MM-DD
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
async getStudentCode(
|
|
|
|
|
options: GetStudentCodeOptions,
|
|
|
|
|
): Promise<GetStudentCodeResponse> {
|
|
|
|
|
const data = await this.makeAuthedRequest(`${this.API_BASE}/getcode`, {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
date: options.dateOfBirth,
|
|
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2022-03-12 11:30:03 +00:00
|
|
|
}
|