@falkenslab/moodle-driver 0.0.0-stage → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +133 -2
- package/dist/areas/activities/build.d.ts +98 -0
- package/dist/areas/activities/build.js +246 -0
- package/dist/areas/activities/build.js.map +1 -0
- package/dist/areas/activities/content.d.ts +53 -0
- package/dist/areas/activities/content.js +113 -0
- package/dist/areas/activities/content.js.map +1 -0
- package/dist/areas/assignments/grader.d.ts +68 -0
- package/dist/areas/assignments/grader.js +169 -0
- package/dist/areas/assignments/grader.js.map +1 -0
- package/dist/areas/assignments/grading.d.ts +86 -0
- package/dist/areas/assignments/grading.js +162 -0
- package/dist/areas/assignments/grading.js.map +1 -0
- package/dist/areas/assignments/student.d.ts +57 -0
- package/dist/areas/assignments/student.js +115 -0
- package/dist/areas/assignments/student.js.map +1 -0
- package/dist/areas/calendar/calendar.d.ts +43 -0
- package/dist/areas/calendar/calendar.js +84 -0
- package/dist/areas/calendar/calendar.js.map +1 -0
- package/dist/areas/completion/completion.d.ts +50 -0
- package/dist/areas/completion/completion.js +112 -0
- package/dist/areas/completion/completion.js.map +1 -0
- package/dist/areas/courses/list.d.ts +59 -0
- package/dist/areas/courses/list.js +74 -0
- package/dist/areas/courses/list.js.map +1 -0
- package/dist/areas/courses/overview.d.ts +83 -0
- package/dist/areas/courses/overview.js +137 -0
- package/dist/areas/courses/overview.js.map +1 -0
- package/dist/areas/courses/state.d.ts +51 -0
- package/dist/areas/courses/state.js +45 -0
- package/dist/areas/courses/state.js.map +1 -0
- package/dist/areas/courses/structure.d.ts +89 -0
- package/dist/areas/courses/structure.js +104 -0
- package/dist/areas/courses/structure.js.map +1 -0
- package/dist/areas/forums/discussions.d.ts +57 -0
- package/dist/areas/forums/discussions.js +119 -0
- package/dist/areas/forums/discussions.js.map +1 -0
- package/dist/areas/forums/posts.d.ts +83 -0
- package/dist/areas/forums/posts.js +114 -0
- package/dist/areas/forums/posts.js.map +1 -0
- package/dist/areas/grades/gradebook.d.ts +104 -0
- package/dist/areas/grades/gradebook.js +250 -0
- package/dist/areas/grades/gradebook.js.map +1 -0
- package/dist/areas/grades/user-report.d.ts +26 -0
- package/dist/areas/grades/user-report.js +71 -0
- package/dist/areas/grades/user-report.js.map +1 -0
- package/dist/areas/h5p/h5p.d.ts +33 -0
- package/dist/areas/h5p/h5p.js +104 -0
- package/dist/areas/h5p/h5p.js.map +1 -0
- package/dist/areas/lessons/lessons.d.ts +60 -0
- package/dist/areas/lessons/lessons.js +145 -0
- package/dist/areas/lessons/lessons.js.map +1 -0
- package/dist/areas/messages/messages.d.ts +68 -0
- package/dist/areas/messages/messages.js +84 -0
- package/dist/areas/messages/messages.js.map +1 -0
- package/dist/areas/participants/participants.d.ts +57 -0
- package/dist/areas/participants/participants.js +135 -0
- package/dist/areas/participants/participants.js.map +1 -0
- package/dist/areas/questions/banks.d.ts +83 -0
- package/dist/areas/questions/banks.js +239 -0
- package/dist/areas/questions/banks.js.map +1 -0
- package/dist/areas/quizzes/attempts.d.ts +123 -0
- package/dist/areas/quizzes/attempts.js +300 -0
- package/dist/areas/quizzes/attempts.js.map +1 -0
- package/dist/areas/quizzes/results.d.ts +36 -0
- package/dist/areas/quizzes/results.js +93 -0
- package/dist/areas/quizzes/results.js.map +1 -0
- package/dist/areas/quizzes/structure.d.ts +42 -0
- package/dist/areas/quizzes/structure.js +100 -0
- package/dist/areas/quizzes/structure.js.map +1 -0
- package/dist/areas/site/info.d.ts +25 -0
- package/dist/areas/site/info.js +45 -0
- package/dist/areas/site/info.js.map +1 -0
- package/dist/areas/site/users.d.ts +56 -0
- package/dist/areas/site/users.js +89 -0
- package/dist/areas/site/users.js.map +1 -0
- package/dist/areas/surveys/choice.d.ts +38 -0
- package/dist/areas/surveys/choice.js +105 -0
- package/dist/areas/surveys/choice.js.map +1 -0
- package/dist/areas/surveys/surveys.d.ts +51 -0
- package/dist/areas/surveys/surveys.js +201 -0
- package/dist/areas/surveys/surveys.js.map +1 -0
- package/dist/browser/chromium.d.ts +15 -0
- package/dist/browser/chromium.js +53 -0
- package/dist/browser/chromium.js.map +1 -0
- package/dist/browser/cookies.d.ts +11 -0
- package/dist/browser/cookies.js +31 -0
- package/dist/browser/cookies.js.map +1 -0
- package/dist/browser/manager.d.ts +57 -0
- package/dist/browser/manager.js +177 -0
- package/dist/browser/manager.js.map +1 -0
- package/dist/browser.d.ts +53 -0
- package/dist/browser.js +167 -0
- package/dist/browser.js.map +1 -0
- package/dist/categories.d.ts +28 -0
- package/dist/categories.js +222 -0
- package/dist/categories.js.map +1 -0
- package/dist/chromiumInstaller.d.ts +15 -0
- package/dist/chromiumInstaller.js +52 -0
- package/dist/chromiumInstaller.js.map +1 -0
- package/dist/cli/args.d.ts +33 -0
- package/dist/cli/args.js +194 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/commands.generated.d.ts +4 -0
- package/dist/cli/commands.generated.js +2203 -0
- package/dist/cli/commands.generated.js.map +1 -0
- package/dist/cli/config.d.ts +46 -0
- package/dist/cli/config.js +107 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +19 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.d.ts +4 -0
- package/dist/cli/output.js +71 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/run.d.ts +15 -0
- package/dist/cli/run.js +194 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/spec.d.ts +42 -0
- package/dist/cli/spec.js +4 -0
- package/dist/cli/spec.js.map +1 -0
- package/dist/client.d.ts +217 -0
- package/dist/client.js +179 -0
- package/dist/client.js.map +1 -0
- package/dist/core/ajax.d.ts +25 -0
- package/dist/core/ajax.js +85 -0
- package/dist/core/ajax.js.map +1 -0
- package/dist/core/editor.d.ts +18 -0
- package/dist/core/editor.js +51 -0
- package/dist/core/editor.js.map +1 -0
- package/dist/core/errors.d.ts +12 -0
- package/dist/core/errors.js +10 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/files.d.ts +16 -0
- package/dist/core/files.js +58 -0
- package/dist/core/files.js.map +1 -0
- package/dist/core/forms.d.ts +45 -0
- package/dist/core/forms.js +200 -0
- package/dist/core/forms.js.map +1 -0
- package/dist/core/http.d.ts +18 -0
- package/dist/core/http.js +22 -0
- package/dist/core/http.js.map +1 -0
- package/dist/core/inPage.d.ts +8 -0
- package/dist/core/inPage.js +10 -0
- package/dist/core/inPage.js.map +1 -0
- package/dist/core/login.d.ts +40 -0
- package/dist/core/login.js +83 -0
- package/dist/core/login.js.map +1 -0
- package/dist/core/pace.d.ts +4 -0
- package/dist/core/pace.js +21 -0
- package/dist/core/pace.js.map +1 -0
- package/dist/core/session.d.ts +55 -0
- package/dist/core/session.js +157 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/site.d.ts +8 -0
- package/dist/core/site.js +36 -0
- package/dist/core/site.js.map +1 -0
- package/dist/core/text.d.ts +21 -0
- package/dist/core/text.js +113 -0
- package/dist/core/text.js.map +1 -0
- package/dist/home.d.ts +19 -0
- package/dist/home.js +54 -0
- package/dist/home.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/internals.d.ts +11 -0
- package/dist/internals.js +15 -0
- package/dist/internals.js.map +1 -0
- package/dist/moodle/activities.d.ts +94 -0
- package/dist/moodle/activities.js +240 -0
- package/dist/moodle/activities.js.map +1 -0
- package/dist/moodle/ajax.d.ts +22 -0
- package/dist/moodle/ajax.js +91 -0
- package/dist/moodle/ajax.js.map +1 -0
- package/dist/moodle/assign.d.ts +65 -0
- package/dist/moodle/assign.js +162 -0
- package/dist/moodle/assign.js.map +1 -0
- package/dist/moodle/calendar.d.ts +41 -0
- package/dist/moodle/calendar.js +80 -0
- package/dist/moodle/calendar.js.map +1 -0
- package/dist/moodle/choice.d.ts +33 -0
- package/dist/moodle/choice.js +100 -0
- package/dist/moodle/choice.js.map +1 -0
- package/dist/moodle/completion.d.ts +48 -0
- package/dist/moodle/completion.js +108 -0
- package/dist/moodle/completion.js.map +1 -0
- package/dist/moodle/content.d.ts +43 -0
- package/dist/moodle/content.js +105 -0
- package/dist/moodle/content.js.map +1 -0
- package/dist/moodle/course.d.ts +51 -0
- package/dist/moodle/course.js +45 -0
- package/dist/moodle/course.js.map +1 -0
- package/dist/moodle/courses.d.ts +57 -0
- package/dist/moodle/courses.js +70 -0
- package/dist/moodle/courses.js.map +1 -0
- package/dist/moodle/editor.d.ts +18 -0
- package/dist/moodle/editor.js +50 -0
- package/dist/moodle/editor.js.map +1 -0
- package/dist/moodle/files.d.ts +16 -0
- package/dist/moodle/files.js +57 -0
- package/dist/moodle/files.js.map +1 -0
- package/dist/moodle/forms.d.ts +44 -0
- package/dist/moodle/forms.js +199 -0
- package/dist/moodle/forms.js.map +1 -0
- package/dist/moodle/forum.d.ts +55 -0
- package/dist/moodle/forum.js +115 -0
- package/dist/moodle/forum.js.map +1 -0
- package/dist/moodle/forumPosts.d.ts +83 -0
- package/dist/moodle/forumPosts.js +113 -0
- package/dist/moodle/forumPosts.js.map +1 -0
- package/dist/moodle/gradebook.d.ts +102 -0
- package/dist/moodle/gradebook.js +246 -0
- package/dist/moodle/gradebook.js.map +1 -0
- package/dist/moodle/grades.d.ts +24 -0
- package/dist/moodle/grades.js +67 -0
- package/dist/moodle/grades.js.map +1 -0
- package/dist/moodle/grading.d.ts +92 -0
- package/dist/moodle/grading.js +161 -0
- package/dist/moodle/grading.js.map +1 -0
- package/dist/moodle/h5p.d.ts +31 -0
- package/dist/moodle/h5p.js +100 -0
- package/dist/moodle/h5p.js.map +1 -0
- package/dist/moodle/inPage.d.ts +8 -0
- package/dist/moodle/inPage.js +10 -0
- package/dist/moodle/inPage.js.map +1 -0
- package/dist/moodle/lesson.d.ts +57 -0
- package/dist/moodle/lesson.js +140 -0
- package/dist/moodle/lesson.js.map +1 -0
- package/dist/moodle/login.d.ts +37 -0
- package/dist/moodle/login.js +77 -0
- package/dist/moodle/login.js.map +1 -0
- package/dist/moodle/messages.d.ts +66 -0
- package/dist/moodle/messages.js +80 -0
- package/dist/moodle/messages.js.map +1 -0
- package/dist/moodle/overview.d.ts +83 -0
- package/dist/moodle/overview.js +137 -0
- package/dist/moodle/overview.js.map +1 -0
- package/dist/moodle/pace.d.ts +4 -0
- package/dist/moodle/pace.js +19 -0
- package/dist/moodle/pace.js.map +1 -0
- package/dist/moodle/participants.d.ts +55 -0
- package/dist/moodle/participants.js +131 -0
- package/dist/moodle/participants.js.map +1 -0
- package/dist/moodle/questionBank.d.ts +81 -0
- package/dist/moodle/questionBank.js +235 -0
- package/dist/moodle/questionBank.js.map +1 -0
- package/dist/moodle/quiz.d.ts +117 -0
- package/dist/moodle/quiz.js +291 -0
- package/dist/moodle/quiz.js.map +1 -0
- package/dist/moodle/quizResults.d.ts +36 -0
- package/dist/moodle/quizResults.js +93 -0
- package/dist/moodle/quizResults.js.map +1 -0
- package/dist/moodle/quizStructure.d.ts +42 -0
- package/dist/moodle/quizStructure.js +100 -0
- package/dist/moodle/quizStructure.js.map +1 -0
- package/dist/moodle/session.d.ts +39 -0
- package/dist/moodle/session.js +99 -0
- package/dist/moodle/session.js.map +1 -0
- package/dist/moodle/site.d.ts +8 -0
- package/dist/moodle/site.js +36 -0
- package/dist/moodle/site.js.map +1 -0
- package/dist/moodle/siteInfo.d.ts +25 -0
- package/dist/moodle/siteInfo.js +45 -0
- package/dist/moodle/siteInfo.js.map +1 -0
- package/dist/moodle/structure.d.ts +94 -0
- package/dist/moodle/structure.js +103 -0
- package/dist/moodle/structure.js.map +1 -0
- package/dist/moodle/submission.d.ts +48 -0
- package/dist/moodle/submission.js +109 -0
- package/dist/moodle/submission.js.map +1 -0
- package/dist/moodle/survey.d.ts +47 -0
- package/dist/moodle/survey.js +197 -0
- package/dist/moodle/survey.js.map +1 -0
- package/dist/moodle/text.d.ts +21 -0
- package/dist/moodle/text.js +113 -0
- package/dist/moodle/text.js.map +1 -0
- package/dist/moodle/user.d.ts +54 -0
- package/dist/moodle/user.js +78 -0
- package/dist/moodle/user.js.map +1 -0
- package/dist/options.d.ts +30 -0
- package/dist/options.js +35 -0
- package/dist/options.js.map +1 -0
- package/dist/sessionCookies.d.ts +11 -0
- package/dist/sessionCookies.js +31 -0
- package/dist/sessionCookies.js.map +1 -0
- package/dist/testing/fakeMoodle.d.ts +55 -0
- package/dist/testing/fakeMoodle.js +103 -0
- package/dist/testing/fakeMoodle.js.map +1 -0
- package/dist/testing/gradingPanel.d.ts +6 -0
- package/dist/testing/gradingPanel.js +22 -0
- package/dist/testing/gradingPanel.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.js +18 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +77 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,mGAAmG;AACnG,gGAAgG;AAEhG,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAC7D,+FAA+F;AAC/F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAG,eAAe,EAAE,UAAU,CAAU,CAAC;AAGlE,4GAA4G;AAC5G,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,WAAW,EAAE,MAAM,CAAU,CAAC;AAkBrD,iCAAiC;AACjC,MAAM,OAAO,cAAe,SAAQ,WAAW;IACpC,IAAI,GAAG,gBAAgB,CAAC;IACjC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC/B,CAAC;CACF;AAED,6FAA6F;AAC7F,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,cAAc,CAAC,sCAAsC,KAAK,IAAI,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,cAAc,CAAC,8CAA8C,KAAK,IAAI,CAAC,CAAC;IACpF,CAAC;IACD,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC;IACrD,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BrowserContext } from "playwright-core";
|
|
2
|
+
/**
|
|
3
|
+
* Chromium drops session cookies (no expiry) when a persistent profile closes, and Moodle's
|
|
4
|
+
* `MoodleSession` is one (confirmed empirically, Edge and playwright-core 1.64, Moodle 5.2): the
|
|
5
|
+
* profile alone would forget the login on every restart. They are kept in this file inside the
|
|
6
|
+
* profile, as sensitive as the profile itself (ADR-003).
|
|
7
|
+
*/
|
|
8
|
+
export declare const SESSION_COOKIES_FILE = "moodle-mcp-session-cookies.json";
|
|
9
|
+
export declare function saveSessionCookies(context: BrowserContext, profileDir: string): Promise<void>;
|
|
10
|
+
/** Puts back the session cookies saved last time; a missing or unreadable file means none. */
|
|
11
|
+
export declare function restoreSessionCookies(context: BrowserContext, profileDir: string): Promise<void>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Chromium drops session cookies (no expiry) when a persistent profile closes, and Moodle's
|
|
5
|
+
* `MoodleSession` is one (confirmed empirically, Edge and playwright-core 1.64, Moodle 5.2): the
|
|
6
|
+
* profile alone would forget the login on every restart. They are kept in this file inside the
|
|
7
|
+
* profile, as sensitive as the profile itself (ADR-003).
|
|
8
|
+
*/
|
|
9
|
+
export const SESSION_COOKIES_FILE = "moodle-mcp-session-cookies.json";
|
|
10
|
+
export async function saveSessionCookies(context, profileDir) {
|
|
11
|
+
const sessionCookies = (await context.cookies()).filter((cookie) => cookie.expires === -1);
|
|
12
|
+
await writeFile(path.join(profileDir, SESSION_COOKIES_FILE), JSON.stringify(sessionCookies), { mode: 0o600 });
|
|
13
|
+
}
|
|
14
|
+
/** Puts back the session cookies saved last time; a missing or unreadable file means none. */
|
|
15
|
+
export async function restoreSessionCookies(context, profileDir) {
|
|
16
|
+
let cookies;
|
|
17
|
+
try {
|
|
18
|
+
cookies = JSON.parse(await readFile(path.join(profileDir, SESSION_COOKIES_FILE), "utf8"));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (!Array.isArray(cookies) || cookies.length === 0)
|
|
24
|
+
return;
|
|
25
|
+
// Cookies the browser kept itself are newer than the file's.
|
|
26
|
+
const kept = new Set((await context.cookies()).map((c) => `${c.name}|${c.domain}|${c.path}`));
|
|
27
|
+
const missing = cookies.filter((c) => !kept.has(`${c.name}|${c.domain}|${c.path}`));
|
|
28
|
+
if (missing.length > 0)
|
|
29
|
+
await context.addCookies(missing).catch(() => undefined);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=sessionCookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionCookies.js","sourceRoot":"","sources":["../src/sessionCookies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,iCAAiC,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAuB,EAAE,UAAkB;IAClF,MAAM,cAAc,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3F,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAChH,CAAC;AAED,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,OAAuB,EAAE,UAAkB;IACrF,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,CAAa,CAAC;IACxG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC5D,6DAA6D;IAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACpF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;AACnF,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type Browser, type BrowserContext } from "playwright-core";
|
|
2
|
+
export declare const SITE = "http://moodle.test/";
|
|
3
|
+
/**
|
|
4
|
+
* A Moodle page reduced to what the driver reads: the body class, `M.cfg` (`wwwroot`, `sesskey`,
|
|
5
|
+
* `userId`), the logout link in the user menu and the page heading, as Moodle 5.2 renders them.
|
|
6
|
+
*/
|
|
7
|
+
export declare function moodlePage({ userId, heading, guest, sesskey, wwwroot, body, bodyId, bodyClass, }: {
|
|
8
|
+
userId: number;
|
|
9
|
+
heading?: string;
|
|
10
|
+
guest?: boolean;
|
|
11
|
+
sesskey?: string;
|
|
12
|
+
wwwroot?: string;
|
|
13
|
+
body?: string;
|
|
14
|
+
bodyId?: string;
|
|
15
|
+
bodyClass?: string;
|
|
16
|
+
}): string;
|
|
17
|
+
/**
|
|
18
|
+
* The first browser that launches headless: the system's Edge or Chrome, or Playwright's own Chromium
|
|
19
|
+
* (the test container, `npm run test:docker`); `undefined` skips the tests that need one.
|
|
20
|
+
*/
|
|
21
|
+
export declare function launchTestBrowser(): Promise<Browser | undefined>;
|
|
22
|
+
/** Thrown by a fake service to answer with Moodle's exception `errorcode`. */
|
|
23
|
+
export declare class ServiceFailure extends Error {
|
|
24
|
+
readonly errorcode: string;
|
|
25
|
+
constructor(errorcode: string);
|
|
26
|
+
}
|
|
27
|
+
export interface FakeMoodleState {
|
|
28
|
+
/** The logged-in user; none means every page is the login page. */
|
|
29
|
+
user?: {
|
|
30
|
+
id: number;
|
|
31
|
+
fullName: string;
|
|
32
|
+
};
|
|
33
|
+
/** The session's sesskey: changing it makes older tabs' service calls fail with `invalidsesskey`. */
|
|
34
|
+
sesskey?: string;
|
|
35
|
+
/** AJAX services by name: what each returns as `data` for its arguments; throwing `ServiceFailure` answers with that error code. */
|
|
36
|
+
services?: Record<string, (args: Record<string, unknown>) => unknown>;
|
|
37
|
+
/** Extra body HTML for the pages at these paths (logged in only). */
|
|
38
|
+
bodies?: Record<string, string>;
|
|
39
|
+
/** Extra body classes for the pages at these paths, as Moodle adds (`format-topics` on a course page). */
|
|
40
|
+
bodyClasses?: Record<string, string>;
|
|
41
|
+
/** Every page path served, for tests that count page loads. */
|
|
42
|
+
pagesServed?: string[];
|
|
43
|
+
/** Every service call received. */
|
|
44
|
+
serviceCalls?: {
|
|
45
|
+
methodname: string;
|
|
46
|
+
args: Record<string, unknown>;
|
|
47
|
+
}[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Serves a fake Moodle at `SITE` in `context`: logged out, every page is the login page, as with
|
|
51
|
+
* Moodle's forced login (served in place: Playwright doesn't route the request after a redirect it
|
|
52
|
+
* fulfilled, confirmed empirically); `state.user` logs someone in. `lib/ajax/service.php` answers
|
|
53
|
+
* like Moodle's, exceptions included.
|
|
54
|
+
*/
|
|
55
|
+
export declare function serveFakeMoodle(context: BrowserContext, state: FakeMoodleState): Promise<void>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { chromium } from "playwright-core";
|
|
2
|
+
import { setTransport } from "../core/http.js";
|
|
3
|
+
export const SITE = "http://moodle.test/";
|
|
4
|
+
// The fake's own blank page, for requests the driver makes without a tab.
|
|
5
|
+
const TRANSPORT_PATH = "__fake-transport";
|
|
6
|
+
/**
|
|
7
|
+
* A Moodle page reduced to what the driver reads: the body class, `M.cfg` (`wwwroot`, `sesskey`,
|
|
8
|
+
* `userId`), the logout link in the user menu and the page heading, as Moodle 5.2 renders them.
|
|
9
|
+
*/
|
|
10
|
+
export function moodlePage({ userId, heading = "Dashboard", guest = false, sesskey = "s1", wwwroot = "http://moodle.test", body = "", bodyId = "", bodyClass = "", }) {
|
|
11
|
+
const loggedIn = userId > 0;
|
|
12
|
+
return `<!DOCTYPE html><html><head><title>${heading}</title>
|
|
13
|
+
<script>var M = {}; M.cfg = {"wwwroot":${JSON.stringify(wwwroot).replaceAll("/", "\\/")},"sesskey":"${sesskey}","userId":${userId},"language":"en","usertimezone":"Europe/Madrid"};</script></head>
|
|
14
|
+
<body${bodyId ? ` id="${bodyId}"` : ""} class="${loggedIn ? "" : "notloggedin"} ${bodyClass}">
|
|
15
|
+
<nav>${loggedIn && !guest ? '<div class="usermenu"><a href="http://moodle.test/login/logout.php?sesskey=x">Log out</a></div>' : '<a href="http://moodle.test/login/index.php">Log in</a>'}</nav>
|
|
16
|
+
<div id="page-header"><div class="page-header-headings"><h1>${heading}</h1></div></div>
|
|
17
|
+
${body}
|
|
18
|
+
</body></html>`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The first browser that launches headless: the system's Edge or Chrome, or Playwright's own Chromium
|
|
22
|
+
* (the test container, `npm run test:docker`); `undefined` skips the tests that need one.
|
|
23
|
+
*/
|
|
24
|
+
export async function launchTestBrowser() {
|
|
25
|
+
for (const channel of ["msedge", "chrome", "chromium"]) {
|
|
26
|
+
try {
|
|
27
|
+
return await chromium.launch({ channel, headless: true });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Try the next one.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
/** Thrown by a fake service to answer with Moodle's exception `errorcode`. */
|
|
36
|
+
export class ServiceFailure extends Error {
|
|
37
|
+
errorcode;
|
|
38
|
+
constructor(errorcode) {
|
|
39
|
+
super(errorcode);
|
|
40
|
+
this.errorcode = errorcode;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Serves a fake Moodle at `SITE` in `context`: logged out, every page is the login page, as with
|
|
45
|
+
* Moodle's forced login (served in place: Playwright doesn't route the request after a redirect it
|
|
46
|
+
* fulfilled, confirmed empirically); `state.user` logs someone in. `lib/ajax/service.php` answers
|
|
47
|
+
* like Moodle's, exceptions included.
|
|
48
|
+
*/
|
|
49
|
+
export async function serveFakeMoodle(context, state) {
|
|
50
|
+
// The driver's requests without a tab (`context.request`) don't go through routes: here they go
|
|
51
|
+
// through a blank page of the site's origin, whose `fetch` does (the page itself isn't counted).
|
|
52
|
+
let transportPage;
|
|
53
|
+
setTransport(context, async (url, request) => {
|
|
54
|
+
transportPage ??= context.newPage().then(async (page) => {
|
|
55
|
+
await page.goto(`${SITE}${TRANSPORT_PATH}`);
|
|
56
|
+
return page;
|
|
57
|
+
});
|
|
58
|
+
const page = await transportPage;
|
|
59
|
+
return page.evaluate(async ({ url, request }) => {
|
|
60
|
+
const g = globalThis;
|
|
61
|
+
const response = await g.fetch(url, { method: request.method ?? "GET", headers: request.headers, body: request.body, credentials: "same-origin" });
|
|
62
|
+
return { status: response.status, url: response.url, body: await response.text() };
|
|
63
|
+
}, { url, request });
|
|
64
|
+
});
|
|
65
|
+
await context.route(`${SITE}**`, async (route) => {
|
|
66
|
+
const url = new URL(route.request().url());
|
|
67
|
+
if (url.pathname === `/${TRANSPORT_PATH}`)
|
|
68
|
+
return route.fulfill({ status: 200, contentType: "text/html", body: "<!DOCTYPE html><title>transport</title>" });
|
|
69
|
+
const sesskey = state.sesskey ?? "s1";
|
|
70
|
+
if (url.pathname === "/lib/ajax/service.php") {
|
|
71
|
+
const json = (body) => route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(body) });
|
|
72
|
+
const [request] = JSON.parse(route.request().postData() ?? "[]");
|
|
73
|
+
if (!request)
|
|
74
|
+
return json([]);
|
|
75
|
+
state.serviceCalls?.push({ methodname: request.methodname, args: request.args });
|
|
76
|
+
const fail = (errorcode) => json([{ error: true, exception: { message: errorcode, errorcode } }]);
|
|
77
|
+
if (!state.user)
|
|
78
|
+
return fail("servicerequireslogin");
|
|
79
|
+
if (url.searchParams.get("sesskey") !== sesskey)
|
|
80
|
+
return fail("invalidsesskey");
|
|
81
|
+
const service = state.services?.[request.methodname];
|
|
82
|
+
if (!service)
|
|
83
|
+
return fail("invalidrecord");
|
|
84
|
+
try {
|
|
85
|
+
return json([{ error: false, data: service(request.args) }]);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error instanceof ServiceFailure)
|
|
89
|
+
return fail(error.errorcode);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
state.pagesServed?.push(url.pathname);
|
|
94
|
+
const html = (body) => route.fulfill({ status: 200, contentType: "text/html", body });
|
|
95
|
+
if (!state.user)
|
|
96
|
+
return html(moodlePage({ userId: 0, heading: "Log in", sesskey }));
|
|
97
|
+
const heading = url.pathname === "/user/profile.php" ? state.user.fullName : "Dashboard";
|
|
98
|
+
// Moodle names each page in the body id: /mod/forum/view.php is page-mod-forum-view.
|
|
99
|
+
const bodyId = `page${url.pathname.replace(/\.php$/, "").replaceAll("/", "-")}`;
|
|
100
|
+
return html(moodlePage({ userId: state.user.id, heading, sesskey, body: state.bodies?.[url.pathname], bodyId, bodyClass: state.bodyClasses?.[url.pathname] }));
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=fakeMoodle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fakeMoodle.js","sourceRoot":"","sources":["../../src/testing/fakeMoodle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A grader panel reduced to its submission status table, as Moodle 5.2 renders it: online text
|
|
3
|
+
* with a summary and a full block, a short online text with only a summary, files, and comments.
|
|
4
|
+
* Made up; no real submission.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PANEL = "<div class=\"submissionstatustable\"><h3>Submission</h3>\n<div class=\"assignsubmission assignsubmission_onlinetext\">\n <div class=\"box plugincontentsummary summary_assignsubmission_onlinetext_8\">\n <a class=\"expandsummaryicon expand_assignsubmission_onlinetext_8\" aria-label=\"View full\" href=\"\"><i class=\"icon\"></i></a>(40 words) First paragraph\u2026\n </div>\n <div class=\"box hidefull full_assignsubmission_onlinetext_8\">\n <a class=\"expandsummaryicon contract_assignsubmission_onlinetext_8\" aria-label=\"View summary\" href=\"\"><i class=\"icon\"></i></a>\n <div class=\"no-overflow\"><p>First paragraph, with <code>x = 1</code>.</p><p>Second<br>line & more.</p><ul><li>one</li><li>two</li></ul></div>\n </div>\n</div>\n<div class=\"box plugincontentsummary summary_assignsubmission_file_8\">\n <div class=\"fileuploadsubmission\"><a href=\"http://moodle.test/pluginfile.php/17/assignsubmission_file/submission_files/8/essay.pdf?forcedownload=1\">essay.pdf</a></div>\n</div>\n<div class=\"box plugincontentsummary summary_assignsubmission_onlinetext_9\"><div class=\"no-overflow\"><p>Short answer.</p></div></div>\n<div class=\"box plugincontentsummary summary_assignsubmission_comments_8\"><a href=\"#\">Comments (0)</a></div>\n</div>";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A grader panel reduced to its submission status table, as Moodle 5.2 renders it: online text
|
|
3
|
+
* with a summary and a full block, a short online text with only a summary, files, and comments.
|
|
4
|
+
* Made up; no real submission.
|
|
5
|
+
*/
|
|
6
|
+
export const PANEL = `<div class="submissionstatustable"><h3>Submission</h3>
|
|
7
|
+
<div class="assignsubmission assignsubmission_onlinetext">
|
|
8
|
+
<div class="box plugincontentsummary summary_assignsubmission_onlinetext_8">
|
|
9
|
+
<a class="expandsummaryicon expand_assignsubmission_onlinetext_8" aria-label="View full" href=""><i class="icon"></i></a>(40 words) First paragraph…
|
|
10
|
+
</div>
|
|
11
|
+
<div class="box hidefull full_assignsubmission_onlinetext_8">
|
|
12
|
+
<a class="expandsummaryicon contract_assignsubmission_onlinetext_8" aria-label="View summary" href=""><i class="icon"></i></a>
|
|
13
|
+
<div class="no-overflow"><p>First paragraph, with <code>x = 1</code>.</p><p>Second<br>line & more.</p><ul><li>one</li><li>two</li></ul></div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="box plugincontentsummary summary_assignsubmission_file_8">
|
|
17
|
+
<div class="fileuploadsubmission"><a href="http://moodle.test/pluginfile.php/17/assignsubmission_file/submission_files/8/essay.pdf?forcedownload=1">essay.pdf</a></div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="box plugincontentsummary summary_assignsubmission_onlinetext_9"><div class="no-overflow"><p>Short answer.</p></div></div>
|
|
20
|
+
<div class="box plugincontentsummary summary_assignsubmission_comments_8"><a href="#">Comments (0)</a></div>
|
|
21
|
+
</div>`;
|
|
22
|
+
//# sourceMappingURL=gradingPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gradingPanel.js","sourceRoot":"","sources":["../../src/testing/gradingPanel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;OAed,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BrowserManager } from "../browser/manager.js";
|
|
2
|
+
export { SITE, ServiceFailure, launchTestBrowser, moodlePage, serveFakeMoodle, type FakeMoodleState } from "./fakeMoodle.js";
|
|
3
|
+
export { PANEL } from "./gradingPanel.js";
|
|
4
|
+
/** A browser manager that never launches anything, with these methods instead. */
|
|
5
|
+
export declare function fakeBrowserManager(overrides?: Partial<BrowserManager>): BrowserManager;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { SITE, ServiceFailure, launchTestBrowser, moodlePage, serveFakeMoodle } from "./fakeMoodle.js";
|
|
2
|
+
export { PANEL } from "./gradingPanel.js";
|
|
3
|
+
/** A browser manager that never launches anything, with these methods instead. */
|
|
4
|
+
export function fakeBrowserManager(overrides = {}) {
|
|
5
|
+
return {
|
|
6
|
+
context: () => Promise.reject(new Error("this test opens no browser")),
|
|
7
|
+
openChannel: () => undefined,
|
|
8
|
+
chromiumDownload: () => undefined,
|
|
9
|
+
visible: () => false,
|
|
10
|
+
setVisible: async () => undefined,
|
|
11
|
+
show: async () => undefined,
|
|
12
|
+
tab: () => Promise.reject(new Error("this test opens no browser")),
|
|
13
|
+
saveSession: async () => undefined,
|
|
14
|
+
close: async () => undefined,
|
|
15
|
+
...overrides,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAwB,MAAM,iBAAiB,CAAC;AAC7H,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,kFAAkF;AAClF,MAAM,UAAU,kBAAkB,CAAC,YAAqC,EAAE;IACxE,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QACtE,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;QAC5B,gBAAgB,EAAE,GAAG,EAAE,CAAC,SAAS;QACjC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;QACpB,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;QACjC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;QAC3B,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAClE,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;QAClC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;QAC5B,GAAG,SAAS;KACb,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,79 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@falkenslab/moodle-driver",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Full control of Moodle as any user, from code or the command line, with their own login: no web services, no tokens, no admin.",
|
|
5
|
+
"author": "Falkenslab",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"moodle",
|
|
9
|
+
"lms",
|
|
10
|
+
"playwright",
|
|
11
|
+
"automation",
|
|
12
|
+
"browser"
|
|
13
|
+
],
|
|
14
|
+
"type": "module",
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=20"
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./internals": {
|
|
24
|
+
"types": "./dist/internals.d.ts",
|
|
25
|
+
"import": "./dist/internals.js"
|
|
26
|
+
},
|
|
27
|
+
"./testing": {
|
|
28
|
+
"types": "./dist/testing/index.d.ts",
|
|
29
|
+
"import": "./dist/testing/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"bin": {
|
|
33
|
+
"moodle": "dist/cli/main.js"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc -p tsconfig.build.json",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"lint": "eslint .",
|
|
42
|
+
"test": "tsx --test --test-concurrency=1 \"test/**/*.test.ts\"",
|
|
43
|
+
"test:docker": "node scripts/in-docker.mjs npm test",
|
|
44
|
+
"prepare": "npm run build",
|
|
45
|
+
"docs:install": "npm --prefix docs ci",
|
|
46
|
+
"docs:start": "npm --prefix docs start",
|
|
47
|
+
"docs:build": "npm --prefix docs run build",
|
|
48
|
+
"docs:check": "node scripts/check-doc-examples.mjs",
|
|
49
|
+
"cli:generate": "node scripts/generate-cli-commands.mjs",
|
|
50
|
+
"prebuild": "node scripts/generate-cli-commands.mjs --check"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"playwright-core": "^1.64.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@eslint/js": "^10.0.1",
|
|
57
|
+
"@types/node": "^20.19.0",
|
|
58
|
+
"eslint": "^10.12.0",
|
|
59
|
+
"globals": "^17.13.0",
|
|
60
|
+
"playwright-core": "^1.64.0",
|
|
61
|
+
"tsx": "^4.23.15",
|
|
62
|
+
"typescript": "~6.0.3",
|
|
63
|
+
"typescript-eslint": "^8.71.1"
|
|
64
|
+
},
|
|
65
|
+
"allowScripts": {
|
|
66
|
+
"esbuild@0.28.2": true
|
|
67
|
+
},
|
|
68
|
+
"homepage": "https://falkenslab.github.io/moodle-driver/",
|
|
69
|
+
"repository": {
|
|
70
|
+
"type": "git",
|
|
71
|
+
"url": "git+https://github.com/falkenslab/moodle-driver.git"
|
|
72
|
+
},
|
|
73
|
+
"bugs": {
|
|
74
|
+
"url": "https://github.com/falkenslab/moodle-driver/issues"
|
|
75
|
+
},
|
|
76
|
+
"publishConfig": {
|
|
77
|
+
"access": "public"
|
|
78
|
+
}
|
|
79
|
+
}
|