diff --git a/apps/web/app/api/cron/bookingReminder/route.ts b/apps/web/app/api/cron/bookingReminder/route.ts index a70199956d..373e3abd41 100644 --- a/apps/web/app/api/cron/bookingReminder/route.ts +++ b/apps/web/app/api/cron/bookingReminder/route.ts @@ -3,7 +3,7 @@ import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; import dayjs from "@calcom/dayjs"; -import { sendOrganizerRequestReminderEmail } from "@calcom/emails"; +import { sendOrganizerRequestReminderEmail } from "@calcom/emails/email-manager"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; diff --git a/apps/web/app/api/cron/monthlyDigestEmail/route.ts b/apps/web/app/api/cron/monthlyDigestEmail/route.ts index 80e55f60f6..ce20c55262 100644 --- a/apps/web/app/api/cron/monthlyDigestEmail/route.ts +++ b/apps/web/app/api/cron/monthlyDigestEmail/route.ts @@ -4,7 +4,7 @@ import { NextResponse } from "next/server"; import { z } from "zod"; import dayjs from "@calcom/dayjs"; -import { sendMonthlyDigestEmails } from "@calcom/emails/email-manager"; +import { sendMonthlyDigestEmail } from "@calcom/emails/workflow-email-service"; import { EventsInsights } from "@calcom/features/insights/server/events"; import { getTranslation } from "@calcom/lib/server/i18n"; import prisma from "@calcom/prisma"; @@ -295,7 +295,7 @@ async function postHandler(request: NextRequest) { // Only send email if user has allowed to receive monthly digest emails if (owner.receiveMonthlyDigestEmail) { - await sendMonthlyDigestEmails({ + await sendMonthlyDigestEmail({ ...EventData, admin: { email: owner?.email ?? "", name: owner?.name ?? "" }, language: t, diff --git a/apps/web/app/api/email/route.ts b/apps/web/app/api/email/route.ts index 90d266e117..6e48c5f859 100644 --- a/apps/web/app/api/email/route.ts +++ b/apps/web/app/api/email/route.ts @@ -1,7 +1,7 @@ import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir"; import { NextResponse } from "next/server"; -import { renderEmail } from "@calcom/emails"; +import renderEmail from "@calcom/emails/src/renderEmail"; import { IS_PRODUCTION } from "@calcom/lib/constants"; import { getTranslation } from "@calcom/lib/server/i18n"; diff --git a/apps/web/test/lib/handleChildrenEventTypes.test.ts b/apps/web/test/lib/handleChildrenEventTypes.test.ts index e63fc1089b..e6c968a208 100644 --- a/apps/web/test/lib/handleChildrenEventTypes.test.ts +++ b/apps/web/test/lib/handleChildrenEventTypes.test.ts @@ -23,7 +23,7 @@ const mockFindFirstEventType = ( return eventType; }; -vi.mock("@calcom/emails/email-manager", () => { +vi.mock("@calcom/emails/integration-email-service", () => { return { sendSlugReplacementEmail: () => ({}), }; @@ -419,7 +419,7 @@ describe("handleChildrenEventTypes", () => { timeZone: _timeZone, parentId: _parentId, userId: _userId, - + requiresBookerEmailVerification, lockTimeZoneToggleOnBookingPage, useEventTypeDestinationCalendarEmail, diff --git a/apps/web/test/utils/bookingScenario/MockPaymentService.ts b/apps/web/test/utils/bookingScenario/MockPaymentService.ts index a10087696e..4ae9633afa 100644 --- a/apps/web/test/utils/bookingScenario/MockPaymentService.ts +++ b/apps/web/test/utils/bookingScenario/MockPaymentService.ts @@ -2,7 +2,7 @@ import prismaMock from "../../../../../tests/libs/__mocks__/prisma"; import "vitest-fetch-mock"; -import { sendAwaitingPaymentEmailAndSMS } from "@calcom/emails"; +import { sendAwaitingPaymentEmailAndSMS } from "@calcom/emails/email-manager"; import logger from "@calcom/lib/logger"; import type { Payment, Prisma, PaymentOption, Booking } from "@calcom/prisma/client"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/app-store/_utils/payments/handlePaymentSuccess.ts b/packages/app-store/_utils/payments/handlePaymentSuccess.ts index dda7a8c9af..4a5c3000e3 100644 --- a/packages/app-store/_utils/payments/handlePaymentSuccess.ts +++ b/packages/app-store/_utils/payments/handlePaymentSuccess.ts @@ -1,5 +1,6 @@ import { eventTypeAppMetadataOptionalSchema } from "@calcom/app-store/zod-utils"; -import { sendScheduledEmailsAndSMS } from "@calcom/emails"; +import { sendScheduledEmailsAndSMS } from "@calcom/emails/email-manager"; +import EventManager, { placeholderCreatedEvent } from "@calcom/features/bookings/lib/EventManager"; import { doesBookingRequireConfirmation } from "@calcom/features/bookings/lib/doesBookingRequireConfirmation"; import { getAllCredentialsIncludeServiceAccountKey } from "@calcom/features/bookings/lib/getAllCredentialsForUsersOnEvent/getAllCredentials"; import { handleBookingRequested } from "@calcom/features/bookings/lib/handleBookingRequested"; @@ -7,7 +8,6 @@ import { handleConfirmation } from "@calcom/features/bookings/lib/handleConfirma import { getBooking } from "@calcom/features/bookings/lib/payment/getBooking"; import { getPlatformParams } from "@calcom/features/platform-oauth-client/get-platform-params"; import { PlatformOAuthClientRepository } from "@calcom/features/platform-oauth-client/platform-oauth-client.repository"; -import EventManager, { placeholderCreatedEvent } from "@calcom/features/bookings/lib/EventManager"; import { HttpError as HttpCode } from "@calcom/lib/http-error"; import logger from "@calcom/lib/logger"; import prisma from "@calcom/prisma"; diff --git a/packages/app-store/routing-forms/emails/templates/response-email.ts b/packages/app-store/routing-forms/emails/templates/response-email.ts index 1c3c9a9435..f0d8a75859 100644 --- a/packages/app-store/routing-forms/emails/templates/response-email.ts +++ b/packages/app-store/routing-forms/emails/templates/response-email.ts @@ -1,4 +1,4 @@ -import { renderEmail } from "@calcom/emails"; +import renderEmail from "@calcom/emails/src/renderEmail"; import BaseEmail from "@calcom/emails/templates/_base-email"; import type { App_RoutingForms_Form } from "@calcom/prisma/client"; diff --git a/packages/app-store/stripepayment/lib/PaymentService.ts b/packages/app-store/stripepayment/lib/PaymentService.ts index 0e48dc560a..8045d27fb9 100644 --- a/packages/app-store/stripepayment/lib/PaymentService.ts +++ b/packages/app-store/stripepayment/lib/PaymentService.ts @@ -2,7 +2,7 @@ import Stripe from "stripe"; import { v4 as uuidv4 } from "uuid"; import z from "zod"; -import { sendAwaitingPaymentEmailAndSMS } from "@calcom/emails"; +import { sendAwaitingPaymentEmailAndSMS } from "@calcom/emails/email-manager"; import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository"; import { ErrorCode } from "@calcom/lib/errorCodes"; import { getErrorFromUnknown } from "@calcom/lib/errors"; diff --git a/packages/app-store/vital/lib/reschedule.ts b/packages/app-store/vital/lib/reschedule.ts index f29ceab2cf..86c7a69f97 100644 --- a/packages/app-store/vital/lib/reschedule.ts +++ b/packages/app-store/vital/lib/reschedule.ts @@ -1,7 +1,7 @@ import type { TFunction } from "i18next"; import dayjs from "@calcom/dayjs"; -import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails"; +import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails/email-manager"; import { deleteMeeting } from "@calcom/features/conferencing/lib/videoClient"; import { CalendarEventBuilder } from "@calcom/lib/builders/CalendarEvent/builder"; import { CalendarEventDirector } from "@calcom/lib/builders/CalendarEvent/director"; diff --git a/packages/app-store/wipemycalother/lib/reschedule.ts b/packages/app-store/wipemycalother/lib/reschedule.ts index 95303b8925..9b9fc96eb5 100644 --- a/packages/app-store/wipemycalother/lib/reschedule.ts +++ b/packages/app-store/wipemycalother/lib/reschedule.ts @@ -1,7 +1,7 @@ import type { TFunction } from "i18next"; import dayjs from "@calcom/dayjs"; -import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails"; +import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails/email-manager"; import { deleteMeeting } from "@calcom/features/conferencing/lib/videoClient"; import { CalendarEventBuilder } from "@calcom/lib/builders/CalendarEvent/builder"; import { CalendarEventDirector } from "@calcom/lib/builders/CalendarEvent/director"; diff --git a/packages/emails/README.md b/packages/emails/README.md index bd5439926a..26750463f7 100644 --- a/packages/emails/README.md +++ b/packages/emails/README.md @@ -6,7 +6,7 @@ ## Usage ```ts -import { renderEmail } from "@calcom/emails"; +import renderEmail from "@calcom/emails/renderEmail"; await renderEmail("TeamInviteEmail", { language: t, diff --git a/packages/emails/auth-email-service.ts b/packages/emails/auth-email-service.ts new file mode 100644 index 0000000000..3fb50adc94 --- /dev/null +++ b/packages/emails/auth-email-service.ts @@ -0,0 +1,37 @@ +import type BaseEmail from "@calcom/emails/templates/_base-email"; + +import type { PasswordReset } from "./templates/forgot-password-email"; +import ForgotPasswordEmail from "./templates/forgot-password-email"; +import type { EmailVerifyLink } from "./templates/account-verify-email"; +import AccountVerifyEmail from "./templates/account-verify-email"; +import type { EmailVerifyCode } from "./templates/attendee-verify-email"; +import AttendeeVerifyEmail from "./templates/attendee-verify-email"; +import type { ChangeOfEmailVerifyLink } from "./templates/change-account-email-verify"; +import ChangeOfEmailVerifyEmail from "./templates/change-account-email-verify"; + +const sendEmail = (prepare: () => BaseEmail) => { + return new Promise((resolve, reject) => { + try { + const email = prepare(); + resolve(email.sendEmail()); + } catch (e) { + reject(console.error(`${prepare.constructor.name}.sendEmail failed`, e)); + } + }); +}; + +export const sendPasswordResetEmail = async (passwordResetEvent: PasswordReset) => { + await sendEmail(() => new ForgotPasswordEmail(passwordResetEvent)); +}; + +export const sendEmailVerificationLink = async (verificationInput: EmailVerifyLink) => { + await sendEmail(() => new AccountVerifyEmail(verificationInput)); +}; + +export const sendEmailVerificationCode = async (verificationInput: EmailVerifyCode) => { + await sendEmail(() => new AttendeeVerifyEmail(verificationInput)); +}; + +export const sendChangeOfEmailVerificationLink = async (verificationInput: ChangeOfEmailVerifyLink) => { + await sendEmail(() => new ChangeOfEmailVerifyEmail(verificationInput)); +}; diff --git a/packages/emails/billing-email-service.ts b/packages/emails/billing-email-service.ts new file mode 100644 index 0000000000..4660482489 --- /dev/null +++ b/packages/emails/billing-email-service.ts @@ -0,0 +1,129 @@ +import type { TFunction } from "i18next"; + +import type BaseEmail from "@calcom/emails/templates/_base-email"; +import type { CalendarEvent, Person } from "@calcom/types/Calendar"; +import type { CreditUsageType } from "@calcom/prisma/enums"; +import type { EventTypeMetadata } from "@calcom/prisma/zod-utils"; + +import OrganizerPaymentRefundFailedEmail from "./templates/organizer-payment-refund-failed-email"; +import NoShowFeeChargedEmail from "./templates/no-show-fee-charged-email"; +import CreditBalanceLowWarningEmail from "./templates/credit-balance-low-warning-email"; +import CreditBalanceLimitReachedEmail from "./templates/credit-balance-limit-reached-email"; + +const sendEmail = (prepare: () => BaseEmail) => { + return new Promise((resolve, reject) => { + try { + const email = prepare(); + resolve(email.sendEmail()); + } catch (e) { + reject(console.error(`${prepare.constructor.name}.sendEmail failed`, e)); + } + }); +}; + +const eventTypeDisableAttendeeEmail = (metadata?: EventTypeMetadata) => { + return !!metadata?.disableStandardEmails?.all?.attendee; +}; + +export const sendOrganizerPaymentRefundFailedEmail = async (calEvent: CalendarEvent) => { + const emailsToSend: Promise[] = []; + emailsToSend.push(sendEmail(() => new OrganizerPaymentRefundFailedEmail({ calEvent }))); + + if (calEvent.team?.members) { + for (const teamMember of calEvent.team.members) { + emailsToSend.push(sendEmail(() => new OrganizerPaymentRefundFailedEmail({ calEvent, teamMember }))); + } + } + + await Promise.all(emailsToSend); +}; + +export const sendNoShowFeeChargedEmail = async ( + attendee: Person, + evt: CalendarEvent, + eventTypeMetadata?: EventTypeMetadata +) => { + if (eventTypeDisableAttendeeEmail(eventTypeMetadata)) return; + await sendEmail(() => new NoShowFeeChargedEmail(evt, attendee)); +}; + +export const sendCreditBalanceLowWarningEmails = async (input: { + team?: { + name: string | null; + id: number; + adminAndOwners: { + id: number; + name: string | null; + email: string; + t: TFunction; + }[]; + }; + user?: { + id: number; + name: string | null; + email: string; + t: TFunction; + }; + balance: number; + creditFor?: CreditUsageType; +}) => { + const { team, balance, user, creditFor } = input; + if ((!team || !team.adminAndOwners.length) && !user) return; + + if (team) { + const emailsToSend: Promise[] = []; + + for (const admin of team.adminAndOwners) { + emailsToSend.push( + sendEmail(() => new CreditBalanceLowWarningEmail({ user: admin, balance, team, creditFor })) + ); + } + + await Promise.all(emailsToSend); + } + + if (user) { + await sendEmail(() => new CreditBalanceLowWarningEmail({ user, balance, creditFor })); + } +}; + +export const sendCreditBalanceLimitReachedEmails = async ({ + team, + user, + creditFor, +}: { + team?: { + name: string; + id: number; + adminAndOwners: { + id: number; + name: string | null; + email: string; + t: TFunction; + }[]; + }; + user?: { + id: number; + name: string | null; + email: string; + t: TFunction; + }; + creditFor?: CreditUsageType; +}) => { + if ((!team || !team.adminAndOwners.length) && !user) return; + + if (team) { + const emailsToSend: Promise[] = []; + + for (const admin of team.adminAndOwners) { + emailsToSend.push( + sendEmail(() => new CreditBalanceLimitReachedEmail({ user: admin, team, creditFor })) + ); + } + await Promise.all(emailsToSend); + } + + if (user) { + await sendEmail(() => new CreditBalanceLimitReachedEmail({ user, creditFor })); + } +}; diff --git a/packages/emails/email-manager.ts b/packages/emails/email-manager.ts index c8f639cb3e..36b7086fb3 100644 --- a/packages/emails/email-manager.ts +++ b/packages/emails/email-manager.ts @@ -1,4 +1,3 @@ -import type { TFunction } from "i18next"; import { default as cloneDeep } from "lodash/cloneDeep"; import type { z } from "zod"; @@ -10,7 +9,6 @@ import { formatCalEvent } from "@calcom/lib/formatCalendarEvent"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; import { withReporting } from "@calcom/lib/sentryWrapper"; -import type { CreditUsageType } from "@calcom/prisma/enums"; import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; import type { CalendarEvent, Person } from "@calcom/types/Calendar"; @@ -23,65 +21,27 @@ import EventRequestSMS from "../sms/attendee/event-request-sms"; import EventRequestToRescheduleSMS from "../sms/attendee/event-request-to-reschedule-sms"; import EventSuccessfullyReScheduledSMS from "../sms/attendee/event-rescheduled-sms"; import EventSuccessfullyScheduledSMS from "../sms/attendee/event-scheduled-sms"; -import type { MonthlyDigestEmailData } from "./src/templates/MonthlyDigestEmail"; -import type { OrganizationAdminNoSlotsEmailInput } from "./src/templates/OrganizationAdminNoSlots"; -import type { EmailVerifyLink } from "./templates/account-verify-email"; -import AccountVerifyEmail from "./templates/account-verify-email"; -import type { OrganizationNotification } from "./templates/admin-organization-notification"; -import AdminOrganizationNotification from "./templates/admin-organization-notification"; import AttendeeAddGuestsEmail from "./templates/attendee-add-guests-email"; import AttendeeAwaitingPaymentEmail from "./templates/attendee-awaiting-payment-email"; import AttendeeCancelledEmail from "./templates/attendee-cancelled-email"; import AttendeeCancelledSeatEmail from "./templates/attendee-cancelled-seat-email"; -import AttendeeDailyVideoDownloadRecordingEmail from "./templates/attendee-daily-video-download-recording-email"; -import AttendeeDailyVideoDownloadTranscriptEmail from "./templates/attendee-daily-video-download-transcript-email"; import AttendeeDeclinedEmail from "./templates/attendee-declined-email"; import AttendeeLocationChangeEmail from "./templates/attendee-location-change-email"; import AttendeeRequestEmail from "./templates/attendee-request-email"; import AttendeeRescheduledEmail from "./templates/attendee-rescheduled-email"; import AttendeeScheduledEmail from "./templates/attendee-scheduled-email"; import AttendeeUpdatedEmail from "./templates/attendee-updated-email"; -import type { EmailVerifyCode } from "./templates/attendee-verify-email"; -import AttendeeVerifyEmail from "./templates/attendee-verify-email"; import AttendeeWasRequestedToRescheduleEmail from "./templates/attendee-was-requested-to-reschedule-email"; -import BookingRedirectEmailNotification from "./templates/booking-redirect-notification"; -import type { IBookingRedirect } from "./templates/booking-redirect-notification"; -import BrokenIntegrationEmail from "./templates/broken-integration-email"; -import type { ChangeOfEmailVerifyLink } from "./templates/change-account-email-verify"; -import ChangeOfEmailVerifyEmail from "./templates/change-account-email-verify"; -import CreditBalanceLimitReachedEmail from "./templates/credit-balance-limit-reached-email"; -import CreditBalanceLowWarningEmail from "./templates/credit-balance-low-warning-email"; -import DelegationCredentialDisabledEmail from "./templates/delegation-credential-disabled-email"; -import DisabledAppEmail from "./templates/disabled-app-email"; -import type { Feedback } from "./templates/feedback-email"; -import FeedbackEmail from "./templates/feedback-email"; -import type { PasswordReset } from "./templates/forgot-password-email"; -import ForgotPasswordEmail from "./templates/forgot-password-email"; -import MonthlyDigestEmail from "./templates/monthly-digest-email"; -import NoShowFeeChargedEmail from "./templates/no-show-fee-charged-email"; -import OrganizationAdminNoSlotsEmail from "./templates/organization-admin-no-slots-email"; -import type { OrganizationCreation } from "./templates/organization-creation-email"; -import OrganizationCreationEmail from "./templates/organization-creation-email"; -import type { OrganizationEmailVerify } from "./templates/organization-email-verification"; -import OrganizationEmailVerification from "./templates/organization-email-verification"; import OrganizerAddGuestsEmail from "./templates/organizer-add-guests-email"; import OrganizerAttendeeCancelledSeatEmail from "./templates/organizer-attendee-cancelled-seat-email"; import OrganizerCancelledEmail from "./templates/organizer-cancelled-email"; -import OrganizerDailyVideoDownloadRecordingEmail from "./templates/organizer-daily-video-download-recording-email"; -import OrganizerDailyVideoDownloadTranscriptEmail from "./templates/organizer-daily-video-download-transcript-email"; import OrganizerLocationChangeEmail from "./templates/organizer-location-change-email"; -import OrganizerPaymentRefundFailedEmail from "./templates/organizer-payment-refund-failed-email"; import OrganizerReassignedEmail from "./templates/organizer-reassigned-email"; import OrganizerRequestEmail from "./templates/organizer-request-email"; import OrganizerRequestReminderEmail from "./templates/organizer-request-reminder-email"; import OrganizerRequestedToRescheduleEmail from "./templates/organizer-requested-to-reschedule-email"; import OrganizerRescheduledEmail from "./templates/organizer-rescheduled-email"; import OrganizerScheduledEmail from "./templates/organizer-scheduled-email"; -import SlugReplacementEmail from "./templates/slug-replacement-email"; -import type { TeamInvite } from "./templates/team-invite-email"; -import TeamInviteEmail from "./templates/team-invite-email"; -import type { WorkflowEmailData } from "./templates/workflow-email"; -import WorkflowEmail from "./templates/workflow-email"; type EventTypeMetadata = z.infer; @@ -571,52 +531,6 @@ export const sendAwaitingPaymentEmailAndSMS = async ( await awaitingPaymentSMS.sendSMSToAttendees(); }; -export const sendOrganizerPaymentRefundFailedEmail = async (calEvent: CalendarEvent) => { - const emailsToSend: Promise[] = []; - emailsToSend.push(sendEmail(() => new OrganizerPaymentRefundFailedEmail({ calEvent }))); - - if (calEvent.team?.members) { - for (const teamMember of calEvent.team.members) { - emailsToSend.push(sendEmail(() => new OrganizerPaymentRefundFailedEmail({ calEvent, teamMember }))); - } - } - - await Promise.all(emailsToSend); -}; - -export const sendPasswordResetEmail = async (passwordResetEvent: PasswordReset) => { - await sendEmail(() => new ForgotPasswordEmail(passwordResetEvent)); -}; - -export const sendTeamInviteEmail = async (teamInviteEvent: TeamInvite) => { - await sendEmail(() => new TeamInviteEmail(teamInviteEvent)); -}; - -export const sendCustomWorkflowEmail = async (emailData: WorkflowEmailData) => { - await sendEmail(() => new WorkflowEmail(emailData)); -}; - -export const sendOrganizationCreationEmail = async (organizationCreationEvent: OrganizationCreation) => { - await sendEmail(() => new OrganizationCreationEmail(organizationCreationEvent)); -}; - -export const sendOrganizationAdminNoSlotsNotification = async ( - orgInviteEvent: OrganizationAdminNoSlotsEmailInput -) => { - await sendEmail(() => new OrganizationAdminNoSlotsEmail(orgInviteEvent)); -}; - -export const sendEmailVerificationLink = async (verificationInput: EmailVerifyLink) => { - await sendEmail(() => new AccountVerifyEmail(verificationInput)); -}; - -export const sendEmailVerificationCode = async (verificationInput: EmailVerifyCode) => { - await sendEmail(() => new AttendeeVerifyEmail(verificationInput)); -}; - -export const sendChangeOfEmailVerificationLink = async (verificationInput: ChangeOfEmailVerifyLink) => { - await sendEmail(() => new ChangeOfEmailVerifyEmail(verificationInput)); -}; export const sendRequestRescheduleEmailAndSMS = async ( calEvent: CalendarEvent, @@ -737,203 +651,3 @@ export const sendAddGuestsEmailsAndSMS = async (args: { await Promise.all(emailsAndSMSToSend); }; - -export const sendFeedbackEmail = async (feedback: Feedback) => { - await sendEmail(() => new FeedbackEmail(feedback)); -}; - -export const sendBrokenIntegrationEmail = async (evt: CalendarEvent, type: "video" | "calendar") => { - const calendarEvent = formatCalEvent(evt); - await sendEmail(() => new BrokenIntegrationEmail(calendarEvent, type)); -}; - -export const sendDisabledAppEmail = async ({ - email, - appName, - appType, - t, - title = undefined, - eventTypeId = undefined, -}: { - email: string; - appName: string; - appType: string[]; - t: TFunction; - title?: string; - eventTypeId?: number; -}) => { - await sendEmail(() => new DisabledAppEmail(email, appName, appType, t, title, eventTypeId)); -}; - -export const sendSlugReplacementEmail = async ({ - email, - name, - teamName, - t, - slug, -}: { - email: string; - name: string; - teamName: string | null; - t: TFunction; - slug: string; -}) => { - await sendEmail(() => new SlugReplacementEmail(email, name, teamName, slug, t)); -}; - -export const sendNoShowFeeChargedEmail = async ( - attendee: Person, - evt: CalendarEvent, - eventTypeMetadata?: EventTypeMetadata -) => { - if (eventTypeDisableAttendeeEmail(eventTypeMetadata)) return; - await sendEmail(() => new NoShowFeeChargedEmail(evt, attendee)); -}; - -export const sendDailyVideoRecordingEmails = async (calEvent: CalendarEvent, downloadLink: string) => { - const calendarEvent = formatCalEvent(calEvent); - const emailsToSend: Promise[] = []; - - emailsToSend.push( - sendEmail(() => new OrganizerDailyVideoDownloadRecordingEmail(calendarEvent, downloadLink)) - ); - - for (const attendee of calendarEvent.attendees) { - emailsToSend.push( - sendEmail(() => new AttendeeDailyVideoDownloadRecordingEmail(calendarEvent, attendee, downloadLink)) - ); - } - await Promise.all(emailsToSend); -}; - -export const sendDailyVideoTranscriptEmails = async (calEvent: CalendarEvent, transcripts: string[]) => { - const emailsToSend: Promise[] = []; - - emailsToSend.push(sendEmail(() => new OrganizerDailyVideoDownloadTranscriptEmail(calEvent, transcripts))); - - for (const attendee of calEvent.attendees) { - emailsToSend.push( - sendEmail(() => new AttendeeDailyVideoDownloadTranscriptEmail(calEvent, attendee, transcripts)) - ); - } - await Promise.all(emailsToSend); -}; - -export const sendOrganizationEmailVerification = async (sendOrgInput: OrganizationEmailVerify) => { - await sendEmail(() => new OrganizationEmailVerification(sendOrgInput)); -}; - -export const sendMonthlyDigestEmails = async (eventData: MonthlyDigestEmailData) => { - await sendEmail(() => new MonthlyDigestEmail(eventData)); -}; - -export const sendAdminOrganizationNotification = async (input: OrganizationNotification) => { - await sendEmail(() => new AdminOrganizationNotification(input)); -}; - -export const sendBookingRedirectNotification = async (bookingRedirect: IBookingRedirect) => { - await sendEmail(() => new BookingRedirectEmailNotification(bookingRedirect)); -}; - -export const sendCreditBalanceLowWarningEmails = async (input: { - team?: { - name: string | null; - id: number; - adminAndOwners: { - id: number; - name: string | null; - email: string; - t: TFunction; - }[]; - }; - user?: { - id: number; - name: string | null; - email: string; - t: TFunction; - }; - balance: number; - creditFor?: CreditUsageType; -}) => { - const { team, balance, user, creditFor } = input; - if ((!team || !team.adminAndOwners.length) && !user) return; - - if (team) { - const emailsToSend: Promise[] = []; - - for (const admin of team.adminAndOwners) { - emailsToSend.push( - sendEmail(() => new CreditBalanceLowWarningEmail({ user: admin, balance, team, creditFor })) - ); - } - - await Promise.all(emailsToSend); - } - - if (user) { - await sendEmail(() => new CreditBalanceLowWarningEmail({ user, balance, creditFor })); - } -}; - -export const sendCreditBalanceLimitReachedEmails = async ({ - team, - user, - creditFor, -}: { - team?: { - name: string; - id: number; - adminAndOwners: { - id: number; - name: string | null; - email: string; - t: TFunction; - }[]; - }; - user?: { - id: number; - name: string | null; - email: string; - t: TFunction; - }; - creditFor?: CreditUsageType; -}) => { - if ((!team || !team.adminAndOwners.length) && !user) return; - - if (team) { - const emailsToSend: Promise[] = []; - - for (const admin of team.adminAndOwners) { - emailsToSend.push( - sendEmail(() => new CreditBalanceLimitReachedEmail({ user: admin, team, creditFor })) - ); - } - await Promise.all(emailsToSend); - } - - if (user) { - await sendEmail(() => new CreditBalanceLimitReachedEmail({ user, creditFor })); - } -}; - -export const sendDelegationCredentialDisabledEmail = async ({ - recipientEmail, - recipientName, - calendarAppName, - conferencingAppName, -}: { - recipientEmail: string; - recipientName?: string; - calendarAppName: string; - conferencingAppName: string; -}) => { - await sendEmail( - () => - new DelegationCredentialDisabledEmail({ - recipientEmail, - recipientName, - calendarAppName, - conferencingAppName, - }) - ); -}; diff --git a/packages/emails/index.ts b/packages/emails/index.ts deleted file mode 100644 index bf927192b9..0000000000 --- a/packages/emails/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./email-manager"; -export { default as renderEmail } from "./src/renderEmail"; diff --git a/packages/emails/integration-email-service.ts b/packages/emails/integration-email-service.ts new file mode 100644 index 0000000000..83bb0d39e5 --- /dev/null +++ b/packages/emails/integration-email-service.ts @@ -0,0 +1,82 @@ +import type { TFunction } from "i18next"; + +import type BaseEmail from "@calcom/emails/templates/_base-email"; +import type { CalendarEvent } from "@calcom/types/Calendar"; +import { formatCalEvent } from "@calcom/lib/formatCalendarEvent"; + +import BrokenIntegrationEmail from "./templates/broken-integration-email"; +import DisabledAppEmail from "./templates/disabled-app-email"; +import SlugReplacementEmail from "./templates/slug-replacement-email"; +import DelegationCredentialDisabledEmail from "./templates/delegation-credential-disabled-email"; + +const sendEmail = (prepare: () => BaseEmail) => { + return new Promise((resolve, reject) => { + try { + const email = prepare(); + resolve(email.sendEmail()); + } catch (e) { + reject(console.error(`${prepare.constructor.name}.sendEmail failed`, e)); + } + }); +}; + +export const sendBrokenIntegrationEmail = async (evt: CalendarEvent, type: "video" | "calendar") => { + const calendarEvent = formatCalEvent(evt); + await sendEmail(() => new BrokenIntegrationEmail(calendarEvent, type)); +}; + +export const sendDisabledAppEmail = async ({ + email, + appName, + appType, + t, + title = undefined, + eventTypeId = undefined, +}: { + email: string; + appName: string; + appType: string[]; + t: TFunction; + title?: string; + eventTypeId?: number; +}) => { + await sendEmail(() => new DisabledAppEmail(email, appName, appType, t, title, eventTypeId)); +}; + +export const sendSlugReplacementEmail = async ({ + email, + name, + teamName, + t, + slug, +}: { + email: string; + name: string; + teamName: string | null; + t: TFunction; + slug: string; +}) => { + await sendEmail(() => new SlugReplacementEmail(email, name, teamName, slug, t)); +}; + +export const sendDelegationCredentialDisabledEmail = async ({ + recipientEmail, + recipientName, + calendarAppName, + conferencingAppName, +}: { + recipientEmail: string; + recipientName?: string; + calendarAppName: string; + conferencingAppName: string; +}) => { + await sendEmail( + () => + new DelegationCredentialDisabledEmail({ + recipientEmail, + recipientName, + calendarAppName, + conferencingAppName, + }) + ); +}; diff --git a/packages/emails/organization-email-service.ts b/packages/emails/organization-email-service.ts new file mode 100644 index 0000000000..7fbd4c229c --- /dev/null +++ b/packages/emails/organization-email-service.ts @@ -0,0 +1,45 @@ +import type BaseEmail from "@calcom/emails/templates/_base-email"; + +import type { TeamInvite } from "./templates/team-invite-email"; +import TeamInviteEmail from "./templates/team-invite-email"; +import type { OrganizationCreation } from "./templates/organization-creation-email"; +import OrganizationCreationEmail from "./templates/organization-creation-email"; +import type { OrganizationAdminNoSlotsEmailInput } from "./src/templates/OrganizationAdminNoSlots"; +import OrganizationAdminNoSlotsEmail from "./templates/organization-admin-no-slots-email"; +import type { OrganizationEmailVerify } from "./templates/organization-email-verification"; +import OrganizationEmailVerification from "./templates/organization-email-verification"; +import type { OrganizationNotification } from "./templates/admin-organization-notification"; +import AdminOrganizationNotification from "./templates/admin-organization-notification"; + +const sendEmail = (prepare: () => BaseEmail) => { + return new Promise((resolve, reject) => { + try { + const email = prepare(); + resolve(email.sendEmail()); + } catch (e) { + reject(console.error(`${prepare.constructor.name}.sendEmail failed`, e)); + } + }); +}; + +export const sendTeamInviteEmail = async (teamInviteEvent: TeamInvite) => { + await sendEmail(() => new TeamInviteEmail(teamInviteEvent)); +}; + +export const sendOrganizationCreationEmail = async (organizationCreationEvent: OrganizationCreation) => { + await sendEmail(() => new OrganizationCreationEmail(organizationCreationEvent)); +}; + +export const sendOrganizationAdminNoSlotsNotification = async ( + orgInviteEvent: OrganizationAdminNoSlotsEmailInput +) => { + await sendEmail(() => new OrganizationAdminNoSlotsEmail(orgInviteEvent)); +}; + +export const sendOrganizationEmailVerification = async (sendOrgInput: OrganizationEmailVerify) => { + await sendEmail(() => new OrganizationEmailVerification(sendOrgInput)); +}; + +export const sendAdminOrganizationNotification = async (input: OrganizationNotification) => { + await sendEmail(() => new AdminOrganizationNotification(input)); +}; diff --git a/packages/emails/recording-email-service.ts b/packages/emails/recording-email-service.ts new file mode 100644 index 0000000000..78f4674451 --- /dev/null +++ b/packages/emails/recording-email-service.ts @@ -0,0 +1,48 @@ +import type BaseEmail from "@calcom/emails/templates/_base-email"; +import type { CalendarEvent } from "@calcom/types/Calendar"; +import { formatCalEvent } from "@calcom/lib/formatCalendarEvent"; + +import OrganizerDailyVideoDownloadRecordingEmail from "./templates/organizer-daily-video-download-recording-email"; +import AttendeeDailyVideoDownloadRecordingEmail from "./templates/attendee-daily-video-download-recording-email"; +import OrganizerDailyVideoDownloadTranscriptEmail from "./templates/organizer-daily-video-download-transcript-email"; +import AttendeeDailyVideoDownloadTranscriptEmail from "./templates/attendee-daily-video-download-transcript-email"; + +const sendEmail = (prepare: () => BaseEmail) => { + return new Promise((resolve, reject) => { + try { + const email = prepare(); + resolve(email.sendEmail()); + } catch (e) { + reject(console.error(`${prepare.constructor.name}.sendEmail failed`, e)); + } + }); +}; + +export const sendDailyVideoRecordingEmails = async (calEvent: CalendarEvent, downloadLink: string) => { + const calendarEvent = formatCalEvent(calEvent); + const emailsToSend: Promise[] = []; + + emailsToSend.push( + sendEmail(() => new OrganizerDailyVideoDownloadRecordingEmail(calendarEvent, downloadLink)) + ); + + for (const attendee of calendarEvent.attendees) { + emailsToSend.push( + sendEmail(() => new AttendeeDailyVideoDownloadRecordingEmail(calendarEvent, attendee, downloadLink)) + ); + } + await Promise.all(emailsToSend); +}; + +export const sendDailyVideoTranscriptEmails = async (calEvent: CalendarEvent, transcripts: string[]) => { + const emailsToSend: Promise[] = []; + + emailsToSend.push(sendEmail(() => new OrganizerDailyVideoDownloadTranscriptEmail(calEvent, transcripts))); + + for (const attendee of calEvent.attendees) { + emailsToSend.push( + sendEmail(() => new AttendeeDailyVideoDownloadTranscriptEmail(calEvent, attendee, transcripts)) + ); + } + await Promise.all(emailsToSend); +}; diff --git a/packages/emails/workflow-email-service.ts b/packages/emails/workflow-email-service.ts new file mode 100644 index 0000000000..837ef95d1d --- /dev/null +++ b/packages/emails/workflow-email-service.ts @@ -0,0 +1,37 @@ +import type BaseEmail from "@calcom/emails/templates/_base-email"; + +import type { MonthlyDigestEmailData } from "./src/templates/MonthlyDigestEmail"; +import type { IBookingRedirect } from "./templates/booking-redirect-notification"; +import BookingRedirectEmailNotification from "./templates/booking-redirect-notification"; +import type { Feedback } from "./templates/feedback-email"; +import FeedbackEmail from "./templates/feedback-email"; +import MonthlyDigestEmail from "./templates/monthly-digest-email"; +import type { WorkflowEmailData } from "./templates/workflow-email"; +import WorkflowEmail from "./templates/workflow-email"; + +const sendEmail = (prepare: () => BaseEmail) => { + return new Promise((resolve, reject) => { + try { + const email = prepare(); + resolve(email.sendEmail()); + } catch (e) { + reject(console.error(`${prepare.constructor.name}.sendEmail failed`, e)); + } + }); +}; + +export const sendFeedbackEmail = async (feedback: Feedback) => { + await sendEmail(() => new FeedbackEmail(feedback)); +}; + +export const sendCustomWorkflowEmail = async (emailData: WorkflowEmailData) => { + await sendEmail(() => new WorkflowEmail(emailData)); +}; + +export const sendMonthlyDigestEmail = async (eventData: MonthlyDigestEmailData) => { + await sendEmail(() => new MonthlyDigestEmail(eventData)); +}; + +export const sendBookingRedirectNotification = async (bookingRedirect: IBookingRedirect) => { + await sendEmail(() => new BookingRedirectEmailNotification(bookingRedirect)); +}; diff --git a/packages/features/auth/lib/passwordResetRequest.ts b/packages/features/auth/lib/passwordResetRequest.ts index 5e502d6ef9..74b069023a 100644 --- a/packages/features/auth/lib/passwordResetRequest.ts +++ b/packages/features/auth/lib/passwordResetRequest.ts @@ -51,7 +51,7 @@ const passwordResetRequest = async (user: Pick ({ }, })); -vi.mock("@calcom/emails", () => ({ +vi.mock("@calcom/emails/billing-email-service", () => ({ sendNoShowFeeChargedEmail: vi.fn(), })); diff --git a/packages/features/bookings/lib/payment/handleNoShowFee.ts b/packages/features/bookings/lib/payment/handleNoShowFee.ts index bae0636869..4d84a3c051 100644 --- a/packages/features/bookings/lib/payment/handleNoShowFee.ts +++ b/packages/features/bookings/lib/payment/handleNoShowFee.ts @@ -1,7 +1,7 @@ import { PaymentServiceMap } from "@calcom/app-store/payment.services.generated"; import { eventTypeMetaDataSchemaWithTypedApps } from "@calcom/app-store/zod-utils"; import dayjs from "@calcom/dayjs"; -import { sendNoShowFeeChargedEmail } from "@calcom/emails"; +import { sendNoShowFeeChargedEmail } from "@calcom/emails/billing-email-service"; import { CredentialRepository } from "@calcom/features/credentials/repositories/CredentialRepository"; import { TeamRepository } from "@calcom/features/ee/teams/repositories/TeamRepository"; import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; diff --git a/packages/features/bookings/lib/payment/handleRefundError.ts b/packages/features/bookings/lib/payment/handleRefundError.ts index 9332a5aa77..d3bedc29e7 100644 --- a/packages/features/bookings/lib/payment/handleRefundError.ts +++ b/packages/features/bookings/lib/payment/handleRefundError.ts @@ -1,4 +1,4 @@ -import { sendOrganizerPaymentRefundFailedEmail } from "@calcom/emails"; +import { sendOrganizerPaymentRefundFailedEmail } from "@calcom/emails/billing-email-service"; import type { CalendarEvent } from "@calcom/types/Calendar"; const handleRefundError = async (opts: { event: CalendarEvent; reason: string; paymentId: string }) => { diff --git a/packages/features/conferencing/lib/videoClient.ts b/packages/features/conferencing/lib/videoClient.ts index ed4e8e5469..8c0b93e4dd 100644 --- a/packages/features/conferencing/lib/videoClient.ts +++ b/packages/features/conferencing/lib/videoClient.ts @@ -4,7 +4,7 @@ import { v5 as uuidv5 } from "uuid"; import { DailyLocationType } from "@calcom/app-store/constants"; import { getDailyAppKeys } from "@calcom/app-store/dailyvideo/lib/getDailyAppKeys"; import { getVideoAdapters } from "@calcom/app-store/getVideoAdapters"; -import { sendBrokenIntegrationEmail } from "@calcom/emails"; +import { sendBrokenIntegrationEmail } from "@calcom/emails/integration-email-service"; import { getUid } from "@calcom/lib/CalEventParser"; import logger from "@calcom/lib/logger"; import { getPiiFreeCalendarEvent, getPiiFreeCredential } from "@calcom/lib/piiFreeData"; @@ -161,7 +161,7 @@ const createMeetingWithCalVideo = async (calEvent: CalendarEvent) => { let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { return; } const [videoAdapter] = await getVideoAdapters([ @@ -184,7 +184,7 @@ export const createInstantMeetingWithCalVideo = async (endTime: string) => { let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { return; } const [videoAdapter] = await getVideoAdapters([ @@ -209,7 +209,7 @@ const getRecordingsOfCalVideoByRoomName = async ( let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { console.error("Error: Cal video provider is not installed."); return; } @@ -235,7 +235,7 @@ const getDownloadLinkOfCalVideoByRecordingId = async ( let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { console.error("Error: Cal video provider is not installed."); return; } @@ -259,7 +259,7 @@ const getAllTranscriptsAccessLinkFromRoomName = async (roomName: string) => { let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { console.error("Error: Cal video provider is not installed."); return; } @@ -283,7 +283,7 @@ const getAllTranscriptsAccessLinkFromMeetingId = async (meetingId: string) => { let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { console.error("Error: Cal video provider is not installed."); return; } @@ -307,7 +307,7 @@ const submitBatchProcessorTranscriptionJob = async (recordingId: string) => { let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { console.error("Error: Cal video provider is not installed."); return; } @@ -343,7 +343,7 @@ const getTranscriptsAccessLinkFromRecordingId = async (recordingId: string) => { let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { console.error("Error: Cal video provider is not installed."); return; } @@ -368,7 +368,7 @@ const checkIfRoomNameMatchesInRecording = async (roomName: string, recordingId: let dailyAppKeys: Awaited>; try { dailyAppKeys = await getDailyAppKeys(); - } catch (e) { + } catch { console.error("Error: Cal video provider is not installed."); return; } diff --git a/packages/features/credentials/handleDeleteCredential.ts b/packages/features/credentials/handleDeleteCredential.ts index b8787fd758..b3f7c3e131 100644 --- a/packages/features/credentials/handleDeleteCredential.ts +++ b/packages/features/credentials/handleDeleteCredential.ts @@ -8,7 +8,7 @@ import { eventTypeAppMetadataOptionalSchema, } from "@calcom/app-store/zod-utils"; import { eventTypeMetaDataSchemaWithTypedApps } from "@calcom/app-store/zod-utils"; -import { sendCancelledEmailsAndSMS } from "@calcom/emails"; +import { sendCancelledEmailsAndSMS } from "@calcom/emails/email-manager"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { deletePayment } from "@calcom/features/bookings/lib/payment/deletePayment"; import { deleteWebhookScheduledTriggers } from "@calcom/features/webhooks/lib/scheduleTrigger"; diff --git a/packages/features/ee/billing/credit-service.test.ts b/packages/features/ee/billing/credit-service.test.ts index 251aa2c66b..1bac738d44 100644 --- a/packages/features/ee/billing/credit-service.test.ts +++ b/packages/features/ee/billing/credit-service.test.ts @@ -2,7 +2,7 @@ import Stripe from "stripe"; import { describe, it, expect, beforeEach, vi } from "vitest"; import dayjs from "@calcom/dayjs"; -import * as EmailManager from "@calcom/emails/email-manager"; +import * as EmailManager from "@calcom/emails/billing-email-service"; import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; import { CreditsRepository } from "@calcom/lib/server/repository/credits"; import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; @@ -70,7 +70,7 @@ vi.mock("@calcom/prisma/enums", async (importOriginal) => { vi.mock("@calcom/lib/server/repository/credits"); vi.mock("@calcom/features/membership/repositories/MembershipRepository"); vi.mock("@calcom/features/ee/teams/repositories/TeamRepository"); -vi.mock("@calcom/emails/email-manager", () => ({ +vi.mock("@calcom/emails/billing-email-service", () => ({ sendCreditBalanceLimitReachedEmails: vi.fn().mockResolvedValue(undefined), sendCreditBalanceLowWarningEmails: vi.fn().mockResolvedValue(undefined), })); diff --git a/packages/features/ee/billing/credit-service.ts b/packages/features/ee/billing/credit-service.ts index da34190248..b362009233 100644 --- a/packages/features/ee/billing/credit-service.ts +++ b/packages/features/ee/billing/credit-service.ts @@ -4,7 +4,7 @@ import dayjs from "@calcom/dayjs"; import { sendCreditBalanceLimitReachedEmails, sendCreditBalanceLowWarningEmails, -} from "@calcom/emails/email-manager"; +} from "@calcom/emails/billing-email-service"; import { StripeBillingService } from "@calcom/features/ee/billing/stripe-billing-service"; import { InternalTeamBilling } from "@calcom/features/ee/billing/teams/internal-team-billing"; import { TeamRepository } from "@calcom/features/ee/teams/repositories/TeamRepository"; diff --git a/packages/features/ee/billing/helpers/handleInsufficientCredits.ts b/packages/features/ee/billing/helpers/handleInsufficientCredits.ts index 9df24f67fe..fd72461fe5 100644 --- a/packages/features/ee/billing/helpers/handleInsufficientCredits.ts +++ b/packages/features/ee/billing/helpers/handleInsufficientCredits.ts @@ -1,4 +1,4 @@ -import { sendCreditBalanceLimitReachedEmails } from "@calcom/emails/email-manager"; +import { sendCreditBalanceLimitReachedEmails } from "@calcom/emails/billing-email-service"; import logger from "@calcom/lib/logger"; import type { PrismaClient } from "@calcom/prisma"; import type { CreditUsageType } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts b/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts index d6b227b830..f21c455a3d 100644 --- a/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts +++ b/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts @@ -1,8 +1,8 @@ -// eslint-disable-next-line no-restricted-imports + import type { DeepMockProxy } from "vitest-mock-extended"; import { eventTypeMetaDataSchemaWithTypedApps } from "@calcom/app-store/zod-utils"; -import { sendSlugReplacementEmail } from "@calcom/emails/email-manager"; +import { sendSlugReplacementEmail } from "@calcom/emails/integration-email-service"; import { getTranslation } from "@calcom/lib/server/i18n"; import type { PrismaClient } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; @@ -93,7 +93,7 @@ export default async function handleChildrenEventTypes({ children, prisma, profileId, - updatedValues, + updatedValues: _updatedValues, }: handleChildrenEventTypesProps) { // Check we are dealing with a managed event type if (updatedEventType?.schedulingType !== SchedulingType.MANAGED) @@ -222,7 +222,7 @@ export default async function handleChildrenEventTypes({ teamName: oldEventType.team?.name || null, }); - const { unlockedFields } = managedEventTypeValues.metadata?.managedEventConfig; + const { unlockedFields } = managedEventTypeValues.metadata?.managedEventConfig ?? {}; const unlockedFieldProps = !unlockedFields ? {} : Object.keys(unlockedFields).reduce((acc, key) => { diff --git a/packages/features/ee/organizations/lib/server/orgCreationUtils.ts b/packages/features/ee/organizations/lib/server/orgCreationUtils.ts index 5e17c3e00c..80ec76348e 100644 --- a/packages/features/ee/organizations/lib/server/orgCreationUtils.ts +++ b/packages/features/ee/organizations/lib/server/orgCreationUtils.ts @@ -1,7 +1,7 @@ import { lookup } from "dns"; import { type TFunction } from "i18next"; -import { sendAdminOrganizationNotification } from "@calcom/emails"; +import { sendAdminOrganizationNotification } from "@calcom/emails/organization-email-service"; import { FeaturesRepository } from "@calcom/features/flags/features.repository"; import { UserRepository } from "@calcom/features/users/repositories/UserRepository"; import { diff --git a/packages/features/ee/organizations/lib/service/onboarding/BaseOnboardingService.ts b/packages/features/ee/organizations/lib/service/onboarding/BaseOnboardingService.ts index ea90348212..362f39fae5 100644 --- a/packages/features/ee/organizations/lib/service/onboarding/BaseOnboardingService.ts +++ b/packages/features/ee/organizations/lib/service/onboarding/BaseOnboardingService.ts @@ -1,6 +1,6 @@ import type { TFunction } from "i18next"; -import { sendOrganizationCreationEmail } from "@calcom/emails/email-manager"; +import { sendOrganizationCreationEmail } from "@calcom/emails/organization-email-service"; import { sendEmailVerification } from "@calcom/features/auth/lib/verifyEmail"; import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; import { diff --git a/packages/features/ee/payments/api/webhook.ts b/packages/features/ee/payments/api/webhook.ts index dbf145bbbc..28b9d6e1cf 100644 --- a/packages/features/ee/payments/api/webhook.ts +++ b/packages/features/ee/payments/api/webhook.ts @@ -4,7 +4,8 @@ import type Stripe from "stripe"; import { handlePaymentSuccess } from "@calcom/app-store/_utils/payments/handlePaymentSuccess"; import { eventTypeMetaDataSchemaWithTypedApps } from "@calcom/app-store/zod-utils"; -import { sendAttendeeRequestEmailAndSMS, sendOrganizerRequestEmail } from "@calcom/emails"; +import { sendAttendeeRequestEmailAndSMS, sendOrganizerRequestEmail } from "@calcom/emails/email-manager"; +import EventManager, { placeholderCreatedEvent } from "@calcom/features/bookings/lib/EventManager"; import { doesBookingRequireConfirmation } from "@calcom/features/bookings/lib/doesBookingRequireConfirmation"; import { getAllCredentialsIncludeServiceAccountKey } from "@calcom/features/bookings/lib/getAllCredentialsForUsersOnEvent/getAllCredentials"; import { handleConfirmation } from "@calcom/features/bookings/lib/handleConfirmation"; @@ -12,7 +13,6 @@ import { getBooking } from "@calcom/features/bookings/lib/payment/getBooking"; import stripe from "@calcom/features/ee/payments/server/stripe"; import { getPlatformParams } from "@calcom/features/platform-oauth-client/get-platform-params"; import { PlatformOAuthClientRepository } from "@calcom/features/platform-oauth-client/platform-oauth-client.repository"; -import EventManager, { placeholderCreatedEvent } from "@calcom/features/bookings/lib/EventManager"; import { IS_PRODUCTION } from "@calcom/lib/constants"; import { getErrorFromUnknown } from "@calcom/lib/errors"; import { HttpError as HttpCode } from "@calcom/lib/http-error"; diff --git a/packages/features/ee/round-robin/roundRobinManualReassignment.test.ts b/packages/features/ee/round-robin/roundRobinManualReassignment.test.ts index b31d2d8e90..295a9124ef 100644 --- a/packages/features/ee/round-robin/roundRobinManualReassignment.test.ts +++ b/packages/features/ee/round-robin/roundRobinManualReassignment.test.ts @@ -466,7 +466,7 @@ describe("roundRobinManualReassignment test", () => { await mockEventManagerReschedule(); const sendRoundRobinReassignedEmailsAndSMSSpy = vi.spyOn( - await import("@calcom/emails"), + await import("@calcom/emails/email-manager"), "sendRoundRobinReassignedEmailsAndSMS" ); diff --git a/packages/features/ee/round-robin/roundRobinManualReassignment.ts b/packages/features/ee/round-robin/roundRobinManualReassignment.ts index 99e96fd541..e7f9d3f74e 100644 --- a/packages/features/ee/round-robin/roundRobinManualReassignment.ts +++ b/packages/features/ee/round-robin/roundRobinManualReassignment.ts @@ -1,7 +1,5 @@ import { cloneDeep } from "lodash"; - - import { enrichUserWithDelegationCredentialsIncludeServiceAccountKey } from "@calcom/app-store/delegationCredential"; import { eventTypeAppMetadataOptionalSchema } from "@calcom/app-store/zod-utils"; import dayjs from "@calcom/dayjs"; @@ -9,16 +7,21 @@ import { sendRoundRobinReassignedEmailsAndSMS, sendRoundRobinScheduledEmailsAndSMS, sendRoundRobinUpdatedEmailsAndSMS, -} from "@calcom/emails"; +} from "@calcom/emails/email-manager"; import EventManager from "@calcom/features/bookings/lib/EventManager"; import { getAllCredentialsIncludeServiceAccountKey } from "@calcom/features/bookings/lib/getAllCredentialsForUsersOnEvent/getAllCredentials"; import { getBookingResponsesPartialSchema } from "@calcom/features/bookings/lib/getBookingResponsesSchema"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { getEventTypesFromDB } from "@calcom/features/bookings/lib/handleNewBooking/getEventTypesFromDB"; import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer"; -import AssignmentReasonRecorder, { RRReassignmentType } from "@calcom/features/ee/round-robin/assignmentReason/AssignmentReasonRecorder"; +import AssignmentReasonRecorder, { + RRReassignmentType, +} from "@calcom/features/ee/round-robin/assignmentReason/AssignmentReasonRecorder"; import { BookingLocationService } from "@calcom/features/ee/round-robin/lib/bookingLocationService"; -import { scheduleEmailReminder, deleteScheduledEmailReminder } from "@calcom/features/ee/workflows/lib/reminders/emailReminderManager"; +import { + scheduleEmailReminder, + deleteScheduledEmailReminder, +} from "@calcom/features/ee/workflows/lib/reminders/emailReminderManager"; import { scheduleWorkflowReminders } from "@calcom/features/ee/workflows/lib/reminders/reminderScheduler"; import { getEventName } from "@calcom/features/eventtypes/lib/eventNaming"; import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser"; @@ -33,15 +36,12 @@ import { WorkflowActions, WorkflowMethods, WorkflowTriggerEvents } from "@calcom import type { EventTypeMetadata, PlatformClientParams } from "@calcom/prisma/zod-utils"; import type { CalendarEvent } from "@calcom/types/Calendar"; - - import { handleRescheduleEventManager } from "./handleRescheduleEventManager"; import type { BookingSelectResult } from "./utils/bookingSelect"; import { bookingSelect } from "./utils/bookingSelect"; import { getDestinationCalendar } from "./utils/getDestinationCalendar"; import { getTeamMembers } from "./utils/getTeamMembers"; - enum ErrorCode { InvalidRoundRobinHost = "invalid_round_robin_host", UserIsFixed = "user_is_round_robin_fixed", @@ -615,4 +615,4 @@ export async function handleWorkflowsUpdate({ }); } -export default roundRobinManualReassignment; \ No newline at end of file +export default roundRobinManualReassignment; diff --git a/packages/features/ee/round-robin/roundRobinReassignment.ts b/packages/features/ee/round-robin/roundRobinReassignment.ts index 1c60f8a95f..5b97357ab9 100644 --- a/packages/features/ee/round-robin/roundRobinReassignment.ts +++ b/packages/features/ee/round-robin/roundRobinReassignment.ts @@ -1,7 +1,5 @@ import { cloneDeep } from "lodash"; - - import { enrichHostsWithDelegationCredentials, enrichUserWithDelegationCredentialsIncludeServiceAccountKey, @@ -13,7 +11,7 @@ import { sendRoundRobinReassignedEmailsAndSMS, sendRoundRobinScheduledEmailsAndSMS, sendRoundRobinUpdatedEmailsAndSMS, -} from "@calcom/emails"; +} from "@calcom/emails/email-manager"; import EventManager from "@calcom/features/bookings/lib/EventManager"; import { getAllCredentialsIncludeServiceAccountKey } from "@calcom/features/bookings/lib/getAllCredentialsForUsersOnEvent/getAllCredentials"; import { getBookingResponsesPartialSchema } from "@calcom/features/bookings/lib/getBookingResponsesSchema"; @@ -519,4 +517,4 @@ export const roundRobinReassignment = async ({ }; }; -export default roundRobinReassignment; \ No newline at end of file +export default roundRobinReassignment; diff --git a/packages/features/ee/workflows/lib/reminders/providers/emailProvider.ts b/packages/features/ee/workflows/lib/reminders/providers/emailProvider.ts index a1766bae1b..d306ae236b 100644 --- a/packages/features/ee/workflows/lib/reminders/providers/emailProvider.ts +++ b/packages/features/ee/workflows/lib/reminders/providers/emailProvider.ts @@ -1,4 +1,4 @@ -import { sendCustomWorkflowEmail } from "@calcom/emails"; +import { sendCustomWorkflowEmail } from "@calcom/emails/workflow-email-service"; import type { WorkflowEmailData } from "@calcom/emails/templates/workflow-email"; import tasker from "@calcom/features/tasker"; diff --git a/packages/features/tasker/tasker.ts b/packages/features/tasker/tasker.ts index 4808c17cfd..12f57e930c 100644 --- a/packages/features/tasker/tasker.ts +++ b/packages/features/tasker/tasker.ts @@ -2,7 +2,6 @@ import type { z } from "zod"; export type TaskerTypes = "internal" | "redis"; type TaskPayloads = { - sendEmail: string; sendWebhook: string; sendSms: string; triggerHostNoShowWebhook: z.infer< diff --git a/packages/features/tasker/tasks/index.ts b/packages/features/tasker/tasks/index.ts index 640caa3dee..9ae6b79788 100644 --- a/packages/features/tasker/tasks/index.ts +++ b/packages/features/tasker/tasks/index.ts @@ -8,7 +8,6 @@ import type { TaskHandler, TaskTypes } from "../tasker"; * The task handlers are imported dynamically to avoid circular dependencies. */ const tasks: Record Promise> = { - sendEmail: () => import("./sendEmail").then((module) => module.sendEmail), sendWebhook: () => import("./sendWebook").then((module) => module.sendWebhook), triggerHostNoShowWebhook: () => import("./triggerNoShow/triggerHostNoShow").then((module) => module.triggerHostNoShow), diff --git a/packages/features/tasker/tasks/sendEmail.ts b/packages/features/tasker/tasks/sendEmail.ts deleted file mode 100644 index 1634411d47..0000000000 --- a/packages/features/tasker/tasks/sendEmail.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from "zod"; - -const sendEmailPayloadSchema = z.object({ - /** */ - to: z.string(), - /** The email template to send */ - template: z.string(), - payload: z.string(), -}); - -export async function sendEmail(payload: string): Promise { - try { - const parsedPayload = sendEmailPayloadSchema.parse(JSON.parse(payload)); - console.log(parsedPayload); - const emails = await import("@calcom/emails"); - const email = emails[parsedPayload.template as keyof typeof emails]; - if (!email) throw new Error("Invalid email template"); - // @ts-expect-error - TODO bring back email type safety - await email(parsedPayload.to); - } catch (error) { - // ... handle error - console.error(error); - throw error; - } -} diff --git a/packages/features/tasker/tasks/sendWorkflowEmails.ts b/packages/features/tasker/tasks/sendWorkflowEmails.ts index 62cbf93427..11c54889a0 100644 --- a/packages/features/tasker/tasks/sendWorkflowEmails.ts +++ b/packages/features/tasker/tasks/sendWorkflowEmails.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { sendCustomWorkflowEmail } from "@calcom/emails"; +import { sendCustomWorkflowEmail } from "@calcom/emails/workflow-email-service"; export const ZSendWorkflowEmailsSchema = z.object({ to: z.array(z.string()), diff --git a/packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts b/packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts index 2f12e57a1a..7f79f4a6de 100644 --- a/packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts +++ b/packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts @@ -1,4 +1,4 @@ -import { sendScheduledEmailsAndSMS } from "@calcom/emails"; +import { sendScheduledEmailsAndSMS } from "@calcom/emails/email-manager"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { scheduleNoShowTriggers } from "@calcom/features/bookings/lib/handleNewBooking/scheduleNoShowTriggers"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; @@ -213,7 +213,7 @@ export const Handler = async ({ ctx, input }: Options) => { eventTypeId: eventType?.id, videoCallData, customReplyToEmail: eventType?.customReplyToEmail, - team: !!updatedBooking.eventType?.team + team: updatedBooking.eventType?.team ? { name: updatedBooking.eventType.team.name, id: updatedBooking.eventType.team.id, diff --git a/packages/trpc/server/routers/viewer/admin/sendPasswordReset.handler.ts b/packages/trpc/server/routers/viewer/admin/sendPasswordReset.handler.ts index 52ca019396..705a344d50 100644 --- a/packages/trpc/server/routers/viewer/admin/sendPasswordReset.handler.ts +++ b/packages/trpc/server/routers/viewer/admin/sendPasswordReset.handler.ts @@ -1,5 +1,5 @@ import dayjs from "@calcom/dayjs"; -import { sendPasswordResetEmail } from "@calcom/emails"; +import { sendPasswordResetEmail } from "@calcom/emails/auth-email-service"; import { PASSWORD_RESET_EXPIRY_HOURS } from "@calcom/features/auth/lib/passwordResetRequest"; import { getTranslation } from "@calcom/lib/server/i18n"; import { prisma } from "@calcom/prisma"; diff --git a/packages/trpc/server/routers/viewer/apps/toggle.handler.ts b/packages/trpc/server/routers/viewer/apps/toggle.handler.ts index 52c6388843..310e7da6fd 100644 --- a/packages/trpc/server/routers/viewer/apps/toggle.handler.ts +++ b/packages/trpc/server/routers/viewer/apps/toggle.handler.ts @@ -1,5 +1,5 @@ import { getLocalAppMetadata } from "@calcom/app-store/utils"; -import { sendDisabledAppEmail } from "@calcom/emails"; +import { sendDisabledAppEmail } from "@calcom/emails/integration-email-service"; import { getTranslation } from "@calcom/lib/server/i18n"; import type { PrismaClient } from "@calcom/prisma"; import { AppCategories } from "@calcom/prisma/enums"; diff --git a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts index 2dadd50a4b..8fd25f63e9 100644 --- a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts @@ -1,7 +1,7 @@ import { getUsersCredentialsIncludeServiceAccountKey } from "@calcom/app-store/delegationCredential"; import type { LocationObject } from "@calcom/app-store/locations"; import { getLocationValueForDB } from "@calcom/app-store/locations"; -import { sendDeclinedEmailsAndSMS } from "@calcom/emails"; +import { sendDeclinedEmailsAndSMS } from "@calcom/emails/email-manager"; import { getAllCredentialsIncludeServiceAccountKey } from "@calcom/features/bookings/lib/getAllCredentialsForUsersOnEvent/getAllCredentials"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { handleConfirmation } from "@calcom/features/bookings/lib/handleConfirmation"; diff --git a/packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts b/packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts index 94a61f29d3..52f840d095 100644 --- a/packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts @@ -3,7 +3,7 @@ import type { z } from "zod"; import { getUsersCredentialsIncludeServiceAccountKey } from "@calcom/app-store/delegationCredential"; import { getEventLocationType, OrganizerDefaultConferencingAppType } from "@calcom/app-store/locations"; import { getAppFromSlug } from "@calcom/app-store/utils"; -import { sendLocationChangeEmailsAndSMS } from "@calcom/emails"; +import { sendLocationChangeEmailsAndSMS } from "@calcom/emails/email-manager"; import EventManager from "@calcom/features/bookings/lib/EventManager"; import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository"; import { CredentialRepository } from "@calcom/features/credentials/repositories/CredentialRepository"; diff --git a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts index 0168c20931..53e082b7c5 100644 --- a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts @@ -4,7 +4,7 @@ import { getCalendar } from "@calcom/app-store/_utils/getCalendar"; import { getDelegationCredentialOrRegularCredential } from "@calcom/app-store/delegationCredential"; import { getUsersCredentialsIncludeServiceAccountKey } from "@calcom/app-store/delegationCredential"; import dayjs from "@calcom/dayjs"; -import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails"; +import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails/email-manager"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { deleteMeeting } from "@calcom/features/conferencing/lib/videoClient"; import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer"; @@ -220,7 +220,9 @@ export const requestRescheduleHandler = async ({ ctx, input }: RequestReschedule const director = new CalendarEventDirector(); director.setBuilder(builder); director.setExistingBooking(bookingToReschedule); - cancellationReason && director.setCancellationReason(cancellationReason); + if (cancellationReason) { + director.setCancellationReason(cancellationReason); + } if (Object.keys(event).length) { // Request Reschedule flow first cancels the booking and then reschedule email is sent. So, we need to allow reschedule for cancelled booking await director.buildForRescheduleEmail({ allowRescheduleForCancelledBooking: true }); diff --git a/packages/trpc/server/routers/viewer/delegationCredential/toggleEnabled.handler.ts b/packages/trpc/server/routers/viewer/delegationCredential/toggleEnabled.handler.ts index 9dd32a3c03..a66712d493 100644 --- a/packages/trpc/server/routers/viewer/delegationCredential/toggleEnabled.handler.ts +++ b/packages/trpc/server/routers/viewer/delegationCredential/toggleEnabled.handler.ts @@ -1,7 +1,7 @@ import type { z } from "zod"; import { checkIfSuccessfullyConfiguredInWorkspace } from "@calcom/app-store/delegationCredential"; -import { sendDelegationCredentialDisabledEmail } from "@calcom/emails/email-manager"; +import { sendDelegationCredentialDisabledEmail } from "@calcom/emails/integration-email-service"; import { DelegationCredentialRepository } from "@calcom/features/delegation-credentials/repositories/DelegationCredentialRepository"; import type { ServiceAccountKey } from "@calcom/features/delegation-credentials/repositories/DelegationCredentialRepository"; import logger from "@calcom/lib/logger"; diff --git a/packages/trpc/server/routers/viewer/ooo/outOfOfficeCreateOrUpdate.handler.ts b/packages/trpc/server/routers/viewer/ooo/outOfOfficeCreateOrUpdate.handler.ts index 480d1d7976..996ee39f29 100644 --- a/packages/trpc/server/routers/viewer/ooo/outOfOfficeCreateOrUpdate.handler.ts +++ b/packages/trpc/server/routers/viewer/ooo/outOfOfficeCreateOrUpdate.handler.ts @@ -2,7 +2,7 @@ import { v4 as uuidv4 } from "uuid"; import { selectOOOEntries } from "@calcom/app-store/zapier/api/subscriptions/listOOOEntries"; import dayjs from "@calcom/dayjs"; -import { sendBookingRedirectNotification } from "@calcom/emails"; +import { sendBookingRedirectNotification } from "@calcom/emails/workflow-email-service"; import type { GetSubscriberOptions } from "@calcom/features/webhooks/lib/getWebhooks"; import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; import type { OOOEntryPayloadType } from "@calcom/features/webhooks/lib/sendPayload"; @@ -47,7 +47,7 @@ export const outOfOfficeCreateOrUpdate = async ({ ctx, input }: TBookingRedirect let oooUserFullName = ctx.user.name; let isAdmin; - if (!!input.forUserId) { + if (input.forUserId) { isAdmin = await isAdminForUser(ctx.user.id, input.forUserId); if (!isAdmin) { throw new TRPCError({ code: "NOT_FOUND", message: "only_admin_can_create_ooo" }); diff --git a/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntryDelete.handler.ts b/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntryDelete.handler.ts index 202c6793ff..22ad598ad8 100644 --- a/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntryDelete.handler.ts +++ b/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntryDelete.handler.ts @@ -1,4 +1,4 @@ -import { sendBookingRedirectNotification } from "@calcom/emails"; +import { sendBookingRedirectNotification } from "@calcom/emails/workflow-email-service"; import { getTranslation } from "@calcom/lib/server/i18n"; import prisma from "@calcom/prisma"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; diff --git a/packages/trpc/server/routers/viewer/organizations/create.handler.ts b/packages/trpc/server/routers/viewer/organizations/create.handler.ts index 062c18181a..5bf471e76c 100644 --- a/packages/trpc/server/routers/viewer/organizations/create.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/create.handler.ts @@ -2,7 +2,7 @@ import { lookup } from "dns"; import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains"; import { isNotACompanyEmail } from "@calcom/ee/organizations/lib/server/orgCreationUtils"; -import { sendAdminOrganizationNotification, sendOrganizationCreationEmail } from "@calcom/emails"; +import { sendAdminOrganizationNotification, sendOrganizationCreationEmail } from "@calcom/emails/organization-email-service"; import { sendEmailVerification } from "@calcom/features/auth/lib/verifyEmail"; import { getOrganizationRepository } from "@calcom/features/ee/organizations/di/OrganizationRepository.container"; import { UserRepository } from "@calcom/features/users/repositories/UserRepository"; diff --git a/packages/trpc/server/routers/viewer/slots/handleNotificationWhenNoSlots.test.ts b/packages/trpc/server/routers/viewer/slots/handleNotificationWhenNoSlots.test.ts index 3531c2a38c..41943baa83 100644 --- a/packages/trpc/server/routers/viewer/slots/handleNotificationWhenNoSlots.test.ts +++ b/packages/trpc/server/routers/viewer/slots/handleNotificationWhenNoSlots.test.ts @@ -4,7 +4,7 @@ import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock"; import { vi, describe, it, beforeAll, afterAll, expect, beforeEach, afterEach } from "vitest"; import dayjs from "@calcom/dayjs"; -import * as CalcomEmails from "@calcom/emails"; +import * as CalcomEmails from "@calcom/emails/organization-email-service"; import { getNoSlotsNotificationService } from "@calcom/features/di/containers/NoSlotsNotification"; import { RedisService } from "@calcom/features/redis/RedisService"; diff --git a/packages/trpc/server/routers/viewer/slots/handleNotificationWhenNoSlots.ts b/packages/trpc/server/routers/viewer/slots/handleNotificationWhenNoSlots.ts index c94c6324f5..be23930e21 100644 --- a/packages/trpc/server/routers/viewer/slots/handleNotificationWhenNoSlots.ts +++ b/packages/trpc/server/routers/viewer/slots/handleNotificationWhenNoSlots.ts @@ -1,5 +1,5 @@ import type { Dayjs } from "@calcom/dayjs"; -import { sendOrganizationAdminNoSlotsNotification } from "@calcom/emails"; +import { sendOrganizationAdminNoSlotsNotification } from "@calcom/emails/organization-email-service"; import type { TeamRepository } from "@calcom/features/ee/teams/repositories/TeamRepository"; import type { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; import type { IRedisService } from "@calcom/features/redis/IRedisService"; diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts index ddfdebf7f8..dd5262f5a4 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts @@ -30,8 +30,6 @@ async function verifyMembershipExists(userId: number, teamId: number): Promise ({ })); // Mock email sending -vi.mock("@calcom/emails", () => ({ +vi.mock("@calcom/emails/organization-email-service", () => ({ sendTeamInviteEmail: vi.fn(() => Promise.resolve()), sendOrganizationAutoJoinEmail: vi.fn(() => Promise.resolve()), })); @@ -401,10 +399,7 @@ describe("inviteMember.handler Integration Tests", () => { ], }); - await verifyMembershipExists( - unverifiedUserWithUnacceptedMembership.id, - organization.id - ); + await verifyMembershipExists(unverifiedUserWithUnacceptedMembership.id, organization.id); const profile = await verifyProfileExists(unverifiedUserWithUnacceptedMembership.id, organization.id); expect(profile?.userId).toBe(unverifiedUserWithUnacceptedMembership.id); @@ -503,7 +498,7 @@ describe("inviteMember.handler Integration Tests", () => { where: { email: newUserEmail }, }); expect(createdUser).toBeTruthy(); - + if (createdUser) { trackUser(createdUser); diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts index e759e0ac64..d00bf42f9c 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts @@ -2,7 +2,7 @@ import { randomBytes } from "crypto"; import type { TFunction } from "i18next"; import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains"; -import { sendTeamInviteEmail } from "@calcom/emails"; +import { sendTeamInviteEmail } from "@calcom/emails/organization-email-service"; import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner"; import { updateNewTeamMemberEventTypes } from "@calcom/features/ee/teams/lib/queries"; import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service"; diff --git a/packages/trpc/server/routers/viewer/teams/resendInvitation.handler.ts b/packages/trpc/server/routers/viewer/teams/resendInvitation.handler.ts index 7a18ae596e..216f99a7a2 100644 --- a/packages/trpc/server/routers/viewer/teams/resendInvitation.handler.ts +++ b/packages/trpc/server/routers/viewer/teams/resendInvitation.handler.ts @@ -1,4 +1,4 @@ -import { sendTeamInviteEmail } from "@calcom/emails"; +import { sendTeamInviteEmail } from "@calcom/emails/organization-email-service"; import { UserRepository } from "@calcom/features/users/repositories/UserRepository"; import { OnboardingPathService } from "@calcom/features/onboarding/lib/onboarding-path.service"; import { WEBAPP_URL } from "@calcom/lib/constants"; diff --git a/setupVitest.ts b/setupVitest.ts index 91d20c1c8c..5d7e1f65e7 100644 --- a/setupVitest.ts +++ b/setupVitest.ts @@ -2,6 +2,7 @@ import matchers from "@testing-library/jest-dom/matchers"; import ResizeObserver from "resize-observer-polyfill"; import { vi, expect } from "vitest"; import createFetchMock from "vitest-fetch-mock"; + import type { CalendarService } from "@calcom/types/Calendar"; global.ResizeObserver = ResizeObserver; @@ -61,9 +62,9 @@ class MockPaymentService { constructor(credentials?: any) { this.credentials = credentials; } - + private credentials: any; - + async create( payment: any, bookingId: number, @@ -78,7 +79,7 @@ class MockPaymentService { ) { const { default: prismaMock } = await import("./tests/libs/__mocks__/prisma"); const externalId = "mock_payment_external_id"; - + const paymentCreateData = { uid: MOCK_PAYMENT_UID, appId: null, @@ -96,7 +97,7 @@ class MockPaymentService { const createdPayment = await prismaMock.payment.create({ data: paymentCreateData, }); - + return createdPayment; } async collectCard() { @@ -112,7 +113,7 @@ class MockPaymentService { return { success: true }; } async afterPayment(event: any, booking: any, paymentData: any) { - const { sendAwaitingPaymentEmailAndSMS } = await import("@calcom/emails"); + const { sendAwaitingPaymentEmailAndSMS } = await import("@calcom/emails/email-manager"); await sendAwaitingPaymentEmailAndSMS({ ...event, paymentInfo: {