feat: report notifications
This commit is contained in:
parent
6e8f5beb3e
commit
36f0ff8398
4 changed files with 50 additions and 16 deletions
|
|
@ -18,4 +18,7 @@ AUTH_GITHUB_SECRET=XXXXXXXXXXXXXXXX
|
|||
# Currently only supports one admin
|
||||
NEXT_PUBLIC_ADMIN_USER_ID=1
|
||||
# Separated by commas
|
||||
NEXT_PUBLIC_CONTRIBUTORS_USER_IDS=176
|
||||
NEXT_PUBLIC_CONTRIBUTORS_USER_IDS=176
|
||||
|
||||
# Sends notifications (such as admin reports) to ntfy
|
||||
NTFY_URL="https://ntfy.yourdomain.com/tomodachi-share"
|
||||
|
|
@ -5,6 +5,7 @@ import { ReportReason, ReportType } from "@prisma/client";
|
|||
import { auth } from "@/lib/auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { RateLimit } from "@/lib/rate-limit";
|
||||
import { MiiWithUsername } from "@/types";
|
||||
|
||||
const reportSchema = z.object({
|
||||
id: z.coerce.number({ message: "ID must be a number" }).int({ message: "ID must be an integer" }).positive({ message: "ID must be valid" }),
|
||||
|
|
@ -29,12 +30,25 @@ export async function POST(request: NextRequest) {
|
|||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
||||
const { id, type, reason, notes } = parsed.data;
|
||||
|
||||
let mii: MiiWithUsername | null = null;
|
||||
|
||||
// Check if the Mii or User exists
|
||||
if (type === "mii") {
|
||||
const mii = await prisma.mii.findUnique({ where: { id } });
|
||||
mii = await prisma.mii.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
username: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!mii) return rateLimit.sendResponse({ error: "Mii not found" }, 404);
|
||||
} else {
|
||||
const user = await prisma.user.findUnique({ where: { id } });
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
if (!user) return rateLimit.sendResponse({ error: "User not found" }, 404);
|
||||
}
|
||||
|
||||
|
|
@ -57,6 +71,7 @@ export async function POST(request: NextRequest) {
|
|||
reason: reason.toUpperCase() as ReportReason,
|
||||
reasonNotes: notes,
|
||||
authorId: Number(session.user.id),
|
||||
creatorId: mii ? mii.userId : undefined,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
@ -64,5 +79,21 @@ export async function POST(request: NextRequest) {
|
|||
return rateLimit.sendResponse({ error: "Failed to create report" }, 500);
|
||||
}
|
||||
|
||||
// Send notification to ntfy
|
||||
if (process.env.NTFY_URL) {
|
||||
// This is only shown if report type is MII
|
||||
const miiCreatorMessage = mii ? `by @${mii.user.username} (ID: ${mii.userId})` : "";
|
||||
|
||||
await fetch(process.env.NTFY_URL, {
|
||||
method: "POST",
|
||||
body: `Report by @${session.user.username} (ID: ${session.user.id}) on ${type.toUpperCase()} (ID: ${id}) ${miiCreatorMessage}`,
|
||||
headers: {
|
||||
Title: "Report recieved - TomodachiShare",
|
||||
Priority: "urgent",
|
||||
Tags: "triangular_flag_on_post",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return rateLimit.sendResponse({ success: true });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,22 +4,11 @@ import fs from "fs/promises";
|
|||
import path from "path";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
import { idSchema } from "@/lib/schemas";
|
||||
import { RateLimit } from "@/lib/rate-limit";
|
||||
import { generateMetadataImage } from "@/lib/images";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
type MiiWithUser = Prisma.MiiGetPayload<{
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
username: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}>;
|
||||
import { MiiWithUsername } from "@/types";
|
||||
|
||||
const searchParamsSchema = z.object({
|
||||
type: z
|
||||
|
|
@ -48,7 +37,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||
|
||||
let buffer: Buffer | undefined;
|
||||
// Only find Mii if image type is 'metadata'
|
||||
let mii: MiiWithUser | null = null;
|
||||
let mii: MiiWithUsername | null = null;
|
||||
|
||||
if (imageType === "metadata") {
|
||||
mii = await prisma.mii.findUnique({
|
||||
|
|
|
|||
11
src/types.d.ts
vendored
11
src/types.d.ts
vendored
|
|
@ -1,3 +1,4 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
import { DefaultSession } from "next-auth";
|
||||
|
||||
declare module "next-auth" {
|
||||
|
|
@ -11,3 +12,13 @@ declare module "next-auth" {
|
|||
username?: string;
|
||||
}
|
||||
}
|
||||
|
||||
type MiiWithUsername = Prisma.MiiGetPayload<{
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
username: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}>;
|
||||
|
|
|
|||
Loading…
Reference in a new issue