Skip to content

Commit 096026b

Browse files
volneiemrysal
andauthored
fix: Vitest is being bundled to client + bump lingo.dev version (calcom#23502)
* Fix vitest on prod * Also extract out verify-email for the purpose of stopping test bundling * Address NIT * Fix lingo.dev imports --------- Co-authored-by: Alex van Andel <me@alexvanandel.com>
1 parent 060eafa commit 096026b

11 files changed

Lines changed: 2848 additions & 581 deletions

File tree

File renamed without changes.
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import type { NextApiRequest, NextApiResponse } from "next";
2+
import { z } from "zod";
3+
4+
import dayjs from "@calcom/dayjs";
5+
import { StripeBillingService } from "@calcom/features/ee/billing/stripe-billling-service";
6+
import { WEBAPP_URL } from "@calcom/lib/constants";
7+
import { IS_STRIPE_ENABLED } from "@calcom/lib/constants";
8+
import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
9+
import { prisma } from "@calcom/prisma";
10+
import { MembershipRole } from "@calcom/prisma/client";
11+
import { CreationSource } from "@calcom/prisma/enums";
12+
import { userMetadata } from "@calcom/prisma/zod-utils";
13+
import { inviteMembersWithNoInviterPermissionCheck } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler";
14+
15+
const verifySchema = z.object({
16+
token: z.string(),
17+
});
18+
19+
const USER_ALREADY_EXISTING_MESSAGE = "A User already exists with this email";
20+
21+
// TODO: To be unit tested
22+
export async function moveUserToMatchingOrg({ email }: { email: string }) {
23+
const org = await OrganizationRepository.findUniqueNonPlatformOrgsByMatchingAutoAcceptEmail({ email });
24+
25+
if (!org) {
26+
return;
27+
}
28+
29+
await inviteMembersWithNoInviterPermissionCheck({
30+
inviterName: null,
31+
teamId: org.id,
32+
language: "en",
33+
creationSource: CreationSource.WEBAPP,
34+
invitations: [
35+
{
36+
usernameOrEmail: email,
37+
role: MembershipRole.MEMBER,
38+
},
39+
],
40+
orgSlug: org.slug || org.requestedSlug,
41+
});
42+
}
43+
44+
export async function handler(req: NextApiRequest, res: NextApiResponse) {
45+
const { token } = verifySchema.parse(req.query);
46+
const billingService = new StripeBillingService();
47+
48+
const foundToken = await prisma.verificationToken.findFirst({
49+
where: {
50+
token,
51+
},
52+
});
53+
54+
if (!foundToken) {
55+
return res.status(401).json({ message: "No token found" });
56+
}
57+
58+
if (dayjs(foundToken?.expires).isBefore(dayjs())) {
59+
return res.status(401).json({ message: "Token expired" });
60+
}
61+
62+
// The user is verifying the secondary email
63+
if (foundToken?.secondaryEmailId) {
64+
await prisma.secondaryEmail.update({
65+
where: {
66+
id: foundToken.secondaryEmailId,
67+
email: foundToken?.identifier,
68+
},
69+
data: {
70+
emailVerified: new Date(),
71+
},
72+
});
73+
74+
await cleanUpVerificationTokens(foundToken.id);
75+
76+
return res.redirect(`${WEBAPP_URL}/settings/my-account/profile`);
77+
}
78+
79+
const user = await prisma.user.findFirst({
80+
where: {
81+
email: foundToken?.identifier,
82+
},
83+
});
84+
85+
if (!user) {
86+
return res.status(401).json({ message: "Cannot find a user attached to this token" });
87+
}
88+
89+
const userMetadataParsed = userMetadata.parse(user.metadata);
90+
// Attach the new email and verify
91+
if (userMetadataParsed?.emailChangeWaitingForVerification) {
92+
// Ensure this email isn't in use
93+
const existingUser = await prisma.user.findUnique({
94+
where: { email: userMetadataParsed?.emailChangeWaitingForVerification },
95+
select: {
96+
id: true,
97+
},
98+
});
99+
if (existingUser) {
100+
return res.status(401).json({ message: USER_ALREADY_EXISTING_MESSAGE });
101+
}
102+
103+
// Ensure this email isn't being added by another user as secondary email
104+
const existingSecondaryUser = await prisma.secondaryEmail.findUnique({
105+
where: {
106+
email: userMetadataParsed?.emailChangeWaitingForVerification,
107+
},
108+
select: {
109+
id: true,
110+
userId: true,
111+
},
112+
});
113+
114+
if (existingSecondaryUser && existingSecondaryUser.userId !== user.id) {
115+
return res.status(401).json({ message: USER_ALREADY_EXISTING_MESSAGE });
116+
}
117+
118+
const oldEmail = user.email;
119+
const updatedEmail = userMetadataParsed.emailChangeWaitingForVerification;
120+
delete userMetadataParsed.emailChangeWaitingForVerification;
121+
122+
// Update and re-verify
123+
await prisma.user.update({
124+
where: {
125+
id: user.id,
126+
},
127+
data: {
128+
email: updatedEmail,
129+
metadata: userMetadataParsed,
130+
},
131+
});
132+
133+
if (IS_STRIPE_ENABLED && userMetadataParsed.stripeCustomerId) {
134+
await billingService.updateCustomer({
135+
customerId: userMetadataParsed.stripeCustomerId,
136+
email: updatedEmail,
137+
});
138+
}
139+
140+
// The user is trying to update the email to an already existing unverified secondary email of his
141+
// so we swap the emails and its verified status
142+
if (existingSecondaryUser?.userId === user.id) {
143+
await prisma.secondaryEmail.update({
144+
where: {
145+
id: existingSecondaryUser.id,
146+
userId: user.id,
147+
},
148+
data: {
149+
email: oldEmail,
150+
emailVerified: user.emailVerified,
151+
},
152+
});
153+
}
154+
155+
await cleanUpVerificationTokens(foundToken.id);
156+
157+
return res.status(200).json({
158+
updatedEmail,
159+
});
160+
}
161+
162+
await prisma.user.update({
163+
where: {
164+
id: user.id,
165+
},
166+
data: {
167+
emailVerified: new Date(),
168+
},
169+
});
170+
171+
const hasCompletedOnboarding = user.completedOnboarding;
172+
173+
await moveUserToMatchingOrg({ email: user.email });
174+
175+
return res.redirect(`${WEBAPP_URL}/${hasCompletedOnboarding ? "/event-types" : "/getting-started"}`);
176+
}
177+
178+
export async function cleanUpVerificationTokens(id: number) {
179+
// Delete token from DB after it has been used
180+
await prisma.verificationToken.delete({
181+
where: {
182+
id,
183+
},
184+
});
185+
}
File renamed without changes.
File renamed without changes.

apps/web/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,8 @@
5656
"@googleapis/oauth2": "^1.0.7",
5757
"@hookform/error-message": "^2.0.0",
5858
"@hookform/resolvers": "^2.9.7",
59-
"@lingo.dev/_sdk": "^0.7.27",
6059
"@next-auth/prisma-adapter": "^1.0.4",
61-
"@next/bundle-analyzer": "^13.1.6",
60+
"@next/bundle-analyzer": "^15.5.2",
6261
"@radix-ui/react-avatar": "^1.0.4",
6362
"@radix-ui/react-collapsible": "^1.0.0",
6463
"@radix-ui/react-dialog": "^1.0.4",

apps/web/pages/_document.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Document, { Head, Html, Main, NextScript } from "next/document";
66

77
import { IS_PRODUCTION } from "@calcom/lib/constants";
88

9-
import { applyTheme, applyToDesktopClass } from "./_applyThemeForDocument";
9+
import { applyTheme, applyToDesktopClass } from "./../lib/pages/document/_applyThemeForDocument";
1010

1111
type Props = Record<string, unknown> & DocumentProps & { newLocale: string };
1212

Lines changed: 1 addition & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -1,185 +1 @@
1-
import type { NextApiRequest, NextApiResponse } from "next";
2-
import { z } from "zod";
3-
4-
import dayjs from "@calcom/dayjs";
5-
import { StripeBillingService } from "@calcom/features/ee/billing/stripe-billling-service";
6-
import { WEBAPP_URL } from "@calcom/lib/constants";
7-
import { IS_STRIPE_ENABLED } from "@calcom/lib/constants";
8-
import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
9-
import { prisma } from "@calcom/prisma";
10-
import { MembershipRole } from "@calcom/prisma/client";
11-
import { CreationSource } from "@calcom/prisma/enums";
12-
import { userMetadata } from "@calcom/prisma/zod-utils";
13-
import { inviteMembersWithNoInviterPermissionCheck } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler";
14-
15-
const verifySchema = z.object({
16-
token: z.string(),
17-
});
18-
19-
const USER_ALREADY_EXISTING_MESSAGE = "A User already exists with this email";
20-
21-
// TODO: To be unit tested
22-
export async function moveUserToMatchingOrg({ email }: { email: string }) {
23-
const org = await OrganizationRepository.findUniqueNonPlatformOrgsByMatchingAutoAcceptEmail({ email });
24-
25-
if (!org) {
26-
return;
27-
}
28-
29-
await inviteMembersWithNoInviterPermissionCheck({
30-
inviterName: null,
31-
teamId: org.id,
32-
language: "en",
33-
creationSource: CreationSource.WEBAPP,
34-
invitations: [
35-
{
36-
usernameOrEmail: email,
37-
role: MembershipRole.MEMBER,
38-
},
39-
],
40-
orgSlug: org.slug || org.requestedSlug,
41-
});
42-
}
43-
44-
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
45-
const { token } = verifySchema.parse(req.query);
46-
const billingService = new StripeBillingService();
47-
48-
const foundToken = await prisma.verificationToken.findFirst({
49-
where: {
50-
token,
51-
},
52-
});
53-
54-
if (!foundToken) {
55-
return res.status(401).json({ message: "No token found" });
56-
}
57-
58-
if (dayjs(foundToken?.expires).isBefore(dayjs())) {
59-
return res.status(401).json({ message: "Token expired" });
60-
}
61-
62-
// The user is verifying the secondary email
63-
if (foundToken?.secondaryEmailId) {
64-
await prisma.secondaryEmail.update({
65-
where: {
66-
id: foundToken.secondaryEmailId,
67-
email: foundToken?.identifier,
68-
},
69-
data: {
70-
emailVerified: new Date(),
71-
},
72-
});
73-
74-
await cleanUpVerificationTokens(foundToken.id);
75-
76-
return res.redirect(`${WEBAPP_URL}/settings/my-account/profile`);
77-
}
78-
79-
const user = await prisma.user.findFirst({
80-
where: {
81-
email: foundToken?.identifier,
82-
},
83-
});
84-
85-
if (!user) {
86-
return res.status(401).json({ message: "Cannot find a user attached to this token" });
87-
}
88-
89-
const userMetadataParsed = userMetadata.parse(user.metadata);
90-
// Attach the new email and verify
91-
if (userMetadataParsed?.emailChangeWaitingForVerification) {
92-
// Ensure this email isn't in use
93-
const existingUser = await prisma.user.findUnique({
94-
where: { email: userMetadataParsed?.emailChangeWaitingForVerification },
95-
select: {
96-
id: true,
97-
},
98-
});
99-
if (existingUser) {
100-
return res.status(401).json({ message: USER_ALREADY_EXISTING_MESSAGE });
101-
}
102-
103-
// Ensure this email isn't being added by another user as secondary email
104-
const existingSecondaryUser = await prisma.secondaryEmail.findUnique({
105-
where: {
106-
email: userMetadataParsed?.emailChangeWaitingForVerification,
107-
},
108-
select: {
109-
id: true,
110-
userId: true,
111-
},
112-
});
113-
114-
if (existingSecondaryUser && existingSecondaryUser.userId !== user.id) {
115-
return res.status(401).json({ message: USER_ALREADY_EXISTING_MESSAGE });
116-
}
117-
118-
const oldEmail = user.email;
119-
const updatedEmail = userMetadataParsed.emailChangeWaitingForVerification;
120-
delete userMetadataParsed.emailChangeWaitingForVerification;
121-
122-
// Update and re-verify
123-
await prisma.user.update({
124-
where: {
125-
id: user.id,
126-
},
127-
data: {
128-
email: updatedEmail,
129-
metadata: userMetadataParsed,
130-
},
131-
});
132-
133-
if (IS_STRIPE_ENABLED && userMetadataParsed.stripeCustomerId) {
134-
await billingService.updateCustomer({
135-
customerId: userMetadataParsed.stripeCustomerId,
136-
email: updatedEmail,
137-
});
138-
}
139-
140-
// The user is trying to update the email to an already existing unverified secondary email of his
141-
// so we swap the emails and its verified status
142-
if (existingSecondaryUser?.userId === user.id) {
143-
await prisma.secondaryEmail.update({
144-
where: {
145-
id: existingSecondaryUser.id,
146-
userId: user.id,
147-
},
148-
data: {
149-
email: oldEmail,
150-
emailVerified: user.emailVerified,
151-
},
152-
});
153-
}
154-
155-
await cleanUpVerificationTokens(foundToken.id);
156-
157-
return res.status(200).json({
158-
updatedEmail,
159-
});
160-
}
161-
162-
await prisma.user.update({
163-
where: {
164-
id: user.id,
165-
},
166-
data: {
167-
emailVerified: new Date(),
168-
},
169-
});
170-
171-
const hasCompletedOnboarding = user.completedOnboarding;
172-
173-
await moveUserToMatchingOrg({ email: user.email });
174-
175-
return res.redirect(`${WEBAPP_URL}/${hasCompletedOnboarding ? "/event-types" : "/getting-started"}`);
176-
}
177-
178-
export async function cleanUpVerificationTokens(id: number) {
179-
// Delete token from DB after it has been used
180-
await prisma.verificationToken.delete({
181-
where: {
182-
id,
183-
},
184-
});
185-
}
1+
export { handler as default } from "@lib/pages/auth/verify-email";

0 commit comments

Comments
 (0)