import { alias, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'; import type { MySql2Database } from 'drizzle-orm/mysql2'; import { and, eq, isNotNull } from 'drizzle-orm'; import { reportStatus } from './reportStatus.ts'; import { generateRandomString } from '@util/random.ts'; import { BASE_PATH } from 'astro:env/server'; import { strikeReason } from '@db/schema/strikeReason.ts'; import { strike } from '@db/schema/strike.ts'; import { user } from '@db/schema/user.ts'; type Database = MySql2Database<{ report: typeof report }>; export const report = mysqlTable('report', { id: int('id').primaryKey().autoincrement(), reason: varchar('reason', { length: 255 }).notNull(), body: text('body'), urlHash: varchar('url_hash', { length: 255 }).notNull(), createdAt: timestamp('created_at', { mode: 'date' }), reporterId: int('reporter_id').references(() => user.id), reportedId: int('reported_id').references(() => user.id) }); export type AddReportReq = { reason: string; body: string | null; createdAt?: Date | null; reporterId?: number; reportedId?: number | null; }; export type EditReportReq = { id: number; reportedId: number | null; }; export type SubmitReportReq = { urlHash: string; reportedId: number | null; reason: string; body: string; }; export type GetReportsReq = { reporter?: string | null; reported?: string | null; includeDrafts?: boolean | null; }; export type GetReportById = { id: number; }; export type GetReportByUrlHash = { urlHash: string; }; export async function addReport(db: Database, values: AddReportReq) { const urlHash = generateRandomString(16); const r = await db .insert(report) .values({ reason: values.reason, body: values.body, urlHash: urlHash, createdAt: values.createdAt, reporterId: values.reporterId, reportedId: values.reportedId }) .$returningId(); return Object.assign(r[0], { url: `${BASE_PATH}/report/${urlHash}` }); } export async function editReport(db: Database, values: EditReportReq) { return db .update(report) .set({ reportedId: values.reportedId }) .where(eq(report.id, values.id)); } export async function submitReport(db: Database, values: SubmitReportReq) { return db .update(report) .set({ reportedId: values.reportedId, reason: values.reason, body: values.body, createdAt: new Date() }) .where(eq(report.urlHash, values.urlHash)); } export async function getReports(db: Database, values: GetReportsReq) { const reporter = alias(user, 'reporter'); const reported = alias(user, 'reported'); return db .select({ id: report.id, reason: report.reason, body: report.body, urlHash: report.urlHash, createdAt: report.createdAt, reporter: { id: reporter.id, username: reporter.username, uuid: reporter.uuid }, reported: { id: reported.id, username: reported.username, uuid: reported.uuid }, status: { status: reportStatus.status, notice: reportStatus.notice, statement: reportStatus.statement }, strike: { strikeReasonId: strikeReason.id } }) .from(report) .innerJoin(reporter, eq(report.reporterId, reporter.id)) .leftJoin(reported, eq(report.reportedId, reported.id)) .leftJoin(reportStatus, eq(report.id, reportStatus.reportId)) .leftJoin(strike, eq(report.id, strike.reportId)) .leftJoin(strikeReason, eq(strike.strikeReasonId, strikeReason.id)) .where( and( values.reporter != null ? eq(reporter.username, values.reporter) : undefined, values.reported != null ? eq(reported.username, values.reported) : undefined, values.includeDrafts == false ? isNotNull(report.createdAt) : undefined ) ); } export async function getReportById(db: Database, values: GetReportById) { const reporter = alias(user, 'reporter'); const reported = alias(user, 'reported'); const reports = await db .select({ id: report.id, reason: report.reason, body: report.body, createdAt: report.createdAt, reporter: { id: reporter.id, username: reporter.username }, reported: { id: reported.id, username: reported.username }, status: { status: reportStatus.status, notice: reportStatus.notice, statement: reportStatus.statement } }) .from(report) .innerJoin(reporter, eq(report.reporterId, reporter.id)) .leftJoin(reported, eq(report.reportedId, reported.id)) .leftJoin(reportStatus, eq(report.id, reportStatus.reportId)) .where(eq(report.id, values.id)); return reports[0] ?? null; } export async function getReportByUrlHash(db: Database, values: GetReportByUrlHash) { const reporter = alias(user, 'reporter'); const reported = alias(user, 'reported'); const reports = await db .select({ id: report.id, reason: report.reason, body: report.body, createdAt: report.createdAt, urlHash: report.urlHash, reporter: { id: reporter.id, username: reporter.username, uuid: reporter.uuid }, reported: { id: reported.id, username: reported.username, uuid: reported.uuid }, status: { status: reportStatus.status, notice: reportStatus.notice, statement: reportStatus.statement } }) .from(report) .innerJoin(reporter, eq(report.reporterId, reporter.id)) .leftJoin(reported, eq(report.reportedId, reported.id)) .leftJoin(reportStatus, eq(report.id, reportStatus.reportId)) .where(eq(report.urlHash, values.urlHash)); return reports[0] ?? null; }