@mo7yw4ng/openape 1.0.1 → 1.0.3
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 +8 -5
- package/esm/_dnt.polyfills.d.ts +83 -6
- package/esm/_dnt.polyfills.d.ts.map +1 -0
- package/esm/_dnt.polyfills.js +127 -1
- package/esm/_dnt.shims.d.ts +1 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/deno.d.ts +2 -0
- package/esm/deno.d.ts.map +1 -0
- package/esm/deno.js +2 -1
- package/esm/src/commands/announcements.d.ts +3 -0
- package/esm/src/commands/announcements.d.ts.map +1 -0
- package/esm/src/commands/announcements.js +135 -0
- package/esm/src/commands/auth.d.ts +3 -0
- package/esm/src/commands/auth.d.ts.map +1 -0
- package/esm/src/commands/auth.js +260 -0
- package/esm/src/commands/calendar.d.ts +3 -0
- package/esm/src/commands/calendar.d.ts.map +1 -0
- package/esm/src/commands/calendar.js +180 -0
- package/esm/src/commands/courses.d.ts +3 -0
- package/esm/src/commands/courses.d.ts.map +1 -0
- package/esm/src/commands/courses.js +348 -0
- package/esm/src/commands/forums.d.ts +3 -0
- package/esm/src/commands/forums.d.ts.map +1 -0
- package/esm/src/commands/forums.js +226 -0
- package/esm/src/commands/grades.d.ts +3 -0
- package/esm/src/commands/grades.d.ts.map +1 -0
- package/esm/src/commands/grades.js +121 -0
- package/esm/src/commands/materials.d.ts +3 -0
- package/esm/src/commands/materials.d.ts.map +1 -0
- package/esm/src/commands/materials.js +522 -0
- package/esm/src/commands/quizzes.d.ts +3 -0
- package/esm/src/commands/quizzes.d.ts.map +1 -0
- package/esm/src/commands/quizzes.js +160 -0
- package/esm/src/commands/skills.d.ts +3 -0
- package/esm/src/commands/skills.d.ts.map +1 -0
- package/esm/src/commands/skills.js +110 -0
- package/esm/src/commands/videos.d.ts +3 -0
- package/esm/src/commands/videos.d.ts.map +1 -0
- package/esm/src/commands/videos.js +335 -0
- package/esm/src/index.d.ts +27 -0
- package/esm/src/index.d.ts.map +1 -0
- package/esm/src/index.js +149 -0
- package/esm/src/lib/auth.d.ts +25 -0
- package/esm/src/lib/auth.d.ts.map +1 -0
- package/esm/src/lib/auth.js +194 -0
- package/esm/src/lib/config.d.ts +6 -0
- package/esm/src/lib/config.d.ts.map +1 -0
- package/esm/src/lib/config.js +36 -0
- package/esm/src/lib/logger.d.ts +3 -0
- package/esm/src/lib/logger.d.ts.map +1 -0
- package/esm/src/lib/logger.js +24 -0
- package/esm/src/lib/moodle.d.ts +251 -0
- package/esm/src/lib/moodle.d.ts.map +1 -0
- package/esm/src/lib/moodle.js +833 -0
- package/esm/src/lib/session.d.ts +8 -0
- package/esm/src/lib/session.d.ts.map +1 -0
- package/esm/src/lib/session.js +42 -0
- package/esm/src/lib/token.d.ts +38 -0
- package/esm/src/lib/token.d.ts.map +1 -0
- package/esm/src/lib/token.js +178 -0
- package/esm/src/lib/types.d.ts +272 -0
- package/esm/src/lib/types.d.ts.map +1 -0
- package/esm/src/lib/types.js +1 -0
- package/esm/src/lib/utils.d.ts +37 -0
- package/esm/src/lib/utils.d.ts.map +1 -0
- package/esm/src/lib/utils.js +82 -0
- package/package.json +4 -4
- package/script/_dnt.polyfills.d.ts +83 -6
- package/script/_dnt.polyfills.d.ts.map +1 -0
- package/script/_dnt.polyfills.js +128 -0
- package/script/_dnt.shims.d.ts +1 -0
- package/script/_dnt.shims.d.ts.map +1 -0
- package/script/deno.d.ts +2 -0
- package/script/deno.d.ts.map +1 -0
- package/script/deno.js +2 -1
- package/script/src/commands/announcements.d.ts +1 -0
- package/script/src/commands/announcements.d.ts.map +1 -0
- package/script/src/commands/announcements.js +75 -222
- package/script/src/commands/auth.d.ts +2 -1
- package/script/src/commands/auth.d.ts.map +1 -0
- package/script/src/commands/auth.js +52 -24
- package/script/src/commands/calendar.d.ts +1 -0
- package/script/src/commands/calendar.d.ts.map +1 -0
- package/script/src/commands/calendar.js +112 -301
- package/script/src/commands/courses.d.ts +1 -0
- package/script/src/commands/courses.d.ts.map +1 -0
- package/script/src/commands/courses.js +43 -173
- package/script/src/commands/forums.d.ts +1 -0
- package/script/src/commands/forums.d.ts.map +1 -0
- package/script/src/commands/forums.js +145 -316
- package/script/src/commands/grades.d.ts +1 -0
- package/script/src/commands/grades.d.ts.map +1 -0
- package/script/src/commands/grades.js +62 -194
- package/script/src/commands/materials.d.ts +1 -0
- package/script/src/commands/materials.d.ts.map +1 -0
- package/script/src/commands/materials.js +283 -178
- package/script/src/commands/quizzes.d.ts +1 -0
- package/script/src/commands/quizzes.d.ts.map +1 -0
- package/script/src/commands/quizzes.js +40 -102
- package/script/src/commands/skills.d.ts +1 -0
- package/script/src/commands/skills.d.ts.map +1 -0
- package/script/src/commands/skills.js +17 -18
- package/script/src/commands/videos.d.ts +1 -0
- package/script/src/commands/videos.d.ts.map +1 -0
- package/script/src/commands/videos.js +127 -120
- package/script/src/index.d.ts +1 -0
- package/script/src/index.d.ts.map +1 -0
- package/script/src/index.js +5 -5
- package/script/src/lib/auth.d.ts +1 -0
- package/script/src/lib/auth.d.ts.map +1 -0
- package/script/src/lib/auth.js +9 -10
- package/script/src/lib/config.d.ts +1 -0
- package/script/src/lib/config.d.ts.map +1 -0
- package/script/src/lib/config.js +6 -7
- package/script/src/lib/logger.d.ts +1 -0
- package/script/src/lib/logger.d.ts.map +1 -0
- package/script/src/lib/logger.js +1 -2
- package/script/src/lib/moodle.d.ts +72 -55
- package/script/src/lib/moodle.d.ts.map +1 -0
- package/script/src/lib/moodle.js +275 -350
- package/script/src/lib/session.d.ts +1 -0
- package/script/src/lib/session.d.ts.map +1 -0
- package/script/src/lib/session.js +3 -29
- package/script/src/lib/token.d.ts +16 -5
- package/script/src/lib/token.d.ts.map +1 -0
- package/script/src/lib/token.js +71 -36
- package/script/src/lib/types.d.ts +11 -0
- package/script/src/lib/types.d.ts.map +1 -0
- package/script/src/lib/utils.d.ts +32 -0
- package/script/src/lib/utils.d.ts.map +1 -0
- package/script/src/lib/utils.js +93 -13
- package/skills/openape/SKILL.md +6 -26
|
@@ -3,16 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.registerCalendarCommand =
|
|
6
|
+
exports.registerCalendarCommand = registerCalendarCommand;
|
|
7
7
|
const utils_js_1 = require("../lib/utils.js");
|
|
8
8
|
const moodle_js_1 = require("../lib/moodle.js");
|
|
9
9
|
const logger_js_1 = require("../lib/logger.js");
|
|
10
|
-
const auth_js_1 = require("../lib/auth.js");
|
|
11
|
-
const session_js_1 = require("../lib/session.js");
|
|
12
|
-
const auth_js_2 = require("../lib/auth.js");
|
|
13
10
|
const token_js_1 = require("../lib/token.js");
|
|
14
|
-
const
|
|
15
|
-
const
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
16
13
|
function registerCalendarCommand(program) {
|
|
17
14
|
const calendarCmd = program.command("calendar");
|
|
18
15
|
calendarCmd.description("Calendar operations");
|
|
@@ -28,14 +25,17 @@ function registerCalendarCommand(program) {
|
|
|
28
25
|
const silent = outputFormat === "json" && !opts.verbose;
|
|
29
26
|
const log = (0, logger_js_1.createLogger)(opts.verbose, silent);
|
|
30
27
|
const baseDir = (0, utils_js_1.getBaseDir)();
|
|
31
|
-
const sessionPath =
|
|
28
|
+
const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
|
|
32
29
|
// Check if session exists
|
|
33
|
-
if (!
|
|
30
|
+
if (!node_fs_1.default.existsSync(sessionPath)) {
|
|
31
|
+
log.error("未找到登入 session。請先執行 'openape auth login' 進行登入。");
|
|
32
|
+
log.info(`Session 預期位置: ${sessionPath}`);
|
|
34
33
|
return null;
|
|
35
34
|
}
|
|
36
35
|
// Try to load WS token
|
|
37
36
|
const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
|
|
38
37
|
if (!wsToken) {
|
|
38
|
+
log.error("未找到 WS token。請先執行 'openape auth login' 進行登入。");
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
return {
|
|
@@ -46,46 +46,6 @@ function registerCalendarCommand(program) {
|
|
|
46
46
|
},
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
// Helper function to create session context
|
|
50
|
-
async function createSessionContext(options, command) {
|
|
51
|
-
// Get global options if command is provided (for --verbose, --silent flags)
|
|
52
|
-
const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
|
|
53
|
-
// Auto-enable silent mode for JSON output (unless --verbose is also set)
|
|
54
|
-
const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
|
|
55
|
-
const silent = outputFormat === "json" && !opts.verbose;
|
|
56
|
-
const log = (0, logger_js_1.createLogger)(opts.verbose, silent);
|
|
57
|
-
// Determine session path
|
|
58
|
-
const baseDir = (0, utils_js_1.getBaseDir)();
|
|
59
|
-
const sessionPath = path_1.default.resolve(baseDir, ".auth", "storage-state.json");
|
|
60
|
-
// Check if session exists
|
|
61
|
-
if (!fs_1.default.existsSync(sessionPath)) {
|
|
62
|
-
log.error("未找到登入 session。請先執行 'openape auth login' 進行登入。");
|
|
63
|
-
log.info(`Session 預期位置: ${sessionPath}`);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
// Create minimal config
|
|
67
|
-
const config = {
|
|
68
|
-
username: "",
|
|
69
|
-
password: "",
|
|
70
|
-
courseUrl: "",
|
|
71
|
-
moodleBaseUrl: "https://ilearning.cycu.edu.tw",
|
|
72
|
-
headless: !options.headed,
|
|
73
|
-
slowMo: 0,
|
|
74
|
-
authStatePath: sessionPath,
|
|
75
|
-
ollamaBaseUrl: "",
|
|
76
|
-
};
|
|
77
|
-
log.info("啟動瀏覽器...");
|
|
78
|
-
const { browser, context, page } = await (0, auth_js_1.launchAuthenticated)(config, log);
|
|
79
|
-
try {
|
|
80
|
-
const session = await (0, session_js_1.extractSessionInfo)(page, config, log);
|
|
81
|
-
return { log, page, session, browser, context };
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
await context.close();
|
|
85
|
-
await browser.close();
|
|
86
|
-
throw err;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
49
|
calendarCmd
|
|
90
50
|
.command("events")
|
|
91
51
|
.description("List calendar events")
|
|
@@ -95,150 +55,71 @@ function registerCalendarCommand(program) {
|
|
|
95
55
|
.option("--output <format>", "Output format: json|csv|table|silent")
|
|
96
56
|
.action(async (options, command) => {
|
|
97
57
|
const days = parseInt(options.days, 10);
|
|
98
|
-
// Try pure API mode (no browser, fast!)
|
|
99
58
|
const apiContext = await createApiContext(options, command);
|
|
100
|
-
if (apiContext) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
59
|
+
if (!apiContext) {
|
|
60
|
+
process.exitCode = 1;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const courses = await (0, moodle_js_1.getEnrolledCoursesApi)(apiContext.session);
|
|
64
|
+
// Calculate time range
|
|
65
|
+
const now = Math.floor(Date.now() / 1000);
|
|
66
|
+
const endTime = now + (days * 24 * 60 * 60);
|
|
67
|
+
let allEvents = [];
|
|
68
|
+
if (options.course) {
|
|
69
|
+
// Get events for specific course
|
|
70
|
+
const courseId = parseInt(options.course, 10);
|
|
71
|
+
const events = await (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
|
|
72
|
+
startTime: now,
|
|
73
|
+
endTime: endTime,
|
|
74
|
+
});
|
|
75
|
+
allEvents = events.filter(e => e.courseid === courseId);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Get events for all courses
|
|
79
|
+
for (const course of courses) {
|
|
80
|
+
try {
|
|
110
81
|
const events = await (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
|
|
82
|
+
courseId: course.id,
|
|
111
83
|
startTime: now,
|
|
112
84
|
endTime: endTime,
|
|
113
85
|
});
|
|
114
|
-
allEvents
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
// Get events for all courses
|
|
118
|
-
for (const course of courses) {
|
|
119
|
-
try {
|
|
120
|
-
const events = await (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
|
|
121
|
-
courseId: course.id,
|
|
122
|
-
startTime: now,
|
|
123
|
-
endTime: endTime,
|
|
124
|
-
});
|
|
125
|
-
allEvents.push(...events);
|
|
126
|
-
}
|
|
127
|
-
catch (err) {
|
|
128
|
-
apiContext.log.debug(`Failed to fetch calendar events for ${course.fullname}: ${err}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// Sort by start time
|
|
133
|
-
allEvents.sort((a, b) => a.timestart - b.timestart);
|
|
134
|
-
// Filter upcoming only if requested
|
|
135
|
-
let filteredEvents = allEvents;
|
|
136
|
-
if (options.upcoming) {
|
|
137
|
-
filteredEvents = allEvents.filter(e => e.timestart > now);
|
|
86
|
+
allEvents.push(...events);
|
|
138
87
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
timestamp: new Date().toISOString(),
|
|
142
|
-
events: filteredEvents.map(e => ({
|
|
143
|
-
id: e.id,
|
|
144
|
-
name: e.name,
|
|
145
|
-
description: e.description,
|
|
146
|
-
course_id: e.courseid,
|
|
147
|
-
event_type: e.eventtype,
|
|
148
|
-
start_time: new Date(e.timestart).toISOString(),
|
|
149
|
-
end_time: e.timeduration ? new Date(e.timestart + e.timeduration / 1000).toISOString() : null,
|
|
150
|
-
location: e.location,
|
|
151
|
-
})),
|
|
152
|
-
summary: {
|
|
153
|
-
total_events: allEvents.length,
|
|
154
|
-
upcoming: allEvents.filter(e => e.timestart > now).length,
|
|
155
|
-
by_type: allEvents.reduce((acc, e) => {
|
|
156
|
-
acc[e.eventtype] = (acc[e.eventtype] || 0) + 1;
|
|
157
|
-
return acc;
|
|
158
|
-
}, {}),
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
console.log(JSON.stringify(output));
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
catch (e) {
|
|
165
|
-
// API failed, fall through to browser mode
|
|
166
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
167
|
-
console.error(`// API mode failed: ${msg}, trying browser mode...`);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
// Fallback to browser mode
|
|
171
|
-
const context = await createSessionContext(options, command);
|
|
172
|
-
if (!context) {
|
|
173
|
-
process.exitCode = 1;
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
const { log, page, session, browser, context: browserContext } = context;
|
|
177
|
-
try {
|
|
178
|
-
const courses = await (0, moodle_js_1.getEnrolledCourses)(page, session, log);
|
|
179
|
-
// Calculate time range
|
|
180
|
-
const now = Math.floor(Date.now() / 1000);
|
|
181
|
-
const endTime = now + (days * 24 * 60 * 60);
|
|
182
|
-
let allEvents = [];
|
|
183
|
-
if (options.course) {
|
|
184
|
-
// Get events for specific course
|
|
185
|
-
const courseId = parseInt(options.course, 10);
|
|
186
|
-
const events = await (0, moodle_js_1.getCalendarEvents)(page, session, {
|
|
187
|
-
startTime: now,
|
|
188
|
-
endTime: endTime,
|
|
189
|
-
});
|
|
190
|
-
allEvents = events.filter(e => e.courseid === courseId);
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
// Get events for all courses
|
|
194
|
-
for (const course of courses) {
|
|
195
|
-
try {
|
|
196
|
-
const events = await (0, moodle_js_1.getCalendarEvents)(page, session, {
|
|
197
|
-
courseId: course.id,
|
|
198
|
-
startTime: now,
|
|
199
|
-
endTime: endTime,
|
|
200
|
-
});
|
|
201
|
-
allEvents.push(...events);
|
|
202
|
-
}
|
|
203
|
-
catch (err) {
|
|
204
|
-
log.debug(`Failed to fetch calendar events for ${course.fullname}: ${err}`);
|
|
205
|
-
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
apiContext.log.debug(`Failed to fetch calendar events for ${course.fullname}: ${err}`);
|
|
206
90
|
}
|
|
207
91
|
}
|
|
208
|
-
// Sort by start time
|
|
209
|
-
allEvents.sort((a, b) => a.timestart - b.timestart);
|
|
210
|
-
// Filter upcoming only if requested
|
|
211
|
-
let filteredEvents = allEvents;
|
|
212
|
-
if (options.upcoming) {
|
|
213
|
-
filteredEvents = allEvents.filter(e => e.timestart > now);
|
|
214
|
-
}
|
|
215
|
-
const output = {
|
|
216
|
-
status: "success",
|
|
217
|
-
timestamp: new Date().toISOString(),
|
|
218
|
-
events: filteredEvents.map(e => ({
|
|
219
|
-
id: e.id,
|
|
220
|
-
name: e.name,
|
|
221
|
-
description: e.description,
|
|
222
|
-
course_id: e.courseid,
|
|
223
|
-
event_type: e.eventtype,
|
|
224
|
-
start_time: new Date(e.timestart).toISOString(),
|
|
225
|
-
end_time: e.timeduration ? new Date(e.timestart + e.timeduration / 1000).toISOString() : null,
|
|
226
|
-
location: e.location,
|
|
227
|
-
})),
|
|
228
|
-
summary: {
|
|
229
|
-
total_events: allEvents.length,
|
|
230
|
-
upcoming: allEvents.filter(e => e.timestart > now).length,
|
|
231
|
-
by_type: allEvents.reduce((acc, e) => {
|
|
232
|
-
acc[e.eventtype] = (acc[e.eventtype] || 0) + 1;
|
|
233
|
-
return acc;
|
|
234
|
-
}, {}),
|
|
235
|
-
},
|
|
236
|
-
};
|
|
237
|
-
console.log(JSON.stringify(output));
|
|
238
92
|
}
|
|
239
|
-
|
|
240
|
-
|
|
93
|
+
// Sort by start time
|
|
94
|
+
allEvents.sort((a, b) => a.timestart - b.timestart);
|
|
95
|
+
// Filter upcoming only if requested
|
|
96
|
+
let filteredEvents = allEvents;
|
|
97
|
+
if (options.upcoming) {
|
|
98
|
+
filteredEvents = allEvents.filter(e => e.timestart > now);
|
|
241
99
|
}
|
|
100
|
+
const output = {
|
|
101
|
+
status: "success",
|
|
102
|
+
timestamp: new Date().toISOString(),
|
|
103
|
+
events: filteredEvents.map(e => ({
|
|
104
|
+
id: e.id,
|
|
105
|
+
name: e.name,
|
|
106
|
+
description: e.description,
|
|
107
|
+
course_id: e.courseid,
|
|
108
|
+
event_type: e.eventtype,
|
|
109
|
+
start_time: new Date(e.timestart).toISOString(),
|
|
110
|
+
end_time: e.timeduration ? new Date(e.timestart + e.timeduration / 1000).toISOString() : null,
|
|
111
|
+
location: e.location,
|
|
112
|
+
})),
|
|
113
|
+
summary: {
|
|
114
|
+
total_events: allEvents.length,
|
|
115
|
+
upcoming: allEvents.filter(e => e.timestart > now).length,
|
|
116
|
+
by_type: allEvents.reduce((acc, e) => {
|
|
117
|
+
acc[e.eventtype] = (acc[e.eventtype] || 0) + 1;
|
|
118
|
+
return acc;
|
|
119
|
+
}, {}),
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
console.log(JSON.stringify(output));
|
|
242
123
|
});
|
|
243
124
|
calendarCmd
|
|
244
125
|
.command("export")
|
|
@@ -246,130 +127,60 @@ function registerCalendarCommand(program) {
|
|
|
246
127
|
.option("--output <path>", "Output file path", "./calendar.json")
|
|
247
128
|
.option("--days <n>", "Number of days ahead to include", "30")
|
|
248
129
|
.action(async (options, command) => {
|
|
249
|
-
// Try pure API mode (no browser, fast!)
|
|
250
130
|
const apiContext = await createApiContext(options, command);
|
|
251
|
-
if (apiContext) {
|
|
252
|
-
try {
|
|
253
|
-
const courses = await (0, moodle_js_1.getEnrolledCoursesApi)(apiContext.session);
|
|
254
|
-
// Calculate time range
|
|
255
|
-
const now = Math.floor(Date.now() / 1000);
|
|
256
|
-
const days = parseInt(options.days, 10);
|
|
257
|
-
const endTime = now + (days * 24 * 60 * 60);
|
|
258
|
-
const allEvents = [];
|
|
259
|
-
for (const course of courses) {
|
|
260
|
-
try {
|
|
261
|
-
const events = await (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
|
|
262
|
-
courseId: course.id,
|
|
263
|
-
startTime: now,
|
|
264
|
-
endTime: endTime,
|
|
265
|
-
});
|
|
266
|
-
allEvents.push(...events);
|
|
267
|
-
}
|
|
268
|
-
catch (err) {
|
|
269
|
-
apiContext.log.debug(`Failed to fetch calendar events for ${course.fullname}: ${err}`);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
// Sort by start time
|
|
273
|
-
allEvents.sort((a, b) => a.timestart - b.timestart);
|
|
274
|
-
// Export data
|
|
275
|
-
const exportData = {
|
|
276
|
-
exported_at: new Date().toISOString(),
|
|
277
|
-
time_range: {
|
|
278
|
-
start: new Date(now * 1000).toISOString(),
|
|
279
|
-
end: new Date(endTime * 1000).toISOString(),
|
|
280
|
-
days: days,
|
|
281
|
-
},
|
|
282
|
-
events: allEvents.map(e => ({
|
|
283
|
-
id: e.id,
|
|
284
|
-
name: e.name,
|
|
285
|
-
description: e.description,
|
|
286
|
-
course_id: e.courseid,
|
|
287
|
-
event_type: e.eventtype,
|
|
288
|
-
start_time: new Date(e.timestart).toISOString(),
|
|
289
|
-
end_time: e.timeduration ? new Date(e.timestart + e.timeduration / 1000).toISOString() : null,
|
|
290
|
-
location: e.location,
|
|
291
|
-
})),
|
|
292
|
-
summary: {
|
|
293
|
-
total_events: allEvents.length,
|
|
294
|
-
by_type: allEvents.reduce((acc, e) => {
|
|
295
|
-
acc[e.eventtype] = (acc[e.eventtype] || 0) + 1;
|
|
296
|
-
return acc;
|
|
297
|
-
}, {}),
|
|
298
|
-
},
|
|
299
|
-
};
|
|
300
|
-
// Write to file
|
|
301
|
-
fs_1.default.writeFileSync(options.output, JSON.stringify(exportData));
|
|
302
|
-
apiContext.log.success(`Exported ${allEvents.length} events to ${options.output}`);
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
catch (e) {
|
|
306
|
-
// API failed, fall through to browser mode
|
|
307
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
308
|
-
console.error(`// API mode failed: ${msg}, trying browser mode...`);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
// Fallback to browser mode
|
|
312
|
-
const context = await createSessionContext(options, command);
|
|
313
|
-
if (!context) {
|
|
131
|
+
if (!apiContext) {
|
|
314
132
|
process.exitCode = 1;
|
|
315
133
|
return;
|
|
316
134
|
}
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
catch (err) {
|
|
335
|
-
log.debug(`Failed to fetch calendar events for ${course.fullname}: ${err}`);
|
|
336
|
-
}
|
|
135
|
+
const courses = await (0, moodle_js_1.getEnrolledCoursesApi)(apiContext.session);
|
|
136
|
+
// Calculate time range
|
|
137
|
+
const now = Math.floor(Date.now() / 1000);
|
|
138
|
+
const days = parseInt(options.days, 10);
|
|
139
|
+
const endTime = now + (days * 24 * 60 * 60);
|
|
140
|
+
const allEvents = [];
|
|
141
|
+
for (const course of courses) {
|
|
142
|
+
try {
|
|
143
|
+
const events = await (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
|
|
144
|
+
courseId: course.id,
|
|
145
|
+
startTime: now,
|
|
146
|
+
endTime: endTime,
|
|
147
|
+
});
|
|
148
|
+
allEvents.push(...events);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
apiContext.log.debug(`Failed to fetch calendar events for ${course.fullname}: ${err}`);
|
|
337
152
|
}
|
|
338
|
-
// Sort by start time
|
|
339
|
-
allEvents.sort((a, b) => a.timestart - b.timestart);
|
|
340
|
-
// Export data
|
|
341
|
-
const exportData = {
|
|
342
|
-
exported_at: new Date().toISOString(),
|
|
343
|
-
time_range: {
|
|
344
|
-
start: new Date(now * 1000).toISOString(),
|
|
345
|
-
end: new Date(endTime * 1000).toISOString(),
|
|
346
|
-
days: days,
|
|
347
|
-
},
|
|
348
|
-
events: allEvents.map(e => ({
|
|
349
|
-
id: e.id,
|
|
350
|
-
name: e.name,
|
|
351
|
-
description: e.description,
|
|
352
|
-
course_id: e.courseid,
|
|
353
|
-
event_type: e.eventtype,
|
|
354
|
-
start_time: new Date(e.timestart).toISOString(),
|
|
355
|
-
end_time: e.timeduration ? new Date(e.timestart + e.timeduration / 1000).toISOString() : null,
|
|
356
|
-
location: e.location,
|
|
357
|
-
})),
|
|
358
|
-
summary: {
|
|
359
|
-
total_events: allEvents.length,
|
|
360
|
-
by_type: allEvents.reduce((acc, e) => {
|
|
361
|
-
acc[e.eventtype] = (acc[e.eventtype] || 0) + 1;
|
|
362
|
-
return acc;
|
|
363
|
-
}, {}),
|
|
364
|
-
},
|
|
365
|
-
};
|
|
366
|
-
// Write to file
|
|
367
|
-
fs_1.default.writeFileSync(options.output, JSON.stringify(exportData));
|
|
368
|
-
log.success(`Exported ${allEvents.length} events to ${options.output}`);
|
|
369
|
-
}
|
|
370
|
-
finally {
|
|
371
|
-
await (0, auth_js_2.closeBrowserSafely)(browser, browserContext);
|
|
372
153
|
}
|
|
154
|
+
// Sort by start time
|
|
155
|
+
allEvents.sort((a, b) => a.timestart - b.timestart);
|
|
156
|
+
// Export data
|
|
157
|
+
const exportData = {
|
|
158
|
+
exported_at: new Date().toISOString(),
|
|
159
|
+
time_range: {
|
|
160
|
+
start: new Date(now * 1000).toISOString(),
|
|
161
|
+
end: new Date(endTime * 1000).toISOString(),
|
|
162
|
+
days: days,
|
|
163
|
+
},
|
|
164
|
+
events: allEvents.map(e => ({
|
|
165
|
+
id: e.id,
|
|
166
|
+
name: e.name,
|
|
167
|
+
description: e.description,
|
|
168
|
+
course_id: e.courseid,
|
|
169
|
+
event_type: e.eventtype,
|
|
170
|
+
start_time: new Date(e.timestart).toISOString(),
|
|
171
|
+
end_time: e.timeduration ? new Date(e.timestart + e.timeduration / 1000).toISOString() : null,
|
|
172
|
+
location: e.location,
|
|
173
|
+
})),
|
|
174
|
+
summary: {
|
|
175
|
+
total_events: allEvents.length,
|
|
176
|
+
by_type: allEvents.reduce((acc, e) => {
|
|
177
|
+
acc[e.eventtype] = (acc[e.eventtype] || 0) + 1;
|
|
178
|
+
return acc;
|
|
179
|
+
}, {}),
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
// Write to file
|
|
183
|
+
node_fs_1.default.writeFileSync(options.output, JSON.stringify(exportData));
|
|
184
|
+
apiContext.log.success(`Exported ${allEvents.length} events to ${options.output}`);
|
|
373
185
|
});
|
|
374
186
|
}
|
|
375
|
-
exports.registerCalendarCommand = registerCalendarCommand;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"courses.d.ts","sourceRoot":"","sources":["../../../src/src/commands/courses.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4Y7D"}
|