mirror of
https://github.com/lukevella/rallly.git
synced 2025-04-29 02:06:34 +02:00
Don’t delete polls with options in the future (#273)
This commit is contained in:
parent
dac1041361
commit
2648be9b0a
3 changed files with 90 additions and 9 deletions
|
@ -4,6 +4,8 @@ import { NextApiRequest, NextApiResponse } from "next";
|
|||
|
||||
import { prisma } from "~/prisma/db";
|
||||
|
||||
import { parseValue } from "../../utils/date-time-utils";
|
||||
|
||||
/**
|
||||
* DANGER: This endpoint will permanently delete polls.
|
||||
*/
|
||||
|
@ -24,12 +26,33 @@ export default async function handler(
|
|||
return;
|
||||
}
|
||||
|
||||
// soft delete polls that have not been accessed for over 30 days
|
||||
const inactivePolls = await prisma.poll.deleteMany({
|
||||
// get polls that have not been accessed for over 30 days
|
||||
const inactivePolls = await prisma.$queryRaw<
|
||||
Array<{ id: string; max: string }>
|
||||
>`
|
||||
SELECT polls.id, MAX(options.value) FROM polls
|
||||
JOIN options ON options.poll_id = polls.id
|
||||
WHERE touched_at <= ${dayjs().add(-30, "days").toDate()} AND deleted = false
|
||||
GROUP BY polls.id;
|
||||
`;
|
||||
|
||||
const pollsToSoftDelete: string[] = [];
|
||||
|
||||
// keep polls that have options that are in the future
|
||||
inactivePolls.forEach(({ id, max: value }) => {
|
||||
const parsedValue = parseValue(value);
|
||||
const date =
|
||||
parsedValue.type === "date" ? parsedValue.date : parsedValue.end;
|
||||
|
||||
if (dayjs(date).isBefore(dayjs())) {
|
||||
pollsToSoftDelete.push(id);
|
||||
}
|
||||
});
|
||||
|
||||
const softDeletedPolls = await prisma.poll.deleteMany({
|
||||
where: {
|
||||
deleted: false,
|
||||
touchedAt: {
|
||||
lte: dayjs().add(-30, "days").toDate(),
|
||||
id: {
|
||||
in: pollsToSoftDelete,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -111,7 +134,7 @@ export default async function handler(
|
|||
}
|
||||
|
||||
res.status(200).json({
|
||||
inactive: inactivePolls.count,
|
||||
softDeleted: softDeletedPolls.count,
|
||||
deleted: pollIdsToDelete.length,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -155,3 +155,19 @@ export const expectTimeOption = (d: DateTimeOption): TimeOption => {
|
|||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
export const parseValue = (value: string): DateTimeOption => {
|
||||
if (isTimeSlot(value)) {
|
||||
const [start, end] = value.split("/");
|
||||
return {
|
||||
type: "timeSlot",
|
||||
start,
|
||||
end,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: "date",
|
||||
date: value,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -75,10 +75,9 @@ test.beforeAll(async ({ request, baseURL }) => {
|
|||
participantUrlId: "p6",
|
||||
adminUrlId: "a6",
|
||||
},
|
||||
// Old demo poll
|
||||
{
|
||||
demo: true,
|
||||
title: "Demo poll",
|
||||
title: "Old demo poll",
|
||||
id: "demo-poll-old",
|
||||
type: "date",
|
||||
userId: "user1",
|
||||
|
@ -86,6 +85,15 @@ test.beforeAll(async ({ request, baseURL }) => {
|
|||
participantUrlId: "p7",
|
||||
adminUrlId: "a7",
|
||||
},
|
||||
{
|
||||
title: "Inactive poll with future option",
|
||||
id: "inactive-poll-future-option",
|
||||
type: "date",
|
||||
userId: "user1",
|
||||
touchedAt: dayjs().add(-30, "days").toDate(),
|
||||
participantUrlId: "p8",
|
||||
adminUrlId: "a8",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -106,6 +114,21 @@ test.beforeAll(async ({ request, baseURL }) => {
|
|||
value: "2022-02-24",
|
||||
pollId: "deleted-poll-7d",
|
||||
},
|
||||
{
|
||||
id: "option-4",
|
||||
value: `${dayjs()
|
||||
.add(10, "days")
|
||||
.format("YYYY-MM-DDTHH:mm:ss")}/${dayjs()
|
||||
.add(10, "days")
|
||||
.add(1, "hour")
|
||||
.format("YYYY-MM-DDTHH:mm:ss")}`,
|
||||
pollId: "inactive-poll-future-option",
|
||||
},
|
||||
{
|
||||
id: "option-5",
|
||||
value: dayjs().add(-1, "days").format("YYYY-MM-DD"),
|
||||
pollId: "inactive-poll",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -144,7 +167,7 @@ test.beforeAll(async ({ request, baseURL }) => {
|
|||
});
|
||||
|
||||
expect(await res.json()).toMatchObject({
|
||||
inactive: 1,
|
||||
softDeleted: 1,
|
||||
deleted: 2,
|
||||
});
|
||||
});
|
||||
|
@ -252,6 +275,16 @@ test("should delete old demo poll", async () => {
|
|||
expect(oldDemoPoll).toBeNull();
|
||||
});
|
||||
|
||||
test("should not delete poll that has options in the future", async () => {
|
||||
const futureOptionPoll = await prisma.poll.findFirst({
|
||||
where: {
|
||||
id: "inactive-poll-future-option",
|
||||
},
|
||||
});
|
||||
|
||||
expect(futureOptionPoll).not.toBeNull();
|
||||
});
|
||||
|
||||
// Teardown
|
||||
test.afterAll(async () => {
|
||||
await prisma.$executeRaw`DELETE FROM polls WHERE id IN (${Prisma.join([
|
||||
|
@ -263,4 +296,13 @@ test.afterAll(async () => {
|
|||
"demo-poll-new",
|
||||
"demo-poll-old",
|
||||
])})`;
|
||||
await prisma.$executeRaw`DELETE FROM options WHERE id IN (${Prisma.join([
|
||||
"active-poll",
|
||||
"deleted-poll-6d",
|
||||
"deleted-poll-7d",
|
||||
"still-active-poll",
|
||||
"inactive-poll",
|
||||
"demo-poll-new",
|
||||
"demo-poll-old",
|
||||
])})`;
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue