Skip to content

Commit b256a17

Browse files
committed
fix: api & types
1 parent 121003b commit b256a17

File tree

4 files changed

+110
-179
lines changed

4 files changed

+110
-179
lines changed

src/commands/canvas/assignments.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ export const data = new SlashCommandBuilder()
1717

1818
export async function execute(interaction: ChatInputCommandInteraction) {
1919
const userId = interaction.user.id;
20-
const { message, courses } = (await fetchCourses(userId)) as {
21-
message: string;
22-
courses: Course[];
23-
};
20+
const courses = await fetchCourses(userId);
2421
if (courses.length === 0) {
25-
await interaction.reply({ content: message, ephemeral: true });
22+
await interaction.reply({
23+
content: "You have no courses.",
24+
ephemeral: true,
25+
});
2626
return;
2727
}
2828

@@ -51,8 +51,11 @@ export async function execute(interaction: ChatInputCommandInteraction) {
5151

5252
collector?.on("collect", async (i) => {
5353
const courseId = i.values[0];
54-
const assignments = await fetchAssignments(parseInt(courseId), userId);
55-
const upcomingAssignments = assignments.filter(
54+
const assignmentsResponse = await fetchAssignments(
55+
parseInt(courseId),
56+
userId,
57+
);
58+
const upcomingAssignments = assignmentsResponse.assignments.filter(
5659
(assignment: { due_at: string }) =>
5760
new Date(assignment.due_at) > new Date(),
5861
);

src/events/ready.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { postAssignment } from "./assignmentChecker";
99
const clientReadyEvent: BotEvent = {
1010
name: Events.ClientReady,
1111
once: true,
12-
execute(client: Client) {
12+
async execute(client: Client) {
1313
console.log(`Up! Logged In As ${client?.user?.tag}`);
1414
client?.user?.setActivity("Your Assignments", {
1515
type: ActivityType.Watching,
@@ -19,7 +19,7 @@ const clientReadyEvent: BotEvent = {
1919
async (userId) => {
2020
const token = await getCanvasToken(userId);
2121
if (token) {
22-
return getAllAnnouncements(token, userId);
22+
return getAllAnnouncements(userId);
2323
} else {
2424
throw new Error("Failed to retrieve Canvas token.");
2525
}

src/helpers/api.ts

Lines changed: 83 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,198 +1,136 @@
1-
import axios from "axios";
1+
import axios, { AxiosRequestConfig } from "axios";
22
import { getCanvasID, getCanvasToken } from "./supabase";
3-
import {
4-
MissingAssignmentResponse,
5-
AnnouncementPost,
6-
Course,
7-
Assignment,
8-
} from "../types";
3+
import { AnnouncementPost, Course, Assignment } from "../types";
94
import { CONFIG } from "../config";
105

116
export async function fetchData<T>(
12-
url: string,
13-
token: string,
14-
params: Record<string, unknown> = {},
7+
userId: string,
8+
endpoint: string,
9+
params: Record<string, string | number | boolean | undefined> = {},
10+
config: AxiosRequestConfig = {},
1511
): Promise<T> {
1612
try {
17-
const response = await axios.get<T>(url, {
13+
const canvasToken = await getCanvasToken(userId);
14+
if (!canvasToken) {
15+
throw new Error("Canvas token is not found.");
16+
}
17+
const response = await axios.get<T>(`${CONFIG.CANVAS_DOMAIN}${endpoint}`, {
18+
timeout: 10000,
1819
headers: {
19-
Authorization: `Bearer ${token}`,
20+
Authorization: `Bearer ${canvasToken}`,
2021
"Content-Type": "application/json",
2122
},
2223
params,
24+
...config,
2325
});
2426
return response.data;
2527
} catch (error) {
2628
if (axios.isAxiosError(error)) {
27-
console.error(`Axios error fetching data from ${url}:`, error.message);
29+
console.error(
30+
`Axios error fetching data from ${endpoint}:`,
31+
error.message,
32+
);
2833
} else {
29-
console.error(`Unexpected error fetching data from ${url}:`, error);
34+
console.error(`Unexpected error fetching data from ${endpoint}:`, error);
3035
}
3136
throw error;
3237
}
3338
}
3439

35-
export async function fetchCourses(
36-
userId: string,
37-
): Promise<{ message: string; courses: Course[] }> {
38-
const canvasToken = await getCanvasToken(userId);
39-
if (!canvasToken) {
40-
return {
41-
message:
42-
"You are not enrolled in any courses; Please enter your token with the command /account",
43-
courses: [],
44-
};
45-
}
40+
export async function fetchCourses(userId: string) {
4641
try {
47-
const response = await axios.get<{ courses: Course[] }>(
48-
`${CONFIG.CANVAS_DOMAIN}courses`,
42+
const canvasID = await getCanvasID(userId);
43+
const courses = await fetchData<Course[]>(
44+
userId,
45+
`users/${canvasID}/courses`,
4946
{
50-
headers: {
51-
Authorization: `Bearer ${canvasToken}`,
52-
"Content-Type": "application/json",
53-
},
54-
params: {
55-
enrollment_type: "student",
56-
enrollment_state: "active",
57-
user_id: userId,
58-
},
47+
enrollment_type: "student",
48+
enrollment_state: "active",
5949
},
6050
);
61-
return {
62-
message: "Courses fetched successfully",
63-
courses: response.data.courses || [],
64-
};
51+
return courses;
6552
} catch (error) {
66-
console.error("Error fetching courses:", error);
67-
return {
68-
message: "An error occurred while fetching courses.",
69-
courses: [],
70-
};
53+
console.error("Failed to fetch courses:", error);
54+
throw new Error("Error fetching courses.");
7155
}
7256
}
7357

7458
export async function fetchAssignments(
7559
courseId: number,
7660
userId: string,
77-
): Promise<Assignment[]> {
78-
const canvasToken = await getCanvasToken(userId);
61+
): Promise<{ message: string; assignments: Assignment[] }> {
7962
try {
80-
const response = await axios.get<Assignment[]>(
81-
`${CONFIG.CANVAS_DOMAIN}courses/${courseId}/assignments`,
82-
{
83-
headers: {
84-
Authorization: `Bearer ${canvasToken}`,
85-
"Content-Type": "application/json",
86-
},
87-
},
63+
const assignments = await fetchData<Assignment[]>(
64+
userId,
65+
`courses/${courseId}/assignments`,
8866
);
89-
console.log("Assignments fetched successfully for course ID:", courseId);
90-
return response.data || [];
67+
return {
68+
message: "Assignments fetched successfully",
69+
assignments: assignments,
70+
};
9171
} catch (error) {
92-
if (axios.isAxiosError(error)) {
93-
console.error(
94-
"Axios error fetching assignments for the course:",
95-
error.message,
96-
);
97-
} else {
98-
console.error(
99-
"Unexpected error fetching assignments for the course:",
100-
error,
101-
);
102-
}
103-
return [];
72+
console.error(`Error fetching assignments for course ${courseId}:`, error);
73+
return {
74+
message: "Failed to fetch assignments",
75+
assignments: [],
76+
};
10477
}
10578
}
10679

10780
export async function getAllAssignments(
10881
userId: string,
109-
): Promise<MissingAssignmentResponse> {
82+
): Promise<{ message: string; courses: Course[] }> {
11083
try {
111-
const canvasToken = await getCanvasToken(userId);
112-
if (!canvasToken) {
113-
return {
114-
message:
115-
"You are not enrolled in any courses; Please enter your token with the command /account",
116-
courses: [],
117-
};
118-
}
119-
120-
const headers = {
121-
Authorization: `Bearer ${canvasToken}`,
122-
"Content-Type": "application/json",
123-
};
124-
125-
const params = {
126-
enrollment_type: "student",
127-
enrollment_state: "active",
128-
user_id: userId,
129-
};
130-
131-
const res = await axios.get<Course[]>(
132-
`${CONFIG.CANVAS_DOMAIN}users/self/missing_submissions?include[]=planner_overrides&filter[]=current_grading_period&filter[]=submittable`,
133-
{ headers, params },
84+
const courses = await fetchData<Course[]>(
85+
userId,
86+
"users/self/missing_submissions",
87+
{
88+
include: "planner_overrides",
89+
filter: "current_grading_period_id,submittable",
90+
},
13491
);
135-
13692
return {
137-
message: "Missing Courses fetched successfully",
138-
courses: res.data || [],
93+
message: "Missing submissions fetched successfully",
94+
courses: courses,
13995
};
14096
} catch (error) {
141-
console.error(
142-
"Error fetching user's missing courses from Canvas:",
143-
error instanceof Error ? error.message : String(error),
144-
);
97+
console.error("Failed to fetch missing submissions:", error);
14598
return {
146-
message: "An error occurred while fetching courses.",
99+
message: "Failed to fetch missing submissions",
147100
courses: [],
148101
};
149102
}
150103
}
151104

152-
export async function getCourses(
153-
canvasToken: string,
154-
userID: string,
155-
): Promise<Course[]> {
105+
export async function getCourses(userId: string): Promise<Course[]> {
156106
try {
157-
const canvasID = await getCanvasID(userID);
158-
const response = await axios.get<Course[]>(
159-
`${CONFIG.CANVAS_DOMAIN}users/${canvasID}/courses`,
160-
{
161-
headers: {
162-
Authorization: `Bearer ${canvasToken}`,
163-
},
164-
},
165-
);
166-
return response.data;
107+
const canvasID = await getCanvasID(userId);
108+
return await fetchData<Course[]>(userId, `users/${canvasID}/courses`);
167109
} catch (error) {
168110
console.error("Failed to fetch courses:", error);
169111
throw new Error("Error fetching courses.");
170112
}
171113
}
172114

173115
export async function getAllAnnouncements(
174-
canvasToken: string,
175-
userID: string,
116+
userId: string,
176117
): Promise<AnnouncementPost[]> {
177118
try {
178-
const courses = await getCourses(canvasToken, userID);
119+
const courses = await getCourses(userId);
179120
const today = new Date();
180121
today.setHours(0, 0, 0, 0);
181122

182123
let allAnnouncements: AnnouncementPost[] = [];
183124

184125
for (const course of courses) {
185126
try {
186-
const response = await axios.get<AnnouncementPost[]>(
187-
`${CONFIG.CANVAS_DOMAIN}announcements?context_codes[]=course_${course.id}`,
188-
{
189-
headers: {
190-
Authorization: `Bearer ${canvasToken}`,
191-
},
192-
},
127+
const announcements = await fetchData<AnnouncementPost[]>(
128+
userId,
129+
"announcements",
130+
{ context_codes: `course_${course.id}` },
193131
);
194132

195-
const filteredAnnouncements = response.data
133+
const filteredAnnouncements = announcements
196134
.filter((announcement) => {
197135
const announcementDate = new Date(announcement.posted_at || "");
198136
return announcementDate >= today;
@@ -223,39 +161,27 @@ export async function getAllAnnouncements(
223161
export async function fetchAssignmentChecker(
224162
userId: string,
225163
): Promise<Assignment[]> {
226-
const canvasToken = await getCanvasToken(userId);
227-
if (!canvasToken) {
228-
throw new Error("Canvas token is null or undefined.");
229-
}
230-
const courses = await getCourses(canvasToken, userId);
231-
232-
const today = new Date();
233-
today.setHours(0, 0, 0, 0);
234-
const tomorrow = new Date(today);
235-
tomorrow.setDate(tomorrow.getDate() + 1);
236-
tomorrow.setHours(23, 59, 59, 999);
237-
238-
let allAssignments: Assignment[] = [];
164+
try {
165+
const courses = await getCourses(userId);
239166

240-
await Promise.all(
241-
courses.map(async (course) => {
242-
const { data: assignments } = await axios.get<Assignment[]>(
243-
`${CONFIG.CANVAS_DOMAIN}courses/${course.id}/assignments`,
244-
{
245-
headers: {
246-
Authorization: `Bearer ${canvasToken}`,
247-
},
248-
},
249-
);
167+
const today = new Date();
168+
today.setHours(0, 0, 0, 0);
169+
const tomorrow = new Date(today);
170+
tomorrow.setDate(tomorrow.getDate() + 1);
171+
tomorrow.setHours(23, 59, 59, 999);
250172

251-
const filteredAssignments = assignments.filter((assignment) => {
252-
const dueDate = new Date(assignment.due_at);
253-
return dueDate >= today && dueDate <= tomorrow;
254-
});
173+
const assignmentPromises = courses.map((course) =>
174+
fetchData<Assignment[]>(userId, `courses/${course.id}/assignments`),
175+
);
255176

256-
allAssignments = allAssignments.concat(filteredAssignments);
257-
}),
258-
);
177+
const allAssignments = await Promise.all(assignmentPromises);
259178

260-
return allAssignments;
179+
return allAssignments.flat().filter((assignment) => {
180+
const dueDate = new Date(assignment.due_at);
181+
return dueDate >= today && dueDate <= tomorrow;
182+
});
183+
} catch (error) {
184+
console.error("Error fetching assignments for next day:", error);
185+
return [];
186+
}
261187
}

0 commit comments

Comments
 (0)