prevent cancellation of past events (#568)

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: Peer_Rich <peeroke@gmail.com>
This commit is contained in:
Malte Delfs 2021-09-28 19:23:50 +02:00 committed by GitHub
parent 230c82e316
commit 3b71c86b1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 13 deletions

View file

@ -7,6 +7,7 @@ import { asStringOrNull } from "@lib/asStringOrNull";
import { CalendarEvent, deleteEvent } from "@lib/calendarClient"; import { CalendarEvent, deleteEvent } from "@lib/calendarClient";
import prisma from "@lib/prisma"; import prisma from "@lib/prisma";
import { deleteMeeting } from "@lib/videoClient"; import { deleteMeeting } from "@lib/videoClient";
import { getSession } from "@lib/auth";
export default async function handler(req, res) { export default async function handler(req, res) {
// just bail if it not a DELETE // just bail if it not a DELETE
@ -15,6 +16,7 @@ export default async function handler(req, res) {
} }
const uid = asStringOrNull(req.body.uid) || ""; const uid = asStringOrNull(req.body.uid) || "";
const session = await getSession({ req: req });
const bookingToDelete = await prisma.booking.findUnique({ const bookingToDelete = await prisma.booking.findUnique({
where: { where: {
@ -24,6 +26,7 @@ export default async function handler(req, res) {
id: true, id: true,
user: { user: {
select: { select: {
id: true,
credentials: true, credentials: true,
email: true, email: true,
timeZone: true, timeZone: true,
@ -48,10 +51,14 @@ export default async function handler(req, res) {
}, },
}); });
if (!bookingToDelete) { if (!bookingToDelete || !bookingToDelete.user) {
return res.status(404).end(); return res.status(404).end();
} }
if ((!session || session.user?.id != bookingToDelete.user?.id) && bookingToDelete.startTime < new Date()) {
return res.status(403).json({ message: "Cannot cancel past events" });
}
// by cancelling first, and blocking whilst doing so; we can ensure a cancel // by cancelling first, and blocking whilst doing so; we can ensure a cancel
// action always succeeds even if subsequent integrations fail cancellation. // action always succeeds even if subsequent integrations fail cancellation.
await prisma.booking.update({ await prisma.booking.update({

View file

@ -6,6 +6,7 @@ import { useState } from "react";
import prisma from "@lib/prisma"; import prisma from "@lib/prisma";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
import { getSession } from "next-auth/client";
import { HeadSeo } from "@components/seo/head-seo"; import { HeadSeo } from "@components/seo/head-seo";
import { Button } from "@components/ui/Button"; import { Button } from "@components/ui/Button";
@ -93,10 +94,16 @@ export default function Type(props) {
</div> </div>
<div className="mt-3 text-center sm:mt-5"> <div className="mt-3 text-center sm:mt-5">
<h3 className="text-lg leading-6 font-medium text-gray-900" id="modal-headline"> <h3 className="text-lg leading-6 font-medium text-gray-900" id="modal-headline">
Really cancel your booking? {props.cancellationAllowed
? "Really cancel your booking?"
: "You cannot cancel this booking"}
</h3> </h3>
<div className="mt-2"> <div className="mt-2">
<p className="text-sm text-gray-500">Instead, you could also reschedule it.</p> <p className="text-sm text-gray-500">
{props.cancellationAllowed
? "Instead, you could also reschedule it."
: "The event is in the past"}
</p>
</div> </div>
<div className="mt-4 border-t border-b py-4"> <div className="mt-4 border-t border-b py-4">
<h2 className="font-cal text-lg font-medium text-gray-600 mb-2"> <h2 className="font-cal text-lg font-medium text-gray-600 mb-2">
@ -111,6 +118,7 @@ export default function Type(props) {
</div> </div>
</div> </div>
</div> </div>
{props.cancellationAllowed && (
<div className="mt-5 sm:mt-6 text-centerspace-x-2"> <div className="mt-5 sm:mt-6 text-centerspace-x-2">
<Button <Button
color="secondary" color="secondary"
@ -121,6 +129,7 @@ export default function Type(props) {
</Button> </Button>
<Button onClick={() => router.push("/reschedule/" + uid)}>Reschedule</Button> <Button onClick={() => router.push("/reschedule/" + uid)}>Reschedule</Button>
</div> </div>
)}
</> </>
)} )}
</div> </div>
@ -133,6 +142,7 @@ export default function Type(props) {
} }
export async function getServerSideProps(context) { export async function getServerSideProps(context) {
const session = await getSession(context);
const booking = await prisma.booking.findUnique({ const booking = await prisma.booking.findUnique({
where: { where: {
uid: context.query.uid, uid: context.query.uid,
@ -186,6 +196,8 @@ export async function getServerSideProps(context) {
props: { props: {
profile, profile,
booking: bookingObj, booking: bookingObj,
cancellationAllowed:
(!!session?.user && session.user.id == booking.user?.id) || booking.startTime >= new Date(),
}, },
}; };
} }