mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
more refactoring by feature
This commit is contained in:
121
src/features/local/lectures/lectureFileStorageService.ts
Normal file
121
src/features/local/lectures/lectureFileStorageService.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
import { Lecture } from "@/features/local/lectures/lectureModel";
|
||||
import { getDateFromStringOrThrow } from "@/models/local/utils/timeUtils";
|
||||
import { getCoursePathByName } from "@/services/fileStorage/globalSettingsFileStorageService";
|
||||
import {
|
||||
lectureFolderName,
|
||||
parseLecture,
|
||||
getLectureWeekName,
|
||||
lectureToString,
|
||||
} from "@/services/fileStorage/utils/lectureUtils";
|
||||
import { LocalCourseSettings, getDayOfWeek } from "../course/localCourseSettings";
|
||||
|
||||
export async function getLectures(courseName: string) {
|
||||
const courseDirectory = await getCoursePathByName(courseName);
|
||||
const courseLectureRoot = path.join(courseDirectory, lectureFolderName);
|
||||
if (!(await directoryExists(courseLectureRoot))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const entries = await fs.readdir(courseLectureRoot, { withFileTypes: true });
|
||||
const lectureWeekFolders = entries
|
||||
.filter((entry) => entry.isDirectory())
|
||||
.map((entry) => entry.name);
|
||||
|
||||
const lecturesByWeek = await Promise.all(
|
||||
lectureWeekFolders.map(async (weekName) => {
|
||||
const weekBasePath = path.join(courseLectureRoot, weekName);
|
||||
const fileNames = await fs.readdir(weekBasePath);
|
||||
const lectures = await Promise.all(
|
||||
fileNames.map(async (fileName) => {
|
||||
const filePath = path.join(weekBasePath, fileName);
|
||||
const fileContent = await fs.readFile(filePath, "utf-8");
|
||||
const lecture = parseLecture(fileContent);
|
||||
return lecture;
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
weekName,
|
||||
lectures,
|
||||
};
|
||||
})
|
||||
);
|
||||
return lecturesByWeek;
|
||||
}
|
||||
|
||||
export async function updateLecture(
|
||||
courseName: string,
|
||||
courseSettings: LocalCourseSettings,
|
||||
lecture: Lecture
|
||||
) {
|
||||
const courseDirectory = await getCoursePathByName(courseName);
|
||||
const courseLectureRoot = path.join(courseDirectory, lectureFolderName);
|
||||
const lectureDate = getDateFromStringOrThrow(
|
||||
lecture.date,
|
||||
"lecture start date in update lecture"
|
||||
);
|
||||
|
||||
const weekFolderName = getLectureWeekName(
|
||||
courseSettings.startDate,
|
||||
lecture.date
|
||||
);
|
||||
const weekPath = path.join(courseLectureRoot, weekFolderName);
|
||||
if (!(await directoryExists(weekPath))) {
|
||||
await fs.mkdir(weekPath, { recursive: true });
|
||||
}
|
||||
|
||||
const lecturePath = path.join(
|
||||
weekPath,
|
||||
`${lectureDate.getDay()}-${getDayOfWeek(lectureDate)}.md`
|
||||
);
|
||||
const lectureContents = lectureToString(lecture);
|
||||
await fs.writeFile(lecturePath, lectureContents);
|
||||
}
|
||||
|
||||
export async function deleteLecture(
|
||||
courseName: string,
|
||||
courseSettings: LocalCourseSettings,
|
||||
dayAsString: string
|
||||
) {
|
||||
console.log("deleting lecture", courseName, dayAsString);
|
||||
const lectureDate = getDateFromStringOrThrow(
|
||||
dayAsString,
|
||||
"lecture start date in update lecture"
|
||||
);
|
||||
|
||||
const weekFolderName = getLectureWeekName(
|
||||
courseSettings.startDate,
|
||||
dayAsString
|
||||
);
|
||||
|
||||
const courseDirectory = await getCoursePathByName(courseName);
|
||||
const courseLectureRoot = path.join(courseDirectory, lectureFolderName);
|
||||
const weekPath = path.join(courseLectureRoot, weekFolderName);
|
||||
const lecturePath = path.join(
|
||||
weekPath,
|
||||
`${lectureDate.getDay()}-${getDayOfWeek(lectureDate)}.md`
|
||||
);
|
||||
try {
|
||||
await fs.access(lecturePath); // throws error if no file
|
||||
await fs.unlink(lecturePath);
|
||||
console.log(`File deleted: ${lecturePath}`);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
if (error?.code === "ENOENT") {
|
||||
console.log(`Cannot delete lecture, file does not exist: ${lecturePath}`);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const directoryExists = async (path: string): Promise<boolean> => {
|
||||
try {
|
||||
const stat = await fs.stat(path);
|
||||
return stat.isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
43
src/features/local/lectures/lectureHooks.ts
Normal file
43
src/features/local/lectures/lectureHooks.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
||||
import { useTRPC } from "@/services/serverFunctions/trpcClient";
|
||||
import {
|
||||
useSuspenseQuery,
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
export const useLecturesSuspenseQuery = () => {
|
||||
const { courseName } = useCourseContext();
|
||||
const trpc = useTRPC();
|
||||
return useSuspenseQuery(
|
||||
trpc.lectures.getLectures.queryOptions({ courseName })
|
||||
);
|
||||
};
|
||||
|
||||
export const useLectureUpdateMutation = () => {
|
||||
const trpc = useTRPC();
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
trpc.lectures.updateLecture.mutationOptions({
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: trpc.lectures.getLectures.queryKey(),
|
||||
});
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export const useDeleteLectureMutation = () => {
|
||||
const trpc = useTRPC();
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
trpc.lectures.deleteLecture.mutationOptions({
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: trpc.lectures.getLectures.queryKey(),
|
||||
});
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
||||
13
src/features/local/lectures/lectureModel.ts
Normal file
13
src/features/local/lectures/lectureModel.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export interface Lecture {
|
||||
name: string
|
||||
date: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export const zodLecture = z.object({
|
||||
name: z.string(),
|
||||
date: z.string(),
|
||||
content: z.string(),
|
||||
});
|
||||
51
src/features/local/lectures/lectureRouter.ts
Normal file
51
src/features/local/lectures/lectureRouter.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { z } from "zod";
|
||||
import publicProcedure from "../../../services/serverFunctions/procedures/public";
|
||||
import { router } from "../../../services/serverFunctions/trpcSetup";
|
||||
import { zodLecture } from "@/features/local/lectures/lectureModel";
|
||||
import {
|
||||
getLectures,
|
||||
updateLecture,
|
||||
deleteLecture,
|
||||
} from "./lectureFileStorageService";
|
||||
import { zodLocalCourseSettings } from "../course/localCourseSettings";
|
||||
|
||||
export const lectureRouter = router({
|
||||
getLectures: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
courseName: z.string(),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { courseName } }) => {
|
||||
return await getLectures(courseName);
|
||||
}),
|
||||
updateLecture: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
courseName: z.string(),
|
||||
lecture: zodLecture,
|
||||
previousDay: z.string().optional(),
|
||||
settings: zodLocalCourseSettings,
|
||||
})
|
||||
)
|
||||
.mutation(
|
||||
async ({ input: { courseName, settings, lecture, previousDay } }) => {
|
||||
await updateLecture(courseName, settings, lecture);
|
||||
|
||||
if (previousDay && previousDay !== lecture.date) {
|
||||
await deleteLecture(courseName, settings, previousDay);
|
||||
}
|
||||
}
|
||||
),
|
||||
deleteLecture: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
courseName: z.string(),
|
||||
lectureDay: z.string(),
|
||||
settings: zodLocalCourseSettings,
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { courseName, settings, lectureDay } }) => {
|
||||
await deleteLecture(courseName, settings, lectureDay);
|
||||
}),
|
||||
});
|
||||
Reference in New Issue
Block a user