Skip to content

Commit 9dbb365

Browse files
author
Rajat
committed
Sealed media
1 parent 33bc898 commit 9dbb365

File tree

46 files changed

+1815
-374
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1815
-374
lines changed

apps/queue/src/domain/__tests__/process-ongoing-sequences.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ describe("processOngoingSequence", () => {
834834
});
835835
await OngoingSequenceModel.deleteOne({ _id: ongoingSeq._id });
836836
await EmailDelivery.deleteMany({});
837-
});
837+
}, 15000);
838838

839839
it("should rewrite links for click tracking", async () => {
840840
// Create a sequence with links in the content
@@ -988,7 +988,7 @@ describe("processOngoingSequence", () => {
988988
});
989989
await OngoingSequenceModel.deleteOne({ _id: ongoingSeq._id });
990990
await EmailDelivery.deleteMany({});
991-
});
991+
}, 15000);
992992

993993
it("should not rewrite mailto, tel, anchor, and API links", async () => {
994994
// Create a sequence with various link types that should NOT be rewritten
@@ -1164,7 +1164,7 @@ describe("processOngoingSequence", () => {
11641164
});
11651165
await OngoingSequenceModel.deleteOne({ _id: ongoingSeq._id });
11661166
await EmailDelivery.deleteMany({});
1167-
});
1167+
}, 15000);
11681168

11691169
it("should include tracking pixel in rendered email", async () => {
11701170
// Spy on renderEmailToHtml before calling processOngoingSequence
@@ -1254,7 +1254,7 @@ describe("processOngoingSequence", () => {
12541254

12551255
await OngoingSequenceModel.deleteOne({ _id: ongoingSeq._id });
12561256
await EmailDelivery.deleteMany({});
1257-
});
1257+
}, 15000);
12581258
});
12591259

12601260
describe("getNextPublishedEmail", () => {

apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/manage/components/certificates.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ const MUTATION_UPDATE_CERTIFICATE_TEMPLATE = `
3838
mutation UpdateCertificateTemplate($courseId: String!, $title: String, $subtitle: String, $description: String, $signatureName: String, $signatureDesignation: String, $signatureImage: MediaInput, $logo: MediaInput) {
3939
updateCourseCertificateTemplate(courseId: $courseId, title: $title, subtitle: $subtitle, description: $description, signatureName: $signatureName, signatureDesignation: $signatureDesignation, signatureImage: $signatureImage, logo: $logo) {
4040
title
41+
signatureImage {
42+
mediaId
43+
originalFileName
44+
file
45+
thumbnail
46+
}
47+
logo {
48+
mediaId
49+
originalFileName
50+
file
51+
thumbnail
52+
}
4153
}
4254
}
4355
`;
@@ -246,12 +258,6 @@ export default function Certificates({
246258
const saveCertificateSignatureImage = async (media?: Media) => {
247259
if (!product?.courseId) return;
248260

249-
// Update local state immediately
250-
setCertificateTemplate((prev) => ({
251-
...prev,
252-
signatureImage: media || {},
253-
}));
254-
255261
// Prepare variables for the mutation
256262
const variables = {
257263
courseId: product.courseId,
@@ -269,6 +275,12 @@ export default function Certificates({
269275
.exec();
270276

271277
if (response?.updateCourseCertificateTemplate) {
278+
setCertificateTemplate({
279+
...certificateTemplate,
280+
signatureImage:
281+
response.updateCourseCertificateTemplate
282+
.signatureImage || {},
283+
});
272284
toast({
273285
title: TOAST_TITLE_SUCCESS,
274286
description: APP_MESSAGE_COURSE_SAVED,
@@ -288,9 +300,6 @@ export default function Certificates({
288300
const saveCertificateLogo = async (media?: Media) => {
289301
if (!product?.courseId) return;
290302

291-
// Update local state immediately
292-
setCertificateTemplate((prev) => ({ ...prev, logo: media || {} }));
293-
294303
// Prepare variables for the mutation
295304
const variables = {
296305
courseId: product.courseId,
@@ -308,6 +317,10 @@ export default function Certificates({
308317
.exec();
309318

310319
if (response?.updateCourseCertificateTemplate) {
320+
setCertificateTemplate({
321+
...certificateTemplate,
322+
logo: response.updateCourseCertificateTemplate.logo || {},
323+
});
311324
toast({
312325
title: TOAST_TITLE_SUCCESS,
313326
description: APP_MESSAGE_COURSE_SAVED,

apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/manage/page.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useEffect } from "react";
44
import DashboardContent from "@components/admin/dashboard-content";
5-
import { redirect, useParams } from "next/navigation";
5+
import { useParams, useRouter } from "next/navigation";
66
import { truncate } from "@ui-lib/utils";
77
import { Constants, UIConstants } from "@courselit/common-models";
88
import useProduct from "@/hooks/use-product";
@@ -58,9 +58,13 @@ export default function SettingsPage() {
5858
}
5959
}, [product]);
6060

61-
if (productLoaded && !product) {
62-
redirect("/dashboard/products");
63-
}
61+
const router = useRouter();
62+
63+
useEffect(() => {
64+
if (productLoaded && !product) {
65+
router.replace("/dashboard/products");
66+
}
67+
}, [productLoaded, product, router]);
6468

6569
if (!product) {
6670
return null;

apps/web/app/api/lessons/[id]/scorm/upload/route.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ export async function POST(
135135

136136
const { packageInfo } = result;
137137

138+
if (lesson.content?.mediaId && lesson.content.mediaId !== mediaId) {
139+
await medialit.delete(lesson.content.mediaId);
140+
}
141+
await medialit.seal(mediaId);
138142
// Update lesson content with SCORM metadata
139143
await Lesson.updateOne(
140144
{ lessonId, domain: domain._id },

apps/web/components/admin/page-editor/index.tsx

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -460,13 +460,6 @@ export default function PageEditor({
460460
};
461461

462462
const deleteWidget = async (widgetId: string) => {
463-
// const widgetIndex = layout.findIndex(
464-
// (widget) => widget.widgetId === widgetId,
465-
// );
466-
// layout.splice(widgetIndex, 1);
467-
// setLayout(layout);
468-
// onClose();
469-
// await savePage({ pageId: page.pageId!, layout });
470463
const mutation = `
471464
mutation ($pageId: String!, $blockId: String!) {
472465
page: deleteBlock(pageId: $pageId, blockId: $blockId) {
@@ -513,7 +506,6 @@ export default function PageEditor({
513506
},
514507
});
515508
setLayout(layout);
516-
//setShowWidgetSelector(false);
517509
onItemClick(widgetId);
518510
setLeftPaneContent("editor");
519511
await savePage({ pageId: page.pageId!, layout: [...layout] });
@@ -579,13 +571,6 @@ export default function PageEditor({
579571
/>
580572
)}
581573
{leftPaneContent === "editor" && editWidget}
582-
{/* {leftPaneContent === "fonts" && (
583-
<FontsList
584-
draftTypefaces={draftTypefaces}
585-
onClose={onClose}
586-
saveDraftTypefaces={saveDraftTypefaces}
587-
/>
588-
)} */}
589574
{leftPaneContent === "theme" && (
590575
<ThemeEditor
591576
onThemeChange={(theme) => {

apps/web/components/community/banner.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,7 @@ export default function Banner({
8080
<AlertDescription>
8181
{isTextEditorNonEmpty(bannerText) ? (
8282
<WidgetErrorBoundary widgetName="text-editor">
83-
<TextRenderer
84-
json={
85-
bannerText as unknown as Record<
86-
string,
87-
unknown
88-
>
89-
}
90-
/>
83+
<TextRenderer json={bannerText} />
9184
</WidgetErrorBoundary>
9285
) : (
9386
canEdit && (

apps/web/components/community/info.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Constants,
66
Membership,
77
PaymentPlan,
8+
TextEditorContent,
89
UIConstants,
910
} from "@courselit/common-models";
1011
import { FormEvent, Fragment, useContext, useState } from "react";
@@ -40,7 +41,7 @@ const { permissions } = UIConstants;
4041
interface CommunityInfoProps {
4142
id: string;
4243
name: string;
43-
description: Record<string, unknown>;
44+
description: TextEditorContent;
4445
image: string;
4546
memberCount: number;
4647
paymentPlan?: PaymentPlan;

apps/web/components/public/lesson-viewer/index.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { Link, Skeleton, useToast } from "@courselit/components-library";
2323
import { TextRenderer } from "@courselit/page-blocks";
2424
import {
2525
Constants,
26+
TextEditorContent,
2627
type Address,
2728
type Lesson,
2829
type Profile,
@@ -311,10 +312,7 @@ export const LessonViewer = ({
311312
<WidgetErrorBoundary widgetName="text-editor">
312313
<TextRenderer
313314
json={
314-
lesson.content as unknown as Record<
315-
string,
316-
unknown
317-
>
315+
lesson.content as TextEditorContent
318316
}
319317
theme={theme.theme}
320318
/>

apps/web/graphql/communities/logic.ts

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { checkPermission, generateUniqueId, slugify } from "@courselit/utils";
1+
import {
2+
checkPermission,
3+
extractMediaIDs,
4+
generateUniqueId,
5+
slugify,
6+
} from "@courselit/utils";
27
import CommunityModel, { InternalCommunity } from "@models/Community";
38
import constants from "../../config/constants";
49
import GQLContext from "../../models/GQLContext";
@@ -57,13 +62,12 @@ import { hasActiveSubscription } from "../users/logic";
5762
import { internal } from "@config/strings";
5863
import { hasCommunityPermission as hasPermission } from "@ui-lib/utils";
5964
import ActivityModel from "@models/Activity";
60-
import getDeletedMediaIds, {
61-
extractMediaIDs,
62-
} from "@/lib/get-deleted-media-ids";
63-
import { deleteMedia } from "@/services/medialit";
65+
import getDeletedMediaIds from "@/lib/get-deleted-media-ids";
66+
import { deleteMedia, sealMedia } from "@/services/medialit";
6467
import CommunityPostSubscriberModel from "@models/CommunityPostSubscriber";
6568
import InvoiceModel from "@models/Invoice";
6669
import { InternalMembership } from "@courselit/common-logic";
70+
import { replaceTempMediaWithSealedMediaInProseMirrorDoc } from "@/lib/replace-temp-media-with-sealed-media-in-prosemirror-doc";
6771

6872
const { permissions, communityPage } = constants;
6973

@@ -272,10 +276,6 @@ export async function updateCommunity({
272276
}): Promise<Community> {
273277
checkIfAuthenticated(ctx);
274278

275-
// if (!checkPermission(ctx.user.permissions, [permissions.manageCommunity])) {
276-
// throw new Error(responses.action_not_allowed);
277-
// }
278-
279279
const community = await CommunityModel.findOne<InternalCommunity>(
280280
getCommunityQuery(ctx, id),
281281
);
@@ -307,7 +307,10 @@ export async function updateCommunity({
307307
);
308308

309309
if (nextDescription) {
310-
community.description = JSON.parse(nextDescription);
310+
community.description =
311+
await replaceTempMediaWithSealedMediaInProseMirrorDoc(
312+
nextDescription,
313+
);
311314
}
312315
}
313316

@@ -321,7 +324,10 @@ export async function updateCommunity({
321324
);
322325

323326
if (nextBanner) {
324-
community.banner = JSON.parse(nextBanner);
327+
community.banner =
328+
await replaceTempMediaWithSealedMediaInProseMirrorDoc(
329+
nextBanner,
330+
);
325331
}
326332
}
327333

@@ -334,7 +340,9 @@ export async function updateCommunity({
334340
}
335341

336342
if (featuredImage !== undefined) {
337-
community.featuredImage = featuredImage;
343+
community.featuredImage = featuredImage?.mediaId
344+
? await sealMedia(featuredImage.mediaId)
345+
: undefined;
338346
}
339347

340348
const plans = await getPlans({
@@ -601,6 +609,14 @@ export async function createCommunityPost({
601609
throw new Error(responses.invalid_category);
602610
}
603611

612+
if (media?.length) {
613+
for (const med of media) {
614+
if (med.media?.mediaId) {
615+
med.media = await sealMedia(med.media.mediaId);
616+
}
617+
}
618+
}
619+
604620
const post = await CommunityPostModel.create({
605621
domain: ctx.subdomain._id,
606622
userId: ctx.user.userId,

apps/web/graphql/courses/__tests__/delete-course.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@ describe("deleteCourse - Comprehensive Test Suite", () => {
112112
);
113113

114114
jest.clearAllMocks();
115-
});
115+
}, 15000);
116116

117117
afterAll(async () => {
118118
await UserModel.deleteMany({ domain: testDomain._id });
119119
await PaymentPlanModel.deleteMany({ domain: testDomain._id });
120120
await DomainModel.deleteOne({ _id: testDomain._id });
121-
});
121+
}, 15000);
122122

123123
describe("Security & Validation", () => {
124124
it("should require authentication", async () => {
@@ -896,7 +896,7 @@ describe("deleteCourse - Comprehensive Test Suite", () => {
896896
updatedRegularUser?.purchases.some(
897897
(p: any) => p.courseId === course.courseId,
898898
),
899-
).toBe(false);
899+
).toBeFalsy();
900900

901901
const updatedAdminUser = await UserModel.findOne({
902902
userId: adminUser.userId,
@@ -905,7 +905,7 @@ describe("deleteCourse - Comprehensive Test Suite", () => {
905905
updatedAdminUser?.purchases.some(
906906
(p: any) => p.courseId === course.courseId,
907907
),
908-
).toBe(false);
908+
).toBeFalsy();
909909
});
910910
});
911911

0 commit comments

Comments
 (0)