diff --git a/pages/api/cancel.ts b/pages/api/cancel.ts index 3610f1da1c..9205f2db40 100644 --- a/pages/api/cancel.ts +++ b/pages/api/cancel.ts @@ -1,15 +1,17 @@ -import prisma from "../../lib/prisma"; -import { deleteEvent } from "../../lib/calendarClient"; +import prisma from "@lib/prisma"; +import { deleteEvent } from "@lib/calendarClient"; import async from "async"; -import { deleteMeeting } from "../../lib/videoClient"; +import { deleteMeeting } from "@lib/videoClient"; +import { asStringOrNull } from "@lib/asStringOrNull"; +import { BookingStatus } from "@prisma/client"; export default async function handler(req, res) { if (req.method == "POST") { - const uid = req.body.uid; + const uid = asStringOrNull(req.body.uid); - const bookingToDelete = await prisma.booking.findFirst({ + const bookingToDelete = await prisma.booking.findUnique({ where: { - uid: uid, + uid, }, select: { id: true, @@ -28,6 +30,21 @@ export default async function handler(req, res) { }, }); + if (!bookingToDelete) { + return res.status(404).end(); + } + + // by cancelling first, and blocking whilst doing so; we can ensure a cancel + // action always succeeds even if subsequent integrations fail cancellation. + await prisma.booking.update({ + where: { + uid, + }, + data: { + status: BookingStatus.CANCELLED, + }, + }); + const apiDeletes = async.mapLimit(bookingToDelete.user.credentials, 5, async (credential) => { const bookingRefUid = bookingToDelete.references.filter((ref) => ref.type === credential.type)[0]?.uid; if (bookingRefUid) { @@ -38,23 +55,20 @@ export default async function handler(req, res) { } } }); + const attendeeDeletes = prisma.attendee.deleteMany({ where: { bookingId: bookingToDelete.id, }, }); + const bookingReferenceDeletes = prisma.bookingReference.deleteMany({ where: { bookingId: bookingToDelete.id, }, }); - const bookingDeletes = prisma.booking.delete({ - where: { - id: bookingToDelete.id, - }, - }); - await Promise.all([apiDeletes, attendeeDeletes, bookingReferenceDeletes, bookingDeletes]); + await Promise.all([apiDeletes, attendeeDeletes, bookingReferenceDeletes]); //TODO Perhaps send emails to user and client to tell about the cancellation diff --git a/pages/bookings/index.tsx b/pages/bookings/index.tsx index 282e8de07c..21be95dddf 100644 --- a/pages/bookings/index.tsx +++ b/pages/bookings/index.tsx @@ -10,6 +10,7 @@ import classNames from "@lib/classNames"; import { ClockIcon, XIcon } from "@heroicons/react/outline"; import Loader from "@components/Loader"; import { getSession } from "@lib/auth"; +import { BookingStatus } from "@prisma/client"; export default function Bookings({ bookings }) { // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -44,8 +45,7 @@ export default function Bookings({ bookings }) {
| @@ -66,11 +66,13 @@ export default function Bookings({ bookings }) { - + {booking.attendees.length !== 0 && ( + + )} |
@@ -232,6 +234,7 @@ export async function getServerSideProps(context) {
id: true,
startTime: true,
endTime: true,
+ status: true,
},
orderBy: {
startTime: "asc",
diff --git a/prisma/migrations/20210904162403_add_booking_status_enum/migration.sql b/prisma/migrations/20210904162403_add_booking_status_enum/migration.sql
new file mode 100644
index 0000000000..a8c7284582
--- /dev/null
+++ b/prisma/migrations/20210904162403_add_booking_status_enum/migration.sql
@@ -0,0 +1,5 @@
+-- CreateEnum
+CREATE TYPE "BookingStatus" AS ENUM ('cancelled', 'accepted', 'rejected', 'pending');
+
+-- AlterTable
+ALTER TABLE "Booking" ADD COLUMN "status" "BookingStatus" NOT NULL DEFAULT E'accepted';
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index a5b8b10b87..4777c2e893 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -136,6 +136,13 @@ model Attendee {
bookingId Int?
}
+enum BookingStatus {
+ CANCELLED @map("cancelled")
+ ACCEPTED @map("accepted")
+ REJECTED @map("rejected")
+ PENDING @map("pending")
+}
+
model Booking {
id Int @id @default(autoincrement())
uid String @unique
@@ -157,6 +164,7 @@ model Booking {
updatedAt DateTime?
confirmed Boolean @default(true)
rejected Boolean @default(false)
+ status BookingStatus @default(ACCEPTED)
}
model Schedule {
|