diff --git a/.yarn/versions/637351c1.yml b/.yarn/versions/637351c1.yml new file mode 100644 index 00000000..b2408d57 --- /dev/null +++ b/.yarn/versions/637351c1.yml @@ -0,0 +1,12 @@ +undecided: + - "@courselit/docs" + - "@courselit/queue" + - "@courselit/web" + - "@courselit/common-models" + - "@courselit/common-widgets" + - "@courselit/components-library" + - "@courselit/icons" + - "@courselit/state-management" + - tailwind-config + - "@courselit/text-editor" + - tsconfig diff --git a/.yarn/versions/ba63f441.yml b/.yarn/versions/ba63f441.yml new file mode 100644 index 00000000..b2408d57 --- /dev/null +++ b/.yarn/versions/ba63f441.yml @@ -0,0 +1,12 @@ +undecided: + - "@courselit/docs" + - "@courselit/queue" + - "@courselit/web" + - "@courselit/common-models" + - "@courselit/common-widgets" + - "@courselit/components-library" + - "@courselit/icons" + - "@courselit/state-management" + - tailwind-config + - "@courselit/text-editor" + - tsconfig diff --git a/apps/docs/package.json b/apps/docs/package.json index c5a0ef0c..5e96d83f 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -1,7 +1,7 @@ { "name": "@courselit/docs", "type": "module", - "version": "0.31.5", + "version": "0.31.7", "private": true, "scripts": { "dev": "astro dev", diff --git a/apps/queue/package.json b/apps/queue/package.json index 4e4e211f..65a82b87 100644 --- a/apps/queue/package.json +++ b/apps/queue/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/queue", - "version": "0.22.5", + "version": "0.22.7", "private": true, "packageManager": "yarn@3.2.0", "scripts": { diff --git a/apps/web/app/dashboard2/blogs/layout.tsx b/apps/web/app/dashboard2/blogs/layout.tsx index 1950d2e2..a4e679cd 100644 --- a/apps/web/app/dashboard2/blogs/layout.tsx +++ b/apps/web/app/dashboard2/blogs/layout.tsx @@ -7,9 +7,8 @@ export async function generateMetadata( parent: ResolvingMetadata, ): Promise { return { - title: `${MANAGE_BLOG_PAGE_HEADING} | ${ - (await parent)?.title?.absolute - }`, + title: `${MANAGE_BLOG_PAGE_HEADING} | ${(await parent)?.title + ?.absolute}`, }; } diff --git a/apps/web/app/dashboard2/pages/layout.tsx b/apps/web/app/dashboard2/pages/layout.tsx index ff4e72c9..4d47cf38 100644 --- a/apps/web/app/dashboard2/pages/layout.tsx +++ b/apps/web/app/dashboard2/pages/layout.tsx @@ -7,9 +7,8 @@ export async function generateMetadata( parent: ResolvingMetadata, ): Promise { return { - title: `${MANAGE_PAGES_PAGE_HEADING} | ${ - (await parent)?.title?.absolute - }`, + title: `${MANAGE_PAGES_PAGE_HEADING} | ${(await parent)?.title + ?.absolute}`, }; } diff --git a/apps/web/app/dashboard2/products/layout.tsx b/apps/web/app/dashboard2/products/layout.tsx index daf605a1..7d96a6ec 100644 --- a/apps/web/app/dashboard2/products/layout.tsx +++ b/apps/web/app/dashboard2/products/layout.tsx @@ -7,9 +7,8 @@ export async function generateMetadata( parent: ResolvingMetadata, ): Promise { return { - title: `${MANAGE_COURSES_PAGE_HEADING} | ${ - (await parent)?.title?.absolute - }`, + title: `${MANAGE_COURSES_PAGE_HEADING} | ${(await parent)?.title + ?.absolute}`, }; } diff --git a/apps/web/app/dashboard2/settings/layout.tsx b/apps/web/app/dashboard2/settings/layout.tsx index 2bbb4fc2..b0ff9382 100644 --- a/apps/web/app/dashboard2/settings/layout.tsx +++ b/apps/web/app/dashboard2/settings/layout.tsx @@ -7,9 +7,8 @@ export async function generateMetadata( parent: ResolvingMetadata, ): Promise { return { - title: `${SITE_SETTINGS_PAGE_HEADING} | ${ - (await parent)?.title?.absolute - }`, + title: `${SITE_SETTINGS_PAGE_HEADING} | ${(await parent)?.title + ?.absolute}`, }; } diff --git a/apps/web/app/verify-domain/route.ts b/apps/web/app/verify-domain/route.ts index f71d5d99..02bccd83 100644 --- a/apps/web/app/verify-domain/route.ts +++ b/apps/web/app/verify-domain/route.ts @@ -57,9 +57,9 @@ export async function GET(req: Request) { if (!domain) { return Response.json( { - message: `${responses.domain_doesnt_exist}: ${ - host?.split(".")[0] - }`, + message: `${responses.domain_doesnt_exist}: ${host?.split( + ".", + )[0]}`, }, { status: 404 }, ); diff --git a/apps/web/auth.ts b/apps/web/auth.ts index 84b92023..250bd732 100644 --- a/apps/web/auth.ts +++ b/apps/web/auth.ts @@ -63,6 +63,9 @@ export const { auth, signIn, signOut, handlers } = NextAuth({ email: sanitizedEmail, }); } + if (!user.active) { + return null; + } return { id: user.userId, email: sanitizedEmail, diff --git a/apps/web/components/admin/mails/sequence-editor.tsx b/apps/web/components/admin/mails/sequence-editor.tsx index c8e02ec1..bec40315 100644 --- a/apps/web/components/admin/mails/sequence-editor.tsx +++ b/apps/web/components/admin/mails/sequence-editor.tsx @@ -635,11 +635,11 @@ const SequenceEditor = ({ value: tag.tag, })) : triggerType === "PRODUCT_PURCHASED" - ? products.map((product) => ({ - label: product.title, - value: product.courseId, - })) - : [] + ? products.map((product) => ({ + label: product.title, + value: product.courseId, + })) + : [] } /> )} diff --git a/apps/web/components/admin/page-editor/index.tsx b/apps/web/components/admin/page-editor/index.tsx index 2e72ea13..fa816a24 100644 --- a/apps/web/components/admin/page-editor/index.tsx +++ b/apps/web/components/admin/page-editor/index.tsx @@ -530,8 +530,8 @@ export default function PageEditor({ typeof page.draftRobotsAllowed === "boolean" ? page.draftRobotsAllowed : typeof page.robotsAllowed === "boolean" - ? page.robotsAllowed - : true + ? page.robotsAllowed + : true } socialImage={page.draftSocialImage || {}} onClose={(e) => setLeftPaneContent("none")} diff --git a/apps/web/components/admin/users/details.tsx b/apps/web/components/admin/users/details.tsx index 0d8a44eb..624424aa 100644 --- a/apps/web/components/admin/users/details.tsx +++ b/apps/web/components/admin/users/details.tsx @@ -257,7 +257,7 @@ const Details = ({ userId, address, dispatch }: DetailsProps) => { /> - + {userData.permissions && } {/* diff --git a/apps/web/graphql/mails/helpers.ts b/apps/web/graphql/mails/helpers.ts index 2c594062..6a484659 100644 --- a/apps/web/graphql/mails/helpers.ts +++ b/apps/web/graphql/mails/helpers.ts @@ -8,6 +8,7 @@ import pug from "pug"; import digitalDownloadTemplate from "../../templates/download-link"; import { send } from "../../services/mail"; import { responses } from "@config/strings"; +import { generateEmailFrom } from "@/lib/utils"; export function areAllEmailIdsValid( emailsOrder: string[], @@ -95,6 +96,10 @@ export async function createTemplateAndSendMail({ to: [user.email], subject: `Thank you for signing up for ${course.title}`, body: emailBody, + from: generateEmailFrom({ + name: ctx.subdomain?.settings?.title || ctx.subdomain.name, + email: process.env.EMAIL_FROM || ctx.subdomain.email, + }), }); } diff --git a/apps/web/graphql/settings/helpers.ts b/apps/web/graphql/settings/helpers.ts index a141964d..67544063 100644 --- a/apps/web/graphql/settings/helpers.ts +++ b/apps/web/graphql/settings/helpers.ts @@ -8,8 +8,8 @@ import { UIConstants, } from "@courselit/common-models"; -const currencyISOCodes = currencies.map((currency) => - currency.isoCode?.toLowerCase(), +const currencyISOCodes = currencies.map( + (currency) => currency.isoCode?.toLowerCase(), ); const verifyCurrencyISOCode = (isoCode: string) => { diff --git a/apps/web/graphql/users/logic.ts b/apps/web/graphql/users/logic.ts index 90d54d4f..a0f5f1c9 100644 --- a/apps/web/graphql/users/logic.ts +++ b/apps/web/graphql/users/logic.ts @@ -29,47 +29,22 @@ import { getCourseOrThrow } from "../courses/logic"; import pug from "pug"; import courseEnrollTemplate from "@/templates/course-enroll"; import { send } from "../../services/mail"; - -const removeAdminFieldsFromUserObject = ({ - id, - name, - userId, - bio, - email, - avatar, -}: { - id: string; - name: string; - userId: string; - bio: string; - email: string; - avatar: Media; -}) => ({ - id, - name, - userId, - bio, - email, - avatar, +import { generateEmailFrom } from "@/lib/utils"; + +const removeAdminFieldsFromUserObject = (user: User) => ({ + id: user._id, + name: user.name, + userId: user.userId, + bio: user.bio, + email: user.email, + avatar: user.avatar, }); -export const getUser = async (email = null, userId = null, ctx: GQLContext) => { - const { user: loggedInUser } = ctx; - const loggedUserEmail = loggedInUser && loggedInUser.email; - const loggedUserId = loggedInUser && loggedInUser.userId; +export const getUser = async (userId = null, ctx: GQLContext) => { + let user: User | undefined | null; + user = ctx.user; - if (!email && !userId && !loggedInUser) { - throw new Error(responses.invalid_user_id); - } - - if (!email && !userId && loggedInUser) { - email = loggedUserEmail; - } - - let user; - if (email) { - user = await UserModel.findOne({ email, domain: ctx.subdomain._id }); - } else { + if (userId) { user = await UserModel.findOne({ userId, domain: ctx.subdomain._id }); } @@ -77,16 +52,14 @@ export const getUser = async (email = null, userId = null, ctx: GQLContext) => { throw new Error(responses.item_not_found); } - user.userId = user.userId || -1; // Set -1 for empty userIds; Backward compatibility; - - return loggedInUser && - (loggedUserEmail === email || - loggedUserId === userId || - checkPermission(loggedInUser.permissions, [ - permissions.manageUsers, - ])) - ? user - : removeAdminFieldsFromUserObject(user); + if ( + user.userId === ctx.user.userId || + checkPermission(ctx.user.permissions, [permissions.manageUsers]) + ) { + return user; + } else { + return removeAdminFieldsFromUserObject(user); + } }; const validateUserProperties = (user) => { @@ -102,39 +75,41 @@ const checkForInvalidPermissions = (user) => { } }; -export const updateUser = async ( - userData: Record, - ctx: GQLContext, -) => { +interface UserData { + id: string; + name?: string; + active?: boolean; + bio?: string; + permissions?: string[]; + subscribedToUpdates?: boolean; + tags?: string[]; + avatar?: Media; +} + +export const updateUser = async (userData: UserData, ctx: GQLContext) => { checkIfAuthenticated(ctx); const { id } = userData; + const keys = Object.keys(userData); const hasPermissionToManageUser = checkPermission(ctx.user.permissions, [ permissions.manageUsers, ]); - if (!hasPermissionToManageUser) { - if (id !== ctx.user._id.toString()) { - throw new Error(responses.action_not_allowed); - } + const isModifyingSelf = id === ctx.user._id.toString(); + const restrictedKeys = ["permissions", "active"]; + + if ( + (isModifyingSelf && keys.some((key) => restrictedKeys.includes(key))) || + (!isModifyingSelf && !hasPermissionToManageUser) + ) { + throw new Error(responses.action_not_allowed); } let user = await UserModel.findOne({ _id: id, domain: ctx.subdomain._id }); if (!user) throw new Error(responses.item_not_found); - for (const key of Object.keys(userData)) { - if (key === "id") { - continue; - } - - // if ( - // !["subscribedToUpdates"].includes(key) && - // id === ctx.user._id.toString() - // ) { - // throw new Error(responses.action_not_allowed); - // } - + for (const key of keys.filter((key) => key !== "id")) { if (key === "tags") { - addTags(userData["tags"], ctx); + addTags(userData["tags"]!, ctx); } user[key] = userData[key]; @@ -207,6 +182,10 @@ export const inviteCustomer = async ( to: [user.email], subject: `You have been invited to ${course.title}`, body: emailBody, + from: generateEmailFrom({ + name: ctx.subdomain?.settings?.title || ctx.subdomain.name, + email: process.env.EMAIL_FROM || ctx.subdomain.email, + }), }); } catch (error) { // eslint-disable-next-line no-console diff --git a/apps/web/graphql/users/query.ts b/apps/web/graphql/users/query.ts index 03c2c79a..40028076 100644 --- a/apps/web/graphql/users/query.ts +++ b/apps/web/graphql/users/query.ts @@ -24,8 +24,8 @@ const queries = { email: { type: GraphQLString }, userId: { type: GraphQLString }, }, - resolve: (_: any, { email, userId }: any, context: GQLContext) => - getUser(email, userId, context), + resolve: (_: any, { userId }: any, context: GQLContext) => + getUser(userId, context), }, getUsers: { type: new GraphQLList(types.userType), diff --git a/apps/web/graphql/users/types.ts b/apps/web/graphql/users/types.ts index 59407147..7edb671f 100644 --- a/apps/web/graphql/users/types.ts +++ b/apps/web/graphql/users/types.ts @@ -27,7 +27,7 @@ const userType = new GraphQLObjectType({ email: { type: new GraphQLNonNull(GraphQLString) }, name: { type: GraphQLString }, purchases: { type: new GraphQLList(progress) }, - active: { type: new GraphQLNonNull(GraphQLBoolean) }, + active: { type: GraphQLBoolean }, userId: { type: new GraphQLNonNull(GraphQLString) }, bio: { type: GraphQLString }, permissions: { type: new GraphQLList(GraphQLString) }, diff --git a/apps/web/lib/utils.ts b/apps/web/lib/utils.ts index ea958c67..7142d7a2 100644 --- a/apps/web/lib/utils.ts +++ b/apps/web/lib/utils.ts @@ -33,3 +33,13 @@ export const getAddress = ( export const getProtocol = (protocol: string | string[] = "http") => { return protocol.includes("https") ? "https" : "http"; }; + +export const generateEmailFrom = ({ + name, + email, +}: { + name: string; + email: string; +}) => { + return `${name} <${email}>`; +}; diff --git a/apps/web/package.json b/apps/web/package.json index 73d9b356..ad82551f 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/web", - "version": "0.54.5", + "version": "0.54.7", "private": true, "scripts": { "dev": "next dev", diff --git a/apps/web/pages/api/auth/code/generate.ts b/apps/web/pages/api/auth/code/generate.ts index cd0fb8d2..0abea653 100644 --- a/apps/web/pages/api/auth/code/generate.ts +++ b/apps/web/pages/api/auth/code/generate.ts @@ -6,6 +6,7 @@ import pug from "pug"; import MagicCodeEmailTemplate from "../../../../templates/magic-code-email"; import { send } from "../../../../services/mail"; import DomainModel, { Domain } from "@models/Domain"; +import { generateEmailFrom } from "@/lib/utils"; export default async function handler( req: NextApiRequest, @@ -42,10 +43,15 @@ export default async function handler( code, hideCourseLitBranding: domain.settings?.hideCourseLitBranding, }); + await send({ to: [sanitizedEmail], subject: `${responses.sign_in_mail_prefix} ${req.headers["host"]}`, body: emailBody, + from: generateEmailFrom({ + name: domain?.settings?.title || domain.name, + email: process.env.EMAIL_FROM || domain.email, + }), }); } catch (err: any) { res.status(500).json({ diff --git a/apps/web/services/mail.ts b/apps/web/services/mail.ts index 16333c00..13ec62a1 100644 --- a/apps/web/services/mail.ts +++ b/apps/web/services/mail.ts @@ -6,7 +6,6 @@ import { addMailJob } from "./queue"; const mailHost = process.env.EMAIL_HOST; const mailUser = process.env.EMAIL_USER; const mailPass = process.env.EMAIL_PASS; -const mailFrom = process.env.EMAIL_FROM || ""; const mailPort = process.env.EMAIL_PORT ? +process.env.EMAIL_PORT : 587; let transporter: any; @@ -36,15 +35,10 @@ interface MailProps { to: string[]; subject: string; body: string; - from?: string; + from: string; } -export const send = async ({ - to, - subject, - body, - from = mailFrom, -}: MailProps) => { +export const send = async ({ to, subject, body, from }: MailProps) => { if (process.env.QUEUE_SERVER) { try { await addMailJob({ diff --git a/packages/common-models/package.json b/packages/common-models/package.json index 59db74d8..17fcbd43 100644 --- a/packages/common-models/package.json +++ b/packages/common-models/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/common-models", - "version": "0.54.5", + "version": "0.54.7", "description": "Models shared between the main app and other packages of CourseLit.", "author": "Rajat Saxena ", "homepage": "https://github.com/codelitdev/courselit#readme", diff --git a/packages/common-widgets/package.json b/packages/common-widgets/package.json index d0e4edeb..7da1cd46 100644 --- a/packages/common-widgets/package.json +++ b/packages/common-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/common-widgets", - "version": "0.54.5", + "version": "0.54.7", "description": "A collection of common widgets for CourseLit LMS", "keywords": [ "widgets", diff --git a/packages/common-widgets/src/banner/widget.tsx b/packages/common-widgets/src/banner/widget.tsx index 7d6bf007..3e2692b1 100644 --- a/packages/common-widgets/src/banner/widget.tsx +++ b/packages/common-widgets/src/banner/widget.tsx @@ -72,8 +72,8 @@ export default function Widget({ : undefined : description : product.description - ? JSON.parse(product.description as string) - : undefined; + ? JSON.parse(product.description as string) + : undefined; let direction: any; switch (alignment) { diff --git a/packages/common-widgets/src/email-form/widget.tsx b/packages/common-widgets/src/email-form/widget.tsx index 91ad94ba..a78588a7 100644 --- a/packages/common-widgets/src/email-form/widget.tsx +++ b/packages/common-widgets/src/email-form/widget.tsx @@ -54,8 +54,8 @@ const Widget = ({ alignment === "center" ? "center" : alignment === "right" - ? "flex-end" - : "flex-start"; + ? "flex-end" + : "flex-start"; useEffect(() => { if (state.config.turnstileSiteKey) { diff --git a/packages/common-widgets/src/header/widget/index.tsx b/packages/common-widgets/src/header/widget/index.tsx index 94495ba1..8006579b 100644 --- a/packages/common-widgets/src/header/widget/index.tsx +++ b/packages/common-widgets/src/header/widget/index.tsx @@ -77,8 +77,8 @@ export default function Widget({ state, settings }: WidgetProps) { linkAlignment === "right" ? "justify-end" : linkAlignment === "center" - ? "justify-center" - : "justify-start" + ? "justify-center" + : "justify-start" }`} style={{ gap: `${spacingBetweenLinks}px`, diff --git a/packages/common-widgets/src/hero/widget.tsx b/packages/common-widgets/src/hero/widget.tsx index 956d87d9..7c3c14f1 100644 --- a/packages/common-widgets/src/hero/widget.tsx +++ b/packages/common-widgets/src/hero/widget.tsx @@ -198,15 +198,15 @@ export default function Widget({ descriptionFontSize === 0 ? "text-base" : descriptionFontSize === 1 - ? "text-lg lg:text-xl" - : `text-${ - descriptionFontSize - - 1 === - 1 - ? "" - : descriptionFontSize - - 1 - }xl lg:text-${descriptionFontSize}xl`, + ? "text-lg lg:text-xl" + : `text-${ + descriptionFontSize - + 1 === + 1 + ? "" + : descriptionFontSize - + 1 + }xl lg:text-${descriptionFontSize}xl`, buttonAction && buttonCaption ? "mb-8" : "mb-0", diff --git a/packages/components-library/package.json b/packages/components-library/package.json index 913b8537..2cd36916 100644 --- a/packages/components-library/package.json +++ b/packages/components-library/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/components-library", - "version": "0.54.5", + "version": "0.54.7", "description": "A library of React components for CourseLit LMS.", "keywords": [ "react", diff --git a/packages/icons/package.json b/packages/icons/package.json index accfa95b..e87b1a02 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/icons", - "version": "0.19.5", + "version": "0.19.7", "description": "Icons for CourseLit", "author": "Rajat Saxena ", "homepage": "https://github.com/codelitdev/courselit#readme", diff --git a/packages/state-management/package.json b/packages/state-management/package.json index 2e3fa2cb..64822b39 100644 --- a/packages/state-management/package.json +++ b/packages/state-management/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/state-management", - "version": "0.54.5", + "version": "0.54.7", "description": "Redux based state management for CourseLit", "author": "Rajat Saxena ", "homepage": "https://github.com/codelitdev/courselit#readme", diff --git a/packages/tailwind-config/package.json b/packages/tailwind-config/package.json index c67fffce..65f1f6b9 100644 --- a/packages/tailwind-config/package.json +++ b/packages/tailwind-config/package.json @@ -1,6 +1,6 @@ { "name": "tailwind-config", - "version": "0.19.5", + "version": "0.19.7", "description": "Tailwind config for CourseLit", "author": "Rajat Saxena ", "homepage": "https://github.com/codelitdev/courselit#readme", diff --git a/packages/text-editor/package.json b/packages/text-editor/package.json index 1fd3e435..d0d558a5 100644 --- a/packages/text-editor/package.json +++ b/packages/text-editor/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/text-editor", - "version": "0.31.5", + "version": "0.31.7", "description": "A text editor based on Remirror", "keywords": [ "text editor", diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json index d33a7f5a..e2545383 100644 --- a/packages/tsconfig/package.json +++ b/packages/tsconfig/package.json @@ -1,6 +1,6 @@ { "name": "tsconfig", - "version": "0.19.5", + "version": "0.19.7", "description": "TSConfig for CourseLit", "author": "Rajat Saxena ", "homepage": "https://github.com/codelitdev/courselit#readme", diff --git a/packages/utils/package.json b/packages/utils/package.json index 398b2e77..33a1e9f6 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@courselit/utils", - "version": "0.54.5", + "version": "0.54.7", "description": "Utilities for CourseLit", "author": "Team CourseLit ", "homepage": "https://github.com/codelitdev/courselit#readme",