2022-05-03 23:16:59 +00:00
|
|
|
import { Prisma } from "@prisma/client";
|
2021-10-28 22:52:39 +00:00
|
|
|
import { v4 } from "uuid";
|
2021-10-25 16:15:52 +00:00
|
|
|
import { z } from "zod";
|
|
|
|
|
2022-03-16 23:36:43 +00:00
|
|
|
import { getErrorFromUnknown } from "@calcom/lib/errors";
|
|
|
|
|
2021-10-28 22:52:39 +00:00
|
|
|
import { WEBHOOK_TRIGGER_EVENTS } from "@lib/webhooks/constants";
|
2021-11-22 11:37:07 +00:00
|
|
|
import sendPayload from "@lib/webhooks/sendPayload";
|
2021-10-25 16:15:52 +00:00
|
|
|
|
|
|
|
import { createProtectedRouter } from "@server/createRouter";
|
2022-02-10 10:44:46 +00:00
|
|
|
import { getTranslation } from "@server/lib/i18n";
|
2021-10-25 16:15:52 +00:00
|
|
|
|
2021-10-28 22:52:39 +00:00
|
|
|
export const webhookRouter = createProtectedRouter()
|
|
|
|
.query("list", {
|
2022-03-02 16:24:57 +00:00
|
|
|
input: z
|
|
|
|
.object({
|
|
|
|
eventTypeId: z.number().optional(),
|
|
|
|
})
|
|
|
|
.optional(),
|
|
|
|
async resolve({ ctx, input }) {
|
2022-05-03 23:16:59 +00:00
|
|
|
let where: Prisma.WebhookWhereInput = {
|
|
|
|
AND: [{ appId: null /* Don't mixup zapier webhooks with normal ones */ }],
|
|
|
|
};
|
|
|
|
if (Array.isArray(where.AND)) {
|
|
|
|
if (input?.eventTypeId) {
|
|
|
|
where.AND?.push({ eventTypeId: input.eventTypeId });
|
|
|
|
} else {
|
|
|
|
where.AND?.push({ userId: ctx.user.id });
|
|
|
|
}
|
2022-03-02 16:24:57 +00:00
|
|
|
}
|
2021-10-28 22:52:39 +00:00
|
|
|
return await ctx.prisma.webhook.findMany({
|
2022-05-03 23:16:59 +00:00
|
|
|
where,
|
2021-10-28 22:52:39 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.mutation("create", {
|
|
|
|
input: z.object({
|
|
|
|
subscriberUrl: z.string().url(),
|
|
|
|
eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(),
|
|
|
|
active: z.boolean(),
|
2022-02-18 17:49:39 +00:00
|
|
|
payloadTemplate: z.string().nullable(),
|
2022-03-02 16:24:57 +00:00
|
|
|
eventTypeId: z.number().optional(),
|
2022-05-03 23:16:59 +00:00
|
|
|
appId: z.string().optional().nullable(),
|
2021-10-28 22:52:39 +00:00
|
|
|
}),
|
|
|
|
async resolve({ ctx, input }) {
|
2022-03-02 16:24:57 +00:00
|
|
|
if (input.eventTypeId) {
|
|
|
|
return await ctx.prisma.webhook.create({
|
|
|
|
data: {
|
|
|
|
id: v4(),
|
|
|
|
...input,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2021-10-28 22:52:39 +00:00
|
|
|
return await ctx.prisma.webhook.create({
|
|
|
|
data: {
|
|
|
|
id: v4(),
|
|
|
|
userId: ctx.user.id,
|
|
|
|
...input,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.mutation("edit", {
|
|
|
|
input: z.object({
|
|
|
|
id: z.string(),
|
|
|
|
subscriberUrl: z.string().url().optional(),
|
|
|
|
eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(),
|
|
|
|
active: z.boolean().optional(),
|
2021-11-22 11:37:07 +00:00
|
|
|
payloadTemplate: z.string().nullable(),
|
2022-03-02 16:24:57 +00:00
|
|
|
eventTypeId: z.number().optional(),
|
2022-05-03 23:16:59 +00:00
|
|
|
appId: z.string().optional().nullable(),
|
2021-10-28 22:52:39 +00:00
|
|
|
}),
|
|
|
|
async resolve({ ctx, input }) {
|
|
|
|
const { id, ...data } = input;
|
2022-03-02 16:24:57 +00:00
|
|
|
const webhook = input.eventTypeId
|
|
|
|
? await ctx.prisma.webhook.findFirst({
|
|
|
|
where: {
|
|
|
|
eventTypeId: input.eventTypeId,
|
|
|
|
id,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
: await ctx.prisma.webhook.findFirst({
|
|
|
|
where: {
|
|
|
|
userId: ctx.user.id,
|
|
|
|
id,
|
|
|
|
},
|
|
|
|
});
|
2021-10-28 22:52:39 +00:00
|
|
|
if (!webhook) {
|
|
|
|
// user does not own this webhook
|
2022-03-02 16:24:57 +00:00
|
|
|
// team event doesn't own this webhook
|
2021-10-28 22:52:39 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return await ctx.prisma.webhook.update({
|
|
|
|
where: {
|
|
|
|
id,
|
|
|
|
},
|
|
|
|
data,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.mutation("delete", {
|
|
|
|
input: z.object({
|
|
|
|
id: z.string(),
|
2022-03-02 16:24:57 +00:00
|
|
|
eventTypeId: z.number().optional(),
|
2021-10-28 22:52:39 +00:00
|
|
|
}),
|
|
|
|
async resolve({ ctx, input }) {
|
|
|
|
const { id } = input;
|
2021-10-29 14:13:51 +00:00
|
|
|
|
2022-03-02 16:24:57 +00:00
|
|
|
input.eventTypeId
|
|
|
|
? await ctx.prisma.eventType.update({
|
|
|
|
where: {
|
|
|
|
id: input.eventTypeId,
|
2022-03-02 15:30:13 +00:00
|
|
|
},
|
2022-03-02 16:24:57 +00:00
|
|
|
data: {
|
|
|
|
webhooks: {
|
|
|
|
delete: {
|
|
|
|
id,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
: await ctx.prisma.user.update({
|
|
|
|
where: {
|
|
|
|
id: ctx.user.id,
|
|
|
|
},
|
|
|
|
data: {
|
|
|
|
webhooks: {
|
|
|
|
delete: {
|
|
|
|
id,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
2021-10-25 16:15:52 +00:00
|
|
|
return {
|
2021-10-28 22:52:39 +00:00
|
|
|
id,
|
2021-10-25 16:15:52 +00:00
|
|
|
};
|
2021-10-28 22:52:39 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
.mutation("testTrigger", {
|
|
|
|
input: z.object({
|
|
|
|
url: z.string().url(),
|
|
|
|
type: z.string(),
|
2021-11-22 11:37:07 +00:00
|
|
|
payloadTemplate: z.string().optional().nullable(),
|
2021-10-28 22:52:39 +00:00
|
|
|
}),
|
|
|
|
async resolve({ input }) {
|
2022-05-03 23:16:59 +00:00
|
|
|
const { url, type, payloadTemplate = null } = input;
|
2022-02-10 10:44:46 +00:00
|
|
|
const translation = await getTranslation("en", "common");
|
|
|
|
const language = {
|
|
|
|
locale: "en",
|
|
|
|
translate: translation,
|
|
|
|
};
|
2021-10-28 22:52:39 +00:00
|
|
|
|
2021-11-22 11:37:07 +00:00
|
|
|
const data = {
|
2022-03-14 11:27:28 +00:00
|
|
|
triggerEvent: "PING",
|
2021-11-22 11:37:07 +00:00
|
|
|
type: "Test",
|
|
|
|
title: "Test trigger event",
|
|
|
|
description: "",
|
|
|
|
startTime: new Date().toISOString(),
|
|
|
|
endTime: new Date().toISOString(),
|
|
|
|
attendees: [
|
|
|
|
{
|
|
|
|
email: "jdoe@example.com",
|
|
|
|
name: "John Doe",
|
|
|
|
timeZone: "Europe/London",
|
2022-02-10 10:44:46 +00:00
|
|
|
language,
|
2021-10-28 22:52:39 +00:00
|
|
|
},
|
2021-11-22 11:37:07 +00:00
|
|
|
],
|
|
|
|
organizer: {
|
|
|
|
name: "Cal",
|
2022-03-14 11:27:28 +00:00
|
|
|
email: "no-reply@cal.com",
|
2021-11-22 11:37:07 +00:00
|
|
|
timeZone: "Europe/London",
|
2022-02-10 10:44:46 +00:00
|
|
|
language,
|
2021-10-28 22:52:39 +00:00
|
|
|
},
|
2021-10-25 16:15:52 +00:00
|
|
|
};
|
2021-10-28 22:52:39 +00:00
|
|
|
|
|
|
|
try {
|
2022-05-03 23:16:59 +00:00
|
|
|
const webhook = { subscriberUrl: url, payloadTemplate, appId: null };
|
|
|
|
return await sendPayload(type, new Date().toISOString(), webhook, data);
|
2021-10-28 22:52:39 +00:00
|
|
|
} catch (_err) {
|
2021-11-22 11:37:07 +00:00
|
|
|
const error = getErrorFromUnknown(_err);
|
2021-10-28 22:52:39 +00:00
|
|
|
return {
|
2021-11-22 11:37:07 +00:00
|
|
|
ok: false,
|
2021-10-28 22:52:39 +00:00
|
|
|
status: 500,
|
2021-11-22 11:37:07 +00:00
|
|
|
message: error.message,
|
2021-10-28 22:52:39 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|