@falkenslab/moodle-driver 0.4.1 → 0.5.0
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/README.md +3 -2
- package/dist/areas/activities/build.d.ts +47 -10
- package/dist/areas/activities/build.js +157 -24
- package/dist/areas/activities/build.js.map +1 -1
- package/dist/areas/activities/conditions.d.ts +77 -0
- package/dist/areas/activities/conditions.js +216 -0
- package/dist/areas/activities/conditions.js.map +1 -0
- package/dist/areas/activities/content.d.ts +3 -0
- package/dist/areas/activities/content.js +1 -0
- package/dist/areas/activities/content.js.map +1 -1
- package/dist/areas/assignments/grader.d.ts +32 -0
- package/dist/areas/assignments/grader.js +66 -2
- package/dist/areas/assignments/grader.js.map +1 -1
- package/dist/areas/assignments/grading.d.ts +69 -6
- package/dist/areas/assignments/grading.js +173 -13
- package/dist/areas/assignments/grading.js.map +1 -1
- package/dist/areas/assignments/student.d.ts +14 -0
- package/dist/areas/assignments/student.js +43 -2
- package/dist/areas/assignments/student.js.map +1 -1
- package/dist/areas/backup/backup.d.ts +86 -0
- package/dist/areas/backup/backup.js +368 -0
- package/dist/areas/backup/backup.js.map +1 -0
- package/dist/areas/calendar/calendar.d.ts +27 -0
- package/dist/areas/calendar/calendar.js +115 -9
- package/dist/areas/calendar/calendar.js.map +1 -1
- package/dist/areas/completion/completion.d.ts +3 -0
- package/dist/areas/completion/completion.js.map +1 -1
- package/dist/areas/courses/list.d.ts +2 -0
- package/dist/areas/courses/list.js.map +1 -1
- package/dist/areas/courses/reset.d.ts +51 -0
- package/dist/areas/courses/reset.js +123 -0
- package/dist/areas/courses/reset.js.map +1 -0
- package/dist/areas/courses/state.d.ts +17 -0
- package/dist/areas/courses/state.js +37 -6
- package/dist/areas/courses/state.js.map +1 -1
- package/dist/areas/courses/structure.d.ts +14 -2
- package/dist/areas/courses/structure.js +11 -5
- package/dist/areas/courses/structure.js.map +1 -1
- package/dist/areas/forums/discussions.d.ts +8 -0
- package/dist/areas/forums/discussions.js +10 -0
- package/dist/areas/forums/discussions.js.map +1 -1
- package/dist/areas/forums/grading.d.ts +49 -0
- package/dist/areas/forums/grading.js +125 -0
- package/dist/areas/forums/grading.js.map +1 -0
- package/dist/areas/forums/posts.d.ts +37 -0
- package/dist/areas/forums/posts.js +141 -6
- package/dist/areas/forums/posts.js.map +1 -1
- package/dist/areas/grades/export.d.ts +38 -0
- package/dist/areas/grades/export.js +88 -0
- package/dist/areas/grades/export.js.map +1 -0
- package/dist/areas/grades/gradebook.d.ts +50 -0
- package/dist/areas/grades/gradebook.js +120 -0
- package/dist/areas/grades/gradebook.js.map +1 -1
- package/dist/areas/grades/singleview.d.ts +39 -0
- package/dist/areas/grades/singleview.js +186 -0
- package/dist/areas/grades/singleview.js.map +1 -0
- package/dist/areas/h5p/h5p.d.ts +2 -0
- package/dist/areas/h5p/h5p.js +12 -7
- package/dist/areas/h5p/h5p.js.map +1 -1
- package/dist/areas/lessons/lessons.d.ts +1 -0
- package/dist/areas/lessons/lessons.js.map +1 -1
- package/dist/areas/messages/messages.d.ts +32 -0
- package/dist/areas/messages/messages.js +44 -2
- package/dist/areas/messages/messages.js.map +1 -1
- package/dist/areas/participants/enrolments.d.ts +60 -0
- package/dist/areas/participants/enrolments.js +218 -0
- package/dist/areas/participants/enrolments.js.map +1 -0
- package/dist/areas/participants/groups.d.ts +75 -0
- package/dist/areas/participants/groups.js +201 -0
- package/dist/areas/participants/groups.js.map +1 -0
- package/dist/areas/participants/methods.d.ts +56 -0
- package/dist/areas/participants/methods.js +154 -0
- package/dist/areas/participants/methods.js.map +1 -0
- package/dist/areas/participants/participants.d.ts +11 -0
- package/dist/areas/participants/participants.js +24 -19
- package/dist/areas/participants/participants.js.map +1 -1
- package/dist/areas/questions/banks.d.ts +36 -1
- package/dist/areas/questions/banks.js +140 -17
- package/dist/areas/questions/banks.js.map +1 -1
- package/dist/areas/quizzes/attempts.d.ts +2 -0
- package/dist/areas/quizzes/attempts.js +9 -0
- package/dist/areas/quizzes/attempts.js.map +1 -1
- package/dist/areas/quizzes/grading.d.ts +50 -0
- package/dist/areas/quizzes/grading.js +131 -0
- package/dist/areas/quizzes/grading.js.map +1 -0
- package/dist/areas/quizzes/results.d.ts +3 -0
- package/dist/areas/quizzes/results.js +2 -1
- package/dist/areas/quizzes/results.js.map +1 -1
- package/dist/areas/quizzes/structure.d.ts +65 -9
- package/dist/areas/quizzes/structure.js +222 -23
- package/dist/areas/quizzes/structure.js.map +1 -1
- package/dist/areas/ratings/ratings.d.ts +26 -0
- package/dist/areas/ratings/ratings.js +108 -0
- package/dist/areas/ratings/ratings.js.map +1 -0
- package/dist/areas/reports/dates.d.ts +18 -0
- package/dist/areas/reports/dates.js +134 -0
- package/dist/areas/reports/dates.js.map +1 -0
- package/dist/areas/reports/reports.d.ts +143 -0
- package/dist/areas/reports/reports.js +267 -0
- package/dist/areas/reports/reports.js.map +1 -0
- package/dist/areas/scorm/scorm.d.ts +1 -0
- package/dist/areas/scorm/scorm.js.map +1 -1
- package/dist/areas/site/users.d.ts +7 -1
- package/dist/areas/site/users.js +9 -2
- package/dist/areas/site/users.js.map +1 -1
- package/dist/areas/surveys/choice.d.ts +2 -0
- package/dist/areas/surveys/choice.js +6 -3
- package/dist/areas/surveys/choice.js.map +1 -1
- package/dist/areas/surveys/surveys.d.ts +3 -0
- package/dist/areas/surveys/surveys.js +1 -0
- package/dist/areas/surveys/surveys.js.map +1 -1
- package/dist/areas/workshops/workshops.d.ts +133 -0
- package/dist/areas/workshops/workshops.js +335 -0
- package/dist/areas/workshops/workshops.js.map +1 -0
- package/dist/browser/background.d.ts +43 -0
- package/dist/browser/background.js +164 -0
- package/dist/browser/background.js.map +1 -0
- package/dist/browser/host.d.ts +30 -0
- package/dist/browser/host.js +373 -0
- package/dist/browser/host.js.map +1 -0
- package/dist/browser/manager.d.ts +9 -0
- package/dist/browser/manager.js +8 -0
- package/dist/browser/manager.js.map +1 -1
- package/dist/categories.d.ts +1 -0
- package/dist/categories.js +67 -0
- package/dist/categories.js.map +1 -1
- package/dist/cli/args.d.ts +8 -0
- package/dist/cli/args.js +49 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/background.d.ts +23 -0
- package/dist/cli/background.js +128 -0
- package/dist/cli/background.js.map +1 -0
- package/dist/cli/command.d.ts +66 -0
- package/dist/cli/command.js +328 -0
- package/dist/cli/command.js.map +1 -0
- package/dist/cli/commands.generated.js +2635 -577
- package/dist/cli/commands.generated.js.map +1 -1
- package/dist/cli/config.d.ts +2 -0
- package/dist/cli/config.js +2 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/main.js +30 -10
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/run.d.ts +3 -14
- package/dist/cli/run.js +9 -185
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/shell.d.ts +9 -0
- package/dist/cli/shell.js +233 -0
- package/dist/cli/shell.js.map +1 -0
- package/dist/client.d.ts +71 -8
- package/dist/client.js +75 -8
- package/dist/client.js.map +1 -1
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/files.d.ts +5 -0
- package/dist/core/files.js +7 -3
- package/dist/core/files.js.map +1 -1
- package/dist/core/forms.d.ts +33 -3
- package/dist/core/forms.js +105 -8
- package/dist/core/forms.js.map +1 -1
- package/dist/core/http.d.ts +7 -0
- package/dist/core/http.js +28 -7
- package/dist/core/http.js.map +1 -1
- package/dist/core/login.d.ts +3 -0
- package/dist/core/login.js +2 -0
- package/dist/core/login.js.map +1 -1
- package/dist/core/session.d.ts +12 -1
- package/dist/core/session.js +12 -1
- package/dist/core/session.js.map +1 -1
- package/dist/index.d.ts +35 -11
- package/dist/index.js +32 -12
- package/dist/index.js.map +1 -1
- package/dist/internals.d.ts +9 -1
- package/dist/internals.js +9 -4
- package/dist/internals.js.map +1 -1
- package/dist/options.d.ts +2 -0
- package/dist/options.js.map +1 -1
- package/dist/testing/fakeMoodle.d.ts +9 -2
- package/dist/testing/fakeMoodle.js +5 -3
- package/dist/testing/fakeMoodle.js.map +1 -1
- package/dist/testing/index.d.ts +7 -0
- package/dist/testing/index.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { NotLoggedInError, htmlSessionFacts, isLoggedIn, moodleErrorMessage, openSitePage } from "../../core/session.js";
|
|
2
|
+
import { siteFetch } from "../../core/http.js";
|
|
3
|
+
import { inPage } from "../../core/inPage.js";
|
|
4
|
+
import { openForm, setFields, submitForm } from "../../core/forms.js";
|
|
5
|
+
import { MoodleError } from "../../core/errors.js";
|
|
6
|
+
/** Reads a members or grouping page: the current and potential lists by option value, the course and the sesskey. */
|
|
7
|
+
async function readAssignPage(context, siteUrl, path, what) {
|
|
8
|
+
const page = await openSitePage(context, siteUrl, path);
|
|
9
|
+
try {
|
|
10
|
+
// A helper inside: through inPage (see the conventions on page.evaluate).
|
|
11
|
+
const read = await inPage(page, () => {
|
|
12
|
+
const g = globalThis;
|
|
13
|
+
// Options' values are ids (a grouping page writes them "5."); its empty lists hold a blank option.
|
|
14
|
+
const ids = (select) => Array.from(g.document.querySelectorAll(`#assignform select#${select} option`)).map((o) => Number.parseInt(o.value, 10)).filter((id) => id > 0);
|
|
15
|
+
return {
|
|
16
|
+
found: g.document.querySelector("#assignform") !== null,
|
|
17
|
+
courseId: g.M?.cfg?.courseId ?? 0,
|
|
18
|
+
sesskey: g.M?.cfg?.sesskey ?? "",
|
|
19
|
+
current: ids("removeselect"),
|
|
20
|
+
potential: ids("addselect"),
|
|
21
|
+
};
|
|
22
|
+
}, null);
|
|
23
|
+
if (!read.found)
|
|
24
|
+
throw new MoodleError(`You can't manage ${what}: ${(await moodleErrorMessage(page)) ?? "it doesn't exist, or you aren't allowed."}`, "not-found");
|
|
25
|
+
return read;
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
await page.close().catch(() => undefined);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Posts a form of the site's group pages, as its buttons do; throws when the session is gone. */
|
|
32
|
+
async function post(context, siteUrl, path, fields) {
|
|
33
|
+
const { url, body } = await siteFetch(context, new URL(path, siteUrl).href, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
36
|
+
body: new URLSearchParams(fields).toString(),
|
|
37
|
+
});
|
|
38
|
+
if (!isLoggedIn(url, siteUrl, htmlSessionFacts(body)))
|
|
39
|
+
throw new NotLoggedInError();
|
|
40
|
+
return body;
|
|
41
|
+
}
|
|
42
|
+
function groupFields(settings) {
|
|
43
|
+
return {
|
|
44
|
+
...(settings.name !== undefined ? { name: settings.name } : {}),
|
|
45
|
+
...(settings.idNumber !== undefined ? { idnumber: settings.idNumber } : {}),
|
|
46
|
+
...(settings.description !== undefined ? { "description_editor[text]": settings.description } : {}),
|
|
47
|
+
...("enrolmentKey" in settings && settings.enrolmentKey !== undefined ? { enrolmentkey: settings.enrolmentKey } : {}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates a group in a course with its group form (`group/group.php`). Throws `FormError` with
|
|
52
|
+
* Moodle's reason when it refuses (a name already used, an enrolment key another group has).
|
|
53
|
+
*/
|
|
54
|
+
export async function createGroup(context, siteUrl, courseId, settings) {
|
|
55
|
+
const page = await openForm(context, siteUrl, `group/group.php?courseid=${courseId}`);
|
|
56
|
+
try {
|
|
57
|
+
await setFields(page, groupFields(settings));
|
|
58
|
+
await submitForm(page, "submitbutton");
|
|
59
|
+
// Moodle goes to the groups page with the new group selected.
|
|
60
|
+
const groupId = Number(new URL(page.url()).searchParams.get("group"));
|
|
61
|
+
if (!groupId)
|
|
62
|
+
throw new MoodleError(`Moodle didn't say which group it created in course ${courseId}.`, "unexpected-page");
|
|
63
|
+
return { changed: `Group ${groupId} "${settings.name}" created in course ${courseId}.`, groupId };
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
await page.close().catch(() => undefined);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Changes a group's name, description, ID number or enrolment key with its form; what isn't given stays. */
|
|
70
|
+
export async function updateGroup(context, siteUrl, groupId, settings) {
|
|
71
|
+
const fields = groupFields(settings);
|
|
72
|
+
if (Object.keys(fields).length === 0)
|
|
73
|
+
throw new MoodleError("Nothing to change: give a name, description, ID number or enrolment key.", "invalid-input");
|
|
74
|
+
const page = await openForm(context, siteUrl, `group/group.php?id=${groupId}`);
|
|
75
|
+
try {
|
|
76
|
+
await setFields(page, fields);
|
|
77
|
+
await submitForm(page, "submitbutton");
|
|
78
|
+
return { changed: `Group ${groupId} updated: ${Object.keys(settings).join(", ")}.` };
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
await page.close().catch(() => undefined);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Deletes a group, as the groups page's "Delete selected group" does once confirmed; its members stay in the course. */
|
|
85
|
+
export async function deleteGroup(context, siteUrl, groupId) {
|
|
86
|
+
const { courseId, sesskey } = await readAssignPage(context, siteUrl, `group/members.php?group=${groupId}`, `group ${groupId}`);
|
|
87
|
+
await post(context, siteUrl, "group/delete.php", [
|
|
88
|
+
["courseid", String(courseId)],
|
|
89
|
+
["groups", String(groupId)],
|
|
90
|
+
["confirm", "1"],
|
|
91
|
+
["sesskey", sesskey],
|
|
92
|
+
]);
|
|
93
|
+
return { changed: `Group ${groupId} deleted from course ${courseId}.` };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Adds and removes a group's members (user ids), as its members page does. Only the course's
|
|
97
|
+
* participants can be added: ids the page doesn't offer (not enrolled, or already members) and
|
|
98
|
+
* members not in it are left as they were and named in `changed`. Returns the members afterwards.
|
|
99
|
+
*/
|
|
100
|
+
export async function setGroupMembers(context, siteUrl, groupId, { add = [], remove = [] }) {
|
|
101
|
+
const path = `group/members.php?group=${groupId}`;
|
|
102
|
+
const before = await readAssignPage(context, siteUrl, path, `the members of group ${groupId}`);
|
|
103
|
+
const toAdd = add.filter((id) => before.potential.includes(id));
|
|
104
|
+
const toRemove = remove.filter((id) => before.current.includes(id));
|
|
105
|
+
if (toAdd.length > 0)
|
|
106
|
+
await post(context, siteUrl, path, [["sesskey", before.sesskey], ["add", "1"], ...toAdd.map((id) => ["addselect[]", String(id)])]);
|
|
107
|
+
if (toRemove.length > 0)
|
|
108
|
+
await post(context, siteUrl, path, [["sesskey", before.sesskey], ["remove", "1"], ...toRemove.map((id) => ["removeselect[]", String(id)])]);
|
|
109
|
+
const { current } = await readAssignPage(context, siteUrl, path, `the members of group ${groupId}`);
|
|
110
|
+
const added = toAdd.filter((id) => current.includes(id));
|
|
111
|
+
const removed = toRemove.filter((id) => !current.includes(id));
|
|
112
|
+
const skipped = [...add.filter((id) => !toAdd.includes(id) && !before.current.includes(id)), ...remove.filter((id) => !toRemove.includes(id) && before.current.includes(id))];
|
|
113
|
+
const parts = [
|
|
114
|
+
added.length > 0 ? `added ${added.join(", ")}` : "",
|
|
115
|
+
removed.length > 0 ? `removed ${removed.join(", ")}` : "",
|
|
116
|
+
skipped.length > 0 ? `couldn't change ${skipped.join(", ")} (not participants the page offers)` : "",
|
|
117
|
+
].filter(Boolean);
|
|
118
|
+
return { changed: `Group ${groupId}: ${parts.join("; ") || "nothing changed"}.`, members: current };
|
|
119
|
+
}
|
|
120
|
+
/** A course's groupings with their groups' ids, from its groupings page and each grouping's groups page. Throws `MoodleError` with Moodle's refusal for a person who can't manage groups. */
|
|
121
|
+
export async function groupings(context, siteUrl, courseId) {
|
|
122
|
+
const page = await openSitePage(context, siteUrl, `group/groupings.php?id=${courseId}`);
|
|
123
|
+
let found;
|
|
124
|
+
try {
|
|
125
|
+
// Moodle's refusal (no moodle/course:managegroups) keeps the page's body id: its error box tells.
|
|
126
|
+
const refusal = await moodleErrorMessage(page);
|
|
127
|
+
if (refusal || (await page.locator("body#page-group-groupings").count()) === 0) {
|
|
128
|
+
throw new MoodleError(`You can't see the groupings of course ${courseId}: ${refusal ?? "it doesn't exist, or you aren't allowed."}`, "not-found");
|
|
129
|
+
}
|
|
130
|
+
found = await page.evaluate(() => {
|
|
131
|
+
const doc = globalThis.document;
|
|
132
|
+
// One row per grouping, its id in the link to its groups page (assign.php?id=), its name in the first cell.
|
|
133
|
+
return Array.from(doc.querySelectorAll("table tbody tr")).flatMap((row) => {
|
|
134
|
+
const href = row.querySelector('a[href*="/group/assign.php?id="]')?.getAttribute("href");
|
|
135
|
+
const id = href ? Number(new URL(href, "http://x/").searchParams.get("id")) : 0;
|
|
136
|
+
return id ? [{ id, name: (row.querySelector("td")?.textContent ?? "").replace(/\s+/g, " ").trim() }] : [];
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
await page.close().catch(() => undefined);
|
|
142
|
+
}
|
|
143
|
+
const result = [];
|
|
144
|
+
for (const grouping of found) {
|
|
145
|
+
const { current } = await readAssignPage(context, siteUrl, `group/assign.php?id=${grouping.id}`, `grouping ${grouping.id}`);
|
|
146
|
+
result.push({ ...grouping, groupIds: current });
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
/** Creates a grouping in a course with its form (`group/grouping.php`); add its groups with `setGroupingGroups`. */
|
|
151
|
+
export async function createGrouping(context, siteUrl, courseId, settings) {
|
|
152
|
+
const before = new Set((await groupings(context, siteUrl, courseId)).map((g) => g.id));
|
|
153
|
+
const page = await openForm(context, siteUrl, `group/grouping.php?courseid=${courseId}`);
|
|
154
|
+
try {
|
|
155
|
+
await setFields(page, groupFields(settings));
|
|
156
|
+
await submitForm(page, "submitbutton");
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
await page.close().catch(() => undefined);
|
|
160
|
+
}
|
|
161
|
+
// Moodle goes back to the groupings page without naming the new one: it's the one that wasn't there.
|
|
162
|
+
const created = (await groupings(context, siteUrl, courseId)).find((g) => !before.has(g.id));
|
|
163
|
+
if (!created)
|
|
164
|
+
throw new MoodleError(`Moodle didn't show the new grouping in course ${courseId}.`, "unexpected-page");
|
|
165
|
+
return { changed: `Grouping ${created.id} "${settings.name}" created in course ${courseId}.`, groupingId: created.id };
|
|
166
|
+
}
|
|
167
|
+
/** Deletes a grouping, as its delete icon does once confirmed; its groups stay. */
|
|
168
|
+
export async function deleteGrouping(context, siteUrl, groupingId) {
|
|
169
|
+
const { courseId, sesskey } = await readAssignPage(context, siteUrl, `group/assign.php?id=${groupingId}`, `grouping ${groupingId}`);
|
|
170
|
+
await post(context, siteUrl, "group/grouping.php", [
|
|
171
|
+
["id", String(groupingId)],
|
|
172
|
+
["delete", "1"],
|
|
173
|
+
["courseid", String(courseId)],
|
|
174
|
+
["confirm", "1"],
|
|
175
|
+
["sesskey", sesskey],
|
|
176
|
+
]);
|
|
177
|
+
return { changed: `Grouping ${groupingId} deleted from course ${courseId}.` };
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Makes a grouping's groups exactly `groupIds`, as its groups page adds and removes them. Groups of
|
|
181
|
+
* other courses aren't offered there and are left out, named in `changed`. Returns the groups afterwards.
|
|
182
|
+
*/
|
|
183
|
+
export async function setGroupingGroups(context, siteUrl, groupingId, groupIds) {
|
|
184
|
+
const path = `group/assign.php?id=${groupingId}`;
|
|
185
|
+
const before = await readAssignPage(context, siteUrl, path, `grouping ${groupingId}`);
|
|
186
|
+
const toAdd = groupIds.filter((id) => before.potential.includes(id));
|
|
187
|
+
const toRemove = before.current.filter((id) => !groupIds.includes(id));
|
|
188
|
+
if (toAdd.length > 0)
|
|
189
|
+
await post(context, siteUrl, path, [["sesskey", before.sesskey], ["add", "1"], ...toAdd.map((id) => ["addselect[]", String(id)])]);
|
|
190
|
+
if (toRemove.length > 0)
|
|
191
|
+
await post(context, siteUrl, path, [["sesskey", before.sesskey], ["remove", "1"], ...toRemove.map((id) => ["removeselect[]", String(id)])]);
|
|
192
|
+
const { current } = await readAssignPage(context, siteUrl, path, `grouping ${groupingId}`);
|
|
193
|
+
const unknown = groupIds.filter((id) => !before.potential.includes(id) && !before.current.includes(id));
|
|
194
|
+
const parts = [
|
|
195
|
+
toAdd.length > 0 ? `added groups ${toAdd.join(", ")}` : "",
|
|
196
|
+
toRemove.length > 0 ? `removed groups ${toRemove.join(", ")}` : "",
|
|
197
|
+
unknown.length > 0 ? `left out ${unknown.join(", ")} (not groups of its course)` : "",
|
|
198
|
+
].filter(Boolean);
|
|
199
|
+
return { changed: `Grouping ${groupingId}: ${parts.join("; ") || "nothing changed"}.`, groupIds: current };
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.js","sourceRoot":"","sources":["../../../src/areas/participants/groups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { BrowserContext } from "playwright-core";
|
|
2
|
+
/** One of a course's enrolment methods, as its methods page and its form show it. */
|
|
3
|
+
export interface EnrolmentMethod {
|
|
4
|
+
id: number;
|
|
5
|
+
/** The enrolment plugin: "manual", "self", "guest", "cohort"… */
|
|
6
|
+
type: string;
|
|
7
|
+
/** Its name on the methods page, in the site's language ("Self enrolment (Student)"). */
|
|
8
|
+
name: string;
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
/** Users enrolled by it. */
|
|
11
|
+
users: number;
|
|
12
|
+
/** The role it gives (manual: the default role; self: the role students get). */
|
|
13
|
+
roleId?: number;
|
|
14
|
+
/** Self enrolment and guest access: whether it asks for a key (the key itself isn't returned). */
|
|
15
|
+
hasKey?: boolean;
|
|
16
|
+
/** Self enrolment: when students may enrol from and until (ISO dates). */
|
|
17
|
+
start?: string;
|
|
18
|
+
end?: string;
|
|
19
|
+
/** Self enrolment: the most users it enrols. */
|
|
20
|
+
maxUsers?: number;
|
|
21
|
+
}
|
|
22
|
+
/** What `setEnrolmentMethod` may change; what isn't given stays. */
|
|
23
|
+
export interface EnrolmentMethodSettings {
|
|
24
|
+
enabled?: boolean;
|
|
25
|
+
/** Self enrolment and guest access: the key to ask for; "" removes it. */
|
|
26
|
+
key?: string;
|
|
27
|
+
/** Self enrolment: from when and until when students may enrol; `null` removes the limit. */
|
|
28
|
+
start?: Date | null;
|
|
29
|
+
end?: Date | null;
|
|
30
|
+
/** The role it gives (manual and self enrolment). */
|
|
31
|
+
roleId?: number;
|
|
32
|
+
/** Self enrolment: the most users it enrols; 0 for no limit. */
|
|
33
|
+
maxUsers?: number;
|
|
34
|
+
/** Self enrolment: the welcome message to send (from the course contact unless another sender is set); `false` sends none. */
|
|
35
|
+
welcome?: string | false;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A course's enrolment methods, in the order Moodle tries them: each one's type, name, whether it's
|
|
39
|
+
* enabled and how many users it enrolled, and from its form the role it gives and, for self enrolment
|
|
40
|
+
* and guest access, whether it asks for a key (never the key), self enrolment's dates and limit.
|
|
41
|
+
* Throws `EnrolmentError` when the person can't manage the course's enrolment methods.
|
|
42
|
+
*/
|
|
43
|
+
export declare function enrolmentMethods(context: BrowserContext, siteUrl: string, courseId: number): Promise<EnrolmentMethod[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Sets an enrolment method with its form: by id, or the course's first method of a type
|
|
46
|
+
* (`{ type: "self" }`), added when the course has none and the "Add method" menu offers it. Only
|
|
47
|
+
* what's given changes. Returns the method afterwards. Throws `EnrolmentError` for a method the
|
|
48
|
+
* course doesn't have or can't add, `FormError` with Moodle's reason when it refuses the form (a key
|
|
49
|
+
* required by the site, an end before the start).
|
|
50
|
+
*/
|
|
51
|
+
export declare function setEnrolmentMethod(context: BrowserContext, siteUrl: string, courseId: number, method: number | {
|
|
52
|
+
type: string;
|
|
53
|
+
}, settings: EnrolmentMethodSettings): Promise<{
|
|
54
|
+
changed: string;
|
|
55
|
+
method: EnrolmentMethod;
|
|
56
|
+
}>;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { moodleErrorMessage, openSitePage } from "../../core/session.js";
|
|
2
|
+
import { inPage } from "../../core/inPage.js";
|
|
3
|
+
import { dateSelectorDate, dateSelectorValues, openForm, setFields, submitForm } from "../../core/forms.js";
|
|
4
|
+
import { EnrolmentError } from "./enrolments.js";
|
|
5
|
+
/** The methods page: each method's row, and the types the "Add method" menu offers. */
|
|
6
|
+
async function readMethodsPage(context, siteUrl, courseId) {
|
|
7
|
+
const page = await openSitePage(context, siteUrl, `enrol/instances.php?id=${courseId}`);
|
|
8
|
+
try {
|
|
9
|
+
if ((await page.locator("body#page-enrol-instances").count()) === 0) {
|
|
10
|
+
throw new EnrolmentError(`You can't manage the enrolment methods of course ${courseId}: ${(await moodleErrorMessage(page)) ?? "it doesn't exist, or you aren't allowed."}`);
|
|
11
|
+
}
|
|
12
|
+
// Helpers inside: through inPage (see the conventions on page.evaluate).
|
|
13
|
+
return await inPage(page, () => {
|
|
14
|
+
const doc = globalThis.document;
|
|
15
|
+
const methods = Array.from(doc.querySelectorAll("table.generaltable tbody tr")).flatMap((row) => {
|
|
16
|
+
const links = Array.from(row.querySelectorAll("a[href]")).map((a) => new URL(a.getAttribute("href") ?? "", "http://x/"));
|
|
17
|
+
const edit = links.find((url) => url.pathname.endsWith("/enrol/editinstance.php"));
|
|
18
|
+
const action = (name) => links.find((url) => url.searchParams.get("action") === name);
|
|
19
|
+
const id = Number(edit?.searchParams.get("id") ?? links.find((url) => url.searchParams.get("instance"))?.searchParams.get("instance"));
|
|
20
|
+
if (!id)
|
|
21
|
+
return [];
|
|
22
|
+
const cells = Array.from(row.querySelectorAll("td"));
|
|
23
|
+
// The enable and disable icons say its state; without them (a plugin off on the site), its name is dimmed when off.
|
|
24
|
+
const enabled = action("disable") ? true : action("enable") ? false : cells[0]?.querySelector(".dimmed_text") === null;
|
|
25
|
+
return [{ id, type: edit?.searchParams.get("type") ?? "", name: (cells[0]?.textContent ?? "").replace(/\s+/g, " ").trim(), enabled, users: Number((cells[1]?.textContent ?? "").trim()) || 0 }];
|
|
26
|
+
});
|
|
27
|
+
// "Add method": options lead to editinstance.php?type=…&courseid=….
|
|
28
|
+
const addable = Array.from(doc.querySelectorAll("select.urlselect option"))
|
|
29
|
+
.map((option) => new URL(option.value || "/", "http://x/"))
|
|
30
|
+
.filter((url) => url.pathname.endsWith("/enrol/editinstance.php"))
|
|
31
|
+
.map((url) => url.searchParams.get("type") ?? "");
|
|
32
|
+
return { methods, addable };
|
|
33
|
+
}, null);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
await page.close().catch(() => undefined);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** A method's settings from its open form: the role, the key, self enrolment's dates and limit. */
|
|
40
|
+
async function readMethodForm(page) {
|
|
41
|
+
const fields = await page.evaluate(() => {
|
|
42
|
+
const doc = globalThis.document;
|
|
43
|
+
return {
|
|
44
|
+
roleId: doc.querySelector('form.mform select[name="roleid"]')?.value,
|
|
45
|
+
key: doc.querySelector('form.mform [name="password"]')?.value,
|
|
46
|
+
maxUsers: doc.querySelector('form.mform [name="customint3"]')?.value,
|
|
47
|
+
hasDates: doc.querySelector('form.mform [name="enrolstartdate[day]"]') !== null,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
const [start, end] = fields.hasDates ? await Promise.all([dateSelectorDate(page, "enrolstartdate"), dateSelectorDate(page, "enrolenddate")]) : [undefined, undefined];
|
|
51
|
+
return {
|
|
52
|
+
...(fields.roleId ? { roleId: Number(fields.roleId) } : {}),
|
|
53
|
+
...(fields.key !== undefined ? { hasKey: fields.key !== "" } : {}),
|
|
54
|
+
...(start ? { start: start.toISOString() } : {}),
|
|
55
|
+
...(end ? { end: end.toISOString() } : {}),
|
|
56
|
+
...(Number(fields.maxUsers) > 0 ? { maxUsers: Number(fields.maxUsers) } : {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** A listed method with what its form adds, when the person may open it. */
|
|
60
|
+
async function withSettings(context, siteUrl, courseId, method) {
|
|
61
|
+
if (!method.type)
|
|
62
|
+
return method;
|
|
63
|
+
let page;
|
|
64
|
+
try {
|
|
65
|
+
page = await openForm(context, siteUrl, `enrol/editinstance.php?courseid=${courseId}&id=${method.id}&type=${method.type}`);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// A method without a form of its own, or one the person can't edit: what the list says.
|
|
69
|
+
return method;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
return { ...method, ...(await readMethodForm(page)) };
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await page.close().catch(() => undefined);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A course's enrolment methods, in the order Moodle tries them: each one's type, name, whether it's
|
|
80
|
+
* enabled and how many users it enrolled, and from its form the role it gives and, for self enrolment
|
|
81
|
+
* and guest access, whether it asks for a key (never the key), self enrolment's dates and limit.
|
|
82
|
+
* Throws `EnrolmentError` when the person can't manage the course's enrolment methods.
|
|
83
|
+
*/
|
|
84
|
+
export async function enrolmentMethods(context, siteUrl, courseId) {
|
|
85
|
+
const { methods } = await readMethodsPage(context, siteUrl, courseId);
|
|
86
|
+
const result = [];
|
|
87
|
+
for (const method of methods)
|
|
88
|
+
result.push(await withSettings(context, siteUrl, courseId, method));
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Sets an enrolment method with its form: by id, or the course's first method of a type
|
|
93
|
+
* (`{ type: "self" }`), added when the course has none and the "Add method" menu offers it. Only
|
|
94
|
+
* what's given changes. Returns the method afterwards. Throws `EnrolmentError` for a method the
|
|
95
|
+
* course doesn't have or can't add, `FormError` with Moodle's reason when it refuses the form (a key
|
|
96
|
+
* required by the site, an end before the start).
|
|
97
|
+
*/
|
|
98
|
+
export async function setEnrolmentMethod(context, siteUrl, courseId, method, settings) {
|
|
99
|
+
const before = await readMethodsPage(context, siteUrl, courseId);
|
|
100
|
+
const existing = typeof method === "number" ? before.methods.find((m) => m.id === method) : before.methods.find((m) => m.type === method.type);
|
|
101
|
+
if (typeof method === "number" && !existing)
|
|
102
|
+
throw new EnrolmentError(`Course ${courseId} has no enrolment method ${method}.`);
|
|
103
|
+
const type = existing?.type ?? method.type;
|
|
104
|
+
if (!existing && !before.addable.includes(type)) {
|
|
105
|
+
throw new EnrolmentError(`Course ${courseId} has no "${type}" enrolment method and you can't add one: the site doesn't enable it, the course may have only one, or you aren't allowed.`);
|
|
106
|
+
}
|
|
107
|
+
if (existing && !existing.type)
|
|
108
|
+
throw new EnrolmentError(`Enrolment method ${existing.id} of course ${courseId} has no settings you can change.`);
|
|
109
|
+
const page = await openForm(context, siteUrl, `enrol/editinstance.php?courseid=${courseId}&type=${type}${existing ? `&id=${existing.id}` : ""}`);
|
|
110
|
+
try {
|
|
111
|
+
const values = {};
|
|
112
|
+
if (settings.enabled !== undefined)
|
|
113
|
+
values.status = settings.enabled ? "0" : "1"; // ENROL_INSTANCE_ENABLED, _DISABLED
|
|
114
|
+
if (settings.key !== undefined)
|
|
115
|
+
values.password = settings.key;
|
|
116
|
+
if (settings.roleId !== undefined)
|
|
117
|
+
values.roleid = String(settings.roleId);
|
|
118
|
+
for (const [name, date] of [["enrolstartdate", settings.start], ["enrolenddate", settings.end]]) {
|
|
119
|
+
if (date === undefined)
|
|
120
|
+
continue;
|
|
121
|
+
values[`${name}[enabled]`] = date !== null;
|
|
122
|
+
if (date)
|
|
123
|
+
Object.assign(values, await dateSelectorValues(page, name, date));
|
|
124
|
+
}
|
|
125
|
+
if (settings.maxUsers !== undefined)
|
|
126
|
+
values.customint3 = String(settings.maxUsers);
|
|
127
|
+
if (settings.welcome !== undefined) {
|
|
128
|
+
const sending = await page.evaluate(() => globalThis.document.querySelector('form.mform select[name="customint4"]')?.value);
|
|
129
|
+
// 0 is "No" (ENROL_DO_NOT_SEND_EMAIL); 1 sends from the course contact.
|
|
130
|
+
if (settings.welcome === false)
|
|
131
|
+
values.customint4 = "0";
|
|
132
|
+
else {
|
|
133
|
+
if (!sending || sending === "0")
|
|
134
|
+
values.customint4 = "1";
|
|
135
|
+
values.customtext1 = settings.welcome;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (Object.keys(values).length === 0 && existing)
|
|
139
|
+
throw new EnrolmentError("Nothing to change: give at least one setting.");
|
|
140
|
+
await setFields(page, values);
|
|
141
|
+
await submitForm(page, "submitbutton");
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
await page.close().catch(() => undefined);
|
|
145
|
+
}
|
|
146
|
+
const after = await readMethodsPage(context, siteUrl, courseId);
|
|
147
|
+
const listed = existing ? after.methods.find((m) => m.id === existing.id) : after.methods.find((m) => m.type === type && !before.methods.some((b) => b.id === m.id));
|
|
148
|
+
if (!listed)
|
|
149
|
+
throw new EnrolmentError(`Moodle didn't show the ${type} enrolment method of course ${courseId} after saving it.`);
|
|
150
|
+
const result = await withSettings(context, siteUrl, courseId, listed);
|
|
151
|
+
const what = Object.keys(settings).join(", ");
|
|
152
|
+
return { changed: existing ? `Enrolment method ${result.id} (${type}) of course ${courseId} updated: ${what}.` : `Enrolment method ${result.id} (${type}) added to course ${courseId}${what ? `: ${what}` : ""}.`, method: result };
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=methods.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"methods.js","sourceRoot":"","sources":["../../../src/areas/participants/methods.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BrowserContext, Page } from "playwright-core";
|
|
2
2
|
import { MoodleError } from "../../core/errors.js";
|
|
3
|
+
/** A participant of a course with their roles and groups, as `participants` lists them. */
|
|
3
4
|
export interface Participant {
|
|
4
5
|
userId: number;
|
|
5
6
|
fullName: string;
|
|
@@ -12,6 +13,7 @@ export interface Participant {
|
|
|
12
13
|
name: string;
|
|
13
14
|
}[];
|
|
14
15
|
}
|
|
16
|
+
/** A group of a course, as `groups` lists it. */
|
|
15
17
|
export interface CourseGroup {
|
|
16
18
|
id: number;
|
|
17
19
|
name: string;
|
|
@@ -23,11 +25,20 @@ export declare class NoParticipantsError extends MoodleError {
|
|
|
23
25
|
name: string;
|
|
24
26
|
constructor(message: string);
|
|
25
27
|
}
|
|
28
|
+
export declare const PARTICIPANTS_PAGE_SIZE = 100;
|
|
29
|
+
export declare const MAX_PARTICIPANT_PAGES = 100;
|
|
30
|
+
export interface Filter {
|
|
31
|
+
name: string;
|
|
32
|
+
jointype: number;
|
|
33
|
+
values: number[];
|
|
34
|
+
}
|
|
26
35
|
/** The rows of a participants table fragment: user id and name, read by link and markup, in any language. */
|
|
27
36
|
export declare function readParticipantRows(page: Page): Promise<{
|
|
28
37
|
userId: number;
|
|
29
38
|
fullName: string;
|
|
30
39
|
}[]>;
|
|
40
|
+
/** One page (from 1) of the participants table matching `filters`, as the HTML fragment the page renders. */
|
|
41
|
+
export declare function participantsTablePage(context: BrowserContext, siteUrl: string, courseId: number, filters: Filter[], pagenumber: number): Promise<string>;
|
|
31
42
|
/**
|
|
32
43
|
* The roles and groups the participants page filters by in a course (its filters' options), as the
|
|
33
44
|
* person may use them: every group, or only their own in a course with separate groups. "No roles"
|
|
@@ -11,8 +11,8 @@ export class NoParticipantsError extends MoodleError {
|
|
|
11
11
|
// The table's join types (core\output\datafilter): a filter's values match any; filters all apply.
|
|
12
12
|
const JOIN_ANY = 1;
|
|
13
13
|
const JOIN_ALL = 2;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
14
|
+
export const PARTICIPANTS_PAGE_SIZE = 100;
|
|
15
|
+
export const MAX_PARTICIPANT_PAGES = 100;
|
|
16
16
|
/** The rows of a participants table fragment: user id and name, read by link and markup, in any language. */
|
|
17
17
|
export function readParticipantRows(page) {
|
|
18
18
|
return page.evaluate(() => {
|
|
@@ -31,30 +31,35 @@ export function readParticipantRows(page) {
|
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
+
/** One page (from 1) of the participants table matching `filters`, as the HTML fragment the page renders. */
|
|
35
|
+
export async function participantsTablePage(context, siteUrl, courseId, filters, pagenumber) {
|
|
36
|
+
const { html } = await callService(context, siteUrl, "core_table_get_dynamic_table_content", {
|
|
37
|
+
component: "core_user",
|
|
38
|
+
handler: "participants",
|
|
39
|
+
uniqueid: `user-index-participants-${courseId}`,
|
|
40
|
+
sortdata: [{ sortby: "lastname", sortorder: 4 }],
|
|
41
|
+
// Integer filters take numbers: a string id fails (confirmed empirically, Moodle 5.2).
|
|
42
|
+
filters: [{ name: "courseid", jointype: JOIN_ANY, values: [courseId] }, ...filters],
|
|
43
|
+
jointype: JOIN_ALL,
|
|
44
|
+
firstinitial: "",
|
|
45
|
+
lastinitial: "",
|
|
46
|
+
pagenumber,
|
|
47
|
+
pagesize: PARTICIPANTS_PAGE_SIZE,
|
|
48
|
+
hiddencolumns: [],
|
|
49
|
+
resetpreferences: false,
|
|
50
|
+
});
|
|
51
|
+
return html;
|
|
52
|
+
}
|
|
34
53
|
/** Every participant matching `filters`, page by page, parsed in `parser` (a blank tab). */
|
|
35
54
|
async function fetchAll(context, siteUrl, parser, courseId, filters) {
|
|
36
55
|
const all = new Map();
|
|
37
|
-
for (let pagenumber = 1; pagenumber <=
|
|
38
|
-
const
|
|
39
|
-
component: "core_user",
|
|
40
|
-
handler: "participants",
|
|
41
|
-
uniqueid: `user-index-participants-${courseId}`,
|
|
42
|
-
sortdata: [{ sortby: "lastname", sortorder: 4 }],
|
|
43
|
-
// Integer filters take numbers: a string id fails (confirmed empirically, Moodle 5.2).
|
|
44
|
-
filters: [{ name: "courseid", jointype: JOIN_ANY, values: [courseId] }, ...filters],
|
|
45
|
-
jointype: JOIN_ALL,
|
|
46
|
-
firstinitial: "",
|
|
47
|
-
lastinitial: "",
|
|
48
|
-
pagenumber,
|
|
49
|
-
pagesize: PAGE_SIZE,
|
|
50
|
-
hiddencolumns: [],
|
|
51
|
-
resetpreferences: false,
|
|
52
|
-
});
|
|
56
|
+
for (let pagenumber = 1; pagenumber <= MAX_PARTICIPANT_PAGES; pagenumber++) {
|
|
57
|
+
const html = await participantsTablePage(context, siteUrl, courseId, filters, pagenumber);
|
|
53
58
|
await parser.setContent(html);
|
|
54
59
|
const rows = await readParticipantRows(parser);
|
|
55
60
|
for (const row of rows)
|
|
56
61
|
all.set(row.userId, row);
|
|
57
|
-
if (rows.length <
|
|
62
|
+
if (rows.length < PARTICIPANTS_PAGE_SIZE)
|
|
58
63
|
break;
|
|
59
64
|
}
|
|
60
65
|
return Array.from(all.values());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"participants.js","sourceRoot":"","sources":["../../../src/areas/participants/participants.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"participants.js","sourceRoot":"","sources":["../../../src/areas/participants/participants.ts"],"names":[],"mappings":"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"}
|