diff --git a/run.sh b/run.sh index e3930ea..0356113 100755 --- a/run.sh +++ b/run.sh @@ -16,6 +16,7 @@ docker run -it --rm \ -v ~/projects/faculty/1405/2025_spring_alex:/app/storage/1405 \ -v ~/projects/faculty/3840_Telemetry/2025_spring_alex/modules:/app/storage/telemetry \ -v ~/projects/faculty/4620_Distributed/2025Spring/modules:/app/storage/distributed \ + -v ~/projects/faculty/1430/2025-spring-jonathan/Modules:/app/storage/jonathan-ux \ -v ~/projects/public:/app/public/images/public \ -v ~/projects/facultyFiles:/app/public/images/facultyFiles \ node \ diff --git a/src/app/providersQueryClientUtils.ts b/src/app/providersQueryClientUtils.ts index 20396b3..8bca402 100644 --- a/src/app/providersQueryClientUtils.ts +++ b/src/app/providersQueryClientUtils.ts @@ -1,4 +1,7 @@ +import { getAxiosErrorMessage } from "@/services/axiosUtils"; import { isServer, QueryCache, QueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; +import toast from "react-hot-toast"; export function makeQueryClient() { return new QueryClient({ @@ -13,6 +16,15 @@ export function makeQueryClient() { retry: 0, refetchOnMount: false, }, + mutations: { + onError: (error) => { + const message = getAxiosErrorMessage(error as AxiosError); + console.error("Mutation error:", message); + if (!isServer) { + toast.error(message); + } + }, + }, }, queryCache: new QueryCache({ onError: (e) => console.log("error in query client", e), diff --git a/src/hooks/canvas/canvasAssignmentHooks.ts b/src/hooks/canvas/canvasAssignmentHooks.ts index 2be8a90..00972bd 100644 --- a/src/hooks/canvas/canvasAssignmentHooks.ts +++ b/src/hooks/canvas/canvasAssignmentHooks.ts @@ -38,8 +38,8 @@ export const useAddAssignmentToCanvasMutation = () => { moduleName: string; }) => { if (!canvasModules) { - console.log("cannot add assignment until modules loaded"); - return; + // console.log("cannot add assignment until modules loaded"); + throw new Error("cannot add assignment until modules loaded"); } const assignmentGroup = settings.assignmentGroups.find( diff --git a/src/services/axiosUtils.ts b/src/services/axiosUtils.ts index f0c167c..70b8e72 100644 --- a/src/services/axiosUtils.ts +++ b/src/services/axiosUtils.ts @@ -17,8 +17,7 @@ if (!isServer) { } else { const token = process.env.CANVAS_TOKEN; if (!token) { - console.error("CANVAS_TOKEN not in environment") - // throw new Error("CANVAS_TOKEN not in environment"); + console.error("CANVAS_TOKEN not in environment"); } else { axiosClient.interceptors.request.use((config) => { if (config.url && config.url.startsWith(canvasBaseUrl)) { @@ -32,28 +31,37 @@ if (!isServer) { axiosClient.interceptors.response.use( (response) => response, (error: AxiosError) => { - if (error.response) { - // console.log("response error", error.response); - const responseErrorText = - typeof error.response.data === "object" - ? (error.response.data as any).error - : error.response.data; - if (!isServer) { - toast.error( - `Error: ${error.response.status} - ${responseErrorText}, ${decodeURI( - error.response.config.url ?? "" - )}` - ); - } - } else if (error.request) { - if (!isServer) { - toast.error("Error: No response from server"); - } - } else { - if (!isServer) { - toast.error(`Error: ${error.message}`); - } - } + const errorMessage = getAxiosErrorMessage(error); + if (errorMessage) toast.error(errorMessage); return Promise.reject(error); } ); + +export function getAxiosErrorMessage(error: AxiosError) { + if (error.response) { + console.log("response error", error.response); + const responseErrorText = + typeof error.response.data === "object" + ? (error.response.data as any).error + : error.response.data; + + if ( + !isServer && + error.config?.method?.toUpperCase() !== "GET" && + error.response.status !== 403 + ) { + return `Error: ${ + error.response.status + } - ${responseErrorText}, ${decodeURI(error.response.config.url ?? "")}`; + } + } else if (error.request) { + if (!isServer) { + return "Error: No response from server"; + } + } else { + if (!isServer) { + return `Error: ${error.message}`; + } + } + return ""; +} diff --git a/src/services/canvas/canvasModuleService.ts b/src/services/canvas/canvasModuleService.ts index bdf5253..06b3153 100644 --- a/src/services/canvas/canvasModuleService.ts +++ b/src/services/canvas/canvasModuleService.ts @@ -50,7 +50,7 @@ export const canvasModuleService = { async getCourseModules(canvasCourseId: number) { const url = `${canvasApi}/courses/${canvasCourseId}/modules`; const response = await paginatedRequest({ url }); - return response + return response; }, async createModule(canvasCourseId: number, moduleName: string) { diff --git a/src/services/canvas/canvasPageService.ts b/src/services/canvas/canvasPageService.ts index e72a9b4..88f83f0 100644 --- a/src/services/canvas/canvasPageService.ts +++ b/src/services/canvas/canvasPageService.ts @@ -9,11 +9,21 @@ import { LocalCourseSettings } from "@/models/local/localCourseSettings"; export const canvasPageService = { async getAll(courseId: number): Promise { console.log("requesting pages"); + try { const url = `${canvasApi}/courses/${courseId}/pages`; const pages = await paginatedRequest({ url, }); return pages.flatMap((pageList) => pageList); + } catch (error: any) { + if (error?.response?.status === 403) { + console.log( + "Canvas API error: 403 Forbidden for pages. Returning empty array." + ); + return []; + } + throw error; + } }, async create( diff --git a/src/services/canvas/canvasQuizService.ts b/src/services/canvas/canvasQuizService.ts index 0363891..62a7fbd 100644 --- a/src/services/canvas/canvasQuizService.ts +++ b/src/services/canvas/canvasQuizService.ts @@ -13,7 +13,6 @@ import { CanvasQuizQuestion } from "@/models/canvas/quizzes/canvasQuizQuestionMo import { LocalCourseSettings } from "@/models/local/localCourseSettings"; import { escapeMatchingText } from "../utils/questionHtmlUtils"; - export const getAnswers = ( question: LocalQuizQuestion, settings: LocalCourseSettings @@ -138,23 +137,27 @@ const createQuizQuestions = async ( export const canvasQuizService = { async getAll(canvasCourseId: number): Promise { - const url = `${canvasApi}/courses/${canvasCourseId}/quizzes`; - const quizzes = await paginatedRequest({ url }); - return quizzes.map((quiz) => ({ - ...quiz, - due_at: quiz.due_at ? new Date(quiz.due_at).toLocaleString() : undefined, - lock_at: quiz.lock_at - ? new Date(quiz.lock_at).toLocaleString() - : undefined, - })); - // const response = await axiosClient.get(url); - // return response.data.map((quiz) => ({ - // ...quiz, - // due_at: quiz.due_at ? new Date(quiz.due_at).toLocaleString() : undefined, - // lock_at: quiz.lock_at - // ? new Date(quiz.lock_at).toLocaleString() - // : undefined, - // })); + try { + const url = `${canvasApi}/courses/${canvasCourseId}/quizzes`; + const quizzes = await paginatedRequest({ url }); + return quizzes.map((quiz) => ({ + ...quiz, + due_at: quiz.due_at + ? new Date(quiz.due_at).toLocaleString() + : undefined, + lock_at: quiz.lock_at + ? new Date(quiz.lock_at).toLocaleString() + : undefined, + })); + } catch (error: any) { + if (error?.response?.status === 403) { + console.log( + "Canvas API error: 403 Forbidden for quizzes. Returning empty array." + ); + return []; + } + throw error; + } }, async create( diff --git a/src/services/canvas/canvasServiceUtils.ts b/src/services/canvas/canvasServiceUtils.ts index 5cc8181..00ff59b 100644 --- a/src/services/canvas/canvasServiceUtils.ts +++ b/src/services/canvas/canvasServiceUtils.ts @@ -39,7 +39,7 @@ export async function paginatedRequest(request: { var requestCount = 1; const url = new URL(request.url); url.searchParams.set("per_page", "100"); - + const { data: firstData, headers: firstHeaders } = await axiosClient.get( url.toString() );