This commit is contained in:
1 parent
50df22928b
commit
7c0ee9f186
38 files changed
+920
-240
No files matched your search
@@ -1,9 +1,12 @@
|
||||
import { CronJob } from "cron";
|
||||
import dotEnv from "dotenv";
|
||||
|
||||
dotEnv.config({ path: "../../.env" });
|
||||
|
||||
async function fetchCron(endpoint: string) {
|
||||
const apiKey = process.env.CRON_API_KEY;
|
||||
|
||||
const res = await fetch(`http://localhost:3000/api${endpoint}?${apiKey}`, {
|
||||
const res = await fetch(`http://localhost:3000/api${endpoint}?apiKey=${apiKey}`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
authorization: `Bearer ${process.env.CRON_SECRET}`,
|
||||
@@ -20,7 +23,7 @@ try {
|
||||
"*/5 * * * * *",
|
||||
async function () {
|
||||
await Promise.allSettled([
|
||||
fetchCron("/tasks/cron"),
|
||||
fetchCron("/calendar-cache/cron"),
|
||||
// fetchCron("/cron/calVideoNoShowWebhookTriggers"),
|
||||
//
|
||||
// fetchCron("/tasks/cleanup"),
|
||||
|
||||
@@ -3,98 +3,92 @@ import { z } from "zod";
|
||||
|
||||
import { getCalendarCredentials, getConnectedCalendars } from "@calcom/core/CalendarManager";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { CalendarCache } from "@calcom/features/calendar-cache/calendar-cache";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import notEmpty from "@calcom/lib/notEmpty";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
|
||||
import { defaultHandler, defaultResponder } from "@calcom/lib/server";
|
||||
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
|
||||
import { UserRepository } from "@calcom/lib/server/repository/user";
|
||||
|
||||
const selectedCalendarSelectSchema = z.object({
|
||||
integration: z.string(),
|
||||
externalId: z.string(),
|
||||
credentialId: z.number().optional(),
|
||||
credentialId: z.coerce.number(),
|
||||
});
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const session = await getServerSession({ req, res });
|
||||
/** Shared authentication middleware for GET, DELETE and POST requests */
|
||||
async function authMiddleware(req: CustomNextApiRequest) {
|
||||
const session = await getServerSession({ req });
|
||||
|
||||
if (!session?.user?.id) {
|
||||
res.status(401).json({ message: "Not authenticated" });
|
||||
return;
|
||||
throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
||||
}
|
||||
|
||||
const userWithCredentials = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: session.user.id,
|
||||
},
|
||||
select: {
|
||||
credentials: {
|
||||
select: credentialForCalendarServiceSelect,
|
||||
},
|
||||
timeZone: true,
|
||||
id: true,
|
||||
selectedCalendars: true,
|
||||
},
|
||||
});
|
||||
const userWithCredentials = await UserRepository.findUserWithCredentials({ id: session.user.id });
|
||||
|
||||
if (!userWithCredentials) {
|
||||
res.status(401).json({ message: "Not authenticated" });
|
||||
return;
|
||||
}
|
||||
const { credentials, ...user } = userWithCredentials;
|
||||
|
||||
if (req.method === "POST") {
|
||||
const { integration, externalId, credentialId } = selectedCalendarSelectSchema.parse(req.body);
|
||||
await prisma.selectedCalendar.upsert({
|
||||
where: {
|
||||
userId_integration_externalId: {
|
||||
userId: user.id,
|
||||
integration,
|
||||
externalId,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
userId: user.id,
|
||||
integration,
|
||||
externalId,
|
||||
credentialId,
|
||||
},
|
||||
// already exists
|
||||
update: {},
|
||||
});
|
||||
res.status(200).json({ message: "Calendar Selection Saved" });
|
||||
}
|
||||
|
||||
if (req.method === "DELETE") {
|
||||
const { integration, externalId } = selectedCalendarSelectSchema.parse(req.query);
|
||||
await prisma.selectedCalendar.delete({
|
||||
where: {
|
||||
userId_integration_externalId: {
|
||||
userId: user.id,
|
||||
externalId,
|
||||
integration,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
res.status(200).json({ message: "Calendar Selection Saved" });
|
||||
}
|
||||
|
||||
if (req.method === "GET") {
|
||||
const selectedCalendarIds = await prisma.selectedCalendar.findMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
select: {
|
||||
externalId: true,
|
||||
},
|
||||
});
|
||||
|
||||
// get user's credentials + their connected integrations
|
||||
const calendarCredentials = getCalendarCredentials(credentials);
|
||||
// get all the connected integrations' calendars (from third party)
|
||||
const { connectedCalendars } = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
|
||||
const calendars = connectedCalendars.flatMap((c) => c.calendars).filter(notEmpty);
|
||||
const selectableCalendars = calendars.map((cal) => {
|
||||
return { selected: selectedCalendarIds.findIndex((s) => s.externalId === cal.externalId) > -1, ...cal };
|
||||
});
|
||||
res.status(200).json(selectableCalendars);
|
||||
throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
||||
}
|
||||
req.userWithCredentials = userWithCredentials;
|
||||
return userWithCredentials;
|
||||
}
|
||||
|
||||
type CustomNextApiRequest = NextApiRequest & {
|
||||
userWithCredentials?: Awaited<ReturnType<typeof authMiddleware>>;
|
||||
};
|
||||
|
||||
async function postHandler(req: CustomNextApiRequest) {
|
||||
if (!req.userWithCredentials) throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
||||
const user = req.userWithCredentials;
|
||||
const { integration, externalId, credentialId } = selectedCalendarSelectSchema.parse(req.body);
|
||||
await SelectedCalendarRepository.upsert({
|
||||
userId: user.id,
|
||||
integration,
|
||||
externalId,
|
||||
credentialId,
|
||||
});
|
||||
|
||||
return { message: "Calendar Selection Saved" };
|
||||
}
|
||||
|
||||
async function deleteHandler(req: CustomNextApiRequest) {
|
||||
if (!req.userWithCredentials) throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
||||
const user = req.userWithCredentials;
|
||||
const { integration, externalId, credentialId } = selectedCalendarSelectSchema.parse(req.query);
|
||||
const calendarCacheRepository = await CalendarCache.initFromCredentialId(credentialId);
|
||||
await calendarCacheRepository.unwatchCalendar({ calendarId: externalId });
|
||||
await SelectedCalendarRepository.delete({
|
||||
userId: user.id,
|
||||
externalId,
|
||||
integration,
|
||||
});
|
||||
|
||||
return { message: "Calendar Selection Saved" };
|
||||
}
|
||||
|
||||
async function getHandler(req: CustomNextApiRequest) {
|
||||
if (!req.userWithCredentials) throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
||||
const user = req.userWithCredentials;
|
||||
const selectedCalendarIds = await SelectedCalendarRepository.findMany({
|
||||
where: { userId: user.id },
|
||||
select: { externalId: true },
|
||||
});
|
||||
// get user's credentials + their connected integrations
|
||||
const calendarCredentials = getCalendarCredentials(user.credentials);
|
||||
// get all the connected integrations' calendars (from third party)
|
||||
const { connectedCalendars } = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
|
||||
const calendars = connectedCalendars.flatMap((c) => c.calendars).filter(notEmpty);
|
||||
const selectableCalendars = calendars.map((cal) => {
|
||||
return { selected: selectedCalendarIds.findIndex((s) => s.externalId === cal.externalId) > -1, ...cal };
|
||||
});
|
||||
return selectableCalendars;
|
||||
}
|
||||
|
||||
export default defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
await authMiddleware(req);
|
||||
return defaultHandler({
|
||||
GET: Promise.resolve({ default: defaultResponder(getHandler) }),
|
||||
POST: Promise.resolve({ default: defaultResponder(postHandler) }),
|
||||
DELETE: Promise.resolve({ default: defaultResponder(deleteHandler) }),
|
||||
})(req, res);
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "@calcom/features/calendar-cache/api/cron";
|
||||
@@ -3,6 +3,12 @@ import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const apiKey = req.headers.authorization || req.query.apiKey;
|
||||
if (![process.env.CRON_API_KEY, `Bearer ${process.env.CRON_SECRET}`].includes(`${apiKey}`)) {
|
||||
res.status(401).json({ message: "Not authenticated" });
|
||||
return;
|
||||
}
|
||||
|
||||
const deleted = await prisma.calendarCache.deleteMany({
|
||||
where: {
|
||||
// Delete all cache entries that expired before now
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"path": "/api/tasks/cron",
|
||||
"schedule": "* * * * *"
|
||||
},
|
||||
{
|
||||
"path": "/api/calendar-cache/cron",
|
||||
"schedule": "* * * * *"
|
||||
},
|
||||
{
|
||||
"path": "/api/tasks/cleanup",
|
||||
"schedule": "0 0 * * *"
|
||||
|
||||
Reference in new issue
Block a user