From bb7c87cae1b9274f1c1260142e1c7f5c10286c0f Mon Sep 17 00:00:00 2001 From: SreeCharan Desu Date: Wed, 8 Jul 2026 23:23:34 +0530 Subject: [PATCH] fix(notifications): use instance URL in push test notification (#29673) Fixes #29567 The test push on subscribe hardcoded app.cal.com. Use WEBAPP_URL instead, wrap JSON.parse in try/catch, and localize the title/body. --- packages/i18n/locales/en/common.json | 2 + ...dNotificationsSubscription.handler.test.ts | 59 +++++++++++++++++++ .../addNotificationsSubscription.handler.ts | 40 +++++++++---- 3 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.test.ts diff --git a/packages/i18n/locales/en/common.json b/packages/i18n/locales/en/common.json index 15fc6481c1..daf2add959 100644 --- a/packages/i18n/locales/en/common.json +++ b/packages/i18n/locales/en/common.json @@ -596,6 +596,8 @@ "please_allow_notifications": "Please allow notifications from the prompt", "push_notifications": "Push notifications", "push_notifications_description": "Receive push notifications when booker submits instant meeting booking.", + "test_notification_title": "Test Notification", + "test_notification_body": "Push notifications activated successfully", "browser_notifications_not_supported": "Your browser does not support Push Notifications. If you are Brave user then enable `Use Google services for push messaging` Option on brave://settings/?search=push+messaging", "email": "Email", "email_placeholder": "jdoe@example.com", diff --git a/packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.test.ts b/packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.test.ts new file mode 100644 index 0000000000..681b21df52 --- /dev/null +++ b/packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.test.ts @@ -0,0 +1,59 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { WEBAPP_URL } from "@calcom/lib/constants"; + +const sendNotification = vi.fn(); + +vi.mock("@calcom/features/notifications/sendNotification", () => ({ + sendNotification, +})); + +vi.mock("@calcom/i18n/server", () => ({ + getTranslation: vi.fn().mockResolvedValue((key: string) => key), +})); + +vi.mock("@calcom/prisma", () => ({ + default: { + notificationsSubscriptions: { + findFirst: vi.fn().mockResolvedValue(null), + create: vi.fn().mockResolvedValue({}), + }, + }, +})); + +describe("addNotificationsSubscriptionHandler", () => { + afterEach(() => { + vi.clearAllMocks(); + vi.resetModules(); + }); + + it("uses WEBAPP_URL for the test notification link", async () => { + const { addNotificationsSubscriptionHandler } = await import("./addNotificationsSubscription.handler"); + + await addNotificationsSubscriptionHandler({ + ctx: { + user: { + id: 1, + locale: "en", + } as never, + }, + input: { + subscription: JSON.stringify({ + endpoint: "https://example.com/push", + keys: { + auth: "auth", + p256dh: "p256dh", + }, + }), + }, + }); + + expect(sendNotification).toHaveBeenCalledWith( + expect.objectContaining({ + url: WEBAPP_URL, + title: "test_notification_title", + body: "test_notification_body", + }) + ); + }); +}); diff --git a/packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.ts b/packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.ts index 74fc62d54e..a7ccfdc953 100644 --- a/packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.ts +++ b/packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.ts @@ -1,5 +1,16 @@ import { z } from "zod"; +import { sendNotification } from "@calcom/features/notifications/sendNotification"; +import { WEBAPP_URL } from "@calcom/lib/constants"; +import logger from "@calcom/lib/logger"; +import { getTranslation } from "@calcom/i18n/server"; +import prisma from "@calcom/prisma"; +import type { TrpcSessionUser } from "@calcom/trpc/server/types"; + +import { TRPCError } from "@trpc/server"; + +import type { TAddNotificationsSubscriptionInputSchema } from "./addNotificationsSubscription.schema"; + const subscriptionSchema = z.object({ endpoint: z.string().url(), keys: z.object({ @@ -7,14 +18,6 @@ const subscriptionSchema = z.object({ p256dh: z.string(), }), }); -import { sendNotification } from "@calcom/features/notifications/sendNotification"; -import logger from "@calcom/lib/logger"; -import prisma from "@calcom/prisma"; -import type { TrpcSessionUser } from "@calcom/trpc/server/types"; - -import { TRPCError } from "@trpc/server"; - -import type { TAddNotificationsSubscriptionInputSchema } from "./addNotificationsSubscription.schema"; type AddSecondaryEmailOptions = { ctx: { @@ -29,7 +32,17 @@ export const addNotificationsSubscriptionHandler = async ({ ctx, input }: AddSec const { user } = ctx; const { subscription } = input; - const parsedSubscription = subscriptionSchema.safeParse(JSON.parse(subscription)); + let parsedJson: unknown; + try { + parsedJson = JSON.parse(subscription); + } catch { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid subscription", + }); + } + + const parsedSubscription = subscriptionSchema.safeParse(parsedJson); if (!parsedSubscription.success) { log.error("Invalid subscription", parsedSubscription.error, JSON.stringify(subscription)); @@ -54,7 +67,8 @@ export const addNotificationsSubscriptionHandler = async ({ ctx, input }: AddSec }); } - // send test notification + const t = await getTranslation(user.locale ?? "en", "common"); + sendNotification({ subscription: { endpoint: parsedSubscription.data.endpoint, @@ -63,9 +77,9 @@ export const addNotificationsSubscriptionHandler = async ({ ctx, input }: AddSec p256dh: parsedSubscription.data.keys.p256dh, }, }, - title: "Test Notification", - body: "Push Notifications activated successfully", - url: "https://app.cal.com/", + title: t("test_notification_title"), + body: t("test_notification_body"), + url: WEBAPP_URL, requireInteraction: false, type: "TEST_NOTIFICATION", });