213 lines
6.8 KiB
TypeScript
213 lines
6.8 KiB
TypeScript
import type { RequestHandler } from '@sveltejs/kit';
|
|
import { getSession } from '$lib/server/session';
|
|
import { Permissions } from '$lib/permissions';
|
|
import { Admin, Report, StrikeReason, User } from '$lib/server/database';
|
|
import type { Attributes } from 'sequelize';
|
|
import { Op } from 'sequelize';
|
|
import { env } from '$env/dynamic/private';
|
|
import crypto from 'crypto';
|
|
import { webhookUserReported } from '$lib/server/webhook';
|
|
|
|
export const POST = (async ({ request, cookies }) => {
|
|
if (getSession(cookies, { permissions: [Permissions.ReportRead] }) == null) {
|
|
return new Response(null, {
|
|
status: 401
|
|
});
|
|
}
|
|
|
|
const data: {
|
|
limit: number | null;
|
|
from: number | null;
|
|
|
|
draft: boolean | null;
|
|
status: 'none' | 'review' | 'reviewed' | null;
|
|
reporter: string | null;
|
|
reported: string | null;
|
|
|
|
hash: string | null;
|
|
} = await request.json();
|
|
|
|
let reportFindOptions: Attributes<Report> = {};
|
|
if (data.draft != null) reportFindOptions.draft = data.draft;
|
|
reportFindOptions.status = data.status == null ? ['none', 'review'] : data.status;
|
|
if (data.reporter != null) {
|
|
const reporter_ids = await User.findAll({
|
|
attributes: ['id'],
|
|
where: { username: { [Op.like]: `%${data.reporter}%` } }
|
|
});
|
|
reportFindOptions.reporter_id = reporter_ids.map((u) => u.id);
|
|
}
|
|
if (data.reported != null) {
|
|
const reported_ids = await User.findAll({
|
|
attributes: ['id'],
|
|
where: { username: { [Op.like]: `%${data.reported}%` } }
|
|
});
|
|
reportFindOptions.reported_id = reported_ids.map((u) => u.id);
|
|
}
|
|
|
|
if (data.hash != null) {
|
|
reportFindOptions = { url_hash: data.hash };
|
|
data.from = 0;
|
|
data.limit = 1;
|
|
}
|
|
|
|
let reports = await Report.findAll({
|
|
where: reportFindOptions,
|
|
include: [
|
|
{ model: User, as: 'reporter' },
|
|
{ model: User, as: 'reported' },
|
|
{ model: Admin, as: 'auditor' },
|
|
{ model: StrikeReason, as: 'strike_reason' }
|
|
],
|
|
order: ['created_at'],
|
|
offset: data.from || 0,
|
|
limit: data.limit || 100
|
|
});
|
|
reports = reports.map((r) => {
|
|
if (r.auditor_id === null && r.status != 'none') {
|
|
// if the report was edited by the admin account set by the env variable, it has no relation to the admin
|
|
// table in the database, so it gets manually created here. we just assume that the auditor_id is never null
|
|
// when not edited by the env admin account
|
|
r.auditor_id = -1;
|
|
r.dataValues.auditor = {
|
|
id: -1,
|
|
username: env.ADMIN_USER,
|
|
permissions: new Permissions(Permissions.allPermissions()),
|
|
createdAt: 0,
|
|
updatedAt: 0
|
|
};
|
|
} else if (r.auditor) {
|
|
delete r.dataValues.auditor.password;
|
|
}
|
|
if (!r.strike_reason) {
|
|
r.strike_reason_id = -1;
|
|
}
|
|
return r;
|
|
});
|
|
|
|
return new Response(
|
|
JSON.stringify({ reports: reports, count: await Report.count({ where: reportFindOptions }) })
|
|
);
|
|
}) satisfies RequestHandler;
|
|
|
|
export const PATCH = (async ({ request, cookies }) => {
|
|
if (getSession(cookies, { permissions: [Permissions.ReportWrite] }) == null) {
|
|
return new Response(null, {
|
|
status: 401
|
|
});
|
|
}
|
|
|
|
const data: {
|
|
id: number;
|
|
reported: string | null;
|
|
auditor: number;
|
|
notice: string | null;
|
|
statement: string | null;
|
|
status: 'none' | 'review' | 'reviewed' | null;
|
|
strike_reason: number | null;
|
|
} = await request.json();
|
|
|
|
if (data.id === null || data.auditor === null) return new Response(null, { status: 400 });
|
|
|
|
const report = await Report.findOne({ where: { id: data.id } });
|
|
const admin = await Admin.findOne({ where: { id: data.auditor } });
|
|
const reported = data.reported
|
|
? await User.findOne({ where: { uuid: data.reported } })
|
|
: undefined;
|
|
if (report === null || (admin === null && data.auditor != -1) || reported === null)
|
|
return new Response(null, { status: 400 });
|
|
|
|
const webhookTriggerUsers: string[] = [];
|
|
if (report.reported_id != reported?.id) {
|
|
const oldReportUser = await User.findByPk(report.reported_id);
|
|
if (oldReportUser) webhookTriggerUsers.push(oldReportUser.uuid);
|
|
if (reported) webhookTriggerUsers.push(reported.uuid);
|
|
} else if (
|
|
reported &&
|
|
report.reported_id != null &&
|
|
report.strike_reason_id != data.strike_reason
|
|
) {
|
|
webhookTriggerUsers.push(reported.uuid);
|
|
}
|
|
|
|
report.reported_id = reported?.id ?? null;
|
|
if (data.notice != null) report.notice = data.notice;
|
|
if (data.statement != null) report.statement = data.statement;
|
|
if (data.status != null) report.status = data.status;
|
|
if (data.strike_reason != null) {
|
|
if (data.status !== 'reviewed') {
|
|
if (data.strike_reason == -1) {
|
|
report.strike_reason_id = null;
|
|
} else {
|
|
const strike_reason = await StrikeReason.findByPk(data.strike_reason);
|
|
if (strike_reason == null) return new Response(null, { status: 400 });
|
|
report.strike_reason_id = strike_reason.id;
|
|
}
|
|
} else if (data.strike_reason == -1 && report.strike_reason_id != null) {
|
|
report.strike_reason_id = null;
|
|
report.striked_at = null;
|
|
} else if (data.strike_reason != -1 && data.strike_reason != report.strike_reason_id) {
|
|
if (!report.reported_id) return new Response(null, { status: 400 });
|
|
const strike_reason = await StrikeReason.findByPk(data.strike_reason);
|
|
if (strike_reason == null) return new Response(null, { status: 400 });
|
|
report.strike_reason_id = strike_reason.id;
|
|
report.striked_at = new Date(Date.now());
|
|
}
|
|
}
|
|
if (admin != null) report.auditor_id = admin.id;
|
|
|
|
await report.save();
|
|
|
|
if (webhookTriggerUsers.length > 0 && data.status == 'reviewed' && env.REPORTED_WEBHOOK) {
|
|
for (const webhookTriggerUser of webhookTriggerUsers) {
|
|
// no `await` to avoid blocking
|
|
webhookUserReported(env.REPORTED_WEBHOOK, webhookTriggerUser);
|
|
}
|
|
}
|
|
|
|
return new Response();
|
|
}) satisfies RequestHandler;
|
|
|
|
export const PUT = (async ({ request, cookies }) => {
|
|
if (getSession(cookies, { permissions: [Permissions.ReportWrite] }) == null) {
|
|
return new Response(null, {
|
|
status: 401
|
|
});
|
|
}
|
|
|
|
const data: {
|
|
reporter: string;
|
|
reported: string | null;
|
|
reason: string;
|
|
body: string | null;
|
|
} = await request.json();
|
|
|
|
if (data.reporter == null || data.reason == null || data.body === undefined)
|
|
return new Response(null, { status: 400 });
|
|
|
|
const reporter = await User.findOne({ where: { uuid: data.reporter } });
|
|
const reported = data.reported ? await User.findOne({ where: { uuid: data.reported } }) : null;
|
|
|
|
if (reporter == null) return new Response(null, { status: 400 });
|
|
|
|
const report = await Report.create({
|
|
subject: data.reason,
|
|
body: data.body,
|
|
draft: data.body === null,
|
|
status: 'none',
|
|
url_hash: crypto.randomBytes(18).toString('hex'),
|
|
completed: false,
|
|
reporter_id: reporter.id,
|
|
reported_id: reported?.id || null
|
|
});
|
|
report.dataValues.reporter = await User.findOne({ where: { id: report.reporter_id } });
|
|
report.dataValues.reported = report.reported_id
|
|
? await User.findOne({ where: { id: report.reported_id } })
|
|
: null;
|
|
report.dataValues.auditor = null;
|
|
|
|
return new Response(JSON.stringify(report), {
|
|
status: 201
|
|
});
|
|
}) satisfies RequestHandler;
|