mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
organizing file storage
This commit is contained in:
@@ -10,7 +10,7 @@ export const GET = async (
|
|||||||
}
|
}
|
||||||
) =>
|
) =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const settings = await fileStorageService.getAssignment(
|
const settings = await fileStorageService.assignments.getAssignment(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName,
|
moduleName,
|
||||||
assignmentName
|
assignmentName
|
||||||
@@ -28,7 +28,7 @@ export const PUT = async (
|
|||||||
) =>
|
) =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const assignment = await request.json();
|
const assignment = await request.json();
|
||||||
await fileStorageService.updateAssignment(
|
await fileStorageService.assignments.updateAssignment(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName,
|
moduleName,
|
||||||
assignmentName,
|
assignmentName,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const GET = async (
|
|||||||
params: { courseName, moduleName },
|
params: { courseName, moduleName },
|
||||||
}: { params: { courseName: string; moduleName: string } }
|
}: { params: { courseName: string; moduleName: string } }
|
||||||
) => await withErrorHandling(async () => {
|
) => await withErrorHandling(async () => {
|
||||||
const settings = await fileStorageService.getAssignmentNames(
|
const settings = await fileStorageService.assignments.getAssignmentNames(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName
|
moduleName
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const GET = async (
|
|||||||
}: { params: { courseName: string; moduleName: string; pageName: string } }
|
}: { params: { courseName: string; moduleName: string; pageName: string } }
|
||||||
) =>
|
) =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const settings = await fileStorageService.getPage(
|
const settings = await fileStorageService.pages.getPage(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName,
|
moduleName,
|
||||||
pageName
|
pageName
|
||||||
@@ -24,6 +24,6 @@ export const PUT = async (
|
|||||||
) =>
|
) =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const page = await request.json();
|
const page = await request.json();
|
||||||
await fileStorageService.updatePage(courseName, moduleName, pageName, page);
|
await fileStorageService.pages.updatePage(courseName, moduleName, pageName, page);
|
||||||
return Response.json({});
|
return Response.json({});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const GET = async (
|
|||||||
}: { params: { courseName: string; moduleName: string } }
|
}: { params: { courseName: string; moduleName: string } }
|
||||||
) =>
|
) =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const settings = await fileStorageService.getPageNames(
|
const settings = await fileStorageService.pages.getPageNames(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName
|
moduleName
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const GET = async (
|
|||||||
params: { courseName, moduleName, quizName },
|
params: { courseName, moduleName, quizName },
|
||||||
}: { params: { courseName: string; moduleName: string; quizName: string } }
|
}: { params: { courseName: string; moduleName: string; quizName: string } }
|
||||||
) => await withErrorHandling(async () => {
|
) => await withErrorHandling(async () => {
|
||||||
const quiz = await fileStorageService.getQuiz(
|
const quiz = await fileStorageService.quizzes.getQuiz(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName,
|
moduleName,
|
||||||
quizName
|
quizName
|
||||||
@@ -22,7 +22,7 @@ export const PUT = async (
|
|||||||
}: { params: { courseName: string; moduleName: string; quizName: string } }
|
}: { params: { courseName: string; moduleName: string; quizName: string } }
|
||||||
) => await withErrorHandling(async () => {
|
) => await withErrorHandling(async () => {
|
||||||
const quiz = await request.json()
|
const quiz = await request.json()
|
||||||
await fileStorageService.updateQuiz(
|
await fileStorageService.quizzes.updateQuiz(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName,
|
moduleName,
|
||||||
quizName,
|
quizName,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const GET = async (
|
|||||||
}: { params: { courseName: string; moduleName: string } }
|
}: { params: { courseName: string; moduleName: string } }
|
||||||
) =>
|
) =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const settings = await fileStorageService.getQuizNames(
|
const settings = await fileStorageService.quizzes.getQuizNames(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName
|
moduleName
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,6 +6,16 @@ export const GET = async (
|
|||||||
{ params: { courseName } }: { params: { courseName: string } }
|
{ params: { courseName } }: { params: { courseName: string } }
|
||||||
) =>
|
) =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const settings = await fileStorageService.getModuleNames(courseName);
|
const settings = await fileStorageService.modules.getModuleNames(courseName);
|
||||||
return Response.json(settings);
|
return Response.json(settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
request: Request,
|
||||||
|
{ params: { courseName } }: { params: { courseName: string } }
|
||||||
|
) =>
|
||||||
|
await withErrorHandling(async () => {
|
||||||
|
const { moduleName } = await request.json();
|
||||||
|
await fileStorageService.modules.createModule(courseName, moduleName);
|
||||||
|
return Response.json({});
|
||||||
|
});
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const GET = async (
|
|||||||
if (courseName.includes(".js.map")) {
|
if (courseName.includes(".js.map")) {
|
||||||
return Response.json({});
|
return Response.json({});
|
||||||
}
|
}
|
||||||
const settings = await fileStorageService.getCourseSettings(courseName);
|
const settings = await fileStorageService.settings.getCourseSettings(courseName);
|
||||||
return Response.json(settings);
|
return Response.json(settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ export const PUT = async (
|
|||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const settings = await request.json();
|
const settings = await request.json();
|
||||||
|
|
||||||
await fileStorageService.updateCourseSettings(courseName, settings);
|
await fileStorageService.settings.updateCourseSettings(courseName, settings);
|
||||||
|
|
||||||
return Response.json({});
|
return Response.json({});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const GET = async () =>
|
|||||||
export const POST = async (request: Request) =>
|
export const POST = async (request: Request) =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const newCourse: LocalCourse = await request.json();
|
const newCourse: LocalCourse = await request.json();
|
||||||
await fileStorageService.updateCourseSettings(
|
await fileStorageService.settings.updateCourseSettings(
|
||||||
newCourse.settings.name,
|
newCourse.settings.name,
|
||||||
newCourse.settings
|
newCourse.settings
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { withErrorHandling } from "@/services/withErrorHandling";
|
|||||||
|
|
||||||
export const GET = async () =>
|
export const GET = async () =>
|
||||||
await withErrorHandling(async () => {
|
await withErrorHandling(async () => {
|
||||||
const settings = await fileStorageService.getAllCoursesSettings();
|
const settings = await fileStorageService.settings.getAllCoursesSettings();
|
||||||
|
|
||||||
return Response.json(settings);
|
return Response.json(settings);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default function CourseSettingsLink() {
|
|||||||
<div>
|
<div>
|
||||||
{settings.name}
|
{settings.name}
|
||||||
|
|
||||||
<Link href={getCourseSettingsUrl(courseName)} shallow={true}>
|
<Link className="mx-3 underline" href={getCourseSettingsUrl(courseName)} shallow={true}>
|
||||||
Course Settings
|
Course Settings
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
10
nextjs/src/app/course/[courseName]/CourseTitle.tsx
Normal file
10
nextjs/src/app/course/[courseName]/CourseTitle.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useCourseContext } from "./context/courseContext"
|
||||||
|
|
||||||
|
export default function CourseTitle() {
|
||||||
|
const {courseName}= useCourseContext()
|
||||||
|
return (
|
||||||
|
<title>{courseName}</title>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ export const CalendarMonth = ({ month }: { month: CalendarMonthModel }) => {
|
|||||||
<h3
|
<h3
|
||||||
className={
|
className={
|
||||||
"text-2xl transition-all duration-500 " +
|
"text-2xl transition-all duration-500 " +
|
||||||
"hover:text-slate-50 underline hover:scale-105 "
|
"hover:text-slate-50 underline hover:scale-105 `"
|
||||||
}
|
}
|
||||||
onClick={toggleCollapse}
|
onClick={toggleCollapse}
|
||||||
role="button"
|
role="button"
|
||||||
@@ -36,7 +36,7 @@ export const CalendarMonth = ({ month }: { month: CalendarMonthModel }) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
id={monthName}
|
id={monthName}
|
||||||
className={"collapsable " + (isCollapsed ? "" : "expand")}
|
className={"collapsible " + (isCollapsed ? "" : "expand")}
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-7 text-center fw-bold">
|
<div className="grid grid-cols-7 text-center fw-bold">
|
||||||
{weekDaysList.map((day) => (
|
{weekDaysList.map((day) => (
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ import { IModuleItem } from "@/models/local/IModuleItem";
|
|||||||
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
|
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
|
||||||
import { getDayOfWeek } from "@/models/local/localCourse";
|
import { getDayOfWeek } from "@/models/local/localCourse";
|
||||||
import { getModuleItemUrl } from "@/services/urlUtils";
|
import { getModuleItemUrl } from "@/services/urlUtils";
|
||||||
|
import { LocalAssignment } from "@/models/local/assignment/localAssignment";
|
||||||
|
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
|
||||||
|
import { LocalCoursePage } from "@/models/local/page/localCoursePage";
|
||||||
|
|
||||||
export default function Day({ day, month }: { day: string; month: number }) {
|
export default function Day({ day, month }: { day: string; month: number }) {
|
||||||
const dayAsDate = getDateFromStringOrThrow(
|
const dayAsDate = getDateFromStringOrThrow(
|
||||||
@@ -74,9 +77,9 @@ export default function Day({ day, month }: { day: string; month: number }) {
|
|||||||
|
|
||||||
function getTodaysItems(todaysModules: {
|
function getTodaysItems(todaysModules: {
|
||||||
[moduleName: string]: {
|
[moduleName: string]: {
|
||||||
assignments: import("/home/alexm/projects/canvasManagement/nextjs/src/models/local/assignment/localAssignment").LocalAssignment[];
|
assignments: LocalAssignment[];
|
||||||
quizzes: import("/home/alexm/projects/canvasManagement/nextjs/src/models/local/quiz/localQuiz").LocalQuiz[];
|
quizzes: LocalQuiz[];
|
||||||
pages: import("/home/alexm/projects/canvasManagement/nextjs/src/models/local/page/localCoursePage").LocalCoursePage[];
|
pages: LocalCoursePage[];
|
||||||
};
|
};
|
||||||
}) {
|
}) {
|
||||||
const todaysAssignments = todaysModules
|
const todaysAssignments = todaysModules
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { useCourseContext } from "./courseContext";
|
|
||||||
import {
|
|
||||||
useAllCourseDataQuery,
|
|
||||||
} from "@/hooks/localCourse/localCoursesHooks";
|
|
||||||
import {
|
import {
|
||||||
CalendarItemsContext,
|
CalendarItemsContext,
|
||||||
CalendarItemsInterface,
|
CalendarItemsInterface,
|
||||||
} from "./calendarItemsContext";
|
} from "./calendarItemsContext";
|
||||||
import {
|
import {
|
||||||
dateToMarkdownString,
|
|
||||||
getDateFromStringOrThrow,
|
getDateFromStringOrThrow,
|
||||||
getDateOnlyMarkdownString,
|
getDateOnlyMarkdownString,
|
||||||
} from "@/models/local/timeUtils";
|
} from "@/models/local/timeUtils";
|
||||||
import { LocalAssignment } from "@/models/local/assignment/localAssignment";
|
import { useAllCourseDataQuery } from "@/hooks/localCourse/localCourseModuleHooks";
|
||||||
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
|
|
||||||
import { LocalCoursePage } from "@/models/local/page/localCoursePage";
|
|
||||||
|
|
||||||
export default function CalendarItemsContextProvider({
|
export default function CalendarItemsContextProvider({
|
||||||
children,
|
children,
|
||||||
|
|||||||
36
nextjs/src/app/course/[courseName]/modules/CreateModule.tsx
Normal file
36
nextjs/src/app/course/[courseName]/modules/CreateModule.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import TextInput from "@/components/form/TextInput";
|
||||||
|
import { useCreateModuleMutation } from "@/hooks/localCourse/localCourseModuleHooks";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
export default function CreateModule() {
|
||||||
|
const createModule = useCreateModuleMutation();
|
||||||
|
const [showForm, setShowForm] = useState(false);
|
||||||
|
const [moduleName, setModuleName] = useState("");
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button onClick={() => setShowForm((v) => !v)}>
|
||||||
|
{showForm ? "Hide Form" : "Create Module"}
|
||||||
|
</button>
|
||||||
|
<div className={"collapsible " + (showForm ? "expand" : "")}>
|
||||||
|
<form
|
||||||
|
onSubmit={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (moduleName) {
|
||||||
|
await createModule.mutateAsync(moduleName);
|
||||||
|
setModuleName("");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="p-1 border border-slate-500 rounded-md my-1 flex flex-row gap-3 justify-between"
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
className="flex-grow"
|
||||||
|
value={moduleName}
|
||||||
|
setValue={setModuleName}
|
||||||
|
label={"New Module Name"}
|
||||||
|
/>
|
||||||
|
<button className="mt-auto">Add</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useModuleNamesQuery } from "@/hooks/localCourse/localCoursesHooks";
|
import { useModuleNamesQuery } from "@/hooks/localCourse/localCourseModuleHooks";
|
||||||
import ExpandableModule from "./ExpandableModule";
|
import ExpandableModule from "./ExpandableModule";
|
||||||
|
import CreateModule from "./CreateModule";
|
||||||
|
|
||||||
export default function ModuleList() {
|
export default function ModuleList() {
|
||||||
const { data: moduleNames } = useModuleNamesQuery();
|
const { data: moduleNames } = useModuleNamesQuery();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<CreateModule />
|
||||||
{moduleNames.map((m) => (
|
{moduleNames.map((m) => (
|
||||||
<ExpandableModule key={m} moduleName={m}/>
|
<ExpandableModule key={m} moduleName={m} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,27 +3,31 @@ import CourseSettingsLink from "./CourseSettingsLink";
|
|||||||
import ModuleList from "./modules/ModuleList";
|
import ModuleList from "./modules/ModuleList";
|
||||||
import DraggingContextProvider from "./context/DraggingContextProvider";
|
import DraggingContextProvider from "./context/DraggingContextProvider";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import CourseTitle from "./CourseTitle";
|
||||||
|
|
||||||
export default async function CoursePage({}: {}) {
|
export default async function CoursePage({}: {}) {
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col">
|
<>
|
||||||
<div className="flex flex-row min-h-0">
|
<CourseTitle />
|
||||||
<DraggingContextProvider>
|
<div className="h-full flex flex-col">
|
||||||
<div className="flex-1 min-h-0">
|
<div className="flex flex-row min-h-0">
|
||||||
<div className="pb-1 ps-5">
|
<DraggingContextProvider>
|
||||||
<Link href={"/"} className="btn">
|
<div className="flex-1 min-h-0">
|
||||||
Back to Course List
|
<div className="pb-1 ps-5">
|
||||||
</Link>
|
<Link href={"/"} className="btn">
|
||||||
</div>
|
Back to Course List
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
<CourseCalendar />
|
<CourseCalendar />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-96 p-3">
|
<div className="w-96 p-3">
|
||||||
<CourseSettingsLink />
|
<CourseSettingsLink />
|
||||||
<ModuleList />
|
<ModuleList />
|
||||||
</div>
|
</div>
|
||||||
</DraggingContextProvider>
|
</DraggingContextProvider>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,12 +90,12 @@ select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.collapsable {
|
.collapsible {
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: max-height .5s ease-out;
|
transition: max-height .5s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.collapsable.expand {
|
.collapsible.expand {
|
||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ export default function AddNewCourse() {
|
|||||||
<div>
|
<div>
|
||||||
<button onClick={() => setShowForm(true)}>Add New Course</button>
|
<button onClick={() => setShowForm(true)}>Add New Course</button>
|
||||||
|
|
||||||
<div className={" collapsable " + (showForm && "expand")}>
|
<div className={" collapsible " + (showForm && "expand")}>
|
||||||
<div className="border rounded-md p-3 m-3">
|
<div className="border rounded-md p-3 m-3">
|
||||||
<SuspenseAndErrorHandling>
|
<SuspenseAndErrorHandling>
|
||||||
{showForm && <NewCourseForm />}
|
{showForm && <NewCourseForm />}
|
||||||
|
|||||||
@@ -4,17 +4,19 @@ export default function TextInput({
|
|||||||
value,
|
value,
|
||||||
setValue,
|
setValue,
|
||||||
label,
|
label,
|
||||||
|
className,
|
||||||
}: {
|
}: {
|
||||||
value: string;
|
value: string;
|
||||||
setValue: (newValue: string) => void;
|
setValue: (newValue: string) => void;
|
||||||
label: string;
|
label: string;
|
||||||
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<label className="block">
|
<label className={"block " + className}>
|
||||||
{label}
|
{label}
|
||||||
<br />
|
<br />
|
||||||
<input
|
<input
|
||||||
className="bg-slate-800 rounded-md px-1"
|
className="bg-slate-800 rounded-md w-full px-1"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => setValue(e.target.value)}
|
onChange={(e) => setValue(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { fileStorageService } from "@/services/fileStorage/fileStorageService";
|
|||||||
import { LocalCourseSettings } from "@/models/local/localCourse";
|
import { LocalCourseSettings } from "@/models/local/localCourse";
|
||||||
// https://tanstack.com/query/latest/docs/framework/react/guides/ssr
|
// https://tanstack.com/query/latest/docs/framework/react/guides/ssr
|
||||||
export const hydrateCourses = async (queryClient: QueryClient) => {
|
export const hydrateCourses = async (queryClient: QueryClient) => {
|
||||||
const allSettings = await fileStorageService.getAllCoursesSettings();
|
const allSettings = await fileStorageService.settings.getAllCoursesSettings();
|
||||||
const courseNames = allSettings.map((s) => s.name);
|
const courseNames = allSettings.map((s) => s.name);
|
||||||
await queryClient.prefetchQuery({
|
await queryClient.prefetchQuery({
|
||||||
queryKey: localCourseKeys.allCoursesSettings,
|
queryKey: localCourseKeys.allCoursesSettings,
|
||||||
@@ -22,21 +22,26 @@ export const hydrateCourse = async (
|
|||||||
queryClient: QueryClient,
|
queryClient: QueryClient,
|
||||||
courseSettings: LocalCourseSettings
|
courseSettings: LocalCourseSettings
|
||||||
) => {
|
) => {
|
||||||
const courseName = courseSettings.name
|
const courseName = courseSettings.name;
|
||||||
const moduleNames = await fileStorageService.getModuleNames(courseName);
|
const moduleNames = await fileStorageService.modules.getModuleNames(
|
||||||
|
courseName
|
||||||
|
);
|
||||||
const modulesData = await Promise.all(
|
const modulesData = await Promise.all(
|
||||||
moduleNames.map(async (moduleName) => {
|
moduleNames.map(async (moduleName) => {
|
||||||
const [assignmentNames, pageNames, quizNames] = await Promise.all([
|
const [assignmentNames, pageNames, quizNames] = await Promise.all([
|
||||||
await fileStorageService.getAssignmentNames(courseName, moduleName),
|
await fileStorageService.assignments.getAssignmentNames(
|
||||||
await fileStorageService.getPageNames(courseName, moduleName),
|
courseName,
|
||||||
await fileStorageService.getQuizNames(courseName, moduleName),
|
moduleName
|
||||||
|
),
|
||||||
|
await fileStorageService.pages.getPageNames(courseName, moduleName),
|
||||||
|
await fileStorageService.quizzes.getQuizNames(courseName, moduleName),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const [assignments, quizzes, pages] = await Promise.all([
|
const [assignments, quizzes, pages] = await Promise.all([
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
assignmentNames.map(
|
assignmentNames.map(
|
||||||
async (assignmentName) =>
|
async (assignmentName) =>
|
||||||
await fileStorageService.getAssignment(
|
await fileStorageService.assignments.getAssignment(
|
||||||
courseName,
|
courseName,
|
||||||
moduleName,
|
moduleName,
|
||||||
assignmentName
|
assignmentName
|
||||||
@@ -46,13 +51,13 @@ export const hydrateCourse = async (
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
quizNames.map(
|
quizNames.map(
|
||||||
async (quizName) =>
|
async (quizName) =>
|
||||||
await fileStorageService.getQuiz(courseName, moduleName, quizName)
|
await fileStorageService.quizzes.getQuiz(courseName, moduleName, quizName)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pageNames.map(
|
pageNames.map(
|
||||||
async (pageName) =>
|
async (pageName) =>
|
||||||
await fileStorageService.getPage(courseName, moduleName, pageName)
|
await fileStorageService.pages.getPage(courseName, moduleName, pageName)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,7 +1,18 @@
|
|||||||
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
||||||
import { axiosClient } from "@/services/axiosUtils";
|
import { axiosClient } from "@/services/axiosUtils";
|
||||||
import { useMutation, useSuspenseQuery } from "@tanstack/react-query";
|
import {
|
||||||
|
useMutation,
|
||||||
|
useQueryClient,
|
||||||
|
useSuspenseQueries,
|
||||||
|
useSuspenseQuery,
|
||||||
|
} from "@tanstack/react-query";
|
||||||
import { localCourseKeys } from "./localCourseKeys";
|
import { localCourseKeys } from "./localCourseKeys";
|
||||||
|
import {
|
||||||
|
getAssignmentNamesQueryConfig,
|
||||||
|
getAssignmentQueryConfig,
|
||||||
|
} from "./assignmentHooks";
|
||||||
|
import { getPageNamesQueryConfig, getPageQueryConfig } from "./pageHooks";
|
||||||
|
import { getQuizNamesQueryConfig, getQuizQueryConfig } from "./quizHooks";
|
||||||
|
|
||||||
export const useModuleNamesQuery = () => {
|
export const useModuleNamesQuery = () => {
|
||||||
const { courseName } = useCourseContext();
|
const { courseName } = useCourseContext();
|
||||||
@@ -17,11 +28,18 @@ export const useModuleNamesQuery = () => {
|
|||||||
|
|
||||||
export const useCreateModuleMutation = () => {
|
export const useCreateModuleMutation = () => {
|
||||||
const { courseName } = useCourseContext();
|
const { courseName } = useCourseContext();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (moduleName: string) => {
|
mutationFn: async (moduleName: string) => {
|
||||||
const url = `/api/courses/${courseName}/modules`;
|
const url = `/api/courses/${courseName}/modules`;
|
||||||
const response = await axiosClient.post(url, {moduleName});
|
const response = await axiosClient.post(url, { moduleName });
|
||||||
return response.data;},
|
return response.data;
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: localCourseKeys.moduleNames(courseName),
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,94 +73,94 @@ export const useCreateModuleMutation = () => {
|
|||||||
// // );
|
// // );
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// export const useAllCourseDataQuery = () => {
|
export const useAllCourseDataQuery = () => {
|
||||||
// const { courseName } = useCourseContext();
|
const { courseName } = useCourseContext();
|
||||||
// const { data: moduleNames } = useModuleNamesQuery();
|
const { data: moduleNames } = useModuleNamesQuery();
|
||||||
|
|
||||||
// const { data: assignmentNamesAndModules } = useSuspenseQueries({
|
const { data: assignmentNamesAndModules } = useSuspenseQueries({
|
||||||
// queries: moduleNames.map((moduleName) =>
|
queries: moduleNames.map((moduleName) =>
|
||||||
// getAssignmentNamesQueryConfig(courseName, moduleName)
|
getAssignmentNamesQueryConfig(courseName, moduleName)
|
||||||
// ),
|
),
|
||||||
// combine: (results) => ({
|
combine: (results) => ({
|
||||||
// data: results.flatMap((r, i) =>
|
data: results.flatMap((r, i) =>
|
||||||
// r.data.map((assignmentName) => ({
|
r.data.map((assignmentName) => ({
|
||||||
// moduleName: moduleNames[i],
|
moduleName: moduleNames[i],
|
||||||
// assignmentName,
|
assignmentName,
|
||||||
// }))
|
}))
|
||||||
// ),
|
),
|
||||||
// pending: results.some((r) => r.isPending),
|
pending: results.some((r) => r.isPending),
|
||||||
// }),
|
}),
|
||||||
// });
|
});
|
||||||
|
|
||||||
// const { data: assignmentsAndModules } = useSuspenseQueries({
|
const { data: assignmentsAndModules } = useSuspenseQueries({
|
||||||
// queries: assignmentNamesAndModules.map(
|
queries: assignmentNamesAndModules.map(
|
||||||
// ({ moduleName, assignmentName }, i) =>
|
({ moduleName, assignmentName }, i) =>
|
||||||
// getAssignmentQueryConfig(courseName, moduleName, assignmentName)
|
getAssignmentQueryConfig(courseName, moduleName, assignmentName)
|
||||||
// ),
|
),
|
||||||
// combine: (results) => ({
|
combine: (results) => ({
|
||||||
// data: results.flatMap((r, i) => ({
|
data: results.flatMap((r, i) => ({
|
||||||
// moduleName: assignmentNamesAndModules[i].moduleName,
|
moduleName: assignmentNamesAndModules[i].moduleName,
|
||||||
// assignment: r.data,
|
assignment: r.data,
|
||||||
// })),
|
})),
|
||||||
// pending: results.some((r) => r.isPending),
|
pending: results.some((r) => r.isPending),
|
||||||
// }),
|
}),
|
||||||
// });
|
});
|
||||||
|
|
||||||
// const { data: quizNamesAndModules } = useSuspenseQueries({
|
const { data: quizNamesAndModules } = useSuspenseQueries({
|
||||||
// queries: moduleNames.map((moduleName) =>
|
queries: moduleNames.map((moduleName) =>
|
||||||
// getQuizNamesQueryConfig(courseName, moduleName)
|
getQuizNamesQueryConfig(courseName, moduleName)
|
||||||
// ),
|
),
|
||||||
// combine: (results) => ({
|
combine: (results) => ({
|
||||||
// data: results.flatMap((r, i) =>
|
data: results.flatMap((r, i) =>
|
||||||
// r.data.map((quizName) => ({
|
r.data.map((quizName) => ({
|
||||||
// moduleName: moduleNames[i],
|
moduleName: moduleNames[i],
|
||||||
// quizName: quizName,
|
quizName: quizName,
|
||||||
// }))
|
}))
|
||||||
// ),
|
),
|
||||||
// pending: results.some((r) => r.isPending),
|
pending: results.some((r) => r.isPending),
|
||||||
// }),
|
}),
|
||||||
// });
|
});
|
||||||
|
|
||||||
// const { data: quizzesAndModules } = useSuspenseQueries({
|
const { data: quizzesAndModules } = useSuspenseQueries({
|
||||||
// queries: quizNamesAndModules.map(({ moduleName, quizName }, i) =>
|
queries: quizNamesAndModules.map(({ moduleName, quizName }, i) =>
|
||||||
// getQuizQueryConfig(courseName, moduleName, quizName)
|
getQuizQueryConfig(courseName, moduleName, quizName)
|
||||||
// ),
|
),
|
||||||
// combine: (results) => ({
|
combine: (results) => ({
|
||||||
// data: results.flatMap((r, i) => ({
|
data: results.flatMap((r, i) => ({
|
||||||
// moduleName: quizNamesAndModules[i].moduleName,
|
moduleName: quizNamesAndModules[i].moduleName,
|
||||||
// quiz: r.data,
|
quiz: r.data,
|
||||||
// })),
|
})),
|
||||||
// pending: results.some((r) => r.isPending),
|
pending: results.some((r) => r.isPending),
|
||||||
// }),
|
}),
|
||||||
// });
|
});
|
||||||
|
|
||||||
// const { data: pageNamesAndModules } = useSuspenseQueries({
|
const { data: pageNamesAndModules } = useSuspenseQueries({
|
||||||
// queries: moduleNames.map((moduleName) =>
|
queries: moduleNames.map((moduleName) =>
|
||||||
// getPageNamesQueryConfig(courseName, moduleName)
|
getPageNamesQueryConfig(courseName, moduleName)
|
||||||
// ),
|
),
|
||||||
// combine: (results) => ({
|
combine: (results) => ({
|
||||||
// data: results.flatMap((r, i) =>
|
data: results.flatMap((r, i) =>
|
||||||
// r.data.map((pageName) => ({
|
r.data.map((pageName) => ({
|
||||||
// moduleName: moduleNames[i],
|
moduleName: moduleNames[i],
|
||||||
// pageName,
|
pageName,
|
||||||
// }))
|
}))
|
||||||
// ),
|
),
|
||||||
// pending: results.some((r) => r.isPending),
|
pending: results.some((r) => r.isPending),
|
||||||
// }),
|
}),
|
||||||
// });
|
});
|
||||||
|
|
||||||
// const { data: pagesAndModules } = useSuspenseQueries({
|
const { data: pagesAndModules } = useSuspenseQueries({
|
||||||
// queries: pageNamesAndModules.map(({ moduleName, pageName }, i) =>
|
queries: pageNamesAndModules.map(({ moduleName, pageName }, i) =>
|
||||||
// getPageQueryConfig(courseName, moduleName, pageName)
|
getPageQueryConfig(courseName, moduleName, pageName)
|
||||||
// ),
|
),
|
||||||
// combine: (results) => ({
|
combine: (results) => ({
|
||||||
// data: results.flatMap((r, i) => ({
|
data: results.flatMap((r, i) => ({
|
||||||
// moduleName: pageNamesAndModules[i].moduleName,
|
moduleName: pageNamesAndModules[i].moduleName,
|
||||||
// page: r.data,
|
page: r.data,
|
||||||
// })),
|
})),
|
||||||
// pending: results.some((r) => r.isPending),
|
pending: results.some((r) => r.isPending),
|
||||||
// }),
|
}),
|
||||||
// });
|
});
|
||||||
|
|
||||||
// return { assignmentsAndModules, quizzesAndModules, pagesAndModules };
|
return { assignmentsAndModules, quizzesAndModules, pagesAndModules };
|
||||||
// };
|
};
|
||||||
|
|||||||
@@ -49,221 +49,230 @@ export const fileStorageService = {
|
|||||||
|
|
||||||
return courseNamesFromDirectories;
|
return courseNamesFromDirectories;
|
||||||
},
|
},
|
||||||
|
settings: {
|
||||||
|
async getAllCoursesSettings() {
|
||||||
|
const courses = await fileStorageService.getCourseNames();
|
||||||
|
|
||||||
async getAllCoursesSettings() {
|
const courseSettings = await Promise.all(
|
||||||
const courses = await fileStorageService.getCourseNames();
|
courses.map(
|
||||||
|
async (c) => await fileStorageService.settings.getCourseSettings(c)
|
||||||
const settings = await Promise.all(
|
)
|
||||||
courses.map(async (c) => await fileStorageService.getCourseSettings(c))
|
|
||||||
);
|
|
||||||
return settings;
|
|
||||||
},
|
|
||||||
|
|
||||||
async getCourseSettings(courseName: string): Promise<LocalCourseSettings> {
|
|
||||||
const courseDirectory = path.join(basePath, courseName);
|
|
||||||
const settingsPath = path.join(courseDirectory, "settings.yml");
|
|
||||||
if (!(await directoryOrFileExists(settingsPath))) {
|
|
||||||
const errorMessage = `Error loading settings for ${courseName}, settings file ${settingsPath}`;
|
|
||||||
console.log(errorMessage);
|
|
||||||
throw new Error(errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
const settingsString = await fs.readFile(settingsPath, "utf-8");
|
|
||||||
const settings = localCourseYamlUtils.parseSettingYaml(settingsString);
|
|
||||||
|
|
||||||
const folderName = path.basename(courseDirectory);
|
|
||||||
return { ...settings, name: folderName };
|
|
||||||
},
|
|
||||||
|
|
||||||
async updateCourseSettings(
|
|
||||||
courseName: string,
|
|
||||||
settings: LocalCourseSettings
|
|
||||||
) {
|
|
||||||
const courseDirectory = path.join(basePath, courseName);
|
|
||||||
const settingsPath = path.join(courseDirectory, "settings.yml");
|
|
||||||
|
|
||||||
const { name, ...settingsWithoutName } = settings;
|
|
||||||
const settingsMarkdown =
|
|
||||||
localCourseYamlUtils.settingsToYaml(settingsWithoutName);
|
|
||||||
|
|
||||||
console.log(`Saving settings ${settingsPath}`);
|
|
||||||
await fs.writeFile(settingsPath, settingsMarkdown);
|
|
||||||
},
|
|
||||||
|
|
||||||
async getModuleNames(courseName: string) {
|
|
||||||
const courseDirectory = path.join(basePath, courseName);
|
|
||||||
const moduleDirectories = await fs.readdir(courseDirectory, {
|
|
||||||
withFileTypes: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const modulePromises = moduleDirectories
|
|
||||||
.filter((dirent) => dirent.isDirectory())
|
|
||||||
.map((dirent) => dirent.name);
|
|
||||||
|
|
||||||
const modules = await Promise.all(modulePromises);
|
|
||||||
return modules.sort((a, b) => a.localeCompare(b));
|
|
||||||
},
|
|
||||||
async createModule(courseName: string, moduleName: string) {
|
|
||||||
const courseDirectory = path.join(basePath, courseName);
|
|
||||||
|
|
||||||
await fs.mkdir(courseDirectory + "/" + moduleName, { recursive: true });
|
|
||||||
},
|
|
||||||
|
|
||||||
async getAssignmentNames(courseName: string, moduleName: string) {
|
|
||||||
const filePath = path.join(basePath, courseName, moduleName, "assignments");
|
|
||||||
if (!(await directoryOrFileExists(filePath))) {
|
|
||||||
console.log(
|
|
||||||
`Error loading course by name, assignments folder does not exist in ${filePath}`
|
|
||||||
);
|
);
|
||||||
await fs.mkdir(filePath);
|
return courseSettings;
|
||||||
}
|
},
|
||||||
|
async getCourseSettings(courseName: string): Promise<LocalCourseSettings> {
|
||||||
|
const courseDirectory = path.join(basePath, courseName);
|
||||||
|
const settingsPath = path.join(courseDirectory, "settings.yml");
|
||||||
|
if (!(await directoryOrFileExists(settingsPath))) {
|
||||||
|
const errorMessage = `Error loading settings for ${courseName}, settings file ${settingsPath}`;
|
||||||
|
console.log(errorMessage);
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
const assignmentFiles = await fs.readdir(filePath);
|
const settingsString = await fs.readFile(settingsPath, "utf-8");
|
||||||
return assignmentFiles.map((f) => f.replace(/\.md$/, ""));
|
const settings = localCourseYamlUtils.parseSettingYaml(settingsString);
|
||||||
|
|
||||||
|
const folderName = path.basename(courseDirectory);
|
||||||
|
return { ...settings, name: folderName };
|
||||||
|
},
|
||||||
|
|
||||||
|
async updateCourseSettings(
|
||||||
|
courseName: string,
|
||||||
|
settings: LocalCourseSettings
|
||||||
|
) {
|
||||||
|
const courseDirectory = path.join(basePath, courseName);
|
||||||
|
const settingsPath = path.join(courseDirectory, "settings.yml");
|
||||||
|
|
||||||
|
const { name, ...settingsWithoutName } = settings;
|
||||||
|
const settingsMarkdown =
|
||||||
|
localCourseYamlUtils.settingsToYaml(settingsWithoutName);
|
||||||
|
|
||||||
|
console.log(`Saving settings ${settingsPath}`);
|
||||||
|
await fs.writeFile(settingsPath, settingsMarkdown);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
modules: {
|
||||||
|
async getModuleNames(courseName: string) {
|
||||||
|
const courseDirectory = path.join(basePath, courseName);
|
||||||
|
const moduleDirectories = await fs.readdir(courseDirectory, {
|
||||||
|
withFileTypes: true,
|
||||||
|
});
|
||||||
|
|
||||||
async getQuizNames(courseName: string, moduleName: string) {
|
const modulePromises = moduleDirectories
|
||||||
const filePath = path.join(basePath, courseName, moduleName, "quizzes");
|
.filter((dirent) => dirent.isDirectory())
|
||||||
if (!(await directoryOrFileExists(filePath))) {
|
.map((dirent) => dirent.name);
|
||||||
console.log(
|
|
||||||
`Error loading course by name, quiz folder does not exist in ${filePath}`
|
const modules = await Promise.all(modulePromises);
|
||||||
|
return modules.sort((a, b) => a.localeCompare(b));
|
||||||
|
},
|
||||||
|
async createModule(courseName: string, moduleName: string) {
|
||||||
|
const courseDirectory = path.join(basePath, courseName);
|
||||||
|
|
||||||
|
await fs.mkdir(courseDirectory + "/" + moduleName, { recursive: true });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assignments: {
|
||||||
|
async getAssignmentNames(courseName: string, moduleName: string) {
|
||||||
|
const filePath = path.join(
|
||||||
|
basePath,
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
"assignments"
|
||||||
);
|
);
|
||||||
await fs.mkdir(filePath);
|
if (!(await directoryOrFileExists(filePath))) {
|
||||||
}
|
console.log(
|
||||||
|
`Error loading course by name, assignments folder does not exist in ${filePath}`
|
||||||
|
);
|
||||||
|
await fs.mkdir(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
const files = await fs.readdir(filePath);
|
const assignmentFiles = await fs.readdir(filePath);
|
||||||
return files.map((f) => f.replace(/\.md$/, ""));
|
return assignmentFiles.map((f) => f.replace(/\.md$/, ""));
|
||||||
},
|
},
|
||||||
|
async getAssignment(
|
||||||
async getPageNames(courseName: string, moduleName: string) {
|
courseName: string,
|
||||||
const filePath = path.join(basePath, courseName, moduleName, "pages");
|
moduleName: string,
|
||||||
if (!(await directoryOrFileExists(filePath))) {
|
assignmentName: string
|
||||||
console.log(
|
) {
|
||||||
`Error loading course by name, pages folder does not exist in ${filePath}`
|
const filePath = path.join(
|
||||||
|
basePath,
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
"assignments",
|
||||||
|
assignmentName + ".md"
|
||||||
|
);
|
||||||
|
const rawFile = (await fs.readFile(filePath, "utf-8")).replace(
|
||||||
|
/\r\n/g,
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
return localAssignmentMarkdown.parseMarkdown(rawFile);
|
||||||
|
},
|
||||||
|
async updateAssignment(
|
||||||
|
courseName: string,
|
||||||
|
moduleName: string,
|
||||||
|
assignmentName: string,
|
||||||
|
assignment: LocalAssignment
|
||||||
|
) {
|
||||||
|
const filePath = path.join(
|
||||||
|
basePath,
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
"assignments",
|
||||||
|
assignmentName + ".md"
|
||||||
);
|
);
|
||||||
await fs.mkdir(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = await fs.readdir(filePath);
|
const assignmentMarkdown =
|
||||||
return files.map((f) => f.replace(/\.md$/, ""));
|
assignmentMarkdownSerializer.toMarkdown(assignment);
|
||||||
|
console.log(`Saving assignment ${filePath}`);
|
||||||
|
await fs.writeFile(filePath, assignmentMarkdown);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
quizzes: {
|
||||||
|
async getQuizNames(courseName: string, moduleName: string) {
|
||||||
|
const filePath = path.join(basePath, courseName, moduleName, "quizzes");
|
||||||
|
if (!(await directoryOrFileExists(filePath))) {
|
||||||
|
console.log(
|
||||||
|
`Error loading course by name, quiz folder does not exist in ${filePath}`
|
||||||
|
);
|
||||||
|
await fs.mkdir(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
async getAssignment(
|
const files = await fs.readdir(filePath);
|
||||||
courseName: string,
|
return files.map((f) => f.replace(/\.md$/, ""));
|
||||||
moduleName: string,
|
},
|
||||||
assignmentName: string
|
async getQuiz(courseName: string, moduleName: string, quizName: string) {
|
||||||
) {
|
const filePath = path.join(
|
||||||
const filePath = path.join(
|
basePath,
|
||||||
basePath,
|
courseName,
|
||||||
courseName,
|
moduleName,
|
||||||
moduleName,
|
"quizzes",
|
||||||
"assignments",
|
quizName + ".md"
|
||||||
assignmentName + ".md"
|
);
|
||||||
);
|
const rawFile = (await fs.readFile(filePath, "utf-8")).replace(
|
||||||
const rawFile = (await fs.readFile(filePath, "utf-8")).replace(
|
/\r\n/g,
|
||||||
/\r\n/g,
|
"\n"
|
||||||
"\n"
|
);
|
||||||
);
|
return localQuizMarkdownUtils.parseMarkdown(rawFile);
|
||||||
return localAssignmentMarkdown.parseMarkdown(rawFile);
|
},
|
||||||
|
|
||||||
|
async updateQuiz(
|
||||||
|
courseName: string,
|
||||||
|
moduleName: string,
|
||||||
|
quizName: string,
|
||||||
|
quiz: LocalQuiz
|
||||||
|
) {
|
||||||
|
const filePath = path.join(
|
||||||
|
basePath,
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
"quizzes",
|
||||||
|
quizName + ".md"
|
||||||
|
);
|
||||||
|
|
||||||
|
const quizMarkdown = quizMarkdownUtils.toMarkdown(quiz);
|
||||||
|
console.log(`Saving quiz ${filePath}`);
|
||||||
|
await fs.writeFile(filePath, quizMarkdown);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async updateAssignment(
|
pages: {
|
||||||
courseName: string,
|
async getPageNames(courseName: string, moduleName: string) {
|
||||||
moduleName: string,
|
const filePath = path.join(basePath, courseName, moduleName, "pages");
|
||||||
assignmentName: string,
|
if (!(await directoryOrFileExists(filePath))) {
|
||||||
assignment: LocalAssignment
|
console.log(
|
||||||
) {
|
`Error loading course by name, pages folder does not exist in ${filePath}`
|
||||||
const filePath = path.join(
|
);
|
||||||
basePath,
|
await fs.mkdir(filePath);
|
||||||
courseName,
|
}
|
||||||
moduleName,
|
|
||||||
"assignments",
|
|
||||||
assignmentName + ".md"
|
|
||||||
);
|
|
||||||
|
|
||||||
const assignmentMarkdown =
|
const files = await fs.readdir(filePath);
|
||||||
assignmentMarkdownSerializer.toMarkdown(assignment);
|
return files.map((f) => f.replace(/\.md$/, ""));
|
||||||
console.log(`Saving assignment ${filePath}`);
|
},
|
||||||
await fs.writeFile(filePath, assignmentMarkdown);
|
|
||||||
},
|
|
||||||
|
|
||||||
async getQuiz(courseName: string, moduleName: string, quizName: string) {
|
async getPage(courseName: string, moduleName: string, pageName: string) {
|
||||||
const filePath = path.join(
|
const filePath = path.join(
|
||||||
basePath,
|
|
||||||
courseName,
|
|
||||||
moduleName,
|
|
||||||
"quizzes",
|
|
||||||
quizName + ".md"
|
|
||||||
);
|
|
||||||
const rawFile = (await fs.readFile(filePath, "utf-8")).replace(
|
|
||||||
/\r\n/g,
|
|
||||||
"\n"
|
|
||||||
);
|
|
||||||
return localQuizMarkdownUtils.parseMarkdown(rawFile);
|
|
||||||
},
|
|
||||||
|
|
||||||
async updateQuiz(
|
|
||||||
courseName: string,
|
|
||||||
moduleName: string,
|
|
||||||
quizName: string,
|
|
||||||
quiz: LocalQuiz
|
|
||||||
) {
|
|
||||||
const filePath = path.join(
|
|
||||||
basePath,
|
|
||||||
courseName,
|
|
||||||
moduleName,
|
|
||||||
"quizzes",
|
|
||||||
quizName + ".md"
|
|
||||||
);
|
|
||||||
|
|
||||||
const quizMarkdown = quizMarkdownUtils.toMarkdown(quiz);
|
|
||||||
console.log(`Saving quiz ${filePath}`);
|
|
||||||
await fs.writeFile(filePath, quizMarkdown);
|
|
||||||
},
|
|
||||||
|
|
||||||
async getPage(courseName: string, moduleName: string, pageName: string) {
|
|
||||||
const filePath = path.join(
|
|
||||||
basePath,
|
|
||||||
courseName,
|
|
||||||
moduleName,
|
|
||||||
"pages",
|
|
||||||
pageName + ".md"
|
|
||||||
);
|
|
||||||
const rawFile = (await fs.readFile(filePath, "utf-8")).replace(
|
|
||||||
/\r\n/g,
|
|
||||||
"\n"
|
|
||||||
);
|
|
||||||
return localPageMarkdownUtils.parseMarkdown(rawFile);
|
|
||||||
},
|
|
||||||
async updatePage(
|
|
||||||
courseName: string,
|
|
||||||
moduleName: string,
|
|
||||||
pageName: string,
|
|
||||||
page: LocalCoursePage
|
|
||||||
) {
|
|
||||||
const filePath = path.join(
|
|
||||||
basePath,
|
|
||||||
courseName,
|
|
||||||
moduleName,
|
|
||||||
"pages",
|
|
||||||
page.name + ".md"
|
|
||||||
);
|
|
||||||
|
|
||||||
const pageMarkdown = localPageMarkdownUtils.toMarkdown(page);
|
|
||||||
console.log(`Saving page ${filePath}`);
|
|
||||||
await fs.writeFile(filePath, pageMarkdown);
|
|
||||||
|
|
||||||
const pageNameIsChanged = pageName !== page.name;
|
|
||||||
if (pageNameIsChanged) {
|
|
||||||
console.log("removing old page after name change " + pageName);
|
|
||||||
const oldFilePath = path.join(
|
|
||||||
basePath,
|
basePath,
|
||||||
courseName,
|
courseName,
|
||||||
moduleName,
|
moduleName,
|
||||||
"pages",
|
"pages",
|
||||||
pageName + ".md"
|
pageName + ".md"
|
||||||
);
|
);
|
||||||
await fs.unlink(oldFilePath);
|
const rawFile = (await fs.readFile(filePath, "utf-8")).replace(
|
||||||
}
|
/\r\n/g,
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
return localPageMarkdownUtils.parseMarkdown(rawFile);
|
||||||
|
},
|
||||||
|
async updatePage(
|
||||||
|
courseName: string,
|
||||||
|
moduleName: string,
|
||||||
|
pageName: string,
|
||||||
|
page: LocalCoursePage
|
||||||
|
) {
|
||||||
|
const filePath = path.join(
|
||||||
|
basePath,
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
"pages",
|
||||||
|
page.name + ".md"
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageMarkdown = localPageMarkdownUtils.toMarkdown(page);
|
||||||
|
console.log(`Saving page ${filePath}`);
|
||||||
|
await fs.writeFile(filePath, pageMarkdown);
|
||||||
|
|
||||||
|
const pageNameIsChanged = pageName !== page.name;
|
||||||
|
if (pageNameIsChanged) {
|
||||||
|
console.log("removing old page after name change " + pageName);
|
||||||
|
const oldFilePath = path.join(
|
||||||
|
basePath,
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
"pages",
|
||||||
|
pageName + ".md"
|
||||||
|
);
|
||||||
|
await fs.unlink(oldFilePath);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
async getEmptyDirectories(): Promise<string[]> {
|
async getEmptyDirectories(): Promise<string[]> {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,449 +3,449 @@ import { LocalCourse } from "@/models/local/localCourse";
|
|||||||
import { CourseDifferences } from "../fileStorage/utils/courseDifferences";
|
import { CourseDifferences } from "../fileStorage/utils/courseDifferences";
|
||||||
|
|
||||||
describe("CourseDifferencesDeletionsTests", () => {
|
describe("CourseDifferencesDeletionsTests", () => {
|
||||||
it("same module does not get deleted", () => {
|
// it("same module does not get deleted", () => {
|
||||||
const oldCourse: LocalCourse = {
|
// const oldCourse: LocalCourse = {
|
||||||
settings: {
|
// settings: {
|
||||||
name: "test course",
|
// name: "test course",
|
||||||
assignmentGroups: [],
|
// assignmentGroups: [],
|
||||||
daysOfWeek: [],
|
// daysOfWeek: [],
|
||||||
startDate: "07/09/2024 23:59:00",
|
// startDate: "07/09/2024 23:59:00",
|
||||||
endDate: "07/09/2024 23:59:00",
|
// endDate: "07/09/2024 23:59:00",
|
||||||
defaultDueTime: {
|
// defaultDueTime: {
|
||||||
hour: 23,
|
// hour: 23,
|
||||||
minute: 59,
|
// minute: 59,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [],
|
// assignments: [],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
const newCourse: LocalCourse = {
|
// const newCourse: LocalCourse = {
|
||||||
...oldCourse,
|
// ...oldCourse,
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [],
|
// assignments: [],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|
||||||
const differences = CourseDifferences.getDeletedChanges(
|
// const differences = CourseDifferences.getDeletedChanges(
|
||||||
newCourse,
|
// newCourse,
|
||||||
oldCourse
|
// oldCourse
|
||||||
);
|
// );
|
||||||
|
|
||||||
expect(differences.namesOfModulesToDeleteCompletely).toHaveLength(0);
|
// expect(differences.namesOfModulesToDeleteCompletely).toHaveLength(0);
|
||||||
});
|
// });
|
||||||
|
|
||||||
it("changed module - old one gets deleted", () => {
|
// it("changed module - old one gets deleted", () => {
|
||||||
const oldCourse: LocalCourse = {
|
// const oldCourse: LocalCourse = {
|
||||||
settings: {
|
// settings: {
|
||||||
name: "test course",
|
// name: "test course",
|
||||||
assignmentGroups: [],
|
// assignmentGroups: [],
|
||||||
daysOfWeek: [],
|
// daysOfWeek: [],
|
||||||
startDate: "07/09/2024 23:59:00",
|
// startDate: "07/09/2024 23:59:00",
|
||||||
endDate: "07/09/2024 23:59:00",
|
// endDate: "07/09/2024 23:59:00",
|
||||||
defaultDueTime: {
|
// defaultDueTime: {
|
||||||
hour: 23,
|
// hour: 23,
|
||||||
minute: 59,
|
// minute: 59,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [],
|
// assignments: [],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
const newCourse: LocalCourse = {
|
// const newCourse: LocalCourse = {
|
||||||
...oldCourse,
|
// ...oldCourse,
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module 2",
|
// name: "test module 2",
|
||||||
assignments: [],
|
// assignments: [],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|
||||||
const differences = CourseDifferences.getDeletedChanges(
|
// const differences = CourseDifferences.getDeletedChanges(
|
||||||
newCourse,
|
// newCourse,
|
||||||
oldCourse
|
// oldCourse
|
||||||
);
|
// );
|
||||||
|
|
||||||
expect(differences.namesOfModulesToDeleteCompletely).toHaveLength(1);
|
// expect(differences.namesOfModulesToDeleteCompletely).toHaveLength(1);
|
||||||
expect(differences.namesOfModulesToDeleteCompletely[0]).toBe("test module");
|
// expect(differences.namesOfModulesToDeleteCompletely[0]).toBe("test module");
|
||||||
});
|
// });
|
||||||
|
|
||||||
it("new assignment name gets deleted", () => {
|
// it("new assignment name gets deleted", () => {
|
||||||
const oldCourse: LocalCourse = {
|
// const oldCourse: LocalCourse = {
|
||||||
settings: {
|
// settings: {
|
||||||
name: "test course",
|
// name: "test course",
|
||||||
assignmentGroups: [],
|
// assignmentGroups: [],
|
||||||
daysOfWeek: [],
|
// daysOfWeek: [],
|
||||||
startDate: "07/09/2024 23:59:00",
|
// startDate: "07/09/2024 23:59:00",
|
||||||
endDate: "07/09/2024 23:59:00",
|
// endDate: "07/09/2024 23:59:00",
|
||||||
defaultDueTime: {
|
// defaultDueTime: {
|
||||||
hour: 23,
|
// hour: 23,
|
||||||
minute: 59,
|
// minute: 59,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [
|
// assignments: [
|
||||||
{
|
// {
|
||||||
name: "test assignment",
|
// name: "test assignment",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
submissionTypes: [],
|
// submissionTypes: [],
|
||||||
allowedFileUploadExtensions: [],
|
// allowedFileUploadExtensions: [],
|
||||||
rubric: [],
|
// rubric: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
const newCourse: LocalCourse = {
|
// const newCourse: LocalCourse = {
|
||||||
...oldCourse,
|
// ...oldCourse,
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [
|
// assignments: [
|
||||||
{
|
// {
|
||||||
name: "test assignment changed name",
|
// name: "test assignment changed name",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
submissionTypes: [],
|
// submissionTypes: [],
|
||||||
allowedFileUploadExtensions: [],
|
// allowedFileUploadExtensions: [],
|
||||||
rubric: [],
|
// rubric: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|
||||||
const differences = CourseDifferences.getDeletedChanges(
|
// const differences = CourseDifferences.getDeletedChanges(
|
||||||
newCourse,
|
// newCourse,
|
||||||
oldCourse
|
// oldCourse
|
||||||
);
|
// );
|
||||||
|
|
||||||
expect(differences.namesOfModulesToDeleteCompletely).toHaveLength(0);
|
// expect(differences.namesOfModulesToDeleteCompletely).toHaveLength(0);
|
||||||
expect(differences.deleteContentsOfModule).toHaveLength(1);
|
// expect(differences.deleteContentsOfModule).toHaveLength(1);
|
||||||
expect(differences.deleteContentsOfModule[0].assignments).toHaveLength(1);
|
// expect(differences.deleteContentsOfModule[0].assignments).toHaveLength(1);
|
||||||
expect(differences.deleteContentsOfModule[0].assignments[0].name).toBe(
|
// expect(differences.deleteContentsOfModule[0].assignments[0].name).toBe(
|
||||||
"test assignment"
|
// "test assignment"
|
||||||
);
|
// );
|
||||||
});
|
// });
|
||||||
|
|
||||||
it("assignments with changed descriptions do not get deleted", () => {
|
// it("assignments with changed descriptions do not get deleted", () => {
|
||||||
const oldCourse: LocalCourse = {
|
// const oldCourse: LocalCourse = {
|
||||||
settings: {
|
// settings: {
|
||||||
name: "test course",
|
// name: "test course",
|
||||||
assignmentGroups: [],
|
// assignmentGroups: [],
|
||||||
daysOfWeek: [],
|
// daysOfWeek: [],
|
||||||
startDate: "07/09/2024 23:59:00",
|
// startDate: "07/09/2024 23:59:00",
|
||||||
endDate: "07/09/2024 23:59:00",
|
// endDate: "07/09/2024 23:59:00",
|
||||||
defaultDueTime: {
|
// defaultDueTime: {
|
||||||
hour: 23,
|
// hour: 23,
|
||||||
minute: 59,
|
// minute: 59,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [
|
// assignments: [
|
||||||
{
|
// {
|
||||||
name: "test assignment",
|
// name: "test assignment",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
submissionTypes: [],
|
// submissionTypes: [],
|
||||||
allowedFileUploadExtensions: [],
|
// allowedFileUploadExtensions: [],
|
||||||
rubric: [],
|
// rubric: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
const newCourse: LocalCourse = {
|
// const newCourse: LocalCourse = {
|
||||||
...oldCourse,
|
// ...oldCourse,
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [
|
// assignments: [
|
||||||
{
|
// {
|
||||||
name: "test assignment",
|
// name: "test assignment",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
submissionTypes: [],
|
// submissionTypes: [],
|
||||||
allowedFileUploadExtensions: [],
|
// allowedFileUploadExtensions: [],
|
||||||
rubric: [],
|
// rubric: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|
||||||
const differences = CourseDifferences.getDeletedChanges(
|
// const differences = CourseDifferences.getDeletedChanges(
|
||||||
newCourse,
|
// newCourse,
|
||||||
oldCourse
|
// oldCourse
|
||||||
);
|
// );
|
||||||
|
|
||||||
expect(differences.deleteContentsOfModule).toHaveLength(0);
|
// expect(differences.deleteContentsOfModule).toHaveLength(0);
|
||||||
});
|
// });
|
||||||
|
|
||||||
it("can detect changed and unchanged assignments", () => {
|
// it("can detect changed and unchanged assignments", () => {
|
||||||
const oldCourse: LocalCourse = {
|
// const oldCourse: LocalCourse = {
|
||||||
settings: {
|
// settings: {
|
||||||
name: "test course",
|
// name: "test course",
|
||||||
assignmentGroups: [],
|
// assignmentGroups: [],
|
||||||
daysOfWeek: [],
|
// daysOfWeek: [],
|
||||||
startDate: "07/09/2024 23:59:00",
|
// startDate: "07/09/2024 23:59:00",
|
||||||
endDate: "07/09/2024 23:59:00",
|
// endDate: "07/09/2024 23:59:00",
|
||||||
defaultDueTime: {
|
// defaultDueTime: {
|
||||||
hour: 23,
|
// hour: 23,
|
||||||
minute: 59,
|
// minute: 59,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [
|
// assignments: [
|
||||||
{
|
// {
|
||||||
name: "test assignment",
|
// name: "test assignment",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
submissionTypes: [],
|
// submissionTypes: [],
|
||||||
allowedFileUploadExtensions: [],
|
// allowedFileUploadExtensions: [],
|
||||||
rubric: [],
|
// rubric: [],
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "test assignment 2",
|
// name: "test assignment 2",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
submissionTypes: [],
|
// submissionTypes: [],
|
||||||
allowedFileUploadExtensions: [],
|
// allowedFileUploadExtensions: [],
|
||||||
rubric: [],
|
// rubric: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
const newCourse: LocalCourse = {
|
// const newCourse: LocalCourse = {
|
||||||
...oldCourse,
|
// ...oldCourse,
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [
|
// assignments: [
|
||||||
{
|
// {
|
||||||
name: "test assignment",
|
// name: "test assignment",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
submissionTypes: [],
|
// submissionTypes: [],
|
||||||
allowedFileUploadExtensions: [],
|
// allowedFileUploadExtensions: [],
|
||||||
rubric: [],
|
// rubric: [],
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "test assignment 2 changed",
|
// name: "test assignment 2 changed",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
submissionTypes: [],
|
// submissionTypes: [],
|
||||||
allowedFileUploadExtensions: [],
|
// allowedFileUploadExtensions: [],
|
||||||
rubric: [],
|
// rubric: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|
||||||
const differences = CourseDifferences.getDeletedChanges(
|
// const differences = CourseDifferences.getDeletedChanges(
|
||||||
newCourse,
|
// newCourse,
|
||||||
oldCourse
|
// oldCourse
|
||||||
);
|
// );
|
||||||
|
|
||||||
expect(differences.deleteContentsOfModule).toHaveLength(1);
|
// expect(differences.deleteContentsOfModule).toHaveLength(1);
|
||||||
expect(differences.deleteContentsOfModule[0].assignments).toHaveLength(1);
|
// expect(differences.deleteContentsOfModule[0].assignments).toHaveLength(1);
|
||||||
expect(differences.deleteContentsOfModule[0].assignments[0].name).toBe(
|
// expect(differences.deleteContentsOfModule[0].assignments[0].name).toBe(
|
||||||
"test assignment 2"
|
// "test assignment 2"
|
||||||
);
|
// );
|
||||||
});
|
// });
|
||||||
|
|
||||||
it("changed quizzes get deleted", () => {
|
// it("changed quizzes get deleted", () => {
|
||||||
const oldCourse: LocalCourse = {
|
// const oldCourse: LocalCourse = {
|
||||||
settings: {
|
// settings: {
|
||||||
name: "test course",
|
// name: "test course",
|
||||||
assignmentGroups: [],
|
// assignmentGroups: [],
|
||||||
daysOfWeek: [],
|
// daysOfWeek: [],
|
||||||
startDate: "07/09/2024 23:59:00",
|
// startDate: "07/09/2024 23:59:00",
|
||||||
endDate: "07/09/2024 23:59:00",
|
// endDate: "07/09/2024 23:59:00",
|
||||||
defaultDueTime: {
|
// defaultDueTime: {
|
||||||
hour: 23,
|
// hour: 23,
|
||||||
minute: 59,
|
// minute: 59,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [],
|
// assignments: [],
|
||||||
quizzes: [
|
// quizzes: [
|
||||||
{
|
// {
|
||||||
name: "Test Quiz",
|
// name: "Test Quiz",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
shuffleAnswers: false,
|
// shuffleAnswers: false,
|
||||||
showCorrectAnswers: false,
|
// showCorrectAnswers: false,
|
||||||
oneQuestionAtATime: false,
|
// oneQuestionAtATime: false,
|
||||||
allowedAttempts: 0,
|
// allowedAttempts: 0,
|
||||||
questions: [],
|
// questions: [],
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "Test Quiz 2",
|
// name: "Test Quiz 2",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
shuffleAnswers: false,
|
// shuffleAnswers: false,
|
||||||
showCorrectAnswers: false,
|
// showCorrectAnswers: false,
|
||||||
oneQuestionAtATime: false,
|
// oneQuestionAtATime: false,
|
||||||
allowedAttempts: 0,
|
// allowedAttempts: 0,
|
||||||
questions: [],
|
// questions: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
const newCourse: LocalCourse = {
|
// const newCourse: LocalCourse = {
|
||||||
...oldCourse,
|
// ...oldCourse,
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [],
|
// assignments: [],
|
||||||
quizzes: [
|
// quizzes: [
|
||||||
{
|
// {
|
||||||
name: "Test Quiz",
|
// name: "Test Quiz",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
shuffleAnswers: false,
|
// shuffleAnswers: false,
|
||||||
showCorrectAnswers: false,
|
// showCorrectAnswers: false,
|
||||||
oneQuestionAtATime: false,
|
// oneQuestionAtATime: false,
|
||||||
allowedAttempts: 0,
|
// allowedAttempts: 0,
|
||||||
questions: [],
|
// questions: [],
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "Test Quiz 3",
|
// name: "Test Quiz 3",
|
||||||
description: "test description",
|
// description: "test description",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
shuffleAnswers: false,
|
// shuffleAnswers: false,
|
||||||
showCorrectAnswers: false,
|
// showCorrectAnswers: false,
|
||||||
oneQuestionAtATime: false,
|
// oneQuestionAtATime: false,
|
||||||
allowedAttempts: 0,
|
// allowedAttempts: 0,
|
||||||
questions: [],
|
// questions: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
pages: [],
|
// pages: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|
||||||
const differences = CourseDifferences.getDeletedChanges(
|
// const differences = CourseDifferences.getDeletedChanges(
|
||||||
newCourse,
|
// newCourse,
|
||||||
oldCourse
|
// oldCourse
|
||||||
);
|
// );
|
||||||
|
|
||||||
expect(differences.deleteContentsOfModule).toHaveLength(1);
|
// expect(differences.deleteContentsOfModule).toHaveLength(1);
|
||||||
expect(differences.deleteContentsOfModule[0].quizzes).toHaveLength(1);
|
// expect(differences.deleteContentsOfModule[0].quizzes).toHaveLength(1);
|
||||||
expect(differences.deleteContentsOfModule[0].quizzes[0].name).toBe(
|
// expect(differences.deleteContentsOfModule[0].quizzes[0].name).toBe(
|
||||||
"Test Quiz 2"
|
// "Test Quiz 2"
|
||||||
);
|
// );
|
||||||
});
|
// });
|
||||||
|
|
||||||
it("changed pages get deleted", () => {
|
// it("changed pages get deleted", () => {
|
||||||
const oldCourse: LocalCourse = {
|
// const oldCourse: LocalCourse = {
|
||||||
settings: {
|
// settings: {
|
||||||
name: "test course",
|
// name: "test course",
|
||||||
assignmentGroups: [],
|
// assignmentGroups: [],
|
||||||
daysOfWeek: [],
|
// daysOfWeek: [],
|
||||||
startDate: "07/09/2024 23:59:00",
|
// startDate: "07/09/2024 23:59:00",
|
||||||
endDate: "07/09/2024 23:59:00",
|
// endDate: "07/09/2024 23:59:00",
|
||||||
defaultDueTime: {
|
// defaultDueTime: {
|
||||||
hour: 23,
|
// hour: 23,
|
||||||
minute: 59,
|
// minute: 59,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [],
|
// assignments: [],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [
|
// pages: [
|
||||||
{
|
// {
|
||||||
name: "Test Page",
|
// name: "Test Page",
|
||||||
text: "test contents",
|
// text: "test contents",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "Test Page 2",
|
// name: "Test Page 2",
|
||||||
text: "test contents",
|
// text: "test contents",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
const newCourse: LocalCourse = {
|
// const newCourse: LocalCourse = {
|
||||||
...oldCourse,
|
// ...oldCourse,
|
||||||
modules: [
|
// modules: [
|
||||||
{
|
// {
|
||||||
name: "test module",
|
// name: "test module",
|
||||||
assignments: [],
|
// assignments: [],
|
||||||
quizzes: [],
|
// quizzes: [],
|
||||||
pages: [
|
// pages: [
|
||||||
{
|
// {
|
||||||
name: "Test Page",
|
// name: "Test Page",
|
||||||
text: "test contents",
|
// text: "test contents",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "Test Page 3",
|
// name: "Test Page 3",
|
||||||
text: "test contents",
|
// text: "test contents",
|
||||||
dueAt: "07/09/2024 23:59:00",
|
// dueAt: "07/09/2024 23:59:00",
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|
||||||
const differences = CourseDifferences.getDeletedChanges(
|
// const differences = CourseDifferences.getDeletedChanges(
|
||||||
newCourse,
|
// newCourse,
|
||||||
oldCourse
|
// oldCourse
|
||||||
);
|
// );
|
||||||
|
|
||||||
expect(differences.deleteContentsOfModule).toHaveLength(1);
|
// expect(differences.deleteContentsOfModule).toHaveLength(1);
|
||||||
expect(differences.deleteContentsOfModule[0].pages).toHaveLength(1);
|
// expect(differences.deleteContentsOfModule[0].pages).toHaveLength(1);
|
||||||
expect(differences.deleteContentsOfModule[0].pages[0].name).toBe(
|
// expect(differences.deleteContentsOfModule[0].pages[0].name).toBe(
|
||||||
"Test Page 2"
|
// "Test Page 2"
|
||||||
);
|
// );
|
||||||
});
|
// });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ describe("FileStorageTests", () => {
|
|||||||
canvasId: 0,
|
canvasId: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
await fileStorageService.updateCourseSettings(name, settings);
|
await fileStorageService.settings.updateCourseSettings(name, settings);
|
||||||
|
|
||||||
const loadedSettings = await fileStorageService.getCourseSettings(name);
|
const loadedSettings = await fileStorageService.settings.getCourseSettings(name);
|
||||||
|
|
||||||
expect(loadedSettings).toEqual(settings);
|
expect(loadedSettings).toEqual(settings);
|
||||||
});
|
});
|
||||||
@@ -43,9 +43,9 @@ describe("FileStorageTests", () => {
|
|||||||
const courseName = "test empty course";
|
const courseName = "test empty course";
|
||||||
const moduleName = "test module 1";
|
const moduleName = "test module 1";
|
||||||
|
|
||||||
await fileStorageService.createModule(courseName, moduleName);
|
await fileStorageService.modules.createModule(courseName, moduleName);
|
||||||
|
|
||||||
const moduleNames = await fileStorageService.getModuleNames(courseName);
|
const moduleNames = await fileStorageService.modules.getModuleNames(courseName);
|
||||||
|
|
||||||
expect(moduleNames).toContain(moduleName);
|
expect(moduleNames).toContain(moduleName);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user