Files
calendar/packages/features/ee/workflows/lib/verifyEmailSender.ts
T
Benny JooGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f98acb7301 refactor: migrate workflows utilities from trpc to features layer (#25534)
* refactor: migrate workflows utilities from trpc to features layer

Move workflow utility functions from packages/trpc/server/routers/viewer/workflows/util.ts
to packages/features/ee/workflows/lib/workflowUtils.ts to break circular dependencies.

Functions migrated:
- isAuthorized
- getAllWorkflowsFromEventType
- scheduleWorkflowNotifications
- scheduleBookingReminders

Changes:
- Created new workflowUtils.ts in features layer with migrated functions
- Added getBookingsForWorkflowReminders to WorkflowRepository (no prisma outside repositories)
- Updated all imports in features layer to use new location
- Updated trpc util.ts to re-export from features for backward compatibility
- Fixed pre-existing lint warning (any -> unknown) in handleMarkNoShow.ts

This is part of the effort to remove circular dependencies between
packages/features and packages/trpc.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: remove re-exports from trpc util.ts, update imports to use features layer

Per user request, removed the backward compatibility re-exports from
packages/trpc/server/routers/viewer/workflows/util.ts and updated all
imports in the trpc package to import directly from the features layer.

Files updated to import from @calcom/features/ee/workflows/lib/workflowUtils:
- confirm.handler.ts (getAllWorkflowsFromEventType)
- delete.handler.ts (isAuthorized)
- update.handler.ts (isAuthorized, scheduleWorkflowNotifications)
- getAllActiveWorkflows.handler.ts (getAllWorkflowsFromEventType)
- get.handler.ts (isAuthorized)
- util.test.ts (isAuthorized)
- delete.handler.test.ts (isAuthorized)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update test imports to use features layer for workflow utilities

Updated test files to import scheduleBookingReminders and
scheduleWorkflowNotifications from @calcom/features/ee/workflows/lib/workflowUtils
instead of @calcom/trpc/server/routers/viewer/workflows/util.

Files updated:
- packages/features/ee/workflows/lib/test/workflows.test.ts
- packages/features/tasker/tasks/scanWorkflowBody.test.ts

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: split workflowUtils.ts into individual files

Split the monolithic workflowUtils.ts into separate files for each function:
- isAuthorized.ts - Authorization check for workflow access
- getAllWorkflowsFromEventType.ts - Get workflows for an event type
- scheduleWorkflowNotifications.ts - Schedule workflow notifications
- scheduleBookingReminders.ts - Schedule booking reminders

The workflowUtils.ts now re-exports from these individual files for
backward compatibility.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix import

* fix more

* wip

* wip

* remove workflowUtils

* wip

* refactor deleteRemindersOfActiveOnIds

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-16 10:17:46 +00:00

137 lines
2.9 KiB
TypeScript

import { ErrorCode } from "@calcom/lib/errorCodes";
import { ErrorWithCode } from "@calcom/lib/errors";
import { prisma } from "@calcom/prisma";
export const verifyEmailSender = async (email: string, userId: number, teamId: number | null) => {
const verifiedEmail = await prisma.verifiedEmail.findFirst({
where: {
email,
OR: [{ userId }, { teamId }],
},
});
if (verifiedEmail) {
if (teamId) {
if (!verifiedEmail.teamId) {
await prisma.verifiedEmail.update({
where: {
id: verifiedEmail.id,
},
data: {
teamId,
},
});
} else if (verifiedEmail.teamId !== teamId) {
await prisma.verifiedEmail.create({
data: {
email,
userId,
teamId,
},
});
}
}
return;
}
const userEmail = await prisma.user.findFirst({
where: {
id: userId,
email,
},
});
if (userEmail) {
await prisma.verifiedEmail.create({
data: {
email,
userId,
teamId,
},
});
return;
}
// Check if it's a verified secondary email of the user
const secondaryEmail = await prisma.secondaryEmail.findFirst({
where: {
userId,
email,
emailVerified: {
not: null,
},
},
});
if (secondaryEmail) {
await prisma.verifiedEmail.create({
data: {
email,
userId,
teamId,
},
});
return;
}
if (teamId) {
const team = await prisma.team.findUnique({
where: {
id: teamId,
},
select: {
members: {
include: {
user: {
select: {
id: true,
email: true,
secondaryEmails: {
select: {
email: true,
emailVerified: true,
},
},
},
},
},
},
},
});
if (!team) {
throw new ErrorWithCode(ErrorCode.NotFound, "Team not found");
}
const isTeamMember = team.members.some((member) => member.userId === userId);
if (!isTeamMember) {
throw new ErrorWithCode(ErrorCode.Forbidden, "You are not a member of this team");
}
let foundTeamMember = team.members.find((member) => member.user.email === email);
// Only check secondary emails if no match was found with primary email
if (!foundTeamMember) {
foundTeamMember = team.members.find((member) =>
member.user.secondaryEmails.some(
(secondary) => secondary.email === email && !!secondary.emailVerified
)
);
}
if (foundTeamMember) {
await prisma.verifiedEmail.create({
data: {
email,
userId,
teamId,
},
});
return;
}
}
throw new ErrorWithCode(ErrorCode.NotFound, "Email not verified");
};