diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..09cf720
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,5 @@
+{
+ "recommendations": [
+ "denoland.vscode-deno"
+ ]
+}
diff --git a/deno.jsonc b/deno.jsonc
index 175e392..f6d841b 100644
--- a/deno.jsonc
+++ b/deno.jsonc
@@ -2,5 +2,8 @@
"tasks": {
"npm": "deno run -A scripts/build_npm.ts"
},
- "exclude": ["npm"]
+ "exclude": ["npm"],
+ "imports": {
+ "~/": "./"
+ }
}
diff --git a/deno.lock b/deno.lock
index f44f1e6..43b65b6 100644
--- a/deno.lock
+++ b/deno.lock
@@ -79,6 +79,38 @@
"https://deno.land/std@0.200.0/assert/unimplemented.ts": "d56fbeecb1f108331a380f72e3e010a1f161baa6956fd0f7cf3e095ae1a4c75a",
"https://deno.land/std@0.200.0/assert/unreachable.ts": "4600dc0baf7d9c15a7f7d234f00c23bca8f3eba8b140286aaca7aa998cf9a536",
"https://deno.land/std@0.200.0/fmt/colors.ts": "a7eecffdf3d1d54db890723b303847b6e0a1ab4b528ba6958b8f2e754cf1b3bc",
+ "https://deno.land/std@0.201.0/assert/_constants.ts": "8a9da298c26750b28b326b297316cdde860bc237533b07e1337c021379e6b2a9",
+ "https://deno.land/std@0.201.0/assert/_diff.ts": "1a3c044aedf77647d6cac86b798c6417603361b66b54c53331b312caeb447aea",
+ "https://deno.land/std@0.201.0/assert/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7",
+ "https://deno.land/std@0.201.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee",
+ "https://deno.land/std@0.201.0/assert/assert_almost_equals.ts": "e15ca1f34d0d5e0afae63b3f5d975cbd18335a132e42b0c747d282f62ad2cd6c",
+ "https://deno.land/std@0.201.0/assert/assert_array_includes.ts": "6856d7f2c3544bc6e62fb4646dfefa3d1df5ff14744d1bca19f0cbaf3b0d66c9",
+ "https://deno.land/std@0.201.0/assert/assert_equals.ts": "d8ec8a22447fbaf2fc9d7c3ed2e66790fdb74beae3e482855d75782218d68227",
+ "https://deno.land/std@0.201.0/assert/assert_exists.ts": "407cb6b9fb23a835cd8d5ad804e2e2edbbbf3870e322d53f79e1c7a512e2efd7",
+ "https://deno.land/std@0.201.0/assert/assert_false.ts": "a9962749f4bf5844e3fa494257f1de73d69e4fe0e82c34d0099287552163a2dc",
+ "https://deno.land/std@0.201.0/assert/assert_greater.ts": "ae2158a2d19313bf675bf7251d31c6dc52973edb12ac64ac8fc7064152af3e63",
+ "https://deno.land/std@0.201.0/assert/assert_greater_or_equal.ts": "1439da5ebbe20855446cac50097ac78b9742abe8e9a43e7de1ce1426d556e89c",
+ "https://deno.land/std@0.201.0/assert/assert_instance_of.ts": "3aedb3d8186e120812d2b3a5dea66a6e42bf8c57a8bd927645770bd21eea554c",
+ "https://deno.land/std@0.201.0/assert/assert_is_error.ts": "c21113094a51a296ffaf036767d616a78a2ae5f9f7bbd464cd0197476498b94b",
+ "https://deno.land/std@0.201.0/assert/assert_less.ts": "aec695db57db42ec3e2b62e97e1e93db0063f5a6ec133326cc290ff4b71b47e4",
+ "https://deno.land/std@0.201.0/assert/assert_less_or_equal.ts": "5fa8b6a3ffa20fd0a05032fe7257bf985d207b85685fdbcd23651b70f928c848",
+ "https://deno.land/std@0.201.0/assert/assert_match.ts": "c4083f80600bc190309903c95e397a7c9257ff8b5ae5c7ef91e834704e672e9b",
+ "https://deno.land/std@0.201.0/assert/assert_not_equals.ts": "9f1acab95bd1f5fc9a1b17b8027d894509a745d91bac1718fdab51dc76831754",
+ "https://deno.land/std@0.201.0/assert/assert_not_instance_of.ts": "0c14d3dfd9ab7a5276ed8ed0b18c703d79a3d106102077ec437bfe7ed912bd22",
+ "https://deno.land/std@0.201.0/assert/assert_not_match.ts": "3796a5b0c57a1ce6c1c57883dd4286be13a26f715ea662318ab43a8491a13ab0",
+ "https://deno.land/std@0.201.0/assert/assert_not_strict_equals.ts": "ca6c6d645e95fbc873d25320efeb8c4c6089a9a5e09f92d7c1c4b6e935c2a6ad",
+ "https://deno.land/std@0.201.0/assert/assert_object_match.ts": "d8fc2867cfd92eeacf9cea621e10336b666de1874a6767b5ec48988838370b54",
+ "https://deno.land/std@0.201.0/assert/assert_rejects.ts": "45c59724de2701e3b1f67c391d6c71c392363635aad3f68a1b3408f9efca0057",
+ "https://deno.land/std@0.201.0/assert/assert_strict_equals.ts": "b1f538a7ea5f8348aeca261d4f9ca603127c665e0f2bbfeb91fa272787c87265",
+ "https://deno.land/std@0.201.0/assert/assert_string_includes.ts": "b821d39ebf5cb0200a348863c86d8c4c4b398e02012ce74ad15666fc4b631b0c",
+ "https://deno.land/std@0.201.0/assert/assert_throws.ts": "63784e951475cb7bdfd59878cd25a0931e18f6dc32a6077c454b2cd94f4f4bcd",
+ "https://deno.land/std@0.201.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
+ "https://deno.land/std@0.201.0/assert/equal.ts": "9f1a46d5993966d2596c44e5858eec821859b45f783a5ee2f7a695dfc12d8ece",
+ "https://deno.land/std@0.201.0/assert/fail.ts": "c36353d7ae6e1f7933d45f8ea51e358c8c4b67d7e7502028598fe1fea062e278",
+ "https://deno.land/std@0.201.0/assert/mod.ts": "37c49a26aae2b254bbe25723434dc28cd7532e444cf0b481a97c045d110ec085",
+ "https://deno.land/std@0.201.0/assert/unimplemented.ts": "d56fbeecb1f108331a380f72e3e010a1f161baa6956fd0f7cf3e095ae1a4c75a",
+ "https://deno.land/std@0.201.0/assert/unreachable.ts": "4600dc0baf7d9c15a7f7d234f00c23bca8f3eba8b140286aaca7aa998cf9a536",
+ "https://deno.land/std@0.201.0/fmt/colors.ts": "87544aa2bc91087bb37f9c077970c85bfb041b48e4c37356129d7b450a415b6f",
"https://deno.land/x/code_block_writer@12.0.0/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5",
"https://deno.land/x/code_block_writer@12.0.0/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff",
"https://deno.land/x/deno_cache@0.5.2/auth_tokens.ts": "5d1d56474c54a9d152e44d43ea17c2e6a398dd1e9682c69811a313567c01ee1e",
diff --git a/deps_dev.ts b/deps_dev.ts
new file mode 100644
index 0000000..e094a6d
--- /dev/null
+++ b/deps_dev.ts
@@ -0,0 +1,5 @@
+export {
+ assertEquals,
+ assertExists,
+ assertRejects,
+} from "https://deno.land/std@0.201.0/assert/mod.ts";
diff --git a/index.html b/index.html
index e005a08..c532332 100644
--- a/index.html
+++ b/index.html
@@ -4,7 +4,10 @@
ClassCharts-API
-
+
-
diff --git a/mod.ts b/mod.ts
index 249b084..7650092 100644
--- a/mod.ts
+++ b/mod.ts
@@ -1,2 +1,2 @@
-export * from "./src/core/studentClient.ts";
-export * from "./src/core/parentClient.ts";
+export * from "~/src/core/studentClient.ts";
+export * from "~/src/core/parentClient.ts";
diff --git a/scripts/build_npm.ts b/scripts/build_npm.ts
index 4d7cf8d..8cce7c8 100644
--- a/scripts/build_npm.ts
+++ b/scripts/build_npm.ts
@@ -1,3 +1,4 @@
+// This dependancy cannot be moved to dev_deps.ts since dnt complains about a top-level await
import { build, emptyDir } from "https://deno.land/x/dnt@0.38.1/mod.ts";
if (!Deno.args[0]) throw new Error("No version specified");
@@ -13,6 +14,7 @@ await build({
path: "./src/types.ts",
}],
outDir: "./npm",
+ importMap: "./deno.jsonc",
shims: {
deno: true,
},
@@ -22,13 +24,12 @@ await build({
},
typeCheck: "both",
package: {
- // package.json properties
name: "classcharts-api",
+ version: String(Deno.args[0]).replace("v", ""),
author: {
name: "James Cook",
email: "james@jaminit.co.uk",
},
- version: Deno.args[0],
description:
"A Typescript wrapper for getting information from the ClassCharts API",
license: "ISC",
@@ -47,7 +48,6 @@ await build({
sideEffects: false,
},
postBuild() {
- // steps to run after building and before running the tests
Deno.copyFileSync("LICENSE", "npm/LICENSE");
Deno.copyFileSync("README.md", "npm/README.md");
},
diff --git a/src/core/baseClient.ts b/src/core/baseClient.ts
index b243d15..8c3ebac 100644
--- a/src/core/baseClient.ts
+++ b/src/core/baseClient.ts
@@ -17,7 +17,7 @@ import type {
LessonsResponse,
PupilFieldsResponse,
} from "../types.ts";
-import { PING_INTERVAL } from "../utils/consts.ts";
+import { PING_INTERVAL } from "~/src/utils/consts.ts";
/**
* Shared client for both parent and student. This is not exported and should not be used directly
@@ -105,7 +105,8 @@ export class BaseClient {
}
}
const request = await fetch(path, requestOptions);
- let responseJSON: ClassChartsResponse;
+ // deno-lint-ignore no-explicit-any
+ let responseJSON: ClassChartsResponse;
try {
responseJSON = await request.json();
} catch {
@@ -116,8 +117,7 @@ export class BaseClient {
if (responseJSON.success == 0) {
throw new Error(responseJSON.error);
}
- // deno-lint-ignore no-explicit-any
- return responseJSON as unknown as any;
+ return responseJSON;
}
/**
* Gets general information about the current student
diff --git a/src/core/parentClient.ts b/src/core/parentClient.ts
index b20882d..6f2451a 100644
--- a/src/core/parentClient.ts
+++ b/src/core/parentClient.ts
@@ -1,8 +1,8 @@
import type { GetPupilsResponse } from "../types.ts";
-import { BaseClient } from "./baseClient.ts";
-import { API_BASE_PARENT, BASE_URL } from "../utils/consts.ts";
-import { parseCookies } from "../utils/utils.ts";
+import { BaseClient } from "~/src/core/baseClient.ts";
+import { API_BASE_PARENT, BASE_URL } from "~/src/utils/consts.ts";
+import { parseCookies } from "~/src/utils/utils.ts";
/**
* Parent Client
*/
@@ -26,6 +26,7 @@ export class ParentClient extends BaseClient {
*/
async login(): Promise {
if (!this.email) throw new Error("Email not provided");
+ if (!this.password) throw new Error("Password not provided");
const formData = new URLSearchParams();
formData.append("_method", "POST");
formData.append("email", this.email);
@@ -39,14 +40,12 @@ export class ParentClient extends BaseClient {
method: "POST",
body: formData,
headers: headers,
- credentials: undefined,
+ redirect: "manual",
});
if (response.status != 302 || !response.headers.has("set-cookie")) {
+ await response.body?.cancel(); // Make deno tests happy by closing the body, unsure whether this is needed for the actual library
throw new Error(
- "Unauthenticated: ClassCharts returned an error: " +
- response.status +
- " " +
- response.statusText,
+ "Unauthenticated: ClassCharts didn't return authentication cookies",
);
}
@@ -56,19 +55,20 @@ export class ParentClient extends BaseClient {
const sessionID = JSON.parse(
String(sessionCookies["parent_session_credentials"]),
);
- super.sessionId = sessionID.session_id;
+ this.sessionId = sessionID.session_id;
this.pupils = await this.getPupils();
if (!this.pupils) throw new Error("Account has no pupils attached");
- super.studentId = this.pupils[0].id;
+ this.studentId = this.pupils[0].id;
}
/**
* Get a list of pupils connected to this parent's account
* @returns an array of Pupils connected to this parent's account
*/
async getPupils(): Promise {
- return await super.makeAuthedRequest(super.API_BASE + "/pupils", {
+ const response = await this.makeAuthedRequest(this.API_BASE + "/pupils", {
method: "GET",
});
+ return response.data;
}
/**
* Selects a pupil to be used with API requests
@@ -82,7 +82,7 @@ export class ParentClient extends BaseClient {
for (let i = 0; i < pupils.length; i++) {
const pupil = pupils[i];
if (pupil.id == pupilId) {
- super.studentId = pupil.id;
+ this.studentId = pupil.id;
return;
}
}
diff --git a/src/core/parentClient_test.ts b/src/core/parentClient_test.ts
new file mode 100644
index 0000000..d947082
--- /dev/null
+++ b/src/core/parentClient_test.ts
@@ -0,0 +1,35 @@
+import { assertRejects } from "~/deps_dev.ts";
+import { ParentClient } from "~/src/core/parentClient.ts";
+
+Deno.test("Throws when no email is provided", async () => {
+ const client = new ParentClient("", "password");
+ await assertRejects(
+ async () => {
+ await client.login();
+ },
+ Error,
+ "Email not provided",
+ );
+});
+
+Deno.test("Throws when no password is provided", async () => {
+ const client = new ParentClient("email", "");
+ await assertRejects(
+ async () => {
+ await client.login();
+ },
+ Error,
+ "Password not provided",
+ );
+});
+
+Deno.test("Throws with invalid username and password", async () => {
+ const client = new ParentClient("invalid", "invalid");
+ await assertRejects(
+ async () => {
+ await client.login();
+ },
+ Error,
+ "Unauthenticated: ClassCharts didn't return authentication cookies",
+ );
+});
diff --git a/src/core/studentClient.ts b/src/core/studentClient.ts
index 2be301d..3e44937 100644
--- a/src/core/studentClient.ts
+++ b/src/core/studentClient.ts
@@ -1,7 +1,7 @@
-import { API_BASE_STUDENT, BASE_URL } from "../utils/consts.ts";
-import { BaseClient } from "./baseClient.ts";
-import { parseCookies } from "../utils/utils.ts";
-import { RewardPurchaseResponse, RewardsResponse } from "../types.ts"
+import { API_BASE_STUDENT, BASE_URL } from "~/src/utils/consts.ts";
+import { BaseClient } from "~/src/core/baseClient.ts";
+import { parseCookies } from "~/src/utils/utils.ts";
+import { RewardPurchaseResponse, RewardsResponse } from "~/src/types.ts"
/**
* Student Client
diff --git a/src/core/studentClient_test.ts b/src/core/studentClient_test.ts
index 6932a75..a5b000a 100644
--- a/src/core/studentClient_test.ts
+++ b/src/core/studentClient_test.ts
@@ -1,6 +1,5 @@
-import { assertRejects } from "https://deno.land/std@0.200.0/assert/mod.ts";
-
-import { StudentClient } from "./studentClient.ts";
+import { assertRejects } from "~/deps_dev.ts";
+import { StudentClient } from "~/src/core/studentClient.ts";
Deno.test("Throws when no student code is provided", async () => {
const client = new StudentClient("");
diff --git a/src/utils/utils_test.ts b/src/utils/utils_test.ts
index 7ecfdff..ccb7696 100644
--- a/src/utils/utils_test.ts
+++ b/src/utils/utils_test.ts
@@ -1,8 +1,4 @@
-import {
- assertEquals,
- assertExists,
-} from "https://deno.land/std@0.200.0/assert/mod.ts";
-
+import { assertEquals, assertExists } from "~/deps_dev.ts";
import { parseCookies } from "./utils.ts";
Deno.test("Parses simple cookie", () => {
const cookie =