mirror of
https://github.com/spacebarchat/server.git
synced 2026-08-28 09:34:07 +00:00
Maybe flags for attachments? i tried
This commit is contained in:
@@ -416,7 +416,7 @@ router.post(
|
||||
for (const currFile of files) {
|
||||
try {
|
||||
const file = await uploadFile(`/attachments/${channel.id}/${messageId}`, currFile);
|
||||
attachments.push(Attachment.create(file));
|
||||
attachments.push(file);
|
||||
} catch (error) {
|
||||
return res.status(400).json({ message: error?.toString() });
|
||||
}
|
||||
@@ -436,7 +436,7 @@ router.post(
|
||||
timestamp: new Date(),
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore dont care2
|
||||
// @ts-ignore dont care
|
||||
message.edited_timestamp = null;
|
||||
|
||||
if (channel.isDm()) {
|
||||
|
||||
@@ -128,7 +128,7 @@ router.post(
|
||||
for (const currFile of files) {
|
||||
try {
|
||||
const file = await uploadFile(`/attachments/${channel.id}/${thread.id}`, currFile);
|
||||
attachments.push(Attachment.create(file));
|
||||
attachments.push(file);
|
||||
} catch (error) {
|
||||
return res.status(400).json({ message: error?.toString() });
|
||||
}
|
||||
|
||||
@@ -47,23 +47,21 @@ import {
|
||||
} from "@spacebar/util";
|
||||
import {
|
||||
ActionRowComponent,
|
||||
AttachmentFlags,
|
||||
BaseMessageComponents,
|
||||
ButtonStyle,
|
||||
ChannelType,
|
||||
Embed,
|
||||
EmbedType,
|
||||
MessageComponentType,
|
||||
MessageCreateAttachment,
|
||||
MessageCreateCloudAttachment,
|
||||
MessageCreateSchema,
|
||||
MessageReferenceType,
|
||||
MessageType,
|
||||
Reaction,
|
||||
ReadStateType,
|
||||
UnfurledMediaItem,
|
||||
v1CompTypes,
|
||||
} from "@spacebar/schemas";
|
||||
import { addPendingPoll } from "../utility/polls";
|
||||
import { MessageOptionAttachment, MessageOptions } from "@spacebar/util/dtos/MessageOptions";
|
||||
|
||||
const allow_empty = false;
|
||||
// TODO: check webhook, application, system author, stickers
|
||||
@@ -597,24 +595,6 @@ export async function sendMessage(opts: MessageOptions) {
|
||||
return message;
|
||||
}
|
||||
|
||||
type MessageOptionAttachment = MessageCreateAttachment | MessageCreateCloudAttachment | Attachment;
|
||||
export interface MessageOptions extends MessageCreateSchema {
|
||||
id?: string;
|
||||
type?: MessageType;
|
||||
pinned?: boolean;
|
||||
author_id?: string;
|
||||
webhook_id?: string;
|
||||
application_id?: string;
|
||||
embeds?: Embed[] | null;
|
||||
reactions?: Reaction[];
|
||||
channel_id?: string;
|
||||
attachments?: (MessageCreateAttachment | MessageCreateCloudAttachment | Attachment)[]; // why are we masking this?
|
||||
edited_timestamp?: Date;
|
||||
timestamp?: Date;
|
||||
username?: string;
|
||||
avatar_url?: string;
|
||||
}
|
||||
|
||||
// Makes for concise code, inspired by Nix' lib.trace
|
||||
function logPassthru<T>(obj: T, ...data: unknown[]) {
|
||||
console.log(...data);
|
||||
@@ -626,8 +606,28 @@ export async function processMessageOptionAttachments(source: MessageOptions, de
|
||||
console.log("[Message] Processing attachments for message", source.id, "->", source.attachments);
|
||||
const tasks = source.attachments?.map(async (src): Promise<Attachment> => {
|
||||
if (src instanceof Attachment) return logPassthru(src, logp, `Got Attachment instance`);
|
||||
if (isCloudAttachment(src))
|
||||
return logPassthru(await convertCloudAttachmentToAttachment(src, destination.channel_id!, destination.id), logp, "Got MessageCreateCloudAttachment contents");
|
||||
if (isCloudAttachment(src)) {
|
||||
const result = logPassthru(await convertCloudAttachmentToAttachment(src, destination.channel_id!, destination.id), logp, "Got MessageCreateCloudAttachment contents");
|
||||
|
||||
result.flags = 0 as AttachmentFlags;
|
||||
result.flags &= (src.is_clip ? 1 : 0) * (AttachmentFlags.IS_CLIP as number);
|
||||
result.flags &= (src.is_remix ? 1 : 0) * (AttachmentFlags.IS_REMIX as number);
|
||||
result.flags &= (src.is_thumbnail ? 1 : 0) * (AttachmentFlags.IS_THUMBNAIL as number);
|
||||
result.flags &= (src.is_spoiler ? 1 : 0) * (AttachmentFlags.IS_SPOILER as number);
|
||||
return logPassthru(result, logp, "Got MessageCreateCloudAttachment contents");
|
||||
}
|
||||
if (isInternalCdnAttachment(src)) {
|
||||
const result = Attachment.create({
|
||||
...src,
|
||||
});
|
||||
|
||||
// result.flags = 0 as AttachmentFlags;
|
||||
// result.flags &= (src.is_clip ? 1 : 0) * (AttachmentFlags.IS_CLIP as number);
|
||||
// result.flags &= (src.is_remix ? 1 : 0) * (AttachmentFlags.IS_REMIX as number);
|
||||
// result.flags &= (src.is_thumbnail ? 1 : 0) * (AttachmentFlags.IS_THUMBNAIL as number);
|
||||
// result.flags &= (src.is_spoiler ? 1 : 0) * (AttachmentFlags.IS_SPOILER as number);
|
||||
return result;
|
||||
}
|
||||
throw new Error(logp + " Unhandled attachment: " + JSON.stringify(src));
|
||||
});
|
||||
|
||||
@@ -641,14 +641,18 @@ export function isCloudAttachment(attachment: MessageOptionAttachment) {
|
||||
return "uploaded_filename" in attachment;
|
||||
}
|
||||
|
||||
export async function convertCloudAttachmentToAttachment(cAtt: MessageCreateCloudAttachment, destinationChannelId: string, destinationMessageId: string) {
|
||||
const attEnt = await CloudAttachment.findOneOrFail({
|
||||
export function isInternalCdnAttachment(attachment: MessageOptionAttachment) {
|
||||
return "url" in attachment;
|
||||
}
|
||||
|
||||
export async function convertCloudAttachmentToAttachment(cloudAttachmentReference: MessageCreateCloudAttachment, destinationChannelId: string, destinationMessageId: string) {
|
||||
const cloudAttachment = await CloudAttachment.findOneOrFail({
|
||||
where: {
|
||||
uploadFilename: cAtt.uploaded_filename,
|
||||
uploadFilename: cloudAttachmentReference.uploaded_filename,
|
||||
},
|
||||
});
|
||||
|
||||
const cloneResponse = await fetch(`${Config.get().cdn.endpointPrivate}/attachments/${attEnt.uploadFilename}/clone_to_message/${destinationMessageId}`, {
|
||||
const cloneResponse = await fetch(`${Config.get().cdn.endpointPrivate}/attachments/${cloudAttachment.uploadFilename}/clone_to_message/${destinationMessageId}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
signature: Config.get().security.requestSignature || "",
|
||||
@@ -656,7 +660,7 @@ export async function convertCloudAttachmentToAttachment(cAtt: MessageCreateClou
|
||||
});
|
||||
|
||||
if (!cloneResponse.ok) {
|
||||
console.error(`[Message] Failed to clone attachment ${attEnt.userFilename} to message ${destinationMessageId}`);
|
||||
console.error(`[Message] Failed to clone attachment ${cloudAttachment.userFilename} to message ${destinationMessageId}`);
|
||||
throw new HTTPError("Failed to process attachment: " + (await cloneResponse.text()), 500);
|
||||
}
|
||||
|
||||
@@ -666,18 +670,19 @@ export async function convertCloudAttachmentToAttachment(cAtt: MessageCreateClou
|
||||
channel_id: destinationChannelId,
|
||||
message_id: destinationMessageId,
|
||||
|
||||
filename: attEnt.userFilename,
|
||||
size: attEnt.size,
|
||||
height: attEnt.height,
|
||||
width: attEnt.width,
|
||||
content_type: attEnt.contentType || attEnt.userOriginalContentType,
|
||||
filename: cloudAttachment.userFilename,
|
||||
size: cloudAttachment.size,
|
||||
height: cloudAttachment.height,
|
||||
width: cloudAttachment.width,
|
||||
content_type: cloudAttachment.contentType || cloudAttachment.userOriginalContentType,
|
||||
|
||||
title: cAtt.title,
|
||||
duration_secs: cAtt.duration_secs,
|
||||
clip_created_at: cAtt.clip_created_at,
|
||||
description: cAtt.description,
|
||||
waveform: cAtt.waveform,
|
||||
title: cloudAttachmentReference.title,
|
||||
duration_secs: cloudAttachmentReference.duration_secs,
|
||||
clip_created_at: cloudAttachmentReference.clip_created_at,
|
||||
description: cloudAttachmentReference.description,
|
||||
waveform: cloudAttachmentReference.waveform,
|
||||
});
|
||||
|
||||
console.log("[Message] Converted cloud attachment to", realAtt);
|
||||
return realAtt;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { sendMessage } from "@spacebar/api";
|
||||
import { EmbedType, MessageReferenceType, MessageType, PollAnswerCount } from "@spacebar/schemas";
|
||||
import { pendingPolls } from "@spacebar/util";
|
||||
import { MessageOptions, sendMessage } from "../handlers/Message";
|
||||
import { Message } from "@spacebar/database";
|
||||
import { MessageOptions } from "@spacebar/util/dtos/MessageOptions";
|
||||
|
||||
export async function generatePollResultsMessage(options: MessageOptions): Promise<MessageOptions> {
|
||||
// TODO: shouldnt this get saved?
|
||||
|
||||
@@ -23,6 +23,7 @@ import { HTTPError } from "lambert-server/HTTPError";
|
||||
import { CloudAttachment } from "@spacebar/database";
|
||||
import { Config, hasValidSignature, NewUrlUserSignatureData, Snowflake, UrlSignResult } from "@spacebar/util";
|
||||
import { storage, multer, cache } from "../util";
|
||||
import { InternalCdnAttachment } from "@spacebar/util/dtos/MessageOptions";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
@@ -45,16 +46,20 @@ router.post("/:channel_id/:message_id", multer.single("file"), async (req: Reque
|
||||
let width;
|
||||
let height;
|
||||
if (mimetype.includes("image")) {
|
||||
const dimensions = imageSize(buffer);
|
||||
if (dimensions) {
|
||||
width = dimensions.width;
|
||||
height = dimensions.height;
|
||||
try {
|
||||
const dimensions = imageSize(buffer);
|
||||
if (dimensions) {
|
||||
width = dimensions.width;
|
||||
height = dimensions.height;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to get image size for attachment of type", mimetype, "because of", e);
|
||||
}
|
||||
}
|
||||
|
||||
const finalUrl = `${endpoint}/${path}`;
|
||||
|
||||
const file = {
|
||||
const file: InternalCdnAttachment = {
|
||||
id: Snowflake.generate(),
|
||||
channel_id,
|
||||
message_id,
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2026 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Embed, MessageCreateAttachment, MessageCreateCloudAttachment, MessageCreateSchema, MessageType, Reaction } from "@spacebar/schemas";
|
||||
|
||||
export type MessageOptionAttachment = MessageCreateAttachment | MessageCreateCloudAttachment | InternalCdnAttachment;
|
||||
|
||||
export interface MessageOptions extends MessageCreateSchema {
|
||||
id?: string;
|
||||
type?: MessageType;
|
||||
pinned?: boolean;
|
||||
author_id?: string;
|
||||
webhook_id?: string;
|
||||
application_id?: string;
|
||||
embeds?: Embed[] | null;
|
||||
reactions?: Reaction[];
|
||||
channel_id?: string;
|
||||
attachments?: MessageOptionAttachment[];
|
||||
edited_timestamp?: Date;
|
||||
timestamp?: Date;
|
||||
username?: string;
|
||||
avatar_url?: string;
|
||||
}
|
||||
|
||||
export interface InternalCdnAttachment {
|
||||
id: string;
|
||||
channel_id: string;
|
||||
message_id: string;
|
||||
content_type: string;
|
||||
filename: string;
|
||||
size: number;
|
||||
url: string;
|
||||
path: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
import FormData from "form-data";
|
||||
import { HTTPError } from "lambert-server/HTTPError";
|
||||
import { Attachment } from "../../database/entities";
|
||||
import { InternalCdnAttachment } from "@spacebar/util/dtos/MessageOptions";
|
||||
import { Config } from "./Config";
|
||||
|
||||
export async function uploadFile(
|
||||
path: string,
|
||||
// These are the only props we use, don't need to enforce the full type.
|
||||
file?: Pick<Express.Multer.File, "mimetype" | "originalname" | "buffer">,
|
||||
): Promise<Attachment> {
|
||||
): Promise<InternalCdnAttachment> {
|
||||
if (!file?.buffer) throw new HTTPError("Missing file in body");
|
||||
|
||||
const form = new FormData();
|
||||
@@ -42,7 +42,7 @@ export async function uploadFile(
|
||||
method: "POST",
|
||||
body: form.getBuffer(),
|
||||
});
|
||||
const result = (await response.json()) as Attachment;
|
||||
const result = (await response.json()) as InternalCdnAttachment;
|
||||
|
||||
if (response.status !== 200) throw result;
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user