From 8ea6c406e0305d2ea43a3d4f20f0e2c7e7f772d0 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Thu, 16 Oct 2025 20:59:46 +0200 Subject: [PATCH] Add webhook to report to discord --- backend/api/src/report.ts | 46 +++++++++++++++++++++++--- common/src/discord/core.ts | 3 ++ common/src/secrets.ts | 1 + web/components/profile/report-user.tsx | 3 +- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/backend/api/src/report.ts b/backend/api/src/report.ts index 1dfdc35e..6f699713 100644 --- a/backend/api/src/report.ts +++ b/backend/api/src/report.ts @@ -1,7 +1,10 @@ -import { APIError, APIHandler } from './helpers/endpoint' -import { createSupabaseDirectClient } from 'shared/supabase/init' -import { tryCatch } from 'common/util/try-catch' -import { insert } from 'shared/supabase/utils' +import {APIError, APIHandler} from './helpers/endpoint' +import {createSupabaseDirectClient} from 'shared/supabase/init' +import {tryCatch} from 'common/util/try-catch' +import {insert} from 'shared/supabase/utils' +import {sendDiscordMessage} from "common/discord/core"; +import {Row} from "common/supabase/utils"; +import {DOMAIN} from "common/envs/constants"; // abusable: people can report the wrong person, that didn't write the comment // but in practice we check it manually and nothing bad happens to them automatically @@ -33,5 +36,38 @@ export const report: APIHandler<'report'> = async (body, auth) => { throw new APIError(500, 'Failed to create report: ' + result.error.message) } - return { success: true } + const continuation = async () => { + try { + const {data: reporter, error} = await tryCatch( + pg.oneOrNone>('select * from users where id = $1', [auth.uid]) + ) + if (error) { + console.error('Failed to get user for report', error) + return + } + const {data: reported, error: userError} = await tryCatch( + pg.oneOrNone>('select * from users where id = $1', [contentOwnerId]) + ) + if (userError) { + console.error('Failed to get reported user for report', userError) + return + } + let message: string = ` + 🚨 **New Report** 🚨 + **Type:** ${contentType} + **Content ID:** ${contentId} + **Reporter:** ${reporter?.name} ([@${reporter?.username}](https://www.${DOMAIN}/${reporter?.username})) + **Reported:** ${reported?.name} ([@${reported?.username}](https://www.${DOMAIN}/${reported?.username})) + ` + await sendDiscordMessage(message, 'reports') + } catch (e) { + console.error('Failed to send discord reports', e) + } + } + + return { + success: true, + result: {}, + continue: continuation, + } } diff --git a/common/src/discord/core.ts b/common/src/discord/core.ts index 80315bd0..7bd13de8 100644 --- a/common/src/discord/core.ts +++ b/common/src/discord/core.ts @@ -5,10 +5,13 @@ export const sendDiscordMessage = async (content: string, channel: string) => { members: process.env.DISCORD_WEBHOOK_MEMBERS, general: process.env.DISCORD_WEBHOOK_GENERAL, health: process.env.DISCORD_WEBHOOK_HEALTH, + reports: process.env.DISCORD_WEBHOOK_REPORTS, }[channel] if (IS_DEV) webhookUrl = process.env.DISCORD_WEBHOOK_DEV + // console.log(`Discord webhook URL: ${webhookUrl}`, channel, content) + if (!webhookUrl) return const response = await fetch(webhookUrl!, { diff --git a/common/src/secrets.ts b/common/src/secrets.ts index 763645bd..782ca0f9 100644 --- a/common/src/secrets.ts +++ b/common/src/secrets.ts @@ -21,6 +21,7 @@ export const secrets = ( 'DISCORD_WEBHOOK_MEMBERS', 'DISCORD_WEBHOOK_GENERAL', 'DISCORD_WEBHOOK_HEALTH', + 'DISCORD_WEBHOOK_REPORTS', // Some typescript voodoo to keep the string literal types while being not readonly. ] as const ).concat() diff --git a/web/components/profile/report-user.tsx b/web/components/profile/report-user.tsx index 2f2236b1..5c70ffc7 100644 --- a/web/components/profile/report-user.tsx +++ b/web/components/profile/report-user.tsx @@ -7,6 +7,7 @@ import { Button } from 'web/components/buttons/button' import Textarea from 'react-expanding-textarea' import { toast } from 'react-hot-toast' import { api } from 'web/lib/api' +import {randomString} from "common/util/random"; export const ReportUser = (props: { user: User; closeModal: () => void }) => { const { user, closeModal } = props @@ -31,7 +32,7 @@ export const ReportUser = (props: { user: User; closeModal: () => void }) => { .promise( api('report', { contentType: 'user', - contentId: user.id, + contentId: randomString(16), contentOwnerId: user.id, description: 'Reasons: ' + [...selectedReportTypes, otherReportType].join(', '),