can upload images

This commit is contained in:
2025-01-24 12:03:16 -07:00
parent a60008c6d7
commit f0c147cd6a
5 changed files with 36 additions and 18 deletions

View File

@@ -21,6 +21,7 @@ import { useRouter } from "next/navigation";
import { AssignmentFooterButtons } from "./AssignmentFooterButtons"; import { AssignmentFooterButtons } from "./AssignmentFooterButtons";
import { useAuthoritativeUpdates } from "@/app/course/[courseName]/utils/useAuthoritativeUpdates"; import { useAuthoritativeUpdates } from "@/app/course/[courseName]/utils/useAuthoritativeUpdates";
import EditAssignmentHeader from "./EditAssignmentHeader"; import EditAssignmentHeader from "./EditAssignmentHeader";
import { Spinner } from "@/components/Spinner";
export default function EditAssignment({ export default function EditAssignment({
moduleName, moduleName,
@@ -37,7 +38,8 @@ export default function EditAssignment({
{ dataUpdatedAt: serverDataUpdatedAt, isFetching: assignmentIsFetching }, { dataUpdatedAt: serverDataUpdatedAt, isFetching: assignmentIsFetching },
] = useAssignmentQuery(moduleName, assignmentName); ] = useAssignmentQuery(moduleName, assignmentName);
const updateAssignment = useUpdateAssignmentMutation(); const updateAssignment = useUpdateAssignmentMutation();
useUpdateImageSettingsForAssignment({ moduleName, assignmentName }); const { isPending: imageUpdateIsPending } =
useUpdateImageSettingsForAssignment({ moduleName, assignmentName });
const { const {
clientIsAuthoritative, clientIsAuthoritative,
@@ -152,6 +154,12 @@ export default function EditAssignment({
<div className="px-3 h-full"> <div className="px-3 h-full">
<ClientOnly> <ClientOnly>
<SuspenseAndErrorHandling showToast={false}> <SuspenseAndErrorHandling showToast={false}>
{imageUpdateIsPending && (
<div className="flex justify-center">
<Spinner /> images being uploaded to canvas
</div>
)}
<AssignmentPreview assignment={assignment} /> <AssignmentPreview assignment={assignment} />
</SuspenseAndErrorHandling> </SuspenseAndErrorHandling>
</ClientOnly> </ClientOnly>

View File

@@ -35,7 +35,7 @@ export const useUpdateImageSettingsForAssignment = ({
const [settings] = useLocalCourseSettingsQuery(); const [settings] = useLocalCourseSettingsQuery();
const [assignment] = useAssignmentQuery(moduleName, assignmentName); const [assignment] = useAssignmentQuery(moduleName, assignmentName);
const updateSettings = useUpdateLocalCourseSettingsMutation(); const updateSettings = useUpdateLocalCourseSettingsMutation();
const [isUpdatingSettings, setIsUpdatingSettings] = useState(false); const [isPending, setIsPending] = useState(false);
const createCanvasUrlMutation = const createCanvasUrlMutation =
trpc.canvasFile.getCanvasFileUrl.useMutation(); trpc.canvasFile.getCanvasFileUrl.useMutation();
@@ -45,18 +45,17 @@ export const useUpdateImageSettingsForAssignment = ({
return; return;
} }
if (isUpdatingSettings) { if (isPending) {
console.log("not updating image assets, still loading"); console.log("not updating image assets, still loading");
return; return;
} }
setIsUpdatingSettings(true); setIsPending(true);
const assignmentMarkdown = markdownToHtmlNoImages(assignment.description); const assignmentMarkdown = markdownToHtmlNoImages(assignment.description);
const imageSources = extractImageSources(assignmentMarkdown); const imageSources = extractImageSources(assignmentMarkdown);
const imagesToUpdate = imageSources.filter((source) => const imagesToUpdate = imageSources.filter((source) =>
settings.assets.every((a) => a.sourceUrl !== source) settings.assets.every((a) => a.sourceUrl !== source)
); );
console.log("images to update", imagesToUpdate);
if (imagesToUpdate.length) { if (imagesToUpdate.length) {
Promise.all( Promise.all(
@@ -78,17 +77,20 @@ export const useUpdateImageSettingsForAssignment = ({
assets: [...settings.assets, ...newAssets], assets: [...settings.assets, ...newAssets],
}, },
}); });
setIsUpdatingSettings(false); setIsPending(false);
}); });
} else {
setIsPending(false)
} }
}, [ }, [
assignment.description, assignment.description,
createCanvasUrlMutation, createCanvasUrlMutation,
isUpdatingSettings, isPending,
settings, settings,
settings.assets, settings.assets,
updateSettings, updateSettings,
]); ]);
return { isPending };
}; };
export const useAssignmentNamesQuery = (moduleName: string) => { export const useAssignmentNamesQuery = (moduleName: string) => {

View File

@@ -29,6 +29,7 @@ export const canvasAssignmentService = {
) { ) {
console.log(`Creating assignment: ${localAssignment.name}`); console.log(`Creating assignment: ${localAssignment.name}`);
const url = `${canvasApi}/courses/${canvasCourseId}/assignments`; const url = `${canvasApi}/courses/${canvasCourseId}/assignments`;
const content = markdownToHTMLSafe(localAssignment.description, settings);
const body = { const body = {
assignment: { assignment: {
name: localAssignment.name, name: localAssignment.name,
@@ -38,7 +39,7 @@ export const canvasAssignmentService = {
allowed_extensions: localAssignment.allowedFileUploadExtensions.map( allowed_extensions: localAssignment.allowedFileUploadExtensions.map(
(e) => e.toString() (e) => e.toString()
), ),
description: markdownToHTMLSafe(localAssignment.description, settings), description: content,
due_at: getDateFromString(localAssignment.dueAt)?.toISOString(), due_at: getDateFromString(localAssignment.dueAt)?.toISOString(),
lock_at: lock_at:
localAssignment.lockAt && localAssignment.lockAt &&

View File

@@ -1,13 +1,15 @@
"use client"; "use client";
import { marked } from "marked"; import { marked } from "marked";
import DOMPurify from "isomorphic-dompurify"; import DOMPurify from "isomorphic-dompurify";
import { LocalCourseSettings } from "@/models/local/localCourseSettings"; import { LocalCourseSettings } from "@/models/local/localCourseSettings";
import markedKatex from "marked-katex-extension"; import markedKatex from "marked-katex-extension";
marked.use(markedKatex({ marked.use(
throwOnError: false, markedKatex({
output: "mathml" throwOnError: false,
})); output: "mathml",
})
);
export function extractImageSources(htmlString: string) { export function extractImageSources(htmlString: string) {
const srcUrls = []; const srcUrls = [];
@@ -46,7 +48,8 @@ export function markdownToHTMLSafe(
markdownString: string, markdownString: string,
settings: LocalCourseSettings settings: LocalCourseSettings
) { ) {
return markdownToHtmlNoImages(markdownString); const html = markdownToHtmlNoImages(markdownString);
return convertImagesToCanvasImages(html, settings);
} }
export function markdownToHtmlNoImages(markdownString: string) { export function markdownToHtmlNoImages(markdownString: string) {

View File

@@ -7,6 +7,8 @@ import {
uploadToCanvasPart2, uploadToCanvasPart2,
} from "@/services/canvas/files/canvasFileService"; } from "@/services/canvas/files/canvasFileService";
const fileStorageLocation = process.env.FILE_STORAGE_LOCATION ?? "/app/public";
export const canvasFileRouter = router({ export const canvasFileRouter = router({
getCanvasFileUrl: publicProcedure getCanvasFileUrl: publicProcedure
.input( .input(
@@ -16,15 +18,17 @@ export const canvasFileRouter = router({
}) })
) )
.mutation(async ({ input: { sourceUrl, canvasCourseId } }) => { .mutation(async ({ input: { sourceUrl, canvasCourseId } }) => {
const localTempFile = await downloadUrlToTempDirectory(sourceUrl); const localFile = sourceUrl.startsWith("/")
console.log("local temp file", localTempFile); ? fileStorageLocation + sourceUrl
: await downloadUrlToTempDirectory(sourceUrl);
console.log("local temp file", localFile);
const { upload_url, upload_params } = await uploadToCanvasPart1( const { upload_url, upload_params } = await uploadToCanvasPart1(
localTempFile, localFile,
canvasCourseId canvasCourseId
); );
console.log("part 1 done", upload_url, upload_params); console.log("part 1 done", upload_url, upload_params);
const canvasUrl = await uploadToCanvasPart2({ const canvasUrl = await uploadToCanvasPart2({
pathToUpload: localTempFile, pathToUpload: localFile,
upload_url, upload_url,
upload_params, upload_params,
}); });