Skip to content

Commit

Permalink
feat: Delete/Create WebhookScheduledTriggers for existing bookings (#…
Browse files Browse the repository at this point in the history
…14121)

* feat: Delete/Create WebhookScheduledTriggers for existing bookings

* fix: type check

* fix: early return, query status in prisma, unnecessary trigger type check

* feat: add/delete scheduled webhook triggers for team and user

---------

Co-authored-by: v0ltZzie <samit091848@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
  • Loading branch information
3 people committed Apr 12, 2024
1 parent 5e98cca commit 5561949
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 20 deletions.
113 changes: 105 additions & 8 deletions packages/features/webhooks/lib/scheduleTrigger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Prisma } from "@prisma/client";
import type { Prisma, Webhook, Booking } from "@prisma/client";
import { v4 } from "uuid";

import { getHumanReadableLocationValue } from "@calcom/core/location";
Expand All @@ -10,6 +10,11 @@ import prisma from "@calcom/prisma";
import type { ApiKey } from "@calcom/prisma/client";
import { BookingStatus, WebhookTriggerEvents } from "@calcom/prisma/enums";

const SCHEDULING_TRIGGER: WebhookTriggerEvents[] = [
WebhookTriggerEvents.MEETING_ENDED,
WebhookTriggerEvents.MEETING_STARTED,
];

const log = logger.getSubLogger({ prefix: ["[node-scheduler]"] });

export async function addSubscription({
Expand Down Expand Up @@ -326,7 +331,9 @@ export async function scheduleTrigger(
export async function cancelScheduledJobs(
booking: { uid: string; scheduledJobs?: string[] },
appId?: string | null,
isReschedule?: boolean
isReschedule?: boolean,
triggerEvent?: WebhookTriggerEvents,
webhookId?: string
) {
if (!booking.scheduledJobs) return;

Expand All @@ -343,12 +350,24 @@ export async function cancelScheduledJobs(
}
} else {
//if no specific appId given, delete all scheduled jobs of booking
await prisma.webhookScheduledTriggers.deleteMany({
where: {
jobName: scheduledJob,
},
});
scheduledJobs = [];
if (triggerEvent) {
const shouldContain = `"triggerEvent":"${triggerEvent}"`;
await prisma.webhookScheduledTriggers.deleteMany({
where: {
payload: {
contains: shouldContain,
},
webhookId: webhookId,
},
});
} else {
await prisma.webhookScheduledTriggers.deleteMany({
where: {
jobName: scheduledJob,
},
});
scheduledJobs = [];
}
}

if (!isReschedule) {
Expand All @@ -369,3 +388,81 @@ export async function cancelScheduledJobs(
console.error("Error cancelling scheduled jobs", error);
}
}

export async function updateTriggerForExistingBookings(
webhook: Webhook,
existingEventTriggers: WebhookTriggerEvents[],
updatedEventTriggers: WebhookTriggerEvents[]
) {
const addedEventTriggers = updatedEventTriggers.filter(
(trigger) => !existingEventTriggers.includes(trigger) && SCHEDULING_TRIGGER.includes(trigger)
);
const removedEventTriggers = existingEventTriggers.filter(
(trigger) => !updatedEventTriggers.includes(trigger) && SCHEDULING_TRIGGER.includes(trigger)
);

if (addedEventTriggers.length === 0 && removedEventTriggers.length === 0) return;

const currentTime = new Date();
const where: Prisma.BookingWhereInput = {
AND: [{ status: BookingStatus.ACCEPTED }],
OR: [{ startTime: { gt: currentTime }, endTime: { gt: currentTime } }],
};

let bookings: Booking[] = [];

if (Array.isArray(where.AND)) {
if (webhook.teamId) {
const teamEvents = await prisma.eventType.findMany({
where: {
teamId: webhook.teamId,
},
select: {
bookings: {
where,
},
},
});

bookings = teamEvents.flatMap((event) => event.bookings);
} else {
if (webhook.eventTypeId) {
where.AND.push({ eventTypeId: webhook.eventTypeId });
} else if (webhook.userId) {
where.AND.push({ userId: webhook.userId });
}

bookings = await prisma.booking.findMany({
where,
});
}
}

if (bookings.length === 0) return;

if (addedEventTriggers.length > 0) {
const promise = bookings.map((booking) => {
return addedEventTriggers.map((trigger) => {
scheduleTrigger(booking, webhook.subscriberUrl, webhook, trigger);
});
});

await Promise.all(promise);
}

if (removedEventTriggers.length > 0) {
const promise = bookings.map((booking) => {
removedEventTriggers.map((trigger) =>
cancelScheduledJobs(
{ uid: booking.uid, scheduledJobs: booking.scheduledJobs },
undefined,
false,
trigger,
webhook.id
)
);
});

await Promise.all(promise);
}
}
28 changes: 17 additions & 11 deletions packages/trpc/server/routers/viewer/webhook/create.handler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Webhook } from "@prisma/client";
import { v4 } from "uuid";

import { updateTriggerForExistingBookings } from "@calcom/features/webhooks/lib/scheduleTrigger";
import { prisma } from "@calcom/prisma";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";

Expand All @@ -15,32 +17,36 @@ type CreateOptions = {
};

export const createHandler = async ({ ctx, input }: CreateOptions) => {
let newWebhook: Webhook;
if (input.platform) {
const { user } = ctx;
if (user?.role !== "ADMIN") {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return await prisma.webhook.create({
newWebhook = await prisma.webhook.create({
data: {
id: v4(),
...input,
},
});
}
if (input.eventTypeId || input.teamId) {
return await prisma.webhook.create({
} else if (input.eventTypeId || input.teamId) {
newWebhook = await prisma.webhook.create({
data: {
id: v4(),
...input,
},
});
} else {
newWebhook = await prisma.webhook.create({
data: {
id: v4(),
userId: ctx.user.id,
...input,
},
});
}

return await prisma.webhook.create({
data: {
id: v4(),
userId: ctx.user.id,
...input,
},
});
await updateTriggerForExistingBookings(newWebhook, [], newWebhook.eventTriggers);

return newWebhook;
};
3 changes: 3 additions & 0 deletions packages/trpc/server/routers/viewer/webhook/delete.handler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Prisma } from "@prisma/client";

import { updateTriggerForExistingBookings } from "@calcom/features/webhooks/lib/scheduleTrigger";
import { prisma } from "@calcom/prisma";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";

Expand Down Expand Up @@ -39,6 +40,8 @@ export const deleteHandler = async ({ ctx, input }: DeleteOptions) => {
id: webhookToDelete.id,
},
});

await updateTriggerForExistingBookings(webhookToDelete, webhookToDelete.eventTriggers, []);
}

return {
Expand Down
7 changes: 6 additions & 1 deletion packages/trpc/server/routers/viewer/webhook/edit.handler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { updateTriggerForExistingBookings } from "@calcom/features/webhooks/lib/scheduleTrigger";
import { prisma } from "@calcom/prisma";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";

Expand Down Expand Up @@ -32,10 +33,14 @@ export const editHandler = async ({ input, ctx }: EditOptions) => {
}
}

return await prisma.webhook.update({
const updatedWebhook = await prisma.webhook.update({
where: {
id,
},
data,
});

await updateTriggerForExistingBookings(webhook, webhook.eventTriggers, updatedWebhook.eventTriggers);

return updatedWebhook;
};

0 comments on commit 5561949

Please sign in to comment.