Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,7 @@ report*.json
.npmrc

# Jest files
globalConfig.json
globalConfig.json

# CourseLit files
domains_to_delete.txt
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ describe("processOngoingSequence", () => {
});
await OngoingSequenceModel.deleteOne({ _id: ongoingSeq._id });
await EmailDelivery.deleteMany({});
});
}, 15000);

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

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

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

await OngoingSequenceModel.deleteOne({ _id: ongoingSeq._id });
await EmailDelivery.deleteMany({});
});
}, 15000);
});

describe("getNextPublishedEmail", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ const MUTATION_UPDATE_CERTIFICATE_TEMPLATE = `
mutation UpdateCertificateTemplate($courseId: String!, $title: String, $subtitle: String, $description: String, $signatureName: String, $signatureDesignation: String, $signatureImage: MediaInput, $logo: MediaInput) {
updateCourseCertificateTemplate(courseId: $courseId, title: $title, subtitle: $subtitle, description: $description, signatureName: $signatureName, signatureDesignation: $signatureDesignation, signatureImage: $signatureImage, logo: $logo) {
title
signatureImage {
mediaId
originalFileName
file
thumbnail
}
logo {
mediaId
originalFileName
file
thumbnail
}
}
}
`;
Expand Down Expand Up @@ -246,12 +258,6 @@ export default function Certificates({
const saveCertificateSignatureImage = async (media?: Media) => {
if (!product?.courseId) return;

// Update local state immediately
setCertificateTemplate((prev) => ({
...prev,
signatureImage: media || {},
}));

// Prepare variables for the mutation
const variables = {
courseId: product.courseId,
Expand All @@ -269,6 +275,12 @@ export default function Certificates({
.exec();

if (response?.updateCourseCertificateTemplate) {
setCertificateTemplate({
...certificateTemplate,
signatureImage:
response.updateCourseCertificateTemplate
.signatureImage || {},
});
toast({
title: TOAST_TITLE_SUCCESS,
description: APP_MESSAGE_COURSE_SAVED,
Expand All @@ -288,9 +300,6 @@ export default function Certificates({
const saveCertificateLogo = async (media?: Media) => {
if (!product?.courseId) return;

// Update local state immediately
setCertificateTemplate((prev) => ({ ...prev, logo: media || {} }));

// Prepare variables for the mutation
const variables = {
courseId: product.courseId,
Expand All @@ -308,6 +317,10 @@ export default function Certificates({
.exec();

if (response?.updateCourseCertificateTemplate) {
setCertificateTemplate({
...certificateTemplate,
logo: response.updateCourseCertificateTemplate.logo || {},
});
toast({
title: TOAST_TITLE_SUCCESS,
description: APP_MESSAGE_COURSE_SAVED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useEffect } from "react";
import DashboardContent from "@components/admin/dashboard-content";
import { redirect, useParams } from "next/navigation";
import { useParams, useRouter } from "next/navigation";
import { truncate } from "@ui-lib/utils";
import { Constants, UIConstants } from "@courselit/common-models";
import useProduct from "@/hooks/use-product";
Expand Down Expand Up @@ -58,9 +58,13 @@ export default function SettingsPage() {
}
}, [product]);

if (productLoaded && !product) {
redirect("/dashboard/products");
}
const router = useRouter();

useEffect(() => {
if (productLoaded && !product) {
router.replace("/dashboard/products");
}
}, [productLoaded, product, router]);

if (!product) {
return null;
Expand Down
4 changes: 4 additions & 0 deletions apps/web/app/api/lessons/[id]/scorm/upload/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ export async function POST(

const { packageInfo } = result;

if (lesson.content?.mediaId && lesson.content.mediaId !== mediaId) {
await medialit.delete(lesson.content.mediaId);
}
await medialit.seal(mediaId);
// Update lesson content with SCORM metadata
await Lesson.updateOne(
{ lessonId, domain: domain._id },
Expand Down
15 changes: 0 additions & 15 deletions apps/web/components/admin/page-editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -460,13 +460,6 @@ export default function PageEditor({
};

const deleteWidget = async (widgetId: string) => {
// const widgetIndex = layout.findIndex(
// (widget) => widget.widgetId === widgetId,
// );
// layout.splice(widgetIndex, 1);
// setLayout(layout);
// onClose();
// await savePage({ pageId: page.pageId!, layout });
const mutation = `
mutation ($pageId: String!, $blockId: String!) {
page: deleteBlock(pageId: $pageId, blockId: $blockId) {
Expand Down Expand Up @@ -513,7 +506,6 @@ export default function PageEditor({
},
});
setLayout(layout);
//setShowWidgetSelector(false);
onItemClick(widgetId);
setLeftPaneContent("editor");
await savePage({ pageId: page.pageId!, layout: [...layout] });
Expand Down Expand Up @@ -579,13 +571,6 @@ export default function PageEditor({
/>
)}
{leftPaneContent === "editor" && editWidget}
{/* {leftPaneContent === "fonts" && (
<FontsList
draftTypefaces={draftTypefaces}
onClose={onClose}
saveDraftTypefaces={saveDraftTypefaces}
/>
)} */}
{leftPaneContent === "theme" && (
<ThemeEditor
onThemeChange={(theme) => {
Expand Down
9 changes: 1 addition & 8 deletions apps/web/components/community/banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,7 @@ export default function Banner({
<AlertDescription>
{isTextEditorNonEmpty(bannerText) ? (
<WidgetErrorBoundary widgetName="text-editor">
<TextRenderer
json={
bannerText as unknown as Record<
string,
unknown
>
}
/>
<TextRenderer json={bannerText} />
</WidgetErrorBoundary>
) : (
canEdit && (
Expand Down
3 changes: 2 additions & 1 deletion apps/web/components/community/info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Constants,
Membership,
PaymentPlan,
TextEditorContent,
UIConstants,
} from "@courselit/common-models";
import { FormEvent, Fragment, useContext, useState } from "react";
Expand Down Expand Up @@ -40,7 +41,7 @@ const { permissions } = UIConstants;
interface CommunityInfoProps {
id: string;
name: string;
description: Record<string, unknown>;
description: TextEditorContent;
image: string;
memberCount: number;
paymentPlan?: PaymentPlan;
Expand Down
6 changes: 2 additions & 4 deletions apps/web/components/public/lesson-viewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { Link, Skeleton, useToast } from "@courselit/components-library";
import { TextRenderer } from "@courselit/page-blocks";
import {
Constants,
TextEditorContent,
type Address,
type Lesson,
type Profile,
Expand Down Expand Up @@ -311,10 +312,7 @@ export const LessonViewer = ({
<WidgetErrorBoundary widgetName="text-editor">
<TextRenderer
json={
lesson.content as unknown as Record<
string,
unknown
>
lesson.content as TextEditorContent
}
theme={theme.theme}
/>
Expand Down
40 changes: 28 additions & 12 deletions apps/web/graphql/communities/logic.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { checkPermission, generateUniqueId, slugify } from "@courselit/utils";
import {
checkPermission,
extractMediaIDs,
generateUniqueId,
slugify,
} from "@courselit/utils";
import CommunityModel, { InternalCommunity } from "@models/Community";
import constants from "../../config/constants";
import GQLContext from "../../models/GQLContext";
Expand Down Expand Up @@ -57,13 +62,12 @@ import { hasActiveSubscription } from "../users/logic";
import { internal } from "@config/strings";
import { hasCommunityPermission as hasPermission } from "@ui-lib/utils";
import ActivityModel from "@models/Activity";
import getDeletedMediaIds, {
extractMediaIDs,
} from "@/lib/get-deleted-media-ids";
import { deleteMedia } from "@/services/medialit";
import getDeletedMediaIds from "@/lib/get-deleted-media-ids";
import { deleteMedia, sealMedia } from "@/services/medialit";
import CommunityPostSubscriberModel from "@models/CommunityPostSubscriber";
import InvoiceModel from "@models/Invoice";
import { InternalMembership } from "@courselit/common-logic";
import { replaceTempMediaWithSealedMediaInProseMirrorDoc } from "@/lib/replace-temp-media-with-sealed-media-in-prosemirror-doc";

const { permissions, communityPage } = constants;

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

// if (!checkPermission(ctx.user.permissions, [permissions.manageCommunity])) {
// throw new Error(responses.action_not_allowed);
// }

const community = await CommunityModel.findOne<InternalCommunity>(
getCommunityQuery(ctx, id),
);
Expand Down Expand Up @@ -307,7 +307,10 @@ export async function updateCommunity({
);

if (nextDescription) {
community.description = JSON.parse(nextDescription);
community.description =
await replaceTempMediaWithSealedMediaInProseMirrorDoc(
nextDescription,
);
}
}

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

if (nextBanner) {
community.banner = JSON.parse(nextBanner);
community.banner =
await replaceTempMediaWithSealedMediaInProseMirrorDoc(
nextBanner,
);
}
}

Expand All @@ -334,7 +340,9 @@ export async function updateCommunity({
}

if (featuredImage !== undefined) {
community.featuredImage = featuredImage;
community.featuredImage = featuredImage?.mediaId
? await sealMedia(featuredImage.mediaId)
: undefined;
}

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

if (media?.length) {
for (const med of media) {
if (med.media?.mediaId) {
med.media = await sealMedia(med.media.mediaId);
}
}
}

const post = await CommunityPostModel.create({
domain: ctx.subdomain._id,
userId: ctx.user.userId,
Expand Down
8 changes: 4 additions & 4 deletions apps/web/graphql/courses/__tests__/delete-course.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,13 @@ describe("deleteCourse - Comprehensive Test Suite", () => {
);

jest.clearAllMocks();
});
}, 15000);

afterAll(async () => {
await UserModel.deleteMany({ domain: testDomain._id });
await PaymentPlanModel.deleteMany({ domain: testDomain._id });
await DomainModel.deleteOne({ _id: testDomain._id });
});
}, 15000);

describe("Security & Validation", () => {
it("should require authentication", async () => {
Expand Down Expand Up @@ -896,7 +896,7 @@ describe("deleteCourse - Comprehensive Test Suite", () => {
updatedRegularUser?.purchases.some(
(p: any) => p.courseId === course.courseId,
),
).toBe(false);
).toBeFalsy();

const updatedAdminUser = await UserModel.findOne({
userId: adminUser.userId,
Expand All @@ -905,7 +905,7 @@ describe("deleteCourse - Comprehensive Test Suite", () => {
updatedAdminUser?.purchases.some(
(p: any) => p.courseId === course.courseId,
),
).toBe(false);
).toBeFalsy();
});
});

Expand Down
Loading
Loading