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:
parent
230c82e316
commit
3b71c86b1e
2 changed files with 32 additions and 13 deletions
|
@ -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({
|
||||||
|
|
|
@ -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,16 +118,18 @@ export default function Type(props) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 sm:mt-6 text-center space-x-2">
|
{props.cancellationAllowed && (
|
||||||
<Button
|
<div className="mt-5 sm:mt-6 text-centerspace-x-2">
|
||||||
color="secondary"
|
<Button
|
||||||
data-testid="cancel"
|
color="secondary"
|
||||||
onClick={cancellationHandler}
|
data-testid="cancel"
|
||||||
loading={loading}>
|
onClick={cancellationHandler}
|
||||||
Cancel
|
loading={loading}>
|
||||||
</Button>
|
Cancel
|
||||||
<Button onClick={() => router.push("/reschedule/" + uid)}>Reschedule</Button>
|
</Button>
|
||||||
</div>
|
<Button onClick={() => router.push("/reschedule/" + uid)}>Reschedule</Button>
|
||||||
|
</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(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue