@mo7yw4ng/openape 1.0.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/esm/_dnt.polyfills.d.ts +24 -0
  4. package/esm/_dnt.polyfills.js +1 -0
  5. package/esm/_dnt.shims.d.ts +5 -0
  6. package/esm/_dnt.shims.js +61 -0
  7. package/esm/deno.d.ts +23 -0
  8. package/esm/deno.js +22 -0
  9. package/esm/package.json +3 -0
  10. package/package.json +34 -0
  11. package/script/_dnt.polyfills.d.ts +24 -0
  12. package/script/_dnt.polyfills.js +2 -0
  13. package/script/_dnt.shims.d.ts +5 -0
  14. package/script/_dnt.shims.js +65 -0
  15. package/script/deno.d.ts +23 -0
  16. package/script/deno.js +24 -0
  17. package/script/package.json +3 -0
  18. package/script/src/commands/announcements.d.ts +2 -0
  19. package/script/src/commands/announcements.js +288 -0
  20. package/script/src/commands/auth.d.ts +2 -0
  21. package/script/src/commands/auth.js +238 -0
  22. package/script/src/commands/calendar.d.ts +2 -0
  23. package/script/src/commands/calendar.js +375 -0
  24. package/script/src/commands/courses.d.ts +2 -0
  25. package/script/src/commands/courses.js +484 -0
  26. package/script/src/commands/forums.d.ts +2 -0
  27. package/script/src/commands/forums.js +403 -0
  28. package/script/src/commands/grades.d.ts +2 -0
  29. package/script/src/commands/grades.js +259 -0
  30. package/script/src/commands/materials.d.ts +2 -0
  31. package/script/src/commands/materials.js +423 -0
  32. package/script/src/commands/quizzes.d.ts +2 -0
  33. package/script/src/commands/quizzes.js +228 -0
  34. package/script/src/commands/skills.d.ts +2 -0
  35. package/script/src/commands/skills.js +117 -0
  36. package/script/src/commands/videos.d.ts +2 -0
  37. package/script/src/commands/videos.js +334 -0
  38. package/script/src/index.d.ts +26 -0
  39. package/script/src/index.js +156 -0
  40. package/script/src/lib/auth.d.ts +24 -0
  41. package/script/src/lib/auth.js +203 -0
  42. package/script/src/lib/config.d.ts +5 -0
  43. package/script/src/lib/config.js +43 -0
  44. package/script/src/lib/logger.d.ts +2 -0
  45. package/script/src/lib/logger.js +28 -0
  46. package/script/src/lib/moodle.d.ts +234 -0
  47. package/script/src/lib/moodle.js +966 -0
  48. package/script/src/lib/session.d.ts +7 -0
  49. package/script/src/lib/session.js +71 -0
  50. package/script/src/lib/token.d.ts +27 -0
  51. package/script/src/lib/token.js +154 -0
  52. package/script/src/lib/types.d.ts +261 -0
  53. package/script/src/lib/types.js +2 -0
  54. package/script/src/lib/utils.d.ts +5 -0
  55. package/script/src/lib/utils.js +43 -0
  56. package/skills/openape/SKILL.md +328 -0
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.closeBrowserSafely = exports.launchAuthenticated = exports.findEdgePath = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const playwright_core_1 = require("playwright-core");
10
+ const token_js_1 = require("./token.js");
11
+ /**
12
+ * Find a Chromium-based browser executable on Windows.
13
+ * Priority: Edge → Chrome → Brave
14
+ */
15
+ function findEdgePath() {
16
+ const roots = [
17
+ process.env.PROGRAMFILES,
18
+ process.env["PROGRAMFILES(X86)"],
19
+ process.env.LOCALAPPDATA,
20
+ ].filter(Boolean);
21
+ const browsers = [
22
+ { name: "Edge", suffix: "Microsoft\\Edge\\Application\\msedge.exe" },
23
+ { name: "Chrome", suffix: "Google\\Chrome\\Application\\chrome.exe" },
24
+ { name: "Brave", suffix: "BraveSoftware\\Brave-Browser\\Application\\brave.exe" },
25
+ ];
26
+ for (const { suffix } of browsers) {
27
+ for (const root of roots) {
28
+ const candidate = path_1.default.join(root, suffix);
29
+ if (fs_1.default.existsSync(candidate))
30
+ return candidate;
31
+ }
32
+ }
33
+ throw new Error("找不到可用的瀏覽器(Edge / Chrome / Brave)。請確認已安裝其中一種。");
34
+ }
35
+ exports.findEdgePath = findEdgePath;
36
+ /**
37
+ * Launch a browser and return an authenticated context.
38
+ * Tries to restore a saved session first; falls back to fresh OAuth login.
39
+ * Also acquires Moodle Web Service Token for API calls.
40
+ */
41
+ async function launchAuthenticated(config, log) {
42
+ const edgePath = findEdgePath();
43
+ log.debug(`Using Edge: ${edgePath}`);
44
+ // Wait a bit to ensure any previous browser process has fully terminated
45
+ await new Promise(resolve => setTimeout(resolve, 1000));
46
+ const browser = await playwright_core_1.chromium.launch({
47
+ executablePath: edgePath,
48
+ headless: config.headless,
49
+ slowMo: config.slowMo,
50
+ });
51
+ // Try loading saved WS token first
52
+ let wsToken = (0, token_js_1.loadWsToken)(config.authStatePath) ?? undefined;
53
+ if (wsToken) {
54
+ log.info("Loaded saved Web Service Token.");
55
+ }
56
+ // Try restoring a saved session
57
+ const restored = await tryRestoreSession(browser, config, log);
58
+ if (restored) {
59
+ const page = restored.pages()[0] ?? (await restored.newPage());
60
+ // If no saved WS token, try to acquire one
61
+ if (!wsToken) {
62
+ try {
63
+ wsToken = await (0, token_js_1.acquireWsToken)(page, config, log);
64
+ (0, token_js_1.saveWsToken)(config.authStatePath, wsToken);
65
+ }
66
+ catch {
67
+ log.warn("Failed to acquire WS Token with restored session, continuing without it.");
68
+ }
69
+ }
70
+ return { browser, context: restored, page, wsToken };
71
+ }
72
+ // Fresh login
73
+ if (config.headless) {
74
+ await browser.close().catch(() => { });
75
+ throw new Error("找不到有效的 Session 或是 Session 已過期。\n" +
76
+ "請先執行 `openape login` 進行手動登入,或是加上 `--headed` 參數執行目前的指令以開啟登入畫面。");
77
+ }
78
+ const context = await browser.newContext();
79
+ const page = await context.newPage();
80
+ await login(page, config, log);
81
+ await saveSession(context, config.authStatePath, log);
82
+ // Acquire WS Token after successful login
83
+ if (!wsToken) {
84
+ try {
85
+ wsToken = await (0, token_js_1.acquireWsToken)(page, config, log);
86
+ (0, token_js_1.saveWsToken)(config.authStatePath, wsToken);
87
+ }
88
+ catch {
89
+ log.warn("Failed to acquire WS Token, continuing with sesskey-only auth.");
90
+ }
91
+ }
92
+ return { browser, context, page, wsToken };
93
+ }
94
+ exports.launchAuthenticated = launchAuthenticated;
95
+ /**
96
+ * Safely close browser and context with timeout.
97
+ * Designed for AI agent usage - no human interaction needed.
98
+ * If noWait is true, initiates cleanup but doesn't wait for completion.
99
+ */
100
+ async function closeBrowserSafely(browser, context, timeoutMs = 5000, noWait = false) {
101
+ const closePromises = [];
102
+ // Close context with error handling
103
+ if (context) {
104
+ closePromises.push(Promise.race([
105
+ context.close().catch(() => { }),
106
+ new Promise(resolve => setTimeout(() => resolve(), timeoutMs))
107
+ ]));
108
+ }
109
+ // Close browser with error handling
110
+ closePromises.push(Promise.race([
111
+ browser.close().catch(() => { }),
112
+ new Promise(resolve => setTimeout(() => resolve(), timeoutMs))
113
+ ]));
114
+ if (noWait) {
115
+ // Fire and forget - don't wait for cleanup
116
+ Promise.allSettled(closePromises);
117
+ return;
118
+ }
119
+ await Promise.allSettled(closePromises);
120
+ }
121
+ exports.closeBrowserSafely = closeBrowserSafely;
122
+ /**
123
+ * Attempt to restore a session from stored state.
124
+ * Returns null if the stored state doesn't exist or the session is expired.
125
+ */
126
+ async function tryRestoreSession(browser, config, log) {
127
+ const statePath = path_1.default.resolve(config.authStatePath);
128
+ if (!fs_1.default.existsSync(statePath)) {
129
+ log.debug("No saved session found, will perform fresh login.");
130
+ return null;
131
+ }
132
+ log.info("Restoring saved session...");
133
+ const context = await browser.newContext({ storageState: statePath });
134
+ const page = await context.newPage();
135
+ try {
136
+ await page.goto(`${config.moodleBaseUrl}/my/`, {
137
+ waitUntil: "domcontentloaded",
138
+ timeout: 15000,
139
+ });
140
+ // If we got redirected to a login page, the session is expired
141
+ const url = page.url();
142
+ if (url.includes("login") || url.includes("microsoftonline")) {
143
+ log.warn("Saved session expired, will re-authenticate.");
144
+ await context.close();
145
+ return null;
146
+ }
147
+ log.success("Session restored successfully.");
148
+ return context;
149
+ }
150
+ catch {
151
+ log.warn("Failed to restore session, will re-authenticate.");
152
+ await context.close();
153
+ return null;
154
+ }
155
+ }
156
+ /**
157
+ * Save the current session state to disk for future reuse.
158
+ */
159
+ async function saveSession(context, statePath, log) {
160
+ try {
161
+ await context.storageState({ path: statePath });
162
+ log.debug("Session saved for future reuse.");
163
+ }
164
+ catch (err) {
165
+ log.warn(`Failed to save session: ${err}`);
166
+ }
167
+ }
168
+ /**
169
+ * Perform Microsoft OAuth login flow.
170
+ */
171
+ async function login(page, config, log) {
172
+ log.info("Starting Microsoft OAuth login...");
173
+ await page.goto(`${config.moodleBaseUrl}/auth/oauth2/login.php`, {
174
+ waitUntil: "domcontentloaded",
175
+ timeout: 30000,
176
+ });
177
+ // Wait for Microsoft login page or redirect back to Moodle
178
+ try {
179
+ await page.waitForURL((url) => url.toString().includes("microsoftonline") ||
180
+ url.toString().includes("login.microsoftonline") ||
181
+ (url.toString().includes("ilearning.cycu.edu.tw") &&
182
+ !url.toString().includes("auth/oauth2/login")), { timeout: 10000 });
183
+ const url = page.url().toString();
184
+ if (url.includes("microsoftonline") || url.includes("login.microsoftonline")) {
185
+ log.info("Microsoft login page detected. Please complete login in the browser.");
186
+ log.info("Waiting for redirect back to Moodle...");
187
+ await page.waitForURL((u) => u.toString().includes("ilearning.cycu.edu.tw") &&
188
+ !u.toString().includes("microsoftonline") &&
189
+ !u.toString().includes("login.microsoftonline"), { timeout: 300000 });
190
+ }
191
+ }
192
+ catch {
193
+ // Already logged in or redirected
194
+ }
195
+ // Verify we're logged in
196
+ const finalUrl = page.url().toString();
197
+ if (finalUrl.includes("login") ||
198
+ finalUrl.includes("microsoftonline") ||
199
+ finalUrl === config.moodleBaseUrl + "/auth/oauth2/login.php") {
200
+ throw new Error(`登入後未重新導向回 Moodle。目前 URL: ${finalUrl}`);
201
+ }
202
+ log.success("Login completed successfully.");
203
+ }
@@ -0,0 +1,5 @@
1
+ import type { AppConfig } from "./types.js";
2
+ /**
3
+ * Load config from .env file (if it exists).
4
+ */
5
+ export declare function loadConfig(baseDir?: string): AppConfig;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadConfig = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ /**
10
+ * Load config from .env file (if it exists).
11
+ */
12
+ function loadConfig(baseDir) {
13
+ const envPath = baseDir ? path_1.default.resolve(baseDir, ".env") : path_1.default.resolve(".env");
14
+ if (fs_1.default.existsSync(envPath)) {
15
+ const envContent = fs_1.default.readFileSync(envPath, "utf8");
16
+ for (const line of envContent.split("\n")) {
17
+ const trimmed = line.trim();
18
+ if (!trimmed || trimmed.startsWith("#"))
19
+ continue;
20
+ const eqIdx = trimmed.indexOf("=");
21
+ if (eqIdx === -1)
22
+ continue;
23
+ const key = trimmed.slice(0, eqIdx).trim();
24
+ const value = trimmed.slice(eqIdx + 1).trim();
25
+ if (!process.env[key])
26
+ process.env[key] = value;
27
+ }
28
+ }
29
+ return buildConfig();
30
+ }
31
+ exports.loadConfig = loadConfig;
32
+ function buildConfig() {
33
+ const moodleBaseUrl = (process.env.MOODLE_BASE_URL ?? "https://ilearning.cycu.edu.tw").replace(/\/$/, "");
34
+ return {
35
+ courseUrl: "",
36
+ moodleBaseUrl,
37
+ headless: process.env.HEADLESS !== "false",
38
+ slowMo: parseInt(process.env.SLOW_MO ?? "0", 10),
39
+ authStatePath: process.env.AUTH_STATE_PATH ?? ".auth/storage-state.json",
40
+ ollamaModel: process.env.MODEL,
41
+ ollamaBaseUrl: (process.env.OLLAMA_BASE_URL ?? "http://localhost:11434").replace(/\/$/, ""),
42
+ };
43
+ }
@@ -0,0 +1,2 @@
1
+ import type { Logger } from "./types.js";
2
+ export declare function createLogger(verbose?: boolean, silent?: boolean): Logger;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLogger = void 0;
4
+ const NO_COLOR = !!process.env.NO_COLOR;
5
+ const c = (code, text) => NO_COLOR ? text : `\x1b[${code}m${text}\x1b[0m`;
6
+ function createLogger(verbose = false, silent = false) {
7
+ if (silent) {
8
+ // Silent logger - no output at all
9
+ return {
10
+ info: (_msg) => { },
11
+ success: (_msg) => { },
12
+ warn: (_msg) => { },
13
+ error: (_msg) => { },
14
+ debug: (_msg) => { },
15
+ };
16
+ }
17
+ return {
18
+ info: (msg) => console.error(c("36", "[INFO]") + ` ${msg}`),
19
+ success: (msg) => console.error(c("32", "[OK]") + ` ${msg}`),
20
+ warn: (msg) => console.error(c("33", "[WARN]") + ` ${msg}`),
21
+ error: (msg) => console.error(c("31", "[ERR]") + ` ${msg}`),
22
+ debug: (msg) => {
23
+ if (verbose)
24
+ console.error(c("90", "[DBG]") + ` ${msg}`);
25
+ },
26
+ };
27
+ }
28
+ exports.createLogger = createLogger;
@@ -0,0 +1,234 @@
1
+ import type { Page } from "playwright-core";
2
+ import type { SessionInfo, Logger, EnrolledCourse, SuperVideoModule, QuizModule, ForumModule, ResourceModule, ForumDiscussion, ForumPost, CalendarEvent, CourseGrade } from "./types.js";
3
+ /**
4
+ * Direct HTTP API call without browser (for WS API only).
5
+ * This is much faster than browser-based calls.
6
+ */
7
+ export declare function moodleApiCall<T = unknown>(session: {
8
+ wsToken: string;
9
+ moodleBaseUrl: string;
10
+ }, methodname: string, args: Record<string, unknown>): Promise<T>;
11
+ /**
12
+ * Send a Moodle AJAX request and return the result.
13
+ * Uses Web Service token if available AND the function is in WS_API_FUNCTIONS,
14
+ * otherwise falls back to sesskey-based AJAX (via /lib/ajax/service.php).
15
+ */
16
+ export declare function moodleAjax<T = unknown>(page: Page, session: SessionInfo, methodname: string, args: Record<string, unknown>): Promise<T>;
17
+ /**
18
+ * Fetch enrolled courses via pure API (no browser required).
19
+ * Fast and lightweight - uses HTTP fetch directly.
20
+ */
21
+ export declare function getEnrolledCoursesApi(session: {
22
+ wsToken: string;
23
+ moodleBaseUrl: string;
24
+ }, options?: {
25
+ classification?: "inprogress" | "past" | "future" | "all";
26
+ limit?: number;
27
+ }): Promise<EnrolledCourse[]>;
28
+ /**
29
+ * Fetch all enrolled courses via Moodle AJAX API.
30
+ */
31
+ export declare function getEnrolledCourses(page: Page, session: SessionInfo, log: Logger, options?: {
32
+ classification?: "inprogress" | "past" | "future";
33
+ limit?: number;
34
+ }): Promise<EnrolledCourse[]>;
35
+ /**
36
+ * Get course state (modules) via core_courseformat_get_state.
37
+ */
38
+ export declare function getCourseState(page: Page, session: SessionInfo, courseId: number): Promise<any>;
39
+ /**
40
+ * Get all SuperVideo modules in a course.
41
+ */
42
+ export declare function getSupervideosInCourse(page: Page, session: SessionInfo, courseId: number, log: Logger, options?: {
43
+ incompleteOnly?: boolean;
44
+ }): Promise<SuperVideoModule[]>;
45
+ /**
46
+ * Get all Quiz modules in a course.
47
+ */
48
+ export declare function getQuizzesInCourse(page: Page, session: SessionInfo, courseId: number, log: Logger): Promise<QuizModule[]>;
49
+ /**
50
+ * Get all forum modules in a course.
51
+ * If WS token is available, fetches forum IDs directly via WS API.
52
+ */
53
+ export declare function getForumsInCourse(page: Page, session: SessionInfo, courseId: number, log: Logger): Promise<ForumModule[]>;
54
+ /**
55
+ * Get all forums via pure WS API (no browser required).
56
+ * Fast and lightweight - uses HTTP fetch directly.
57
+ */
58
+ export declare function getForumsApi(session: {
59
+ wsToken: string;
60
+ moodleBaseUrl: string;
61
+ }, courseIds: number[]): Promise<Array<{
62
+ id: number;
63
+ cmid: number;
64
+ name: string;
65
+ courseid: number;
66
+ }>>;
67
+ /**
68
+ * Extract forum ID from forum page.
69
+ * First tries to find it in embedded page data, then falls back to
70
+ * extracting it from discussion posts API.
71
+ */
72
+ export declare function getForumIdFromPage(page: Page, cmid: number, session?: SessionInfo): Promise<number | null>;
73
+ /**
74
+ * Get forums by course IDs via AJAX.
75
+ * Returns forum instance IDs directly from Moodle API.
76
+ * This is the cleanest way to get forum instance IDs.
77
+ */
78
+ export declare function getForumsByCourseIds(page: Page, session: SessionInfo, courseIds: number[]): Promise<Array<{
79
+ id: number;
80
+ course: number;
81
+ name: string;
82
+ }>>;
83
+ /**
84
+ * Get discussions in a forum via AJAX.
85
+ * Note: Requires forum instance ID, not cmid. Use getForumsByCourseIds() first.
86
+ */
87
+ export declare function getForumDiscussions(page: Page, session: SessionInfo, forumId: number): Promise<ForumDiscussion[]>;
88
+ /**
89
+ * Get posts in a discussion via AJAX.
90
+ */
91
+ export declare function getDiscussionPosts(page: Page, session: SessionInfo, discussionId: number): Promise<ForumPost[]>;
92
+ /**
93
+ * Get all resource modules in a course.
94
+ */
95
+ export declare function getResourcesInCourse(page: Page, session: SessionInfo, courseId: number, log: Logger): Promise<ResourceModule[]>;
96
+ /**
97
+ * Get course grades for the current user via AJAX.
98
+ */
99
+ export declare function getCourseGrades(page: Page, session: SessionInfo, courseId: number): Promise<CourseGrade>;
100
+ /**
101
+ * Get course grades for the current user via pure WS API (no browser required).
102
+ * Fast and lightweight - uses HTTP fetch directly.
103
+ */
104
+ export declare function getCourseGradesApi(session: {
105
+ wsToken: string;
106
+ moodleBaseUrl: string;
107
+ }, courseId: number): Promise<CourseGrade>;
108
+ /**
109
+ * Get calendar events via AJAX.
110
+ */
111
+ export declare function getCalendarEvents(page: Page, session: SessionInfo, options?: {
112
+ courseId?: number;
113
+ startTime?: number;
114
+ endTime?: number;
115
+ events?: {
116
+ courseid?: number;
117
+ groupid?: number;
118
+ categoryid?: number;
119
+ }[];
120
+ }): Promise<CalendarEvent[]>;
121
+ /**
122
+ * Get calendar events via pure WS API (no browser required).
123
+ * Fast and lightweight - uses HTTP fetch directly.
124
+ */
125
+ export declare function getCalendarEventsApi(session: {
126
+ wsToken: string;
127
+ moodleBaseUrl: string;
128
+ }, options?: {
129
+ courseId?: number;
130
+ startTime?: number;
131
+ endTime?: number;
132
+ events?: {
133
+ courseid?: number;
134
+ groupid?: number;
135
+ categoryid?: number;
136
+ }[];
137
+ }): Promise<CalendarEvent[]>;
138
+ /**
139
+ * Visit a SuperVideo activity page and extract view_id + duration.
140
+ */
141
+ export declare function getVideoMetadata(page: Page, activityUrl: string, log: Logger): Promise<{
142
+ name: string;
143
+ url: string;
144
+ viewId: number;
145
+ duration: number;
146
+ existingPercent: number;
147
+ videoSources: string[];
148
+ youtubeIds?: string[];
149
+ }>;
150
+ /**
151
+ * Download a video from SuperVideo activity.
152
+ * Supports direct video URLs (pluginfile.php) and YouTube videos.
153
+ */
154
+ export declare function downloadVideo(page: Page, metadata: {
155
+ name: string;
156
+ videoSources: string[];
157
+ youtubeIds?: string[];
158
+ }, outputPath: string, log: Logger): Promise<{
159
+ success: boolean;
160
+ path?: string;
161
+ error?: string;
162
+ type?: string;
163
+ }>;
164
+ /**
165
+ * Complete a video by forging progress AJAX call.
166
+ */
167
+ export declare function completeVideo(page: Page, session: SessionInfo, video: {
168
+ viewId: number;
169
+ duration: number;
170
+ url: string;
171
+ cmid?: string;
172
+ }, log: Logger): Promise<boolean>;
173
+ /**
174
+ * Get site info including current user ID via pure WS API.
175
+ */
176
+ export declare function getSiteInfoApi(session: {
177
+ wsToken: string;
178
+ moodleBaseUrl: string;
179
+ }): Promise<{
180
+ userid: number;
181
+ username: string;
182
+ fullname: string;
183
+ sitename: string;
184
+ }>;
185
+ /**
186
+ * Get course contents and filter for SuperVideo modules via pure WS API.
187
+ */
188
+ export declare function getSupervideosInCourseApi(session: {
189
+ wsToken: string;
190
+ moodleBaseUrl: string;
191
+ }, courseId: number): Promise<SuperVideoModule[]>;
192
+ /**
193
+ * Extended QuizModule with courseId for API responses.
194
+ */
195
+ export interface QuizModuleWithCourse extends QuizModule {
196
+ courseId: number;
197
+ }
198
+ /**
199
+ * Get quizzes in courses via pure WS API.
200
+ */
201
+ export declare function getQuizzesByCoursesApi(session: {
202
+ wsToken: string;
203
+ moodleBaseUrl: string;
204
+ }, courseIds: number[]): Promise<QuizModuleWithCourse[]>;
205
+ /**
206
+ * Get resources in courses via pure WS API.
207
+ */
208
+ export declare function getResourcesByCoursesApi(session: {
209
+ wsToken: string;
210
+ moodleBaseUrl: string;
211
+ }, courseIds: number[]): Promise<ResourceModule[]>;
212
+ export interface Message {
213
+ id: number;
214
+ useridfrom: number;
215
+ useridto: number;
216
+ subject: string;
217
+ text: string;
218
+ timecreated: number;
219
+ fullmessage: string;
220
+ fullmessageformat: number;
221
+ fullmessagehtml: string;
222
+ }
223
+ /**
224
+ * Get messages for the current user via pure WS API.
225
+ */
226
+ export declare function getMessagesApi(session: {
227
+ wsToken: string;
228
+ moodleBaseUrl: string;
229
+ }, userIdTo: number, options?: {
230
+ useridfrom?: number;
231
+ read?: boolean;
232
+ limitfrom?: number;
233
+ limitnum?: number;
234
+ }): Promise<Message[]>;