diff --git a/packages/emails/lib/generateIcsString.ts b/packages/emails/lib/generateIcsString.ts index d1a5f940ca..d04143dd81 100644 --- a/packages/emails/lib/generateIcsString.ts +++ b/packages/emails/lib/generateIcsString.ts @@ -1,5 +1,6 @@ -import type { DateArray } from "ics"; +import type { DateArray, ParticipationStatus, ParticipationRole } from "ics"; import { createEvent } from "ics"; +import type { TFunction } from "next-i18next"; import { RRule } from "rrule"; import dayjs from "@calcom/dayjs"; @@ -8,16 +9,17 @@ import type { CalendarEvent, Person } from "@calcom/types/Calendar"; const generateIcsString = ({ event, - recipient, + t, role, }: { event: CalendarEvent; - recipient: Person; + t: TFunction; role: "attendee" | "organizer"; }) => { - const t = recipient.language.translate; // Taking care of recurrence rule let recurrenceRule: string | undefined = undefined; + const partstat: ParticipationStatus = "ACCEPTED"; + const icsRole: ParticipationRole = "REQ-PARTICIPANT"; if (event.recurringEvent?.count) { // ics appends "RRULE:" already, so removing it from RRule generated string recurrenceRule = new RRule(event.recurringEvent).toString().replace("RRULE:", ""); @@ -62,14 +64,21 @@ ${getRichDescription(event, t)} ...event.attendees.map((attendee: Person) => ({ name: attendee.name, email: attendee.email, + partstat, + role: icsRole, + rsvp: true, })), ...(event.team?.members ? event.team?.members.map((member: Person) => ({ name: member.name, email: member.email, + partstat, + role: icsRole, + rsvp: true, })) : []), ], + method: "REQUEST", status: "CONFIRMED", }); if (icsEvent.error) { diff --git a/packages/emails/templates/attendee-scheduled-email.ts b/packages/emails/templates/attendee-scheduled-email.ts index 7d7d672ea8..92aa734aec 100644 --- a/packages/emails/templates/attendee-scheduled-email.ts +++ b/packages/emails/templates/attendee-scheduled-email.ts @@ -1,16 +1,13 @@ -import type { DateArray, ParticipationStatus, ParticipationRole } from "ics"; -import { createEvent } from "ics"; // eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; import type { TFunction } from "next-i18next"; -import { RRule } from "rrule"; -import dayjs from "@calcom/dayjs"; import { getRichDescription } from "@calcom/lib/CalEventParser"; import { TimeFormat } from "@calcom/lib/timeFormat"; import type { CalendarEvent, Person } from "@calcom/types/Calendar"; import { renderEmail } from "../"; +import generateIcsString from "../lib/generateIcsString"; import BaseEmail from "./_base-email"; export default class AttendeeScheduledEmail extends BaseEmail { @@ -32,65 +29,13 @@ export default class AttendeeScheduledEmail extends BaseEmail { this.t = attendee.language.translate; } - protected getiCalEventAsString(): string | undefined { - // Taking care of recurrence rule - let recurrenceRule: string | undefined = undefined; - if (this.calEvent.recurringEvent?.count) { - // ics appends "RRULE:" already, so removing it from RRule generated string - recurrenceRule = new RRule(this.calEvent.recurringEvent).toString().replace("RRULE:", ""); - } - const partstat: ParticipationStatus = "ACCEPTED"; - const role: ParticipationRole = "REQ-PARTICIPANT"; - const icsEvent = createEvent({ - uid: this.calEvent.iCalUID || this.calEvent.uid!, - start: dayjs(this.calEvent.startTime) - .utc() - .toArray() - .slice(0, 6) - .map((v, i) => (i === 1 ? v + 1 : v)) as DateArray, - startInputType: "utc", - productId: "calcom/ics", - title: this.calEvent.title, - description: this.getTextBody(), - duration: { minutes: dayjs(this.calEvent.endTime).diff(dayjs(this.calEvent.startTime), "minute") }, - organizer: { name: this.calEvent.organizer.name, email: this.calEvent.organizer.email }, - attendees: [ - ...this.calEvent.attendees.map((attendee: Person) => ({ - name: attendee.name, - email: attendee.email, - partstat, - role, - rsvp: true, - })), - ...(this.calEvent.team?.members - ? this.calEvent.team?.members.map((member: Person) => ({ - name: member.name, - email: member.email, - partstat, - role, - rsvp: true, - })) - : []), - ], - method: "REQUEST", - ...{ recurrenceRule }, - status: "CONFIRMED", - }); - if (icsEvent.error) { - throw icsEvent.error; - } - return icsEvent.value; - } - protected getNodeMailerPayload(): Record { const clonedCalEvent = cloneDeep(this.calEvent); - this.getiCalEventAsString(); - return { icalEvent: { filename: "event.ics", - content: this.getiCalEventAsString(), + content: generateIcsString({ event: this.calEvent, t: this.t, role: "attendee" }), method: "REQUEST", }, to: `${this.attendee.name} <${this.attendee.email}>`, diff --git a/packages/emails/templates/organizer-scheduled-email.ts b/packages/emails/templates/organizer-scheduled-email.ts index 92b454a730..e8a4b6bf43 100644 --- a/packages/emails/templates/organizer-scheduled-email.ts +++ b/packages/emails/templates/organizer-scheduled-email.ts @@ -1,17 +1,14 @@ -import type { DateArray } from "ics"; -import { createEvent } from "ics"; // eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; import type { TFunction } from "next-i18next"; -import { RRule } from "rrule"; -import dayjs from "@calcom/dayjs"; import { getRichDescription } from "@calcom/lib/CalEventParser"; import { APP_NAME } from "@calcom/lib/constants"; import { TimeFormat } from "@calcom/lib/timeFormat"; import type { CalendarEvent, Person } from "@calcom/types/Calendar"; import { renderEmail } from "../"; +import generateIcsString from "../lib/generateIcsString"; import BaseEmail from "./_base-email"; export default class OrganizerScheduledEmail extends BaseEmail { @@ -29,47 +26,6 @@ export default class OrganizerScheduledEmail extends BaseEmail { this.teamMember = input.teamMember; } - protected getiCalEventAsString(): string | undefined { - // Taking care of recurrence rule - let recurrenceRule: string | undefined = undefined; - if (this.calEvent.recurringEvent?.count) { - // ics appends "RRULE:" already, so removing it from RRule generated string - recurrenceRule = new RRule(this.calEvent.recurringEvent).toString().replace("RRULE:", ""); - } - const icsEvent = createEvent({ - uid: this.calEvent.iCalUID || this.calEvent.uid!, - start: dayjs(this.calEvent.startTime) - .utc() - .toArray() - .slice(0, 6) - .map((v, i) => (i === 1 ? v + 1 : v)) as DateArray, - startInputType: "utc", - productId: "calcom/ics", - title: this.calEvent.title, - description: this.getTextBody(), - duration: { minutes: dayjs(this.calEvent.endTime).diff(dayjs(this.calEvent.startTime), "minute") }, - organizer: { name: this.calEvent.organizer.name, email: this.calEvent.organizer.email }, - ...{ recurrenceRule }, - attendees: [ - ...this.calEvent.attendees.map((attendee: Person) => ({ - name: attendee.name, - email: attendee.email, - })), - ...(this.calEvent.team?.members - ? this.calEvent.team?.members.map((member: Person) => ({ - name: member.name, - email: member.email, - })) - : []), - ], - status: "CONFIRMED", - }); - if (icsEvent.error) { - throw icsEvent.error; - } - return icsEvent.value; - } - protected getNodeMailerPayload(): Record { const clonedCalEvent = cloneDeep(this.calEvent); const toAddresses = [this.teamMember?.email || this.calEvent.organizer.email]; @@ -77,7 +33,8 @@ export default class OrganizerScheduledEmail extends BaseEmail { return { icalEvent: { filename: "event.ics", - content: this.getiCalEventAsString(), + content: generateIcsString({ event: this.calEvent, t: this.t, role: "organizer" }), + method: "REQUEST", }, from: `${APP_NAME} <${this.getMailerOptions().from}>`, to: toAddresses.join(","),