@mo7yw4ng/openape 1.0.5 → 1.0.6

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 (77) hide show
  1. package/README.md +11 -8
  2. package/esm/deno.js +1 -1
  3. package/esm/src/commands/announcements.d.ts.map +1 -1
  4. package/esm/src/commands/announcements.js +22 -85
  5. package/esm/src/commands/assignments.d.ts.map +1 -1
  6. package/esm/src/commands/assignments.js +2 -3
  7. package/esm/src/commands/calendar.d.ts.map +1 -1
  8. package/esm/src/commands/calendar.js +32 -84
  9. package/esm/src/commands/courses.d.ts.map +1 -1
  10. package/esm/src/commands/courses.js +2 -38
  11. package/esm/src/commands/forums.d.ts.map +1 -1
  12. package/esm/src/commands/forums.js +47 -175
  13. package/esm/src/commands/grades.d.ts.map +1 -1
  14. package/esm/src/commands/grades.js +10 -47
  15. package/esm/src/commands/materials.d.ts.map +1 -1
  16. package/esm/src/commands/materials.js +47 -58
  17. package/esm/src/commands/quizzes.d.ts.map +1 -1
  18. package/esm/src/commands/quizzes.js +2 -37
  19. package/esm/src/commands/skills.js +3 -3
  20. package/esm/src/commands/upload.d.ts.map +1 -1
  21. package/esm/src/commands/upload.js +2 -5
  22. package/esm/src/commands/videos.d.ts.map +1 -1
  23. package/esm/src/commands/videos.js +6 -76
  24. package/esm/src/index.d.ts +2 -1
  25. package/esm/src/index.d.ts.map +1 -1
  26. package/esm/src/index.js +5 -1
  27. package/esm/src/lib/auth.d.ts +21 -2
  28. package/esm/src/lib/auth.d.ts.map +1 -1
  29. package/esm/src/lib/auth.js +78 -19
  30. package/esm/src/lib/logger.d.ts +2 -2
  31. package/esm/src/lib/logger.d.ts.map +1 -1
  32. package/esm/src/lib/logger.js +1 -2
  33. package/esm/src/lib/moodle.d.ts +14 -0
  34. package/esm/src/lib/moodle.d.ts.map +1 -1
  35. package/esm/src/lib/moodle.js +35 -0
  36. package/esm/src/lib/utils.d.ts +3 -8
  37. package/esm/src/lib/utils.d.ts.map +1 -1
  38. package/esm/src/lib/utils.js +3 -10
  39. package/package.json +1 -1
  40. package/script/deno.js +1 -1
  41. package/script/src/commands/announcements.d.ts.map +1 -1
  42. package/script/src/commands/announcements.js +23 -89
  43. package/script/src/commands/assignments.d.ts.map +1 -1
  44. package/script/src/commands/assignments.js +2 -3
  45. package/script/src/commands/calendar.d.ts.map +1 -1
  46. package/script/src/commands/calendar.js +33 -85
  47. package/script/src/commands/courses.d.ts.map +1 -1
  48. package/script/src/commands/courses.js +9 -48
  49. package/script/src/commands/forums.d.ts.map +1 -1
  50. package/script/src/commands/forums.js +50 -181
  51. package/script/src/commands/grades.d.ts.map +1 -1
  52. package/script/src/commands/grades.js +14 -54
  53. package/script/src/commands/materials.d.ts.map +1 -1
  54. package/script/src/commands/materials.js +47 -58
  55. package/script/src/commands/quizzes.d.ts.map +1 -1
  56. package/script/src/commands/quizzes.js +11 -49
  57. package/script/src/commands/skills.js +3 -3
  58. package/script/src/commands/upload.d.ts.map +1 -1
  59. package/script/src/commands/upload.js +2 -5
  60. package/script/src/commands/videos.d.ts.map +1 -1
  61. package/script/src/commands/videos.js +11 -81
  62. package/script/src/index.d.ts +2 -1
  63. package/script/src/index.d.ts.map +1 -1
  64. package/script/src/index.js +5 -1
  65. package/script/src/lib/auth.d.ts +21 -2
  66. package/script/src/lib/auth.d.ts.map +1 -1
  67. package/script/src/lib/auth.js +83 -56
  68. package/script/src/lib/logger.d.ts +2 -2
  69. package/script/src/lib/logger.d.ts.map +1 -1
  70. package/script/src/lib/logger.js +1 -2
  71. package/script/src/lib/moodle.d.ts +14 -0
  72. package/script/src/lib/moodle.d.ts.map +1 -1
  73. package/script/src/lib/moodle.js +36 -0
  74. package/script/src/lib/utils.d.ts +3 -8
  75. package/script/src/lib/utils.d.ts.map +1 -1
  76. package/script/src/lib/utils.js +3 -11
  77. package/skills/openape/SKILL.md +6 -6
@@ -1,51 +1,13 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.registerAnnouncementsCommand = registerAnnouncementsCommand;
7
4
  const utils_js_1 = require("../lib/utils.js");
8
5
  const moodle_js_1 = require("../lib/moodle.js");
9
- const logger_js_1 = require("../lib/logger.js");
10
- const token_js_1 = require("../lib/token.js");
11
- const node_path_1 = __importDefault(require("node:path"));
12
- const node_fs_1 = __importDefault(require("node:fs"));
6
+ const auth_js_1 = require("../lib/auth.js");
7
+ const index_js_1 = require("../index.js");
13
8
  function registerAnnouncementsCommand(program) {
14
9
  const announcementsCmd = program.command("announcements");
15
10
  announcementsCmd.description("Announcement operations");
16
- // Helper to get output format from global or local options
17
- function getOutputFormat(command) {
18
- const opts = command.optsWithGlobals();
19
- return opts.output || "json";
20
- }
21
- // Pure API context - no browser required (fast!)
22
- async function createApiContext(options, command) {
23
- const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
24
- const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
25
- const silent = outputFormat === "json" && !opts.verbose;
26
- const log = (0, logger_js_1.createLogger)(opts.verbose, silent, outputFormat);
27
- const baseDir = (0, utils_js_1.getBaseDir)();
28
- const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
29
- // Check if session exists
30
- if (!node_fs_1.default.existsSync(sessionPath)) {
31
- console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
32
- log.info(`Session 預期位置: ${sessionPath}`);
33
- return null;
34
- }
35
- // Try to load WS token
36
- const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
37
- if (!wsToken) {
38
- console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
39
- return null;
40
- }
41
- return {
42
- log,
43
- session: {
44
- wsToken,
45
- moodleBaseUrl: "https://ilearning.cycu.edu.tw",
46
- },
47
- };
48
- }
49
11
  announcementsCmd
50
12
  .command("list-all")
51
13
  .description("List all announcements across all courses")
@@ -54,55 +16,31 @@ function registerAnnouncementsCommand(program) {
54
16
  .option("--limit <n>", "Maximum number of announcements to show", "20")
55
17
  .option("--output <format>", "Output format: json|csv|table|silent")
56
18
  .action(async (options, command) => {
19
+ const output = (0, utils_js_1.getOutputFormat)(command);
57
20
  const limit = parseInt(options.limit, 10);
58
- const apiContext = await createApiContext(options, command);
21
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
59
22
  if (!apiContext) {
60
23
  process.exitCode = 1;
61
24
  return;
62
25
  }
63
- // Get site info to retrieve userid
64
26
  const siteInfo = await (0, moodle_js_1.getSiteInfoApi)(apiContext.session);
65
- // Get messages for the current user
66
27
  const messages = await (0, moodle_js_1.getMessagesApi)(apiContext.session, siteInfo.userid, {
67
28
  limitnum: limit,
68
29
  });
69
- // Convert messages to announcement format
70
30
  const allAnnouncements = messages.map(m => ({
71
- course_id: 0, // Messages don't have courseId
31
+ course_id: 0,
72
32
  course_name: "Notifications",
73
33
  id: m.id,
74
34
  subject: m.subject,
75
35
  author: `User ${m.useridfrom}`,
76
- authorId: m.useridfrom,
77
- createdAt: m.timecreated,
78
- modifiedAt: m.timecreated,
79
- unread: false, // Messages API doesn't provide unread status
80
- forumId: 0,
36
+ author_id: m.useridfrom,
37
+ created_at: (0, utils_js_1.formatTimestamp)(m.timecreated),
38
+ modified_at: (0, utils_js_1.formatTimestamp)(m.timecreated),
39
+ unread: false,
81
40
  }));
82
- // Sort by created date (newest first)
83
- allAnnouncements.sort((a, b) => b.createdAt - a.createdAt);
84
- // Apply limit
85
- let filteredAnnouncements = allAnnouncements.slice(0, limit);
86
- console.log(JSON.stringify({
87
- status: "success",
88
- timestamp: new Date().toISOString(),
89
- level: options.level,
90
- total_announcements: allAnnouncements.length,
91
- shown: filteredAnnouncements.length,
92
- }));
93
- for (const a of filteredAnnouncements) {
94
- console.log(JSON.stringify({
95
- course_id: a.course_id,
96
- course_name: a.course_name,
97
- id: a.id,
98
- subject: a.subject,
99
- author: a.author,
100
- author_id: a.authorId,
101
- created_at: (0, utils_js_1.formatTimestamp)(a.createdAt),
102
- modified_at: (0, utils_js_1.formatTimestamp)(a.modifiedAt),
103
- unread: a.unread,
104
- }));
105
- }
41
+ allAnnouncements.sort((a, b) => b.created_at > a.created_at ? 1 : -1);
42
+ const shown = allAnnouncements.slice(0, limit);
43
+ (0, index_js_1.formatAndOutput)(shown, output, apiContext.log, { status: "success", timestamp: new Date().toISOString(), total_announcements: allAnnouncements.length, shown: shown.length });
106
44
  });
107
45
  announcementsCmd
108
46
  .command("read")
@@ -110,7 +48,8 @@ function registerAnnouncementsCommand(program) {
110
48
  .argument("<announcement-id>", "Discussion ID of the announcement")
111
49
  .option("--output <format>", "Output format: json|csv|table|silent")
112
50
  .action(async (announcementId, options, command) => {
113
- const apiContext = await createApiContext(options, command);
51
+ const output = (0, utils_js_1.getOutputFormat)(command);
52
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
114
53
  if (!apiContext) {
115
54
  process.exitCode = 1;
116
55
  return;
@@ -122,19 +61,14 @@ function registerAnnouncementsCommand(program) {
122
61
  return;
123
62
  }
124
63
  const firstPost = posts[0];
125
- const output = {
126
- status: "success",
127
- timestamp: new Date().toISOString(),
128
- announcement: {
129
- id: announcementId,
130
- subject: firstPost.subject,
131
- author: firstPost.author,
132
- author_id: firstPost.authorId,
133
- created_at: (0, utils_js_1.formatTimestamp)(firstPost.created),
134
- modified_at: (0, utils_js_1.formatTimestamp)(firstPost.modified),
135
- message: firstPost.message,
136
- },
137
- };
138
- console.log(JSON.stringify(output));
64
+ (0, index_js_1.formatAndOutput)({
65
+ id: announcementId,
66
+ subject: firstPost.subject,
67
+ author: firstPost.author,
68
+ author_id: firstPost.authorId,
69
+ created_at: (0, utils_js_1.formatTimestamp)(firstPost.created),
70
+ modified_at: (0, utils_js_1.formatTimestamp)(firstPost.modified),
71
+ message: firstPost.message,
72
+ }, output, apiContext.log);
139
73
  });
140
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"assignments.d.ts","sourceRoot":"","sources":["../../../src/src/commands/assignments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0PjE"}
1
+ {"version":3,"file":"assignments.d.ts","sourceRoot":"","sources":["../../../src/src/commands/assignments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyPjE"}
@@ -197,9 +197,9 @@ function registerAssignmentsCommand(program) {
197
197
  // Upload file if --file option is provided
198
198
  if (options.file) {
199
199
  const resolvedPath = node_path_1.default.resolve(options.file);
200
- // Check if file exists
200
+ let stats;
201
201
  try {
202
- await promises_1.default.access(resolvedPath);
202
+ stats = await promises_1.default.stat(resolvedPath);
203
203
  }
204
204
  catch {
205
205
  const errorResult = {
@@ -210,7 +210,6 @@ function registerAssignmentsCommand(program) {
210
210
  process.exitCode = 1;
211
211
  return;
212
212
  }
213
- const stats = await promises_1.default.stat(resolvedPath);
214
213
  const fileSizeKB = (0, utils_js_1.formatFileSize)(stats.size);
215
214
  const uploadResult = await (0, moodle_js_1.uploadFileApi)(apiContext.session, resolvedPath);
216
215
  if (!uploadResult.success) {
@@ -1 +1 @@
1
- {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/src/commands/calendar.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmM9D"}
1
+ {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/src/commands/calendar.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqJ9D"}
@@ -6,46 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
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
- const logger_js_1 = require("../lib/logger.js");
10
- const token_js_1 = require("../lib/token.js");
11
- const node_path_1 = __importDefault(require("node:path"));
9
+ const auth_js_1 = require("../lib/auth.js");
10
+ const index_js_1 = require("../index.js");
12
11
  const node_fs_1 = __importDefault(require("node:fs"));
13
12
  function registerCalendarCommand(program) {
14
13
  const calendarCmd = program.command("calendar");
15
14
  calendarCmd.description("Calendar operations");
16
- // Helper to get output format from global or local options
17
- function getOutputFormat(command) {
18
- const opts = command.optsWithGlobals();
19
- return opts.output || "json";
20
- }
21
- // Pure API context - no browser required (fast!)
22
- async function createApiContext(options, command) {
23
- const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
24
- const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
25
- const silent = outputFormat === "json" && !opts.verbose;
26
- const log = (0, logger_js_1.createLogger)(opts.verbose, silent, outputFormat);
27
- const baseDir = (0, utils_js_1.getBaseDir)();
28
- const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
29
- // Check if session exists
30
- if (!node_fs_1.default.existsSync(sessionPath)) {
31
- console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
32
- log.info(`Session 預期位置: ${sessionPath}`);
33
- return null;
34
- }
35
- // Try to load WS token
36
- const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
37
- if (!wsToken) {
38
- console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
39
- return null;
40
- }
41
- return {
42
- log,
43
- session: {
44
- wsToken,
45
- moodleBaseUrl: "https://ilearning.cycu.edu.tw",
46
- },
47
- };
48
- }
49
15
  calendarCmd
50
16
  .command("events")
51
17
  .description("List calendar events")
@@ -54,19 +20,18 @@ function registerCalendarCommand(program) {
54
20
  .option("--course <id>", "Filter by course ID")
55
21
  .option("--output <format>", "Output format: json|csv|table|silent")
56
22
  .action(async (options, command) => {
23
+ const output = (0, utils_js_1.getOutputFormat)(command);
57
24
  const days = parseInt(options.days, 10);
58
- const apiContext = await createApiContext(options, command);
25
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
59
26
  if (!apiContext) {
60
27
  process.exitCode = 1;
61
28
  return;
62
29
  }
63
30
  const courses = await (0, moodle_js_1.getEnrolledCoursesApi)(apiContext.session);
64
- // Calculate time range
65
31
  const now = Math.floor(Date.now() / 1000);
66
32
  const endTime = now + (days * 24 * 60 * 60);
67
33
  let allEvents = [];
68
34
  if (options.course) {
69
- // Get events for specific course
70
35
  const courseId = parseInt(options.course, 10);
71
36
  const events = await (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
72
37
  startTime: now,
@@ -75,29 +40,32 @@ function registerCalendarCommand(program) {
75
40
  allEvents = events.filter(e => e.courseid === courseId);
76
41
  }
77
42
  else {
78
- // Get events for all courses
79
- for (const course of courses) {
80
- try {
81
- const events = await (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
82
- courseId: course.id,
83
- startTime: now,
84
- endTime: endTime,
85
- });
86
- allEvents.push(...events);
87
- }
88
- catch (err) {
89
- apiContext.log.debug(`Failed to fetch calendar events for ${course.fullname}: ${err}`);
90
- }
43
+ const results = await Promise.allSettled(courses.map(course => (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
44
+ courseId: course.id,
45
+ startTime: now,
46
+ endTime: endTime,
47
+ })));
48
+ for (const result of results) {
49
+ if (result.status === "fulfilled")
50
+ allEvents.push(...result.value);
91
51
  }
92
52
  }
93
- // Sort by start time
94
53
  allEvents.sort((a, b) => a.timestart - b.timestart);
95
- // Filter upcoming only if requested
96
54
  let filteredEvents = allEvents;
97
55
  if (options.upcoming) {
98
56
  filteredEvents = allEvents.filter(e => e.timestart > now);
99
57
  }
100
- console.log(JSON.stringify({
58
+ const items = filteredEvents.map(e => ({
59
+ id: e.id,
60
+ name: e.name,
61
+ description: e.description,
62
+ course_id: e.courseid,
63
+ event_type: e.eventtype,
64
+ start_time: (0, utils_js_1.formatTimestamp)(e.timestart),
65
+ end_time: e.timeduration ? (0, utils_js_1.formatTimestamp)(e.timestart + Math.floor(e.timeduration / 1000)) : null,
66
+ location: e.location,
67
+ }));
68
+ (0, index_js_1.formatAndOutput)(items, output, apiContext.log, {
101
69
  status: "success",
102
70
  timestamp: new Date().toISOString(),
103
71
  total_events: allEvents.length,
@@ -106,19 +74,7 @@ function registerCalendarCommand(program) {
106
74
  acc[e.eventtype] = (acc[e.eventtype] || 0) + 1;
107
75
  return acc;
108
76
  }, {}),
109
- }));
110
- for (const e of filteredEvents) {
111
- console.log(JSON.stringify({
112
- id: e.id,
113
- name: e.name,
114
- description: e.description,
115
- course_id: e.courseid,
116
- event_type: e.eventtype,
117
- start_time: (0, utils_js_1.formatTimestamp)(e.timestart),
118
- end_time: e.timeduration ? (0, utils_js_1.formatTimestamp)(e.timestart + Math.floor(e.timeduration / 1000)) : null,
119
- location: e.location,
120
- }));
121
- }
77
+ });
122
78
  });
123
79
  calendarCmd
124
80
  .command("export")
@@ -126,33 +82,26 @@ function registerCalendarCommand(program) {
126
82
  .option("--output <path>", "Output file path", "./calendar.json")
127
83
  .option("--days <n>", "Number of days ahead to include", "30")
128
84
  .action(async (options, command) => {
129
- const apiContext = await createApiContext(options, command);
85
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
130
86
  if (!apiContext) {
131
87
  process.exitCode = 1;
132
88
  return;
133
89
  }
134
90
  const courses = await (0, moodle_js_1.getEnrolledCoursesApi)(apiContext.session);
135
- // Calculate time range
136
91
  const now = Math.floor(Date.now() / 1000);
137
92
  const days = parseInt(options.days, 10);
138
93
  const endTime = now + (days * 24 * 60 * 60);
139
94
  const allEvents = [];
140
- for (const course of courses) {
141
- try {
142
- const events = await (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
143
- courseId: course.id,
144
- startTime: now,
145
- endTime: endTime,
146
- });
147
- allEvents.push(...events);
148
- }
149
- catch (err) {
150
- apiContext.log.debug(`Failed to fetch calendar events for ${course.fullname}: ${err}`);
151
- }
95
+ const results = await Promise.allSettled(courses.map(course => (0, moodle_js_1.getCalendarEventsApi)(apiContext.session, {
96
+ courseId: course.id,
97
+ startTime: now,
98
+ endTime: endTime,
99
+ })));
100
+ for (const result of results) {
101
+ if (result.status === "fulfilled")
102
+ allEvents.push(...result.value);
152
103
  }
153
- // Sort by start time
154
104
  allEvents.sort((a, b) => a.timestart - b.timestart);
155
- // Export data
156
105
  const exportData = {
157
106
  exported_at: new Date().toISOString(),
158
107
  time_range: {
@@ -178,7 +127,6 @@ function registerCalendarCommand(program) {
178
127
  }, {}),
179
128
  },
180
129
  };
181
- // Write to file
182
130
  node_fs_1.default.writeFileSync(options.output, JSON.stringify(exportData));
183
131
  apiContext.log.success(`Exported ${allEvents.length} events to ${options.output}`);
184
132
  });
@@ -1 +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"}
1
+ {"version":3,"file":"courses.d.ts","sourceRoot":"","sources":["../../../src/src/commands/courses.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkW7D"}
@@ -1,52 +1,13 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.registerCoursesCommand = registerCoursesCommand;
7
4
  const utils_js_1 = require("../lib/utils.js");
8
5
  const moodle_js_1 = require("../lib/moodle.js");
9
- const logger_js_1 = require("../lib/logger.js");
10
- const token_js_1 = require("../lib/token.js");
6
+ const auth_js_1 = require("../lib/auth.js");
11
7
  const index_js_1 = require("../index.js");
12
- const node_path_1 = __importDefault(require("node:path"));
13
- const node_fs_1 = __importDefault(require("node:fs"));
14
8
  function registerCoursesCommand(program) {
15
9
  const coursesCmd = program.command("courses");
16
10
  coursesCmd.description("Course operations");
17
- // Helper to get output format from global or local options
18
- function getOutputFormat(command) {
19
- const opts = command.optsWithGlobals();
20
- return opts.output || "json";
21
- }
22
- // Pure API context - no browser required (fast!)
23
- async function createApiContext(options, command) {
24
- const opts = command?.optsWithGlobals ? command.optsWithGlobals() : options;
25
- const outputFormat = getOutputFormat(command || { optsWithGlobals: () => ({ output: "json" }) });
26
- const silent = outputFormat === "json" && !opts.verbose;
27
- const log = (0, logger_js_1.createLogger)(opts.verbose, silent, outputFormat);
28
- const baseDir = (0, utils_js_1.getBaseDir)();
29
- const sessionPath = node_path_1.default.resolve(baseDir, ".auth", "storage-state.json");
30
- // Check if session exists
31
- if (!node_fs_1.default.existsSync(sessionPath)) {
32
- console.error("未找到登入 session。請先執行 'openape login' 進行登入。");
33
- log.info(`Session 預期位置: ${sessionPath}`);
34
- return null;
35
- }
36
- // Try to load WS token
37
- const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
38
- if (!wsToken) {
39
- console.error("未找到 WS token。請先執行 'openape login' 進行登入。");
40
- return null;
41
- }
42
- return {
43
- log,
44
- session: {
45
- wsToken,
46
- moodleBaseUrl: "https://ilearning.cycu.edu.tw",
47
- },
48
- };
49
- }
50
11
  coursesCmd
51
12
  .command("list")
52
13
  .description("List enrolled courses")
@@ -54,8 +15,8 @@ function registerCoursesCommand(program) {
54
15
  .option("--output <format>", "Output format: json|csv|table|silent")
55
16
  .option("--level <type>", "Course level: in_progress (default) | past | future | all", "in_progress")
56
17
  .action(async (options, command) => {
57
- const output = getOutputFormat(command);
58
- const apiContext = await createApiContext(options, command);
18
+ const output = (0, utils_js_1.getOutputFormat)(command);
19
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
59
20
  if (!apiContext) {
60
21
  process.exitCode = 1;
61
22
  return;
@@ -79,8 +40,8 @@ function registerCoursesCommand(program) {
79
40
  .argument("<course-id>", "Course ID")
80
41
  .option("--output <format>", "Output format: json|csv|table|silent")
81
42
  .action(async (courseId, options, command) => {
82
- const output = getOutputFormat(command);
83
- const apiContext = await createApiContext(options, command);
43
+ const output = (0, utils_js_1.getOutputFormat)(command);
44
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
84
45
  if (!apiContext) {
85
46
  process.exitCode = 1;
86
47
  return;
@@ -100,8 +61,8 @@ function registerCoursesCommand(program) {
100
61
  .argument("<course-id>", "Course ID")
101
62
  .option("--output <format>", "Output format: json|csv|table|silent")
102
63
  .action(async (courseId, options, command) => {
103
- const output = getOutputFormat(command);
104
- const apiContext = await createApiContext(options, command);
64
+ const output = (0, utils_js_1.getOutputFormat)(command);
65
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
105
66
  if (!apiContext) {
106
67
  process.exitCode = 1;
107
68
  return;
@@ -309,8 +270,8 @@ function registerCoursesCommand(program) {
309
270
  .argument("<course-id>", "Course ID")
310
271
  .option("--output <format>", "Output format: json|csv|table|silent")
311
272
  .action(async (courseId, options, command) => {
312
- const output = getOutputFormat(command);
313
- const apiContext = await createApiContext(options, command);
273
+ const output = (0, utils_js_1.getOutputFormat)(command);
274
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
314
275
  if (!apiContext) {
315
276
  process.exitCode = 1;
316
277
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"forums.d.ts","sourceRoot":"","sources":["../../../src/src/commands/forums.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkX5D"}
1
+ {"version":3,"file":"forums.d.ts","sourceRoot":"","sources":["../../../src/src/commands/forums.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+O5D"}