canvaslms-cli 1.6.2 → 1.6.4-fix
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/CHANGELOG.md +64 -31
- package/README.md +131 -129
- package/dist/commands/announcements.d.ts +2 -2
- package/dist/commands/announcements.d.ts.map +1 -1
- package/dist/commands/announcements.js +29 -20
- package/dist/commands/announcements.js.map +1 -1
- package/dist/commands/api.d.ts +1 -1
- package/dist/commands/api.d.ts.map +1 -1
- package/dist/commands/api.js +1 -1
- package/dist/commands/api.js.map +1 -1
- package/dist/commands/assignments.d.ts +2 -2
- package/dist/commands/assignments.d.ts.map +1 -1
- package/dist/commands/assignments.js +24 -19
- package/dist/commands/assignments.js.map +1 -1
- package/dist/commands/calendar.d.ts +7 -0
- package/dist/commands/calendar.d.ts.map +1 -0
- package/dist/commands/calendar.js +150 -0
- package/dist/commands/calendar.js.map +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +102 -85
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/grades.d.ts +2 -2
- package/dist/commands/grades.d.ts.map +1 -1
- package/dist/commands/grades.js +296 -176
- package/dist/commands/grades.js.map +1 -1
- package/dist/commands/list.d.ts +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +21 -19
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/modules.d.ts +5 -0
- package/dist/commands/modules.d.ts.map +1 -0
- package/dist/commands/modules.js +263 -0
- package/dist/commands/modules.js.map +1 -0
- package/dist/commands/profile.d.ts.map +1 -1
- package/dist/commands/profile.js +57 -32
- package/dist/commands/profile.js.map +1 -1
- package/dist/commands/submit.d.ts +1 -2
- package/dist/commands/submit.d.ts.map +1 -1
- package/dist/commands/submit.js +88 -79
- package/dist/commands/submit.js.map +1 -1
- package/dist/index.d.ts +16 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -14
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +3 -0
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +31 -16
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/config-validator.d.ts.map +1 -1
- package/dist/lib/config-validator.js +12 -12
- package/dist/lib/config-validator.js.map +1 -1
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +16 -14
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/display.d.ts +10 -4
- package/dist/lib/display.d.ts.map +1 -1
- package/dist/lib/display.js +263 -167
- package/dist/lib/display.js.map +1 -1
- package/dist/lib/file-upload.d.ts.map +1 -1
- package/dist/lib/file-upload.js +17 -17
- package/dist/lib/file-upload.js.map +1 -1
- package/dist/lib/interactive.d.ts +1 -1
- package/dist/lib/interactive.d.ts.map +1 -1
- package/dist/lib/interactive.js +196 -144
- package/dist/lib/interactive.js.map +1 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +83 -63
- package/dist/src/index.js.map +1 -1
- package/dist/types/index.d.ts +34 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +10 -3
- package/dist/commands/coursenames.d.ts +0 -15
- package/dist/commands/coursenames.d.ts.map +0 -1
- package/dist/commands/coursenames.js +0 -150
- package/dist/commands/coursenames.js.map +0 -1
- package/dist/lib/course-utils.d.ts +0 -6
- package/dist/lib/course-utils.d.ts.map +0 -1
- package/dist/lib/course-utils.js +0 -17
- package/dist/lib/course-utils.js.map +0 -1
package/dist/commands/grades.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { makeCanvasRequest } from
|
|
2
|
-
import { createReadlineInterface, askQuestionWithValidation } from
|
|
3
|
-
import { pad } from
|
|
4
|
-
import chalk from
|
|
1
|
+
import { makeCanvasRequest, getCanvasCourse } from "../lib/api-client.js";
|
|
2
|
+
import { createReadlineInterface, askQuestionWithValidation, } from "../lib/interactive.js";
|
|
3
|
+
import { pad } from "../lib/display.js";
|
|
4
|
+
import chalk from "chalk";
|
|
5
5
|
async function showDetailedGrades(courseId, options) {
|
|
6
|
-
console.log(chalk.cyan.bold(
|
|
7
|
-
console.log(chalk.cyan.bold(
|
|
8
|
-
const course = await makeCanvasRequest(
|
|
9
|
-
const enrollmentParams = [
|
|
10
|
-
enrollmentParams.push(
|
|
11
|
-
enrollmentParams.push(
|
|
12
|
-
enrollmentParams.push(
|
|
13
|
-
enrollmentParams.push(
|
|
14
|
-
enrollmentParams.push(
|
|
15
|
-
enrollmentParams.push(
|
|
16
|
-
const enrollments = await makeCanvasRequest(
|
|
6
|
+
console.log(chalk.cyan.bold("\n" + "=".repeat(80)));
|
|
7
|
+
console.log(chalk.cyan.bold("Loading course grades, please wait..."));
|
|
8
|
+
const course = await makeCanvasRequest("get", `courses/${courseId}`);
|
|
9
|
+
const enrollmentParams = ["user_id=self", "include[]=total_scores"];
|
|
10
|
+
enrollmentParams.push("state[]=active");
|
|
11
|
+
enrollmentParams.push("state[]=invited");
|
|
12
|
+
enrollmentParams.push("state[]=creation_pending");
|
|
13
|
+
enrollmentParams.push("state[]=rejected");
|
|
14
|
+
enrollmentParams.push("state[]=completed");
|
|
15
|
+
enrollmentParams.push("state[]=inactive");
|
|
16
|
+
const enrollments = await makeCanvasRequest("get", `courses/${courseId}/enrollments`, enrollmentParams);
|
|
17
17
|
if (!enrollments || enrollments.length === 0) {
|
|
18
|
-
console.log(chalk.red(
|
|
18
|
+
console.log(chalk.red("Error: No enrollment found for this course."));
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
const enrollment = enrollments[0];
|
|
22
22
|
const grades = enrollment?.grades;
|
|
23
|
-
const assignments = await makeCanvasRequest(
|
|
24
|
-
console.log(chalk.cyan.bold(
|
|
23
|
+
const assignments = await makeCanvasRequest("get", `courses/${courseId}/assignments`, ["include[]=submission", "per_page=100"]);
|
|
24
|
+
console.log(chalk.cyan.bold("\n" + "=".repeat(80)));
|
|
25
25
|
console.log(chalk.cyan.bold(`Course: ${course.name}`));
|
|
26
|
-
console.log(chalk.cyan(
|
|
27
|
-
const assignmentGrades = assignments.map(assignment => {
|
|
26
|
+
console.log(chalk.cyan("=".repeat(80)));
|
|
27
|
+
const assignmentGrades = assignments.map((assignment) => {
|
|
28
28
|
const submission = assignment.submission;
|
|
29
29
|
return {
|
|
30
30
|
name: assignment.name,
|
|
@@ -33,67 +33,117 @@ async function showDetailedGrades(courseId, options) {
|
|
|
33
33
|
pointsPossible: assignment.points_possible || 0,
|
|
34
34
|
submitted: !!(submission && submission.submitted_at),
|
|
35
35
|
graded: submission?.score !== null && submission?.score !== undefined,
|
|
36
|
-
dueAt: assignment.due_at
|
|
36
|
+
dueAt: assignment.due_at,
|
|
37
37
|
};
|
|
38
38
|
});
|
|
39
|
-
const gradedAssignments = assignmentGrades.filter(a => a.graded);
|
|
39
|
+
const gradedAssignments = assignmentGrades.filter((a) => a.graded);
|
|
40
40
|
const totalPointsEarned = gradedAssignments.reduce((sum, a) => sum + (a.score || 0), 0);
|
|
41
41
|
const totalPointsPossible = gradedAssignments.reduce((sum, a) => sum + a.pointsPossible, 0);
|
|
42
42
|
const calculatedPercentage = totalPointsPossible > 0
|
|
43
43
|
? ((totalPointsEarned / totalPointsPossible) * 100).toFixed(2)
|
|
44
|
-
:
|
|
45
|
-
console.log(chalk.white.bold(
|
|
44
|
+
: "N/A";
|
|
45
|
+
console.log(chalk.white.bold("\nOverall Grades:"));
|
|
46
46
|
const termWidth = process.stdout.columns || 80;
|
|
47
47
|
const borderOverhead = 10;
|
|
48
48
|
const availableWidth = Math.max(60, termWidth - borderOverhead);
|
|
49
49
|
const colMetric = Math.max(18, Math.floor(availableWidth * 0.35));
|
|
50
|
-
const colScore = Math.max(20, Math.floor(availableWidth * 0.
|
|
50
|
+
const colScore = Math.max(20, Math.floor(availableWidth * 0.4));
|
|
51
51
|
const colStatus = Math.max(12, availableWidth - colMetric - colScore);
|
|
52
|
-
console.log(chalk.gray(
|
|
53
|
-
chalk.gray(
|
|
54
|
-
chalk.gray(
|
|
55
|
-
|
|
56
|
-
chalk.
|
|
57
|
-
chalk.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
chalk.
|
|
52
|
+
console.log(chalk.gray("╭─") +
|
|
53
|
+
chalk.gray("─".repeat(colMetric)) +
|
|
54
|
+
chalk.gray("┬─") +
|
|
55
|
+
chalk.gray("─".repeat(colScore)) +
|
|
56
|
+
chalk.gray("┬─") +
|
|
57
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
58
|
+
chalk.gray("╮"));
|
|
59
|
+
console.log(chalk.gray("│ ") +
|
|
60
|
+
chalk.cyan.bold(pad("Metric", colMetric)) +
|
|
61
|
+
chalk.gray("│ ") +
|
|
62
|
+
chalk.cyan.bold(pad("Score/Grade", colScore)) +
|
|
63
|
+
chalk.gray("│ ") +
|
|
64
|
+
chalk.cyan.bold(pad("Status", colStatus)) +
|
|
65
|
+
chalk.gray("│"));
|
|
66
|
+
console.log(chalk.gray("├─") +
|
|
67
|
+
chalk.gray("─".repeat(colMetric)) +
|
|
68
|
+
chalk.gray("┼─") +
|
|
69
|
+
chalk.gray("─".repeat(colScore)) +
|
|
70
|
+
chalk.gray("┼─") +
|
|
71
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
72
|
+
chalk.gray("┤"));
|
|
61
73
|
if (grades) {
|
|
62
|
-
const currentScoreValue = grades.current_score !== null ? `${grades.current_score}%` :
|
|
63
|
-
const finalScoreValue = grades.final_score !== null ? `${grades.final_score}%` :
|
|
64
|
-
const currentGradeValue = grades.current_grade ||
|
|
65
|
-
const finalGradeValue = grades.final_grade ||
|
|
66
|
-
console.log(chalk.gray(
|
|
67
|
-
chalk.
|
|
68
|
-
chalk.gray(
|
|
69
|
-
|
|
70
|
-
chalk.
|
|
71
|
-
chalk.gray(pad(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
chalk.
|
|
75
|
-
|
|
76
|
-
chalk.green.bold(pad(
|
|
77
|
-
chalk.gray(
|
|
78
|
-
|
|
79
|
-
chalk.gray(
|
|
80
|
-
|
|
74
|
+
const currentScoreValue = grades.current_score !== null ? `${grades.current_score}%` : "N/A";
|
|
75
|
+
const finalScoreValue = grades.final_score !== null ? `${grades.final_score}%` : "N/A";
|
|
76
|
+
const currentGradeValue = grades.current_grade || "N/A";
|
|
77
|
+
const finalGradeValue = grades.final_grade || "N/A";
|
|
78
|
+
console.log(chalk.gray("│ ") +
|
|
79
|
+
chalk.white(pad("Current Score", colMetric)) +
|
|
80
|
+
chalk.gray("│ ") +
|
|
81
|
+
chalk.green.bold(pad(currentScoreValue, colScore)) +
|
|
82
|
+
chalk.gray("│ ") +
|
|
83
|
+
chalk.gray(pad("Official", colStatus)) +
|
|
84
|
+
chalk.gray("│"));
|
|
85
|
+
console.log(chalk.gray("│ ") +
|
|
86
|
+
chalk.white(pad("Final Score", colMetric)) +
|
|
87
|
+
chalk.gray("│ ") +
|
|
88
|
+
chalk.green.bold(pad(finalScoreValue, colScore)) +
|
|
89
|
+
chalk.gray("│ ") +
|
|
90
|
+
chalk.gray(pad("Official", colStatus)) +
|
|
91
|
+
chalk.gray("│"));
|
|
92
|
+
console.log(chalk.gray("│ ") +
|
|
93
|
+
chalk.white(pad("Current Grade", colMetric)) +
|
|
94
|
+
chalk.gray("│ ") +
|
|
95
|
+
chalk.green.bold(pad(currentGradeValue, colScore)) +
|
|
96
|
+
chalk.gray("│ ") +
|
|
97
|
+
chalk.gray(pad("Letter Grade", colStatus)) +
|
|
98
|
+
chalk.gray("│"));
|
|
99
|
+
console.log(chalk.gray("│ ") +
|
|
100
|
+
chalk.white(pad("Final Grade", colMetric)) +
|
|
101
|
+
chalk.gray("│ ") +
|
|
102
|
+
chalk.green.bold(pad(finalGradeValue, colScore)) +
|
|
103
|
+
chalk.gray("│ ") +
|
|
104
|
+
chalk.gray(pad("Letter Grade", colStatus)) +
|
|
105
|
+
chalk.gray("│"));
|
|
106
|
+
console.log(chalk.gray("├─") +
|
|
107
|
+
chalk.gray("─".repeat(colMetric)) +
|
|
108
|
+
chalk.gray("┼─") +
|
|
109
|
+
chalk.gray("─".repeat(colScore)) +
|
|
110
|
+
chalk.gray("┼─") +
|
|
111
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
112
|
+
chalk.gray("┤"));
|
|
81
113
|
}
|
|
82
|
-
console.log(chalk.gray(
|
|
83
|
-
chalk.
|
|
84
|
-
chalk.gray(
|
|
85
|
-
|
|
86
|
-
chalk.
|
|
87
|
-
chalk.gray(pad(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
chalk.
|
|
91
|
-
|
|
92
|
-
chalk.
|
|
93
|
-
chalk.gray(
|
|
94
|
-
|
|
114
|
+
console.log(chalk.gray("│ ") +
|
|
115
|
+
chalk.white(pad("Graded Assignments", colMetric)) +
|
|
116
|
+
chalk.gray("│ ") +
|
|
117
|
+
chalk.cyan.bold(pad(`${gradedAssignments.length} / ${assignments.length}`, colScore)) +
|
|
118
|
+
chalk.gray("│ ") +
|
|
119
|
+
chalk.gray(pad("Completed", colStatus)) +
|
|
120
|
+
chalk.gray("│"));
|
|
121
|
+
console.log(chalk.gray("│ ") +
|
|
122
|
+
chalk.white(pad("Points Earned", colMetric)) +
|
|
123
|
+
chalk.gray("│ ") +
|
|
124
|
+
chalk.cyan.bold(pad(`${totalPointsEarned.toFixed(2)} / ${totalPointsPossible.toFixed(2)}`, colScore)) +
|
|
125
|
+
chalk.gray("│ ") +
|
|
126
|
+
chalk.gray(pad("Total", colStatus)) +
|
|
127
|
+
chalk.gray("│"));
|
|
128
|
+
console.log(chalk.gray("│ ") +
|
|
129
|
+
chalk.white(pad("Calculated Average", colMetric)) +
|
|
130
|
+
chalk.gray("│ ") +
|
|
131
|
+
chalk.cyan.bold(pad(typeof calculatedPercentage === "string"
|
|
132
|
+
? calculatedPercentage
|
|
133
|
+
: `${calculatedPercentage}%`, colScore)) +
|
|
134
|
+
chalk.gray("│ ") +
|
|
135
|
+
chalk.gray(pad("From Graded", colStatus)) +
|
|
136
|
+
chalk.gray("│"));
|
|
137
|
+
console.log(chalk.gray("╰─") +
|
|
138
|
+
chalk.gray("─".repeat(colMetric)) +
|
|
139
|
+
chalk.gray("┴─") +
|
|
140
|
+
chalk.gray("─".repeat(colScore)) +
|
|
141
|
+
chalk.gray("┴─") +
|
|
142
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
143
|
+
chalk.gray("╯"));
|
|
144
|
+
console.log(chalk.white.bold("\nAssignment Breakdown:"));
|
|
95
145
|
if (assignments.length === 0) {
|
|
96
|
-
console.log(chalk.yellow(
|
|
146
|
+
console.log(chalk.yellow(" No assignments found for this course."));
|
|
97
147
|
}
|
|
98
148
|
else {
|
|
99
149
|
const tw = process.stdout.columns || 100;
|
|
@@ -104,200 +154,270 @@ async function showDetailedGrades(courseId, options) {
|
|
|
104
154
|
const colStatus = Math.max(10, Math.min(15, Math.floor(available * 0.12)));
|
|
105
155
|
const colDate = Math.max(12, Math.min(20, Math.floor(available * 0.18)));
|
|
106
156
|
const colName = Math.max(20, available - colNo - colScore - colStatus - colDate);
|
|
107
|
-
console.log(chalk.gray(
|
|
108
|
-
chalk.gray(
|
|
109
|
-
chalk.gray(
|
|
110
|
-
chalk.gray(
|
|
111
|
-
chalk.gray(
|
|
112
|
-
|
|
113
|
-
chalk.
|
|
114
|
-
chalk.
|
|
115
|
-
chalk.
|
|
116
|
-
chalk.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
chalk.
|
|
120
|
-
chalk.gray(
|
|
121
|
-
chalk.
|
|
157
|
+
console.log(chalk.gray("╭─") +
|
|
158
|
+
chalk.gray("─".repeat(colNo)) +
|
|
159
|
+
chalk.gray("┬─") +
|
|
160
|
+
chalk.gray("─".repeat(colName)) +
|
|
161
|
+
chalk.gray("┬─") +
|
|
162
|
+
chalk.gray("─".repeat(colScore)) +
|
|
163
|
+
chalk.gray("┬─") +
|
|
164
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
165
|
+
chalk.gray("┬─") +
|
|
166
|
+
chalk.gray("─".repeat(colDate)) +
|
|
167
|
+
chalk.gray("╮"));
|
|
168
|
+
console.log(chalk.gray("│ ") +
|
|
169
|
+
chalk.cyan.bold(pad("#", colNo)) +
|
|
170
|
+
chalk.gray("│ ") +
|
|
171
|
+
chalk.cyan.bold(pad("Assignment Name", colName)) +
|
|
172
|
+
chalk.gray("│ ") +
|
|
173
|
+
chalk.cyan.bold(pad("Score", colScore)) +
|
|
174
|
+
chalk.gray("│ ") +
|
|
175
|
+
chalk.cyan.bold(pad("Status", colStatus)) +
|
|
176
|
+
chalk.gray("│ ") +
|
|
177
|
+
chalk.cyan.bold(pad("Due Date", colDate)) +
|
|
178
|
+
chalk.gray("│"));
|
|
179
|
+
console.log(chalk.gray("├─") +
|
|
180
|
+
chalk.gray("─".repeat(colNo)) +
|
|
181
|
+
chalk.gray("┼─") +
|
|
182
|
+
chalk.gray("─".repeat(colName)) +
|
|
183
|
+
chalk.gray("┼─") +
|
|
184
|
+
chalk.gray("─".repeat(colScore)) +
|
|
185
|
+
chalk.gray("┼─") +
|
|
186
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
187
|
+
chalk.gray("┼─") +
|
|
188
|
+
chalk.gray("─".repeat(colDate)) +
|
|
189
|
+
chalk.gray("┤"));
|
|
122
190
|
assignmentGrades.forEach((assignment, index) => {
|
|
123
191
|
const scoreDisplay = assignment.graded
|
|
124
192
|
? `${(assignment.score || 0).toFixed(1)}/${assignment.pointsPossible}`
|
|
125
193
|
: assignment.pointsPossible > 0
|
|
126
194
|
? `–/${assignment.pointsPossible}`
|
|
127
|
-
:
|
|
128
|
-
let statusDisplay =
|
|
195
|
+
: "N/A";
|
|
196
|
+
let statusDisplay = "";
|
|
129
197
|
let statusColor = chalk.gray;
|
|
130
198
|
if (assignment.graded) {
|
|
131
199
|
const percentage = assignment.pointsPossible > 0
|
|
132
200
|
? ((assignment.score || 0) / assignment.pointsPossible) * 100
|
|
133
201
|
: 0;
|
|
134
202
|
if (percentage >= 80) {
|
|
135
|
-
statusDisplay =
|
|
203
|
+
statusDisplay = "✓ Graded";
|
|
136
204
|
statusColor = chalk.green;
|
|
137
205
|
}
|
|
138
206
|
else if (percentage >= 50) {
|
|
139
|
-
statusDisplay =
|
|
207
|
+
statusDisplay = "✓ Graded";
|
|
140
208
|
statusColor = chalk.yellow;
|
|
141
209
|
}
|
|
142
210
|
else {
|
|
143
|
-
statusDisplay =
|
|
211
|
+
statusDisplay = "✓ Graded";
|
|
144
212
|
statusColor = chalk.red;
|
|
145
213
|
}
|
|
146
214
|
}
|
|
147
215
|
else if (assignment.submitted) {
|
|
148
|
-
statusDisplay =
|
|
216
|
+
statusDisplay = "Pending";
|
|
149
217
|
statusColor = chalk.cyan;
|
|
150
218
|
}
|
|
151
219
|
else {
|
|
152
|
-
statusDisplay =
|
|
220
|
+
statusDisplay = "Not Done";
|
|
153
221
|
statusColor = chalk.gray;
|
|
154
222
|
}
|
|
155
223
|
const dueDate = assignment.dueAt
|
|
156
224
|
? new Date(assignment.dueAt).toLocaleDateString()
|
|
157
|
-
:
|
|
225
|
+
: "No due date";
|
|
158
226
|
let displayName = assignment.name;
|
|
159
227
|
if (displayName.length > colName) {
|
|
160
|
-
displayName = displayName.substring(0, colName - 3) +
|
|
228
|
+
displayName = displayName.substring(0, colName - 3) + "...";
|
|
161
229
|
}
|
|
162
|
-
console.log(chalk.gray(
|
|
163
|
-
chalk.white(pad(
|
|
164
|
-
chalk.
|
|
165
|
-
|
|
166
|
-
chalk.gray(
|
|
230
|
+
console.log(chalk.gray("│ ") +
|
|
231
|
+
chalk.white(pad((index + 1).toString(), colNo)) +
|
|
232
|
+
chalk.gray("│ ") +
|
|
233
|
+
chalk.white(pad(displayName, colName)) +
|
|
234
|
+
chalk.gray("│ ") +
|
|
235
|
+
chalk.white(pad(scoreDisplay, colScore)) +
|
|
236
|
+
chalk.gray("│ ") +
|
|
237
|
+
statusColor(pad(statusDisplay, colStatus)) +
|
|
238
|
+
chalk.gray("│ ") +
|
|
239
|
+
chalk.gray(pad(dueDate, colDate)) +
|
|
240
|
+
chalk.gray("│"));
|
|
167
241
|
});
|
|
168
|
-
console.log(chalk.gray(
|
|
169
|
-
chalk.gray(
|
|
170
|
-
chalk.gray(
|
|
171
|
-
chalk.gray(
|
|
172
|
-
chalk.gray(
|
|
242
|
+
console.log(chalk.gray("╰─") +
|
|
243
|
+
chalk.gray("─".repeat(colNo)) +
|
|
244
|
+
chalk.gray("┴─") +
|
|
245
|
+
chalk.gray("─".repeat(colName)) +
|
|
246
|
+
chalk.gray("┴─") +
|
|
247
|
+
chalk.gray("─".repeat(colScore)) +
|
|
248
|
+
chalk.gray("┴─") +
|
|
249
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
250
|
+
chalk.gray("┴─") +
|
|
251
|
+
chalk.gray("─".repeat(colDate)) +
|
|
252
|
+
chalk.gray("╯"));
|
|
173
253
|
}
|
|
174
|
-
console.log(chalk.cyan(
|
|
254
|
+
console.log(chalk.cyan("=".repeat(80)));
|
|
175
255
|
if (options.verbose && enrollment) {
|
|
176
|
-
console.log(chalk.cyan(
|
|
177
|
-
console.log(chalk.cyan.bold(
|
|
178
|
-
console.log(chalk.white(
|
|
179
|
-
console.log(chalk.white(
|
|
180
|
-
console.log(chalk.white(
|
|
181
|
-
console.log(chalk.cyan(
|
|
256
|
+
console.log(chalk.cyan("\n" + "-".repeat(80)));
|
|
257
|
+
console.log(chalk.cyan.bold("Enrollment Details:"));
|
|
258
|
+
console.log(chalk.white(" Enrollment ID: ") + enrollment.id);
|
|
259
|
+
console.log(chalk.white(" Type: ") + enrollment.type);
|
|
260
|
+
console.log(chalk.white(" State: ") + enrollment.enrollment_state);
|
|
261
|
+
console.log(chalk.cyan("-".repeat(80)));
|
|
182
262
|
}
|
|
183
263
|
}
|
|
184
|
-
export async function showGrades(
|
|
264
|
+
export async function showGrades(courseName, options = {}) {
|
|
185
265
|
try {
|
|
186
|
-
if (
|
|
187
|
-
await
|
|
266
|
+
if (courseName) {
|
|
267
|
+
const course = await getCanvasCourse(courseName);
|
|
268
|
+
if (!course) {
|
|
269
|
+
console.log(chalk.red(`Error: Course "${courseName}" not found.`));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
console.log(chalk.green(`✓ Using course: ${course.name}`));
|
|
273
|
+
await showDetailedGrades(course.id.toString(), options);
|
|
188
274
|
}
|
|
189
275
|
else {
|
|
190
276
|
const rl = createReadlineInterface();
|
|
191
|
-
console.log(chalk.cyan.bold(
|
|
192
|
-
console.log(chalk.cyan.bold(
|
|
193
|
-
const enrollmentState = options.all ? undefined :
|
|
277
|
+
console.log(chalk.cyan.bold("\n" + "=".repeat(80)));
|
|
278
|
+
console.log(chalk.cyan.bold("Loading your courses, please wait..."));
|
|
279
|
+
const enrollmentState = options.all ? undefined : "active";
|
|
194
280
|
const queryParams = [
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
281
|
+
"include[]=total_scores",
|
|
282
|
+
"include[]=current_grading_period_scores",
|
|
283
|
+
"per_page=100",
|
|
198
284
|
];
|
|
199
285
|
if (enrollmentState) {
|
|
200
286
|
queryParams.unshift(`enrollment_state=${enrollmentState}`);
|
|
201
287
|
}
|
|
202
|
-
let courses = await makeCanvasRequest(
|
|
288
|
+
let courses = await makeCanvasRequest("get", "courses", queryParams);
|
|
203
289
|
if (!courses || courses.length === 0) {
|
|
204
|
-
console.log(chalk.red(
|
|
290
|
+
console.log(chalk.red("Error: No courses found."));
|
|
205
291
|
rl.close();
|
|
206
292
|
return;
|
|
207
293
|
}
|
|
208
294
|
if (courses.length === 0) {
|
|
209
|
-
console.log(chalk.red(
|
|
295
|
+
console.log(chalk.red("Error: No courses found (after filtering)."));
|
|
210
296
|
rl.close();
|
|
211
297
|
return;
|
|
212
298
|
}
|
|
213
299
|
const coursesWithGrades = [];
|
|
214
300
|
for (const course of courses) {
|
|
215
301
|
try {
|
|
216
|
-
const enrollmentParams = [
|
|
217
|
-
enrollmentParams.push(
|
|
218
|
-
enrollmentParams.push(
|
|
219
|
-
enrollmentParams.push(
|
|
220
|
-
enrollmentParams.push(
|
|
221
|
-
enrollmentParams.push(
|
|
222
|
-
enrollmentParams.push(
|
|
223
|
-
const enrollments = await makeCanvasRequest(
|
|
302
|
+
const enrollmentParams = ["user_id=self", "include[]=total_scores"];
|
|
303
|
+
enrollmentParams.push("state[]=active");
|
|
304
|
+
enrollmentParams.push("state[]=invited");
|
|
305
|
+
enrollmentParams.push("state[]=creation_pending");
|
|
306
|
+
enrollmentParams.push("state[]=rejected");
|
|
307
|
+
enrollmentParams.push("state[]=completed");
|
|
308
|
+
enrollmentParams.push("state[]=inactive");
|
|
309
|
+
const enrollments = await makeCanvasRequest("get", `courses/${course.id}/enrollments`, enrollmentParams);
|
|
224
310
|
coursesWithGrades.push({
|
|
225
311
|
course,
|
|
226
|
-
enrollment: enrollments[0] || null
|
|
312
|
+
enrollment: enrollments[0] || null,
|
|
227
313
|
});
|
|
228
314
|
}
|
|
229
|
-
catch
|
|
315
|
+
catch {
|
|
230
316
|
coursesWithGrades.push({
|
|
231
317
|
course,
|
|
232
|
-
enrollment: null
|
|
318
|
+
enrollment: null,
|
|
233
319
|
});
|
|
234
320
|
}
|
|
235
321
|
}
|
|
236
|
-
console.log(chalk.cyan.bold(
|
|
237
|
-
console.log(chalk.cyan.bold(
|
|
238
|
-
console.log(chalk.green(`✓ Found ${coursesWithGrades.length} course(s)${options.all ?
|
|
322
|
+
console.log(chalk.cyan.bold("\n" + "=".repeat(80)));
|
|
323
|
+
console.log(chalk.cyan.bold("Your Courses - Grades Summary"));
|
|
324
|
+
console.log(chalk.green(`✓ Found ${coursesWithGrades.length} course(s)${options.all ? " (including inactive)" : " (active only)"}.`));
|
|
239
325
|
const colNo = Math.max(3, coursesWithGrades.length.toString().length + 1);
|
|
240
|
-
const colStatus = Math.max(8, ...coursesWithGrades.map(c => (c.course.workflow_state ===
|
|
241
|
-
|
|
326
|
+
const colStatus = Math.max(8, ...coursesWithGrades.map((c) => (c.course.workflow_state === "available"
|
|
327
|
+
? "Active"
|
|
328
|
+
: c.course.workflow_state || "Inactive").length));
|
|
329
|
+
const colCurrent = Math.max(9, ...coursesWithGrades.map((c) => {
|
|
242
330
|
const s = c.enrollment?.grades?.current_score;
|
|
243
331
|
return s !== null && s !== undefined ? `${s}%`.length : 3;
|
|
244
332
|
}));
|
|
245
|
-
const colFinal = Math.max(7, ...coursesWithGrades.map(c => {
|
|
333
|
+
const colFinal = Math.max(7, ...coursesWithGrades.map((c) => {
|
|
246
334
|
const s = c.enrollment?.grades?.final_score;
|
|
247
335
|
return s !== null && s !== undefined ? `${s}%`.length : 3;
|
|
248
336
|
}));
|
|
249
337
|
const terminalWidth = process.stdout.columns || 80;
|
|
250
338
|
const overhead = 16;
|
|
251
339
|
const availableForName = Math.max(20, terminalWidth - (colNo + colStatus + colCurrent + colFinal + overhead));
|
|
252
|
-
const maxNameLength = Math.max(11, ...coursesWithGrades.map(c => c.course.name.length));
|
|
340
|
+
const maxNameLength = Math.max(11, ...coursesWithGrades.map((c) => c.course.name.length));
|
|
253
341
|
const colName = Math.min(maxNameLength, availableForName);
|
|
254
|
-
console.log(chalk.gray(
|
|
255
|
-
chalk.gray(
|
|
256
|
-
chalk.gray(
|
|
257
|
-
chalk.gray(
|
|
258
|
-
chalk.gray(
|
|
259
|
-
|
|
260
|
-
chalk.
|
|
261
|
-
chalk.
|
|
262
|
-
chalk.
|
|
263
|
-
chalk.
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
chalk.
|
|
267
|
-
chalk.gray(
|
|
268
|
-
chalk.
|
|
342
|
+
console.log(chalk.gray("╭─") +
|
|
343
|
+
chalk.gray("─".repeat(colNo)) +
|
|
344
|
+
chalk.gray("┬─") +
|
|
345
|
+
chalk.gray("─".repeat(colName)) +
|
|
346
|
+
chalk.gray("┬─") +
|
|
347
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
348
|
+
chalk.gray("┬─") +
|
|
349
|
+
chalk.gray("─".repeat(colCurrent)) +
|
|
350
|
+
chalk.gray("┬─") +
|
|
351
|
+
chalk.gray("─".repeat(colFinal)) +
|
|
352
|
+
chalk.gray("╮"));
|
|
353
|
+
console.log(chalk.gray("│ ") +
|
|
354
|
+
chalk.cyan.bold(pad("#", colNo)) +
|
|
355
|
+
chalk.gray("│ ") +
|
|
356
|
+
chalk.cyan.bold(pad("Course Name", colName)) +
|
|
357
|
+
chalk.gray("│ ") +
|
|
358
|
+
chalk.cyan.bold(pad("Status", colStatus)) +
|
|
359
|
+
chalk.gray("│ ") +
|
|
360
|
+
chalk.cyan.bold(pad("Current", colCurrent)) +
|
|
361
|
+
chalk.gray("│ ") +
|
|
362
|
+
chalk.cyan.bold(pad("Final", colFinal)) +
|
|
363
|
+
chalk.gray("│"));
|
|
364
|
+
console.log(chalk.gray("├─") +
|
|
365
|
+
chalk.gray("─".repeat(colNo)) +
|
|
366
|
+
chalk.gray("┼─") +
|
|
367
|
+
chalk.gray("─".repeat(colName)) +
|
|
368
|
+
chalk.gray("┼─") +
|
|
369
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
370
|
+
chalk.gray("┼─") +
|
|
371
|
+
chalk.gray("─".repeat(colCurrent)) +
|
|
372
|
+
chalk.gray("┼─") +
|
|
373
|
+
chalk.gray("─".repeat(colFinal)) +
|
|
374
|
+
chalk.gray("┤"));
|
|
269
375
|
coursesWithGrades.forEach((item, index) => {
|
|
270
376
|
const { course, enrollment } = item;
|
|
271
377
|
const grades = enrollment?.grades;
|
|
272
378
|
const currentScore = grades?.current_score !== null && grades?.current_score !== undefined
|
|
273
379
|
? `${grades.current_score}%`
|
|
274
|
-
:
|
|
380
|
+
: "N/A";
|
|
275
381
|
const finalScore = grades?.final_score !== null && grades?.final_score !== undefined
|
|
276
382
|
? `${grades.final_score}%`
|
|
277
|
-
:
|
|
278
|
-
const statusText = course.workflow_state ===
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
383
|
+
: "N/A";
|
|
384
|
+
const statusText = course.workflow_state === "available"
|
|
385
|
+
? "Active"
|
|
386
|
+
: course.workflow_state || "Inactive";
|
|
387
|
+
const statusColored = course.workflow_state === "available"
|
|
388
|
+
? chalk.green(pad(statusText, colStatus))
|
|
389
|
+
: chalk.gray(pad(statusText, colStatus));
|
|
282
390
|
let displayName = course.name;
|
|
283
391
|
if (displayName.length > colName) {
|
|
284
|
-
displayName = displayName.substring(0, colName - 3) +
|
|
392
|
+
displayName = displayName.substring(0, colName - 3) + "...";
|
|
285
393
|
}
|
|
286
|
-
console.log(chalk.gray(
|
|
287
|
-
chalk.white(pad(
|
|
288
|
-
|
|
289
|
-
chalk.white(pad(
|
|
290
|
-
chalk.
|
|
394
|
+
console.log(chalk.gray("│ ") +
|
|
395
|
+
chalk.white(pad((index + 1).toString(), colNo)) +
|
|
396
|
+
chalk.gray("│ ") +
|
|
397
|
+
chalk.white(pad(displayName, colName)) +
|
|
398
|
+
chalk.gray("│ ") +
|
|
399
|
+
statusColored +
|
|
400
|
+
chalk.gray("│ ") +
|
|
401
|
+
chalk.white(pad(currentScore, colCurrent)) +
|
|
402
|
+
chalk.gray("│ ") +
|
|
403
|
+
chalk.white(pad(finalScore, colFinal)) +
|
|
404
|
+
chalk.gray("│"));
|
|
291
405
|
});
|
|
292
|
-
console.log(chalk.gray(
|
|
293
|
-
chalk.gray(
|
|
294
|
-
chalk.gray(
|
|
295
|
-
chalk.gray(
|
|
296
|
-
chalk.gray(
|
|
297
|
-
|
|
298
|
-
|
|
406
|
+
console.log(chalk.gray("╰─") +
|
|
407
|
+
chalk.gray("─".repeat(colNo)) +
|
|
408
|
+
chalk.gray("┴─") +
|
|
409
|
+
chalk.gray("─".repeat(colName)) +
|
|
410
|
+
chalk.gray("┴─") +
|
|
411
|
+
chalk.gray("─".repeat(colStatus)) +
|
|
412
|
+
chalk.gray("┴─") +
|
|
413
|
+
chalk.gray("─".repeat(colCurrent)) +
|
|
414
|
+
chalk.gray("┴─") +
|
|
415
|
+
chalk.gray("─".repeat(colFinal)) +
|
|
416
|
+
chalk.gray("╯"));
|
|
417
|
+
console.log(chalk.yellow("\nSelect a course to view detailed grades for all assignments."));
|
|
418
|
+
console.log(chalk.gray(" Or enter 0 to exit."));
|
|
299
419
|
if (!options.all) {
|
|
300
|
-
console.log(chalk.gray(
|
|
420
|
+
console.log(chalk.gray(" Tip: Use --all flag to include inactive courses.\n"));
|
|
301
421
|
}
|
|
302
422
|
else {
|
|
303
423
|
console.log();
|
|
@@ -306,11 +426,11 @@ export async function showGrades(courseId, options = {}) {
|
|
|
306
426
|
const num = parseInt(input);
|
|
307
427
|
return !isNaN(num) && num >= 0 && num <= coursesWithGrades.length;
|
|
308
428
|
};
|
|
309
|
-
const answer = await askQuestionWithValidation(rl, chalk.bold.cyan(
|
|
429
|
+
const answer = await askQuestionWithValidation(rl, chalk.bold.cyan("Enter course number: "), validator, chalk.red(`Please enter a number between 0 and ${coursesWithGrades.length}.`));
|
|
310
430
|
const choice = parseInt(answer);
|
|
311
431
|
rl.close();
|
|
312
432
|
if (choice === 0) {
|
|
313
|
-
console.log(chalk.yellow(
|
|
433
|
+
console.log(chalk.yellow("\nExiting grades viewer."));
|
|
314
434
|
return;
|
|
315
435
|
}
|
|
316
436
|
const selectedCourse = coursesWithGrades[choice - 1];
|
|
@@ -322,7 +442,7 @@ export async function showGrades(courseId, options = {}) {
|
|
|
322
442
|
}
|
|
323
443
|
catch (error) {
|
|
324
444
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
325
|
-
console.error(chalk.red(
|
|
445
|
+
console.error(chalk.red("Error fetching grades:"), errorMessage);
|
|
326
446
|
process.exit(1);
|
|
327
447
|
}
|
|
328
448
|
}
|