@mo7yw4ng/openape 1.0.2 → 1.0.4

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 (81) hide show
  1. package/README.md +37 -9
  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 +13 -14
  5. package/esm/src/commands/assignments.d.ts +3 -0
  6. package/esm/src/commands/assignments.d.ts.map +1 -0
  7. package/esm/src/commands/assignments.js +230 -0
  8. package/esm/src/commands/auth.d.ts +1 -1
  9. package/esm/src/commands/auth.d.ts.map +1 -1
  10. package/esm/src/commands/auth.js +24 -8
  11. package/esm/src/commands/calendar.d.ts.map +1 -1
  12. package/esm/src/commands/calendar.js +17 -18
  13. package/esm/src/commands/courses.js +3 -3
  14. package/esm/src/commands/forums.d.ts.map +1 -1
  15. package/esm/src/commands/forums.js +132 -45
  16. package/esm/src/commands/materials.d.ts.map +1 -1
  17. package/esm/src/commands/materials.js +176 -48
  18. package/esm/src/commands/quizzes.d.ts.map +1 -1
  19. package/esm/src/commands/quizzes.js +165 -65
  20. package/esm/src/commands/skills.d.ts.map +1 -1
  21. package/esm/src/commands/skills.js +4 -8
  22. package/esm/src/commands/upload.d.ts +3 -0
  23. package/esm/src/commands/upload.d.ts.map +1 -0
  24. package/esm/src/commands/upload.js +58 -0
  25. package/esm/src/commands/videos.d.ts.map +1 -1
  26. package/esm/src/commands/videos.js +113 -79
  27. package/esm/src/index.d.ts.map +1 -1
  28. package/esm/src/index.js +14 -3
  29. package/esm/src/lib/auth.d.ts +23 -1
  30. package/esm/src/lib/auth.d.ts.map +1 -1
  31. package/esm/src/lib/auth.js +36 -3
  32. package/esm/src/lib/moodle.d.ts +226 -2
  33. package/esm/src/lib/moodle.d.ts.map +1 -1
  34. package/esm/src/lib/moodle.js +648 -37
  35. package/esm/src/lib/types.d.ts +82 -164
  36. package/esm/src/lib/types.d.ts.map +1 -1
  37. package/esm/src/lib/types.js +1 -0
  38. package/esm/src/lib/utils.d.ts +40 -0
  39. package/esm/src/lib/utils.d.ts.map +1 -1
  40. package/esm/src/lib/utils.js +82 -4
  41. package/package.json +1 -2
  42. package/script/deno.js +1 -1
  43. package/script/src/commands/announcements.d.ts.map +1 -1
  44. package/script/src/commands/announcements.js +12 -13
  45. package/script/src/commands/assignments.d.ts +3 -0
  46. package/script/src/commands/assignments.d.ts.map +1 -0
  47. package/script/src/commands/assignments.js +269 -0
  48. package/script/src/commands/auth.d.ts +1 -1
  49. package/script/src/commands/auth.d.ts.map +1 -1
  50. package/script/src/commands/auth.js +24 -8
  51. package/script/src/commands/calendar.d.ts.map +1 -1
  52. package/script/src/commands/calendar.js +16 -17
  53. package/script/src/commands/courses.js +2 -2
  54. package/script/src/commands/forums.d.ts.map +1 -1
  55. package/script/src/commands/forums.js +132 -45
  56. package/script/src/commands/materials.d.ts.map +1 -1
  57. package/script/src/commands/materials.js +177 -49
  58. package/script/src/commands/quizzes.d.ts.map +1 -1
  59. package/script/src/commands/quizzes.js +163 -63
  60. package/script/src/commands/skills.d.ts.map +1 -1
  61. package/script/src/commands/skills.js +4 -8
  62. package/script/src/commands/upload.d.ts +3 -0
  63. package/script/src/commands/upload.d.ts.map +1 -0
  64. package/script/src/commands/upload.js +64 -0
  65. package/script/src/commands/videos.d.ts.map +1 -1
  66. package/script/src/commands/videos.js +114 -80
  67. package/script/src/index.d.ts.map +1 -1
  68. package/script/src/index.js +13 -2
  69. package/script/src/lib/auth.d.ts +23 -1
  70. package/script/src/lib/auth.d.ts.map +1 -1
  71. package/script/src/lib/auth.js +70 -3
  72. package/script/src/lib/moodle.d.ts +226 -2
  73. package/script/src/lib/moodle.d.ts.map +1 -1
  74. package/script/src/lib/moodle.js +663 -37
  75. package/script/src/lib/types.d.ts +82 -164
  76. package/script/src/lib/types.d.ts.map +1 -1
  77. package/script/src/lib/types.js +1 -0
  78. package/script/src/lib/utils.d.ts +40 -0
  79. package/script/src/lib/utils.d.ts.map +1 -1
  80. package/script/src/lib/utils.js +89 -3
  81. package/skills/openape/SKILL.md +73 -291
@@ -0,0 +1,269 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.registerAssignmentsCommand = registerAssignmentsCommand;
40
+ const utils_js_1 = require("../lib/utils.js");
41
+ const moodle_js_1 = require("../lib/moodle.js");
42
+ const auth_js_1 = require("../lib/auth.js");
43
+ const index_js_1 = require("../index.js");
44
+ const node_path_1 = __importDefault(require("node:path"));
45
+ const promises_1 = __importDefault(require("node:fs/promises"));
46
+ function registerAssignmentsCommand(program) {
47
+ const assignmentsCmd = program.command("assignments");
48
+ assignmentsCmd.description("Assignment operations");
49
+ assignmentsCmd
50
+ .command("list")
51
+ .description("List assignments in a course")
52
+ .argument("<course-id>", "Course ID")
53
+ .option("--output <format>", "Output format: json|csv|table|silent")
54
+ .action(async (courseId, options, command) => {
55
+ const output = (0, utils_js_1.getOutputFormat)(command);
56
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
57
+ if (!apiContext) {
58
+ process.exitCode = 1;
59
+ return;
60
+ }
61
+ const apiAssignments = await (0, moodle_js_1.getAssignmentsByCoursesApi)(apiContext.session, [parseInt(courseId, 10)]);
62
+ const assignments = apiAssignments.map(a => ({
63
+ id: a.id,
64
+ courseName: courseId,
65
+ name: a.name,
66
+ url: a.url,
67
+ cmid: a.cmid,
68
+ duedate: (0, utils_js_1.formatMoodleDate)(a.duedate),
69
+ cutoffdate: (0, utils_js_1.formatMoodleDate)(a.cutoffdate),
70
+ allowSubmissionsFromDate: (0, utils_js_1.formatMoodleDate)(a.allowSubmissionsFromDate),
71
+ }));
72
+ apiContext.log.info(`\n找到 ${assignments.length} 個作業。`);
73
+ (0, index_js_1.formatAndOutput)(assignments, output, apiContext.log);
74
+ });
75
+ assignmentsCmd
76
+ .command("list-all")
77
+ .description("List all assignments across all courses")
78
+ .option("--level <type>", "Course level: in_progress (default) | all", "in_progress")
79
+ .option("--output <format>", "Output format: json|csv|table|silent")
80
+ .action(async (options, command) => {
81
+ const output = (0, utils_js_1.getOutputFormat)(command);
82
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
83
+ if (!apiContext) {
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ const classification = options.level === "all" ? undefined : "inprogress";
88
+ const courses = await (0, moodle_js_1.getEnrolledCoursesApi)(apiContext.session, {
89
+ classification,
90
+ });
91
+ // Get assignments via WS API (no browser needed!)
92
+ const courseIds = courses.map(c => c.id);
93
+ const apiAssignments = await (0, moodle_js_1.getAssignmentsByCoursesApi)(apiContext.session, courseIds);
94
+ // Build a map of courseId -> course for quick lookup
95
+ const courseMap = new Map(courses.map(c => [c.id, c]));
96
+ const allAssignments = [];
97
+ for (const a of apiAssignments) {
98
+ const course = courseMap.get(a.courseId);
99
+ if (course) {
100
+ allAssignments.push({
101
+ id: a.id,
102
+ courseName: course.fullname,
103
+ name: a.name,
104
+ url: a.url,
105
+ cmid: a.cmid,
106
+ duedate: (0, utils_js_1.formatMoodleDate)(a.duedate),
107
+ cutoffdate: (0, utils_js_1.formatMoodleDate)(a.cutoffdate),
108
+ allowSubmissionsFromDate: (0, utils_js_1.formatMoodleDate)(a.allowSubmissionsFromDate),
109
+ });
110
+ }
111
+ }
112
+ apiContext.log.info(`\n總計發現 ${allAssignments.length} 個作業。`);
113
+ (0, index_js_1.formatAndOutput)(allAssignments, output, apiContext.log);
114
+ });
115
+ // ── Submission Status ───────────────────────────────────────────────────────
116
+ assignmentsCmd
117
+ .command("status")
118
+ .description("Check assignment submission status")
119
+ .argument("<assignment-id>", "Assignment instance ID (from list-all)")
120
+ .option("--output <format>", "Output format: json|csv|table|silent")
121
+ .action(async (assignmentId, options, command) => {
122
+ const output = (0, utils_js_1.getOutputFormat)(command);
123
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
124
+ if (!apiContext) {
125
+ process.exitCode = 1;
126
+ return;
127
+ }
128
+ const id = parseInt(assignmentId, 10);
129
+ apiContext.log.info("檢查繳交狀態...");
130
+ const status = await (0, moodle_js_1.getSubmissionStatusApi)(apiContext.session, id);
131
+ // Build status data object
132
+ const statusData = {
133
+ submitted: status.submitted,
134
+ submitted_text: status.submitted ? "已繳交" : "尚未繳交",
135
+ graded: status.graded,
136
+ graded_text: status.graded ? "已評分" : "尚未評分",
137
+ last_modified: status.lastModified ? new Date(status.lastModified * 1000).toISOString() : null,
138
+ last_modified_text: status.lastModified ? new Date(status.lastModified * 1000).toLocaleString("zh-TW") : null,
139
+ grader: status.grader,
140
+ grade: status.grade,
141
+ feedback: status.feedback,
142
+ files: status.extensions.map(f => ({
143
+ filename: f.filename,
144
+ filesize: f.filesize,
145
+ filesize_kb: (0, utils_js_1.formatFileSize)(f.filesize),
146
+ })),
147
+ };
148
+ (0, index_js_1.formatAndOutput)(statusData, output, apiContext.log);
149
+ });
150
+ // ── Submit Assignment ────────────────────────────────────────────────────────
151
+ assignmentsCmd
152
+ .command("submit")
153
+ .description("Submit an assignment (online text or file)")
154
+ .argument("<assignment-id>", "Assignment instance ID (from list-all)")
155
+ .option("--text <content>", "Online text content to submit")
156
+ .option("--file-id <id>", "Draft file ID from file upload")
157
+ .option("--file <path>", "Upload and submit a file directly")
158
+ .option("--output <format>", "Output format: json|csv|table|silent")
159
+ .action(async (assignmentId, options, command) => {
160
+ const output = (0, utils_js_1.getOutputFormat)(command);
161
+ const apiContext = await (0, auth_js_1.createApiContext)(options, command);
162
+ if (!apiContext) {
163
+ process.exitCode = 1;
164
+ return;
165
+ }
166
+ const id = parseInt(assignmentId, 10);
167
+ // Check submission status first
168
+ const status = await (0, moodle_js_1.getSubmissionStatusApi)(apiContext.session, id);
169
+ let fileUploaded;
170
+ let cancelled = false;
171
+ if (status.submitted) {
172
+ const confirm = await promptConfirm("此作業已經繳交!確定要重新繳交嗎?(y/N): ");
173
+ if (!confirm) {
174
+ cancelled = true;
175
+ }
176
+ }
177
+ if (cancelled) {
178
+ const cancelResult = {
179
+ success: false,
180
+ cancelled: true,
181
+ message: "Submission cancelled by user",
182
+ };
183
+ (0, index_js_1.formatAndOutput)(cancelResult, output, apiContext.log);
184
+ return;
185
+ }
186
+ // Validate options
187
+ if (!options.text && !options.fileId && !options.file) {
188
+ const errorResult = {
189
+ success: false,
190
+ error: "請提供 --text、--file-id 或 --file 選項。",
191
+ };
192
+ (0, index_js_1.formatAndOutput)(errorResult, output, apiContext.log);
193
+ process.exitCode = 1;
194
+ return;
195
+ }
196
+ let fileId = options.fileId ? parseInt(options.fileId, 10) : undefined;
197
+ // Upload file if --file option is provided
198
+ if (options.file) {
199
+ const resolvedPath = node_path_1.default.resolve(options.file);
200
+ // Check if file exists
201
+ try {
202
+ await promises_1.default.access(resolvedPath);
203
+ }
204
+ catch {
205
+ const errorResult = {
206
+ success: false,
207
+ error: `檔案不存在: ${options.file}`,
208
+ };
209
+ (0, index_js_1.formatAndOutput)(errorResult, output, apiContext.log);
210
+ process.exitCode = 1;
211
+ return;
212
+ }
213
+ const stats = await promises_1.default.stat(resolvedPath);
214
+ const fileSizeKB = (0, utils_js_1.formatFileSize)(stats.size);
215
+ const uploadResult = await (0, moodle_js_1.uploadFileApi)(apiContext.session, resolvedPath);
216
+ if (!uploadResult.success) {
217
+ const errorResult = {
218
+ success: false,
219
+ error: `檔案上傳失敗: ${uploadResult.error}`,
220
+ };
221
+ (0, index_js_1.formatAndOutput)(errorResult, output, apiContext.log);
222
+ process.exitCode = 1;
223
+ return;
224
+ }
225
+ fileId = uploadResult.draftId;
226
+ fileUploaded = {
227
+ filename: node_path_1.default.basename(resolvedPath),
228
+ filesize: stats.size,
229
+ filesize_kb: (0, utils_js_1.formatFileSize)(stats.size),
230
+ draft_id: fileId,
231
+ };
232
+ }
233
+ // Submit
234
+ const result = await (0, moodle_js_1.saveSubmissionApi)(apiContext.session, id, {
235
+ onlineText: options.text ? { text: options.text } : undefined,
236
+ fileId: fileId,
237
+ });
238
+ const submitResult = {
239
+ success: result.success,
240
+ assignment_id: id,
241
+ submitted: !!result.success,
242
+ online_text: !!options.text,
243
+ file_uploaded: fileUploaded,
244
+ file_id: fileId ?? null,
245
+ error: result.success ? undefined : result.error,
246
+ message: result.success ? "Assignment submitted successfully" : result.error,
247
+ };
248
+ (0, index_js_1.formatAndOutput)(submitResult, output, apiContext.log);
249
+ if (!result.success) {
250
+ process.exitCode = 1;
251
+ }
252
+ });
253
+ }
254
+ /**
255
+ * Prompt user for yes/no confirmation.
256
+ */
257
+ async function promptConfirm(prompt) {
258
+ const readline = await Promise.resolve().then(() => __importStar(require("node:readline")));
259
+ const rl = readline.createInterface({
260
+ input: process.stdin,
261
+ output: process.stdout,
262
+ });
263
+ return new Promise((resolve) => {
264
+ rl.question(prompt, (answer) => {
265
+ rl.close();
266
+ resolve(/^y/i.test(answer));
267
+ });
268
+ });
269
+ }
@@ -1,3 +1,3 @@
1
1
  import { Command } from "commander";
2
- export declare function registerAuthCommand(program: Command): void;
2
+ export declare function registerCommand(program: Command): void;
3
3
  //# sourceMappingURL=auth.d.ts.map
@@ -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;AAUpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyQ1D"}
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,CAuRtD"}
@@ -3,18 +3,16 @@ 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.registerAuthCommand = registerAuthCommand;
6
+ exports.registerCommand = registerCommand;
7
7
  const utils_js_1 = require("../lib/utils.js");
8
8
  const playwright_core_1 = require("playwright-core");
9
9
  const logger_js_1 = require("../lib/logger.js");
10
10
  const auth_js_1 = require("../lib/auth.js");
11
11
  const token_js_1 = require("../lib/token.js");
12
+ const moodle_js_1 = require("../lib/moodle.js");
12
13
  const node_path_1 = __importDefault(require("node:path"));
13
14
  const node_fs_1 = __importDefault(require("node:fs"));
14
- function registerAuthCommand(program) {
15
- const authCmd = program.command("auth");
16
- authCmd.description("Authentication commands");
17
- // Register login directly on program (not under auth subcommand)
15
+ function registerCommand(program) {
18
16
  program
19
17
  .command("login")
20
18
  .description("Login to iLearning manually and save session")
@@ -192,8 +190,7 @@ function registerAuthCommand(program) {
192
190
  await new Promise(resolve => setTimeout(resolve, 500));
193
191
  }
194
192
  });
195
- // auth subcommand group (for status and other auth-related commands)
196
- authCmd
193
+ program
197
194
  .command("status")
198
195
  .description("Check session status")
199
196
  .option("--session <path>", "Session file path", ".auth/storage-state.json")
@@ -221,6 +218,25 @@ function registerAuthCommand(program) {
221
218
  exists: false
222
219
  }
223
220
  };
221
+ // Try to get user info from WS API
222
+ try {
223
+ const wsToken = (0, token_js_1.loadWsToken)(sessionPath);
224
+ if (wsToken) {
225
+ const session = {
226
+ wsToken,
227
+ moodleBaseUrl: "https://ilearning.cycu.edu.tw"
228
+ };
229
+ const siteInfo = await (0, moodle_js_1.getSiteInfoApi)(session);
230
+ result.user = {
231
+ userid: siteInfo.userid,
232
+ username: siteInfo.username,
233
+ fullname: siteInfo.fullname
234
+ };
235
+ }
236
+ }
237
+ catch {
238
+ // WS token might not be available or expired, skip user info
239
+ }
224
240
  console.log(JSON.stringify(result, null, 2));
225
241
  }
226
242
  catch {
@@ -242,7 +258,7 @@ function registerAuthCommand(program) {
242
258
  console.log(JSON.stringify(result, null, 2));
243
259
  }
244
260
  });
245
- authCmd
261
+ program
246
262
  .command("logout")
247
263
  .description("Remove saved session")
248
264
  .option("--session <path>", "Session file path", ".auth/storage-state.json")
@@ -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,CAoM9D"}
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"}
@@ -97,29 +97,28 @@ function registerCalendarCommand(program) {
97
97
  if (options.upcoming) {
98
98
  filteredEvents = allEvents.filter(e => e.timestart > now);
99
99
  }
100
- const output = {
100
+ console.log(JSON.stringify({
101
101
  status: "success",
102
102
  timestamp: new Date().toISOString(),
103
- events: filteredEvents.map(e => ({
103
+ total_events: allEvents.length,
104
+ upcoming: allEvents.filter(e => e.timestart > now).length,
105
+ by_type: allEvents.reduce((acc, e) => {
106
+ acc[e.eventtype] = (acc[e.eventtype] || 0) + 1;
107
+ return acc;
108
+ }, {}),
109
+ }));
110
+ for (const e of filteredEvents) {
111
+ console.log(JSON.stringify({
104
112
  id: e.id,
105
113
  name: e.name,
106
114
  description: e.description,
107
115
  course_id: e.courseid,
108
116
  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,
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,
111
119
  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));
120
+ }));
121
+ }
123
122
  });
124
123
  calendarCmd
125
124
  .command("export")
@@ -167,8 +166,8 @@ function registerCalendarCommand(program) {
167
166
  description: e.description,
168
167
  course_id: e.courseid,
169
168
  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,
169
+ start_time: (0, utils_js_1.formatTimestamp)(e.timestart),
170
+ end_time: e.timeduration ? (0, utils_js_1.formatTimestamp)(e.timestart + Math.floor(e.timeduration / 1000)) : null,
172
171
  location: e.location,
173
172
  })),
174
173
  summary: {
@@ -117,8 +117,8 @@ function registerCoursesCommand(program) {
117
117
  courseId: course.id,
118
118
  courseName: course.fullname,
119
119
  progress: course.progress ?? 0,
120
- startDate: course.startdate ? new Date(course.startdate * 1000).toISOString() : null,
121
- endDate: course.enddate ? new Date(course.enddate * 1000).toISOString() : null,
120
+ startDate: course.startdate ? (0, utils_js_1.formatTimestamp)(course.startdate) : null,
121
+ endDate: course.enddate ? (0, utils_js_1.formatTimestamp)(course.enddate) : null,
122
122
  };
123
123
  (0, index_js_1.formatAndOutput)(progressData, output, apiContext.log);
124
124
  });
@@ -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;AAiBpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0Q5D"}
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"}