passing settings into markdown rendering

This commit is contained in:
2024-11-19 14:14:08 -07:00
parent e2eb63660d
commit cf200dab7f
19 changed files with 104 additions and 35 deletions

View File

@@ -7,6 +7,7 @@ import { CanvasRubricCreationResponse } from "@/models/canvas/assignments/canvas
import { assignmentPoints } from "@/models/local/assignment/utils/assignmentPointsUtils";
import { getDateFromString } from "@/models/local/utils/timeUtils";
import { getRubricCriterion } from "./canvasRubricUtils";
import { LocalCourseSettings } from "@/models/local/localCourseSettings";
export const canvasAssignmentService = {
async getAll(courseId: number): Promise<CanvasAssignment[]> {
@@ -23,6 +24,7 @@ export const canvasAssignmentService = {
async create(
canvasCourseId: number,
localAssignment: LocalAssignment,
settings: LocalCourseSettings,
canvasAssignmentGroupId?: number
) {
console.log(`Creating assignment: ${localAssignment.name}`);
@@ -36,7 +38,7 @@ export const canvasAssignmentService = {
allowed_extensions: localAssignment.allowedFileUploadExtensions.map(
(e) => e.toString()
),
description: markdownToHTMLSafe(localAssignment.description),
description: markdownToHTMLSafe(localAssignment.description, settings),
due_at: getDateFromString(localAssignment.dueAt)?.toISOString(),
lock_at:
localAssignment.lockAt &&
@@ -58,6 +60,7 @@ export const canvasAssignmentService = {
courseId: number,
canvasAssignmentId: number,
localAssignment: LocalAssignment,
settings: LocalCourseSettings,
canvasAssignmentGroupId?: number
) {
console.log(`Updating assignment: ${localAssignment.name}`);
@@ -71,7 +74,7 @@ export const canvasAssignmentService = {
allowed_extensions: localAssignment.allowedFileUploadExtensions.map(
(e) => e.toString()
),
description: markdownToHTMLSafe(localAssignment.description),
description: markdownToHTMLSafe(localAssignment.description, settings),
due_at: getDateFromString(localAssignment.dueAt)?.toISOString(),
lock_at:
localAssignment.lockAt &&

View File

@@ -4,6 +4,7 @@ import { canvasApi, paginatedRequest } from "./canvasServiceUtils";
import { markdownToHTMLSafe } from "../htmlMarkdownUtils";
import { axiosClient } from "../axiosUtils";
import { rateLimitAwareDelete } from "./canvasWebRequestor";
import { LocalCourseSettings } from "@/models/local/localCourseSettings";
export const canvasPageService = {
async getAll(courseId: number): Promise<CanvasPage[]> {
@@ -17,14 +18,15 @@ export const canvasPageService = {
async create(
canvasCourseId: number,
page: LocalCoursePage
page: LocalCoursePage,
settings: LocalCourseSettings
): Promise<CanvasPage> {
console.log(`Creating course page: ${page.name}`);
const url = `${canvasApi}/courses/${canvasCourseId}/pages`;
const body = {
wiki_page: {
title: page.name,
body: markdownToHTMLSafe(page.text),
body: markdownToHTMLSafe(page.text, settings),
},
};
@@ -38,14 +40,15 @@ export const canvasPageService = {
async update(
courseId: number,
canvasPageId: number,
page: LocalCoursePage
page: LocalCoursePage,
settings: LocalCourseSettings
): Promise<void> {
console.log(`Updating course page: ${page.name}`);
const url = `${canvasApi}/courses/${courseId}/pages/${canvasPageId}`;
const body = {
wiki_page: {
title: page.name,
body: markdownToHTMLSafe(page.text),
body: markdownToHTMLSafe(page.text, settings),
},
};
await axiosClient.put(url, body);

View File

@@ -10,8 +10,12 @@ import {
QuestionType,
} from "@/models/local/quiz/localQuizQuestion";
import { CanvasQuizQuestion } from "@/models/canvas/quizzes/canvasQuizQuestionModel";
import { LocalCourseSettings } from "@/models/local/localCourseSettings";
const getAnswers = (question: LocalQuizQuestion) => {
const getAnswers = (
question: LocalQuizQuestion,
settings: LocalCourseSettings
) => {
if (question.questionType === QuestionType.MATCHING)
return question.answers.map((a) => ({
answer_match_left: a.text,
@@ -19,7 +23,7 @@ const getAnswers = (question: LocalQuizQuestion) => {
}));
return question.answers.map((answer) => ({
answer_html: markdownToHTMLSafe(answer.text),
answer_html: markdownToHTMLSafe(answer.text, settings),
answer_weight: answer.correct ? 100 : 0,
}));
};
@@ -28,18 +32,19 @@ const createQuestionOnly = async (
canvasCourseId: number,
canvasQuizId: number,
question: LocalQuizQuestion,
position: number
position: number,
settings: LocalCourseSettings
) => {
console.log("Creating individual question"); //, question);
const url = `${canvasApi}/courses/${canvasCourseId}/quizzes/${canvasQuizId}/questions`;
const body = {
question: {
question_text: markdownToHTMLSafe(question.text),
question_text: markdownToHTMLSafe(question.text, settings),
question_type: `${question.questionType}_question`,
points_possible: question.points,
position,
answers: getAnswers(question),
answers: getAnswers(question, settings),
},
};
@@ -93,13 +98,20 @@ const hackFixRedundantAssignments = async (canvasCourseId: number) => {
const createQuizQuestions = async (
canvasCourseId: number,
canvasQuizId: number,
localQuiz: LocalQuiz
localQuiz: LocalQuiz,
settings: LocalCourseSettings
) => {
console.log("Creating quiz questions"); //, localQuiz);
const tasks = localQuiz.questions.map(
async (question, index) =>
await createQuestionOnly(canvasCourseId, canvasQuizId, question, index)
await createQuestionOnly(
canvasCourseId,
canvasQuizId,
question,
index,
settings
)
);
const questionAndPositions = await Promise.all(tasks);
await hackFixQuestionOrdering(
@@ -126,15 +138,17 @@ export const canvasQuizService = {
async create(
canvasCourseId: number,
localQuiz: LocalQuiz,
settings: LocalCourseSettings,
canvasAssignmentGroupId?: number
) {
console.log("Creating quiz", localQuiz);
const url = `${canvasApi}/courses/${canvasCourseId}/quizzes`;
const body = {
quiz: {
title: localQuiz.name,
description: markdownToHTMLSafe(localQuiz.description),
description: markdownToHTMLSafe(localQuiz.description, settings),
shuffle_answers: localQuiz.shuffleAnswers,
access_code: localQuiz.password,
show_correct_answers: localQuiz.showCorrectAnswers,
@@ -158,7 +172,7 @@ export const canvasQuizService = {
};
const { data: canvasQuiz } = await axiosClient.post<CanvasQuiz>(url, body);
await createQuizQuestions(canvasCourseId, canvasQuiz.id, localQuiz);
await createQuizQuestions(canvasCourseId, canvasQuiz.id, localQuiz, settings);
return canvasQuiz.id;
},
async delete(canvasCourseId: number, canvasQuizId: number) {

View File

@@ -50,6 +50,9 @@ const populateDefaultValues = (settingsFromFile: LocalCourseSettings) => {
holidays: Array.isArray(settingsFromFile.holidays)
? settingsFromFile.holidays
: [],
assets: Array.isArray(settingsFromFile.assets)
? settingsFromFile.assets
: [],
};
return settings;
};

View File

@@ -1,18 +1,27 @@
"use client";
import { marked } from "marked";
// import markedKatex from "marked-katex-extension";
import * as DOMPurify from "isomorphic-dompurify";
import { LocalCourseSettings } from "@/models/local/localCourseSettings";
export function markdownToHTMLSafe(markdownString: string) {
// const options = {
// throwOnError: false,
// nonStandard: true
// };
// marked.use(markedKatex(options));
function extractImageSources(html: string) {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
const imgElements = doc.querySelectorAll("img");
const srcUrls = Array.from(imgElements).map((img) => img.src);
return srcUrls;
}
function handleImages(html: string, settings: LocalCourseSettings) {
const imageSources = extractImageSources(html);
console.log(imageSources);
}
export function markdownToHTMLSafe(
markdownString: string,
settings: LocalCourseSettings
) {
const clean = DOMPurify.sanitize(
marked.parse(markdownString, { async: false, pedantic: false, gfm: true })
);
handleImages(clean, settings);
return clean;
}

View File

@@ -31,6 +31,7 @@ describe("FileStorageTests", () => {
defaultAssignmentSubmissionTypes: [],
defaultFileUploadTypes: [],
holidays: [],
assets: []
};
await fileStorageService.settings.updateCourseSettings(name, settings);