mirror of
https://github.com/spacebarchat/server.git
synced 2026-08-28 07:24:08 +00:00
maybe processing media?
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { EmbedHandlers } from "@spacebar/api";
|
||||
import { EmbedHandlers, randomString } from "@spacebar/api";
|
||||
import {
|
||||
Application,
|
||||
Attachment,
|
||||
@@ -104,12 +104,86 @@ function checkActionRow(row: ActionRowComponent, knownComponentIds: string[], er
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function processMedia(media: UnfurledMediaItem) {
|
||||
async function processMedia(media: UnfurledMediaItem, messageId: string, batchId: string, user: User, channel: Channel, id: string) {
|
||||
if (Object.keys(media).length > 1) throw new HTTPError("no, you can't send those");
|
||||
if (!URL.canParse(media.url)) throw new HTTPError("media URL must be a URI");
|
||||
const url = new URL(media.url);
|
||||
if (!["http", "https", "attachment"].includes(url.protocol)) throw new HTTPError("invalid media protocol");
|
||||
let attEnt: CloudAttachment;
|
||||
let delWhenDone = false;
|
||||
if (url.protocol !== "attachment") {
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new HTTPError("URL did not return OK");
|
||||
const blob = await res.blob();
|
||||
const name = url.pathname.split("/").findLast((_) => _) || id;
|
||||
const uploadFilename = `${channel.id}/${batchId}/${id ?? "0"}/${name}`;
|
||||
attEnt = CloudAttachment.create({
|
||||
user: user,
|
||||
channel: channel,
|
||||
uploadFilename: uploadFilename,
|
||||
userAttachmentId: "0",
|
||||
userFilename: name,
|
||||
userFileSize: blob.size,
|
||||
userIsClip: false,
|
||||
});
|
||||
await attEnt.save();
|
||||
const cdnUrl = Config.get().cdn.endpointPublic;
|
||||
const fetchUrl = `${cdnUrl}/attachments/${attEnt.uploadFilename}`;
|
||||
await (
|
||||
await fetch(fetchUrl, {
|
||||
method: "PUT",
|
||||
body: blob,
|
||||
})
|
||||
).text();
|
||||
// re-fetch due to changed DB entry
|
||||
attEnt = await CloudAttachment.findOneOrFail({
|
||||
where: {
|
||||
id: attEnt.id,
|
||||
},
|
||||
});
|
||||
delWhenDone = true;
|
||||
} else {
|
||||
attEnt = await CloudAttachment.findOneOrFail({
|
||||
where: {
|
||||
uploadFilename: url.hostname,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const cloneResponse = await fetch(`${Config.get().cdn.endpointPrivate}/attachments/${attEnt.uploadFilename}/clone_to_message/${messageId}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
signature: Config.get().security.requestSignature || "",
|
||||
},
|
||||
});
|
||||
|
||||
if (!cloneResponse.ok) {
|
||||
console.error(`[Message] Failed to clone attachment ${attEnt.userFilename} to message ${messageId}`);
|
||||
throw new HTTPError("Failed to process attachment: " + (await cloneResponse.text()), 500);
|
||||
}
|
||||
|
||||
const cloneRespBody = (await cloneResponse.json()) as { success: boolean; new_path: string };
|
||||
//TODO maybe this needs to be a new DB object? I don't see a reason to do this rn though, though this id *should* technically be different from the id of the attachment
|
||||
media.id = attEnt.id;
|
||||
media.proxy_url = `${Config.get().cdn.endpointPublic}/${cloneRespBody.new_path}`;
|
||||
if (url.protocol !== "attachment") media.url = media.proxy_url;
|
||||
media.height = attEnt.height;
|
||||
media.width = attEnt.width;
|
||||
media.content_type = attEnt.contentType;
|
||||
//TODO flags?
|
||||
media.attachment_id = attEnt.id;
|
||||
//TODO preview stuff
|
||||
|
||||
if (delWhenDone) {
|
||||
fetch(`${Config.get().cdn.endpointPrivate}/attachments/${attEnt.uploadFilename}`, {
|
||||
headers: {
|
||||
signature: Config.get().security.requestSignature,
|
||||
},
|
||||
method: "DELETE",
|
||||
}).then(() => {
|
||||
attEnt.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleMessage(opts: MessageOptions): Promise<Message> {
|
||||
@@ -197,8 +271,6 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
|
||||
throw FieldErrors(errors);
|
||||
}
|
||||
|
||||
await Promise.all(medias.map(processMedia));
|
||||
|
||||
const channel = await Channel.findOneOrFail({
|
||||
where: { id: opts.channel_id },
|
||||
relations: { recipients: true },
|
||||
@@ -246,6 +318,18 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
|
||||
components: opts.components ?? undefined, // Fix Discord-Go?
|
||||
message_reference: opts.message_reference ?? undefined,
|
||||
});
|
||||
const batchId = `CLOUD_${message.author_id}_${randomString(128)}`;
|
||||
|
||||
if (opts.author_id) {
|
||||
message.author = await User.findOneOrFail({
|
||||
where: { id: opts.author_id },
|
||||
});
|
||||
const rights = await getRights(opts.author_id);
|
||||
rights.hasThrow("SEND_MESSAGES");
|
||||
}
|
||||
|
||||
await Promise.all(medias.map((m, index) => processMedia(m, message.id, batchId, message.author as User, channel, index + "")));
|
||||
|
||||
const ephermal = (message.flags & (1 << 6)) !== 0;
|
||||
if (!ephermal && channel.type === ChannelType.GUILD_PUBLIC_THREAD) {
|
||||
const rep = Channel.getRepository();
|
||||
@@ -308,14 +392,6 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
|
||||
throw new HTTPError("Content length over max character limit");
|
||||
}
|
||||
|
||||
if (opts.author_id) {
|
||||
message.author = await User.findOneOrFail({
|
||||
where: { id: opts.author_id },
|
||||
});
|
||||
message.author.clean_data();
|
||||
const rights = await getRights(opts.author_id);
|
||||
rights.hasThrow("SEND_MESSAGES");
|
||||
}
|
||||
if (opts.application_id) {
|
||||
message.application = await Application.findOneOrFail({
|
||||
where: { id: opts.application_id },
|
||||
|
||||
Reference in New Issue
Block a user