Skip to content

Commit bb7c87c

Browse files
fix(notifications): use instance URL in push test notification (calcom#29673)
Fixes calcom#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.
1 parent 0968bce commit bb7c87c

3 files changed

Lines changed: 87 additions & 12 deletions

File tree

packages/i18n/locales/en/common.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,8 @@
596596
"please_allow_notifications": "Please allow notifications from the prompt",
597597
"push_notifications": "Push notifications",
598598
"push_notifications_description": "Receive push notifications when booker submits instant meeting booking.",
599+
"test_notification_title": "Test Notification",
600+
"test_notification_body": "Push notifications activated successfully",
599601
"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",
600602
"email": "Email",
601603
"email_placeholder": "jdoe@example.com",
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { afterEach, describe, expect, it, vi } from "vitest";
2+
3+
import { WEBAPP_URL } from "@calcom/lib/constants";
4+
5+
const sendNotification = vi.fn();
6+
7+
vi.mock("@calcom/features/notifications/sendNotification", () => ({
8+
sendNotification,
9+
}));
10+
11+
vi.mock("@calcom/i18n/server", () => ({
12+
getTranslation: vi.fn().mockResolvedValue((key: string) => key),
13+
}));
14+
15+
vi.mock("@calcom/prisma", () => ({
16+
default: {
17+
notificationsSubscriptions: {
18+
findFirst: vi.fn().mockResolvedValue(null),
19+
create: vi.fn().mockResolvedValue({}),
20+
},
21+
},
22+
}));
23+
24+
describe("addNotificationsSubscriptionHandler", () => {
25+
afterEach(() => {
26+
vi.clearAllMocks();
27+
vi.resetModules();
28+
});
29+
30+
it("uses WEBAPP_URL for the test notification link", async () => {
31+
const { addNotificationsSubscriptionHandler } = await import("./addNotificationsSubscription.handler");
32+
33+
await addNotificationsSubscriptionHandler({
34+
ctx: {
35+
user: {
36+
id: 1,
37+
locale: "en",
38+
} as never,
39+
},
40+
input: {
41+
subscription: JSON.stringify({
42+
endpoint: "https://example.com/push",
43+
keys: {
44+
auth: "auth",
45+
p256dh: "p256dh",
46+
},
47+
}),
48+
},
49+
});
50+
51+
expect(sendNotification).toHaveBeenCalledWith(
52+
expect.objectContaining({
53+
url: WEBAPP_URL,
54+
title: "test_notification_title",
55+
body: "test_notification_body",
56+
})
57+
);
58+
});
59+
});

packages/trpc/server/routers/loggedInViewer/addNotificationsSubscription.handler.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
import { z } from "zod";
22

3-
const subscriptionSchema = z.object({
4-
endpoint: z.string().url(),
5-
keys: z.object({
6-
auth: z.string(),
7-
p256dh: z.string(),
8-
}),
9-
});
103
import { sendNotification } from "@calcom/features/notifications/sendNotification";
4+
import { WEBAPP_URL } from "@calcom/lib/constants";
115
import logger from "@calcom/lib/logger";
6+
import { getTranslation } from "@calcom/i18n/server";
127
import prisma from "@calcom/prisma";
138
import type { TrpcSessionUser } from "@calcom/trpc/server/types";
149

1510
import { TRPCError } from "@trpc/server";
1611

1712
import type { TAddNotificationsSubscriptionInputSchema } from "./addNotificationsSubscription.schema";
1813

14+
const subscriptionSchema = z.object({
15+
endpoint: z.string().url(),
16+
keys: z.object({
17+
auth: z.string(),
18+
p256dh: z.string(),
19+
}),
20+
});
21+
1922
type AddSecondaryEmailOptions = {
2023
ctx: {
2124
user: NonNullable<TrpcSessionUser>;
@@ -29,7 +32,17 @@ export const addNotificationsSubscriptionHandler = async ({ ctx, input }: AddSec
2932
const { user } = ctx;
3033
const { subscription } = input;
3134

32-
const parsedSubscription = subscriptionSchema.safeParse(JSON.parse(subscription));
35+
let parsedJson: unknown;
36+
try {
37+
parsedJson = JSON.parse(subscription);
38+
} catch {
39+
throw new TRPCError({
40+
code: "BAD_REQUEST",
41+
message: "Invalid subscription",
42+
});
43+
}
44+
45+
const parsedSubscription = subscriptionSchema.safeParse(parsedJson);
3346

3447
if (!parsedSubscription.success) {
3548
log.error("Invalid subscription", parsedSubscription.error, JSON.stringify(subscription));
@@ -54,7 +67,8 @@ export const addNotificationsSubscriptionHandler = async ({ ctx, input }: AddSec
5467
});
5568
}
5669

57-
// send test notification
70+
const t = await getTranslation(user.locale ?? "en", "common");
71+
5872
sendNotification({
5973
subscription: {
6074
endpoint: parsedSubscription.data.endpoint,
@@ -63,9 +77,9 @@ export const addNotificationsSubscriptionHandler = async ({ ctx, input }: AddSec
6377
p256dh: parsedSubscription.data.keys.p256dh,
6478
},
6579
},
66-
title: "Test Notification",
67-
body: "Push Notifications activated successfully",
68-
url: "https://app.cal.com/",
80+
title: t("test_notification_title"),
81+
body: t("test_notification_body"),
82+
url: WEBAPP_URL,
6983
requireInteraction: false,
7084
type: "TEST_NOTIFICATION",
7185
});

0 commit comments

Comments
 (0)