@mo7yw4ng/openape 1.0.4 → 1.0.5
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/esm/deno.js +1 -1
- package/esm/src/commands/announcements.js +3 -3
- package/esm/src/commands/auth.d.ts.map +1 -1
- package/esm/src/commands/auth.js +24 -14
- package/esm/src/commands/calendar.js +3 -3
- package/esm/src/commands/courses.js +3 -3
- package/esm/src/commands/forums.js +3 -3
- package/esm/src/commands/grades.js +3 -3
- package/esm/src/commands/materials.d.ts.map +1 -1
- package/esm/src/commands/materials.js +114 -191
- package/esm/src/commands/quizzes.d.ts.map +1 -1
- package/esm/src/commands/quizzes.js +33 -22
- package/esm/src/commands/videos.js +5 -5
- package/esm/src/lib/auth.js +2 -2
- package/esm/src/lib/logger.d.ts +1 -1
- package/esm/src/lib/logger.d.ts.map +1 -1
- package/esm/src/lib/logger.js +7 -4
- package/esm/src/lib/moodle.d.ts +4 -0
- package/esm/src/lib/moodle.d.ts.map +1 -1
- package/esm/src/lib/moodle.js +19 -2
- package/package.json +1 -1
- package/script/deno.js +1 -1
- package/script/src/commands/announcements.js +3 -3
- package/script/src/commands/auth.d.ts.map +1 -1
- package/script/src/commands/auth.js +24 -14
- package/script/src/commands/calendar.js +3 -3
- package/script/src/commands/courses.js +3 -3
- package/script/src/commands/forums.js +3 -3
- package/script/src/commands/grades.js +3 -3
- package/script/src/commands/materials.d.ts.map +1 -1
- package/script/src/commands/materials.js +111 -188
- package/script/src/commands/quizzes.d.ts.map +1 -1
- package/script/src/commands/quizzes.js +32 -21
- package/script/src/commands/videos.js +5 -5
- package/script/src/lib/auth.js +2 -2
- package/script/src/lib/logger.d.ts +1 -1
- package/script/src/lib/logger.d.ts.map +1 -1
- package/script/src/lib/logger.js +7 -4
- package/script/src/lib/moodle.d.ts +4 -0
- package/script/src/lib/moodle.d.ts.map +1 -1
- package/script/src/lib/moodle.js +20 -2
- package/skills/openape/SKILL.md +4 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getBaseDir, formatTimestamp } from "../lib/utils.js";
|
|
2
|
-
import { getEnrolledCoursesApi, getQuizzesByCoursesApi, startQuizAttemptApi, getQuizAttemptDataApi, processQuizAttemptApi } from "../lib/moodle.js";
|
|
2
|
+
import { getEnrolledCoursesApi, getQuizzesByCoursesApi, startQuizAttemptApi, getQuizAttemptDataApi, getAllQuizAttemptDataApi, processQuizAttemptApi } from "../lib/moodle.js";
|
|
3
3
|
import { createLogger } from "../lib/logger.js";
|
|
4
4
|
import { formatAndOutput } from "../index.js";
|
|
5
5
|
import { loadWsToken } from "../lib/token.js";
|
|
@@ -41,6 +41,21 @@ function parseSavedAnswer(html) {
|
|
|
41
41
|
return textMatch[1];
|
|
42
42
|
return null;
|
|
43
43
|
}
|
|
44
|
+
function parseQuizQuestions(questions) {
|
|
45
|
+
return Object.values(questions).map((q) => {
|
|
46
|
+
const parsed = parseQuestionHtml(q.html ?? "");
|
|
47
|
+
const savedAnswer = parseSavedAnswer(q.html ?? "");
|
|
48
|
+
return {
|
|
49
|
+
slot: q.slot,
|
|
50
|
+
type: q.type,
|
|
51
|
+
status: q.status,
|
|
52
|
+
stateclass: q.stateclass,
|
|
53
|
+
savedAnswer,
|
|
54
|
+
question: parsed.text,
|
|
55
|
+
options: parsed.options,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
}
|
|
44
59
|
export function registerQuizzesCommand(program) {
|
|
45
60
|
const quizzesCmd = program.command("quizzes");
|
|
46
61
|
quizzesCmd.description("Quiz operations");
|
|
@@ -53,19 +68,19 @@ export function registerQuizzesCommand(program) {
|
|
|
53
68
|
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
54
69
|
const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
|
|
55
70
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
56
|
-
const log = createLogger(opts.verbose, silent);
|
|
71
|
+
const log = createLogger(opts.verbose, silent, outputFormat);
|
|
57
72
|
const baseDir = getBaseDir();
|
|
58
73
|
const sessionPath = path.resolve(baseDir, ".auth", "storage-state.json");
|
|
59
74
|
// Check if session exists
|
|
60
75
|
if (!fs.existsSync(sessionPath)) {
|
|
61
|
-
log.error("未找到登入 session。請先執行 'openape
|
|
76
|
+
log.error("未找到登入 session。請先執行 'openape login' 進行登入。");
|
|
62
77
|
log.info(`Session 預期位置: ${sessionPath}`);
|
|
63
78
|
return null;
|
|
64
79
|
}
|
|
65
80
|
// Try to load WS token
|
|
66
81
|
const wsToken = loadWsToken(sessionPath);
|
|
67
82
|
if (!wsToken) {
|
|
68
|
-
log.error("未找到 WS token。請先執行 'openape
|
|
83
|
+
log.error("未找到 WS token。請先執行 'openape login' 進行登入。");
|
|
69
84
|
return null;
|
|
70
85
|
}
|
|
71
86
|
return {
|
|
@@ -154,8 +169,12 @@ export function registerQuizzesCommand(program) {
|
|
|
154
169
|
}
|
|
155
170
|
try {
|
|
156
171
|
const result = await startQuizAttemptApi(apiContext.session, quizCmid);
|
|
172
|
+
apiContext.log.success(`Quiz attempt ${result.attempt.attemptid} started.`);
|
|
173
|
+
const attemptId = result.attempt.attemptid;
|
|
174
|
+
const data = await getAllQuizAttemptDataApi(apiContext.session, attemptId);
|
|
175
|
+
const questions = parseQuizQuestions(data.questions);
|
|
157
176
|
const outputData = [{
|
|
158
|
-
attemptId
|
|
177
|
+
attemptId,
|
|
159
178
|
quizId: result.attempt.quizid,
|
|
160
179
|
state: result.attempt.state,
|
|
161
180
|
timeStart: formatTimestamp(result.attempt.timestart),
|
|
@@ -163,8 +182,9 @@ export function registerQuizzesCommand(program) {
|
|
|
163
182
|
? formatTimestamp(result.attempt.timefinish)
|
|
164
183
|
: null,
|
|
165
184
|
isPreview: result.attempt.preview,
|
|
185
|
+
totalQuestions: questions.length,
|
|
186
|
+
questions,
|
|
166
187
|
}];
|
|
167
|
-
apiContext.log.success(`Quiz attempt ${result.attempt.attemptid} started.`);
|
|
168
188
|
formatAndOutput(outputData, output, apiContext.log);
|
|
169
189
|
}
|
|
170
190
|
catch (error) {
|
|
@@ -176,7 +196,7 @@ export function registerQuizzesCommand(program) {
|
|
|
176
196
|
.command("info")
|
|
177
197
|
.description("Get quiz attempt data and questions")
|
|
178
198
|
.argument("<attempt-id>", "Quiz attempt ID")
|
|
179
|
-
.option("--page <number>", "Page number", "
|
|
199
|
+
.option("--page <number>", "Page number (-1 for all pages)", "-1")
|
|
180
200
|
.option("--output <format>", "Output format: json|csv|table|silent")
|
|
181
201
|
.action(async (attemptId, options, command) => {
|
|
182
202
|
const output = getOutputFormat(command);
|
|
@@ -186,20 +206,11 @@ export function registerQuizzesCommand(program) {
|
|
|
186
206
|
return;
|
|
187
207
|
}
|
|
188
208
|
try {
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
number: q.questionnumber ?? q.slot,
|
|
195
|
-
type: q.type,
|
|
196
|
-
status: q.status,
|
|
197
|
-
stateclass: q.stateclass,
|
|
198
|
-
savedAnswer,
|
|
199
|
-
question: parsed.text,
|
|
200
|
-
options: parsed.options,
|
|
201
|
-
};
|
|
202
|
-
});
|
|
209
|
+
const pageNumber = parseInt(options.page);
|
|
210
|
+
const data = pageNumber === -1
|
|
211
|
+
? await getAllQuizAttemptDataApi(apiContext.session, parseInt(attemptId))
|
|
212
|
+
: await getQuizAttemptDataApi(apiContext.session, parseInt(attemptId), pageNumber);
|
|
213
|
+
const questions = parseQuizQuestions(data.questions);
|
|
203
214
|
const outputData = [{
|
|
204
215
|
attemptId: data.attempt.attemptid,
|
|
205
216
|
quizId: data.attempt.quizid,
|
|
@@ -240,7 +251,7 @@ export function registerQuizzesCommand(program) {
|
|
|
240
251
|
}
|
|
241
252
|
try {
|
|
242
253
|
// Get attempt data to find uniqueid and sequencecheck values
|
|
243
|
-
const attemptData = await
|
|
254
|
+
const attemptData = await getAllQuizAttemptDataApi(apiContext.session, parseInt(attemptId));
|
|
244
255
|
const uniqueId = attemptData.attempt.uniqueid ?? attemptData.attempt.attemptid;
|
|
245
256
|
const sequenceChecks = new Map();
|
|
246
257
|
for (const q of Object.values(attemptData.questions)) {
|
|
@@ -17,19 +17,19 @@ export function registerVideosCommand(program) {
|
|
|
17
17
|
// Don't silence logs for commands that don't have explicit output format control
|
|
18
18
|
const outputFormat = command && command.optsWithGlobals ? getOutputFormat(command) : "table";
|
|
19
19
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
20
|
-
const log = createLogger(opts.verbose, silent);
|
|
20
|
+
const log = createLogger(opts.verbose, silent, outputFormat);
|
|
21
21
|
const baseDir = getBaseDir();
|
|
22
22
|
const sessionPath = path.resolve(baseDir, ".auth", "storage-state.json");
|
|
23
23
|
// Check if session exists
|
|
24
24
|
if (!fs.existsSync(sessionPath)) {
|
|
25
|
-
|
|
25
|
+
console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
|
|
26
26
|
log.info(`Session 預期位置: ${sessionPath}`);
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
29
29
|
// Try to load WS token
|
|
30
30
|
const wsToken = loadWsToken(sessionPath);
|
|
31
31
|
if (!wsToken) {
|
|
32
|
-
|
|
32
|
+
console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
35
|
return {
|
|
@@ -45,11 +45,11 @@ export function registerVideosCommand(program) {
|
|
|
45
45
|
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
46
46
|
const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
|
|
47
47
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
48
|
-
const log = createLogger(opts.verbose, silent);
|
|
48
|
+
const log = createLogger(opts.verbose, silent, outputFormat);
|
|
49
49
|
const baseDir = getBaseDir();
|
|
50
50
|
const sessionPath = path.resolve(baseDir, ".auth", "storage-state.json");
|
|
51
51
|
if (!fs.existsSync(sessionPath)) {
|
|
52
|
-
|
|
52
|
+
console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
55
|
const config = {
|
package/esm/src/lib/auth.js
CHANGED
|
@@ -209,12 +209,12 @@ export async function createApiContext(options, command) {
|
|
|
209
209
|
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
210
210
|
const outputFormat = command ? getOutputFormat(command) : "json";
|
|
211
211
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
212
|
-
const log = createLogger(opts.verbose, silent);
|
|
212
|
+
const log = createLogger(opts.verbose, silent, outputFormat);
|
|
213
213
|
const sessionPath = getSessionPath();
|
|
214
214
|
// Try to load WS token
|
|
215
215
|
const wsToken = loadWsToken(sessionPath);
|
|
216
216
|
if (!wsToken) {
|
|
217
|
-
|
|
217
|
+
console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
|
|
218
218
|
return null;
|
|
219
219
|
}
|
|
220
220
|
return {
|
package/esm/src/lib/logger.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/src/lib/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAOzC,wBAAgB,YAAY,CAAC,OAAO,UAAQ,EAAE,MAAM,UAAQ,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/src/lib/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAOzC,wBAAgB,YAAY,CAAC,OAAO,UAAQ,EAAE,MAAM,UAAQ,EAAE,YAAY,GAAE,MAAe,GAAG,MAAM,CAwBnG"}
|
package/esm/src/lib/logger.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
const NO_COLOR = !!process.env.NO_COLOR;
|
|
2
2
|
const c = (code, text) => NO_COLOR ? text : `\x1b[${code}m${text}\x1b[0m`;
|
|
3
|
-
export function createLogger(verbose = false, silent = false) {
|
|
3
|
+
export function createLogger(verbose = false, silent = false, outputFormat = "json") {
|
|
4
|
+
const jsonError = outputFormat === "json";
|
|
5
|
+
const errorFn = jsonError
|
|
6
|
+
? (msg) => console.error(JSON.stringify({ error: msg }))
|
|
7
|
+
: (msg) => console.error(c("31", "[ERR]") + ` ${msg}`);
|
|
4
8
|
if (silent) {
|
|
5
|
-
// Silent logger - no output at all
|
|
6
9
|
return {
|
|
7
10
|
info: (_msg) => { },
|
|
8
11
|
success: (_msg) => { },
|
|
9
12
|
warn: (_msg) => { },
|
|
10
|
-
error:
|
|
13
|
+
error: errorFn,
|
|
11
14
|
debug: (_msg) => { },
|
|
12
15
|
};
|
|
13
16
|
}
|
|
@@ -15,7 +18,7 @@ export function createLogger(verbose = false, silent = false) {
|
|
|
15
18
|
info: (msg) => console.error(c("36", "[INFO]") + ` ${msg}`),
|
|
16
19
|
success: (msg) => console.error(c("32", "[OK]") + ` ${msg}`),
|
|
17
20
|
warn: (msg) => console.error(c("33", "[WARN]") + ` ${msg}`),
|
|
18
|
-
error:
|
|
21
|
+
error: errorFn,
|
|
19
22
|
debug: (msg) => {
|
|
20
23
|
if (verbose)
|
|
21
24
|
console.error(c("90", "[DBG]") + ` ${msg}`);
|
package/esm/src/lib/moodle.d.ts
CHANGED
|
@@ -269,6 +269,10 @@ export declare function startQuizAttemptApi(session: {
|
|
|
269
269
|
/**
|
|
270
270
|
* Get quiz attempt data including questions via pure WS API.
|
|
271
271
|
*/
|
|
272
|
+
export declare function getAllQuizAttemptDataApi(session: {
|
|
273
|
+
wsToken: string;
|
|
274
|
+
moodleBaseUrl: string;
|
|
275
|
+
}, attemptId: number): Promise<QuizAttemptData>;
|
|
272
276
|
export declare function getQuizAttemptDataApi(session: {
|
|
273
277
|
wsToken: string;
|
|
274
278
|
moodleBaseUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"moodle.d.ts","sourceRoot":"","sources":["../../../src/src/lib/moodle.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"moodle.d.ts","sourceRoot":"","sources":["../../../src/src/lib/moodle.ts"],"names":[],"mappings":"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"}
|
package/esm/src/lib/moodle.js
CHANGED
|
@@ -340,7 +340,6 @@ export async function addForumDiscussionApi(session, forumId, subject, message)
|
|
|
340
340
|
forumid: forumId,
|
|
341
341
|
subject,
|
|
342
342
|
message: message.replace(/\n/g, "<br>"),
|
|
343
|
-
messageformat: 1,
|
|
344
343
|
});
|
|
345
344
|
if (data?.discussionid) {
|
|
346
345
|
return { success: true, discussionId: data.discussionid };
|
|
@@ -973,6 +972,24 @@ export async function startQuizAttemptApi(session, quizId, options = {}) {
|
|
|
973
972
|
/**
|
|
974
973
|
* Get quiz attempt data including questions via pure WS API.
|
|
975
974
|
*/
|
|
975
|
+
export async function getAllQuizAttemptDataApi(session, attemptId) {
|
|
976
|
+
const firstPage = await getQuizAttemptDataApi(session, attemptId, 0);
|
|
977
|
+
// Moodle re-indexes question keys per page (always starts at 0),
|
|
978
|
+
// so we must re-key by actual slot number to avoid overwrites.
|
|
979
|
+
const allQuestions = {};
|
|
980
|
+
for (const q of Object.values(firstPage.questions)) {
|
|
981
|
+
allQuestions[q.slot] = q;
|
|
982
|
+
}
|
|
983
|
+
let nextPage = firstPage.nextpage;
|
|
984
|
+
while (nextPage !== undefined && nextPage !== null && nextPage !== -1) {
|
|
985
|
+
const pageData = await getQuizAttemptDataApi(session, attemptId, nextPage);
|
|
986
|
+
for (const q of Object.values(pageData.questions)) {
|
|
987
|
+
allQuestions[q.slot] = q;
|
|
988
|
+
}
|
|
989
|
+
nextPage = pageData.nextpage;
|
|
990
|
+
}
|
|
991
|
+
return { ...firstPage, questions: allQuestions, nextpage: undefined };
|
|
992
|
+
}
|
|
976
993
|
export async function getQuizAttemptDataApi(session, attemptId, page = 0) {
|
|
977
994
|
const data = await moodleApiCall(session, "mod_quiz_get_attempt_data", { attemptid: attemptId, page });
|
|
978
995
|
if (!data?.attempt || !data?.questions) {
|
|
@@ -1218,7 +1235,7 @@ export async function uploadFileApi(session, filePath, options) {
|
|
|
1218
1235
|
// Prepare multipart form data
|
|
1219
1236
|
const formData = new FormData();
|
|
1220
1237
|
formData.append("token", session.wsToken);
|
|
1221
|
-
formData.append("file", new Blob([fileContent]), fileName);
|
|
1238
|
+
formData.append("file", new Blob([new Uint8Array(fileContent)]), fileName);
|
|
1222
1239
|
formData.append("filepath", options?.filepath || "/");
|
|
1223
1240
|
formData.append("itemid", String(draftItemId)); // Use our generated draft ID
|
|
1224
1241
|
formData.append("contextid", String(userContextId)); // Use calculated user context
|
package/package.json
CHANGED
package/script/deno.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = {
|
|
4
4
|
"name": "@openape/openape",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.5",
|
|
6
6
|
"description": "CLI tool for CYCU i-Learning platform",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"exports": "./src/index.ts",
|
|
@@ -23,19 +23,19 @@ function registerAnnouncementsCommand(program) {
|
|
|
23
23
|
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
24
24
|
const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
|
|
25
25
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
26
|
-
const log = (0, logger_js_1.createLogger)(opts.verbose, silent);
|
|
26
|
+
const log = (0, logger_js_1.createLogger)(opts.verbose, silent, outputFormat);
|
|
27
27
|
const baseDir = (0, utils_js_1.getBaseDir)();
|
|
28
28
|
const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
|
|
29
29
|
// Check if session exists
|
|
30
30
|
if (!node_fs_1.default.existsSync(sessionPath)) {
|
|
31
|
-
|
|
31
|
+
console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
|
|
32
32
|
log.info(`Session 預期位置: ${sessionPath}`);
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
35
|
// Try to load WS token
|
|
36
36
|
const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
|
|
37
37
|
if (!wsToken) {
|
|
38
|
-
|
|
38
|
+
console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/src/commands/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/src/commands/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkStD"}
|
|
@@ -135,31 +135,41 @@ function registerCommand(program) {
|
|
|
135
135
|
catch {
|
|
136
136
|
// Ignore sesskey extraction errors
|
|
137
137
|
}
|
|
138
|
-
//
|
|
138
|
+
// Acquire WS token
|
|
139
|
+
let wsToken;
|
|
139
140
|
try {
|
|
140
|
-
|
|
141
|
-
username: "",
|
|
142
|
-
password: "",
|
|
143
|
-
courseUrl: "",
|
|
144
|
-
moodleBaseUrl: "https://ilearning.cycu.edu.tw",
|
|
145
|
-
headless: false,
|
|
146
|
-
slowMo: 0,
|
|
147
|
-
authStatePath: sessionPath,
|
|
148
|
-
ollamaBaseUrl: "",
|
|
149
|
-
};
|
|
150
|
-
const wsToken = await (0, token_js_1.acquireWsToken)(page, config, log);
|
|
141
|
+
wsToken = await (0, token_js_1.acquireWsToken)(page, { moodleBaseUrl: "https://ilearning.cycu.edu.tw" }, log);
|
|
151
142
|
(0, token_js_1.saveWsToken)(sessionPath, wsToken);
|
|
152
143
|
}
|
|
153
144
|
catch {
|
|
154
145
|
// WS token is optional, ignore errors
|
|
155
146
|
}
|
|
156
147
|
const stats = node_fs_1.default.statSync(sessionPath);
|
|
148
|
+
// Get user info via WS API
|
|
149
|
+
let user;
|
|
150
|
+
try {
|
|
151
|
+
if (wsToken) {
|
|
152
|
+
const siteInfo = await (0, moodle_js_1.getSiteInfoApi)({
|
|
153
|
+
wsToken,
|
|
154
|
+
moodleBaseUrl: "https://ilearning.cycu.edu.tw",
|
|
155
|
+
});
|
|
156
|
+
user = {
|
|
157
|
+
userid: siteInfo.userid,
|
|
158
|
+
username: siteInfo.username,
|
|
159
|
+
fullname: siteInfo.fullname,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Ignore
|
|
165
|
+
}
|
|
157
166
|
const result = {
|
|
158
167
|
status: "success",
|
|
159
168
|
message: "Login successful",
|
|
160
169
|
session_path: sessionPath,
|
|
161
170
|
session_size: stats.size,
|
|
162
|
-
updated: true
|
|
171
|
+
updated: true,
|
|
172
|
+
...(user ? { user } : {}),
|
|
163
173
|
};
|
|
164
174
|
console.log(JSON.stringify(result, null, 2));
|
|
165
175
|
}
|
|
@@ -253,7 +263,7 @@ function registerCommand(program) {
|
|
|
253
263
|
status: "error",
|
|
254
264
|
error: "Session not found",
|
|
255
265
|
session_path: sessionPath,
|
|
256
|
-
hint: "Run 'openape
|
|
266
|
+
hint: "Run 'openape login' first"
|
|
257
267
|
};
|
|
258
268
|
console.log(JSON.stringify(result, null, 2));
|
|
259
269
|
}
|
|
@@ -23,19 +23,19 @@ function registerCalendarCommand(program) {
|
|
|
23
23
|
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
24
24
|
const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
|
|
25
25
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
26
|
-
const log = (0, logger_js_1.createLogger)(opts.verbose, silent);
|
|
26
|
+
const log = (0, logger_js_1.createLogger)(opts.verbose, silent, outputFormat);
|
|
27
27
|
const baseDir = (0, utils_js_1.getBaseDir)();
|
|
28
28
|
const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
|
|
29
29
|
// Check if session exists
|
|
30
30
|
if (!node_fs_1.default.existsSync(sessionPath)) {
|
|
31
|
-
|
|
31
|
+
console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
|
|
32
32
|
log.info(`Session 預期位置: ${sessionPath}`);
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
35
|
// Try to load WS token
|
|
36
36
|
const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
|
|
37
37
|
if (!wsToken) {
|
|
38
|
-
|
|
38
|
+
console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
return {
|
|
@@ -24,19 +24,19 @@ function registerCoursesCommand(program) {
|
|
|
24
24
|
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
25
25
|
const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
|
|
26
26
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
27
|
-
const log = (0, logger_js_1.createLogger)(opts.verbose, silent);
|
|
27
|
+
const log = (0, logger_js_1.createLogger)(opts.verbose, silent, outputFormat);
|
|
28
28
|
const baseDir = (0, utils_js_1.getBaseDir)();
|
|
29
29
|
const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
|
|
30
30
|
// Check if session exists
|
|
31
31
|
if (!node_fs_1.default.existsSync(sessionPath)) {
|
|
32
|
-
|
|
32
|
+
console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
|
|
33
33
|
log.info(`Session 預期位置: ${sessionPath}`);
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
// Try to load WS token
|
|
37
37
|
const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
|
|
38
38
|
if (!wsToken) {
|
|
39
|
-
|
|
39
|
+
console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
|
|
40
40
|
return null;
|
|
41
41
|
}
|
|
42
42
|
return {
|
|
@@ -18,19 +18,19 @@ function registerForumsCommand(program) {
|
|
|
18
18
|
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
19
19
|
const outputFormat = (0, utils_js_1.getOutputFormat)(command || { optsWithGlobals: () => ({ output: "json" }) });
|
|
20
20
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
21
|
-
const log = (0, logger_js_1.createLogger)(opts.verbose, silent);
|
|
21
|
+
const log = (0, logger_js_1.createLogger)(opts.verbose, silent, outputFormat);
|
|
22
22
|
const baseDir = (0, utils_js_1.getBaseDir)();
|
|
23
23
|
const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
|
|
24
24
|
// Check if session exists
|
|
25
25
|
if (!node_fs_1.default.existsSync(sessionPath)) {
|
|
26
|
-
|
|
26
|
+
console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
|
|
27
27
|
log.info(`Session 預期位置: ${sessionPath}`);
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
// Try to load WS token
|
|
31
31
|
const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
|
|
32
32
|
if (!wsToken) {
|
|
33
|
-
|
|
33
|
+
console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
// Try to load sesskey from cache
|
|
@@ -23,19 +23,19 @@ function registerGradesCommand(program) {
|
|
|
23
23
|
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
24
24
|
const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
|
|
25
25
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
26
|
-
const log = (0, logger_js_1.createLogger)(opts.verbose, silent);
|
|
26
|
+
const log = (0, logger_js_1.createLogger)(opts.verbose, silent, outputFormat);
|
|
27
27
|
const baseDir = (0, utils_js_1.getBaseDir)();
|
|
28
28
|
const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
|
|
29
29
|
// Check if session exists
|
|
30
30
|
if (!node_fs_1.default.existsSync(sessionPath)) {
|
|
31
|
-
|
|
31
|
+
console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
|
|
32
32
|
log.info(`Session 預期位置: ${sessionPath}`);
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
35
|
// Try to load WS token
|
|
36
36
|
const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
|
|
37
37
|
if (!wsToken) {
|
|
38
|
-
|
|
38
|
+
console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../../src/src/commands/materials.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../../src/src/commands/materials.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4BpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAid/D"}
|