mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-12 22:26:12 -05:00
Deleting VoDs feature Closes #1765
This commit is contained in:
5
app/features/vods/VodRepository.server.ts
Normal file
5
app/features/vods/VodRepository.server.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { db } from "~/db/sql";
|
||||
|
||||
export function deleteById(id: number) {
|
||||
return db.deleteFrom("UnvalidatedVideo").where("id", "=", id).execute();
|
||||
}
|
||||
25
app/features/vods/actions/vods.$id.server.ts
Normal file
25
app/features/vods/actions/vods.$id.server.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { type ActionFunctionArgs, redirect } from "@remix-run/node";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import { badRequestIfFalsy, unauthorizedIfFalsy } from "~/utils/remix";
|
||||
import { userVodsPage } from "~/utils/urls";
|
||||
import * as VodRepository from "../VodRepository.server";
|
||||
import { findVodById } from "../queries/findVodById.server";
|
||||
import { canEditVideo } from "../vods-utils";
|
||||
|
||||
export const action = async ({ request, params }: ActionFunctionArgs) => {
|
||||
const user = await requireUser(request);
|
||||
|
||||
const vod = badRequestIfFalsy(findVodById(Number(params.id)));
|
||||
|
||||
unauthorizedIfFalsy(
|
||||
canEditVideo({
|
||||
userId: user.id,
|
||||
submitterUserId: vod.submitterUserId,
|
||||
povUserId: typeof vod.pov === "string" ? undefined : vod.pov?.id,
|
||||
}),
|
||||
);
|
||||
|
||||
await VodRepository.deleteById(vod.id);
|
||||
|
||||
return redirect(userVodsPage(user));
|
||||
};
|
||||
@@ -8,9 +8,12 @@ import clsx from "clsx";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button, LinkButton } from "~/components/Button";
|
||||
import { FormWithConfirm } from "~/components/FormWithConfirm";
|
||||
import { Image, WeaponImage } from "~/components/Image";
|
||||
import { Main } from "~/components/Main";
|
||||
import { YouTubeEmbed } from "~/components/YouTubeEmbed";
|
||||
import { EditIcon } from "~/components/icons/Edit";
|
||||
import { TrashIcon } from "~/components/icons/Trash";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { useSearchParamState } from "~/hooks/useSearchParamState";
|
||||
@@ -34,6 +37,9 @@ import { canEditVideo } from "../vods-utils";
|
||||
|
||||
import "../vods.css";
|
||||
|
||||
import { action } from "../actions/vods.$id.server";
|
||||
export { action };
|
||||
|
||||
export const handle: SendouRouteHandle = {
|
||||
breadcrumb: ({ match }) => {
|
||||
const data = match.data as SerializeFrom<typeof loader> | undefined;
|
||||
@@ -79,7 +85,7 @@ export default function VodPage() {
|
||||
const isMounted = useIsMounted();
|
||||
const [autoplay, setAutoplay] = React.useState(false);
|
||||
const data = useLoaderData<typeof loader>();
|
||||
const { t } = useTranslation(["common"]);
|
||||
const { t } = useTranslation(["common", "vods"]);
|
||||
const user = useUser();
|
||||
|
||||
return (
|
||||
@@ -118,13 +124,30 @@ export default function VodPage() {
|
||||
povUserId:
|
||||
typeof data.vod.pov === "string" ? undefined : data.vod.pov?.id,
|
||||
}) ? (
|
||||
<LinkButton
|
||||
to={newVodPage(data.vod.id)}
|
||||
size="tiny"
|
||||
testId="edit-vod-button"
|
||||
>
|
||||
{t("common:actions.edit")}
|
||||
</LinkButton>
|
||||
<div className="stack horizontal md">
|
||||
<LinkButton
|
||||
to={newVodPage(data.vod.id)}
|
||||
size="tiny"
|
||||
testId="edit-vod-button"
|
||||
icon={<EditIcon />}
|
||||
>
|
||||
{t("common:actions.edit")}
|
||||
</LinkButton>
|
||||
<FormWithConfirm
|
||||
dialogHeading={t("vods:deleteConfirm", {
|
||||
title: data.vod.title,
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
variant="minimal-destructive"
|
||||
size="tiny"
|
||||
type="submit"
|
||||
icon={<TrashIcon />}
|
||||
>
|
||||
{t("common:actions.delete")}
|
||||
</Button>
|
||||
</FormWithConfirm>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,13 +28,18 @@ export function notFoundIfNullLike<T>(value: T | null | undefined): T {
|
||||
|
||||
export function badRequestIfFalsy<T>(value: T | null | undefined): T {
|
||||
if (!value) {
|
||||
noticeError(new Error("Value is falsy"));
|
||||
throw new Response(null, { status: 400 });
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function unauthorizedIfFalsy<T>(value: T | null | undefined): T {
|
||||
if (!value) throw new Response(null, { status: 401 });
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function parseSearchParams<T extends z.ZodTypeAny>({
|
||||
request,
|
||||
schema,
|
||||
|
||||
@@ -22,5 +22,6 @@
|
||||
"forms.action.deleteMatch": "Delete match",
|
||||
"noVods": "No videos found matching this filter. Are we missing something? Message Sendou on Discord to get YouTube video submission permissions.",
|
||||
"addVod": "Add video",
|
||||
"gainPerms": "Please post on the helpdesk of our Discord to gain permissions to upload videos."
|
||||
"gainPerms": "Please post on the helpdesk of our Discord to gain permissions to upload videos.",
|
||||
"deleteConfirm": "Delete video with the title '{{title}}'?"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user