summary refs log tree commit diff
path: root/src/api/util
diff options
context:
space:
mode:
authorMathMan05 <mathmanrm@gmail.com>2026-03-01 23:01:58 -0600
committerRory& <root@rory.gay>2026-03-20 16:31:32 +0100
commit9ba95abb02d29393ebf586751b15ec42ed708ef9 (patch)
tree84be6b6c0e0fb8aa24aae39fa2aa7c183487fe3c /src/api/util
parenta lot of small fixes (diff)
downloadserver-ts-9ba95abb02d29393ebf586751b15ec42ed708ef9.tar.xz
fixes for pluralkit
Diffstat (limited to 'src/api/util')
-rw-r--r--src/api/util/handlers/Message.ts31
-rw-r--r--src/api/util/handlers/route.ts34
2 files changed, 49 insertions, 16 deletions
diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts

index 2c927403..be40f754 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts
@@ -67,6 +67,7 @@ import { Reaction, ReadStateType, UnfurledMediaItem, + BaseMessageComponents, } from "@spacebar/schemas"; const allow_empty = false; // TODO: check webhook, application, system author, stickers @@ -201,20 +202,19 @@ async function processMedia(media: UnfurledMediaItem, messageId: string, batchId }); } } - -export async function handleMessage(opts: MessageOptions): Promise<Message> { +export function handleComps(components: BaseMessageComponents[], flags: number) { const errors: Record<string, { code?: string; message: string }> = {}; const knownComponentIds: string[] = []; - const compv2 = (opts.flags || 0) & Number(MessageFlags.FLAGS.IS_COMPONENTS_V2); + const compv2 = (flags || 0) & Number(MessageFlags.FLAGS.IS_COMPONENTS_V2); const medias: UnfurledMediaItem[] = []; - for (const comp of opts.components || []) { + for (const comp of components || []) { if (comp.type === MessageComponentType.ActionRow) { - checkActionRow(comp, knownComponentIds, errors, opts.components!.indexOf(comp)); + checkActionRow(comp, knownComponentIds, errors, components!.indexOf(comp)); } else if (comp.type === MessageComponentType.Section) { if (!compv2) throw new HTTPError("Must be comp v2"); const accessory = comp.accessory; if (comp.components.length < 1 || comp.components.length > 3) { - errors[`data.components[${opts.components!.indexOf(comp)}].components`] = { + errors[`data.components[${components!.indexOf(comp)}].components`] = { code: "TOO_LONG", message: "Component list is too long", }; @@ -227,7 +227,7 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { } else if (comp.type === MessageComponentType.MediaGallery) { if (!compv2) throw new HTTPError("Must be comp v2"); if (comp.items.length < 1 || comp.items.length > 10) { - errors[`data.components[${opts.components!.indexOf(comp)}].items`] = { + errors[`data.components[${components!.indexOf(comp)}].items`] = { code: "TOO_LONG", message: "Media list is too long", }; @@ -248,7 +248,7 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { case MessageComponentType.Section: { const accessory = elm.accessory; if (elm.components.length < 1 || elm.components.length > 3) { - errors[`data.components[${opts.components!.indexOf(comp)}].components[${comp.components!.indexOf(elm)}].components`] = { + errors[`data.components[${components!.indexOf(comp)}].components[${comp.components!.indexOf(elm)}].components`] = { code: "TOO_LONG", message: "Component list is too long", }; @@ -260,7 +260,7 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { } case MessageComponentType.MediaGallery: if (elm.items.length < 1 || elm.items.length > 10) { - errors[`data.components[${opts.components!.indexOf(comp)}].components[${comp.components!.indexOf(elm)}].items`] = { + errors[`data.components[${components!.indexOf(comp)}].components[${comp.components!.indexOf(elm)}].items`] = { code: "TOO_LONG", message: "Media list is too long", }; @@ -272,7 +272,7 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { break; } case MessageComponentType.ActionRow: - checkActionRow(elm, knownComponentIds, errors, opts.components!.indexOf(elm)); + checkActionRow(elm, knownComponentIds, errors, components!.indexOf(elm)); break; default: elm satisfies never; @@ -286,6 +286,13 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { if (Object.keys(errors).length > 0) { throw FieldErrors(errors); } + return async (messageId: string, user: User, channel: Channel) => { + const batchId = `CLOUD_compUploads_${randomString(128)}`; + (await Promise.all(medias.map((m, index) => processMedia(m, messageId, batchId, user, channel, index + "")))).forEach((_) => _?.()); + }; +} +export async function handleMessage(opts: MessageOptions): Promise<Message> { + const handle = opts.components ? handleComps(opts.components, opts.flags || 0) : undefined; const channel = await Channel.findOneOrFail({ where: { id: opts.channel_id }, @@ -335,7 +342,6 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { components: opts.components ?? undefined, // Fix Discord-Go? }); message.channel = channel; - const batchId = `CLOUD_${message.author_id}_${randomString(128)}`; if (opts.author_id) { message.author = await User.findOneOrFail({ @@ -345,8 +351,6 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { rights.hasThrow("SEND_MESSAGES"); } - (await Promise.all(medias.map((m, index) => processMedia(m, message.id, batchId, message.author as User, channel, index + "")))).forEach((_) => _?.()); - const ephermal = (message.flags & (1 << 6)) !== 0; if (!ephermal && channel.type === ChannelType.GUILD_PUBLIC_THREAD) { const rep = Channel.getRepository(); @@ -360,6 +364,7 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { if (cloudAttachments && cloudAttachments.length > 0) { console.log("[Message] Processing attachments for message", message.id, ":", message.attachments); + handle?.(message.id, message.author as User, message.channel); const uploadedAttachments = await Promise.all( cloudAttachments.map(async (att) => { const cAtt = att.attachment; diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts
index 455ce21b..17501524 100644 --- a/src/api/util/handlers/route.ts +++ b/src/api/util/handlers/route.ts
@@ -41,7 +41,7 @@ export type RouteResponse = { body?: `${string}Response`; headers?: Record<string, string>; }; - +export type stripNulls = { [key: string]: true | stripNulls }; export interface RouteOptions { permission?: PermissionResolvable; right?: RightResolvable; @@ -52,6 +52,7 @@ export interface RouteOptions { body?: string; }; }; + stripNulls?: stripNulls; event?: EVENT | EVENT[]; summary?: string; description?: string; @@ -73,7 +74,31 @@ export interface RouteOptions { // headers?: Record<string, string>; // }; } - +export function stripNull(obj: object) { + console.log(Object.entries(obj)); + for (const [key, value] of Object.entries(obj)) { + if (value instanceof Object || (value && !value.__proto__)) { + stripNull(value); + } else if (value === null) { + //@ts-expect-error this is fine + delete obj[key]; + } + } +} +// eslint-disable-next-line +export function followNullPath(obj1: any, nullObj: stripNulls) { + for (const [key, value] of Object.entries(nullObj)) { + if (key in obj1) + if (value instanceof Object) { + if (obj1[key] instanceof Object) + //@ts-expect-error this works lol + followNullPath(obj1[key], nullObj[key]); + else delete obj1[key]; + } else if (obj1[key] instanceof Object) { + stripNull(obj1[key]); + } + } +} export function route(opts: RouteOptions) { let validate: AnyValidateFunction | undefined; if (opts.requestBody) { @@ -111,9 +136,12 @@ export function route(opts: RouteOptions) { } if (validate && !ignoredRequestSchemas.includes(opts.requestBody!)) { + if (opts.stripNulls) { + followNullPath(req.body, opts.stripNulls); + } const valid = validate(req.body); if (!valid) { - console.log(req.body); + console.log(JSON.stringify(req.body)); const fields: Record<string, { code?: string; message: string }> = {}; validate.errors?.forEach( (x) =>