Implement cloning cloud attachments into messages
This commit is contained in:
parent
19ca94fc32
commit
c167a7b541
@ -189,4 +189,28 @@ router.delete("/:channel_id/:batch_id/:attachment_id/:filename", async (req: Req
|
|||||||
return res.status(404).send("Attachment not found");
|
return res.status(404).send("Attachment not found");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post("/:channel_id/:batch_id/:attachment_id/:filename/clone_to_message/:message_id", async (req: Request, res: Response) => {
|
||||||
|
if (req.headers.signature !== Config.get().security.requestSignature) throw new HTTPError("Invalid request signature");
|
||||||
|
|
||||||
|
const { channel_id, batch_id, attachment_id, filename } = req.params;
|
||||||
|
const path = `attachments/${channel_id}/${batch_id}/${attachment_id}/${filename}`;
|
||||||
|
const newPath = `attachments/${channel_id}/${filename}`;
|
||||||
|
|
||||||
|
const att = await CloudAttachment.findOne({
|
||||||
|
where: {
|
||||||
|
uploadFilename: `${channel_id}/${batch_id}/${attachment_id}/${filename}`,
|
||||||
|
channelId: channel_id,
|
||||||
|
userAttachmentId: attachment_id,
|
||||||
|
userFilename: filename,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (att) {
|
||||||
|
await storage.clone(path, newPath);
|
||||||
|
return res.send({ success: true, new_path: newPath });
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(404).send("Attachment not found");
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
Copyright (C) 2025 Spacebar and Spacebar Contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@ -51,6 +51,17 @@ export class FileStorage implements Storage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clone(path: string, newPath: string) {
|
||||||
|
path = getPath(path);
|
||||||
|
newPath = getPath(newPath);
|
||||||
|
|
||||||
|
if (!fs.existsSync(dirname(newPath)))
|
||||||
|
fs.mkdirSync(dirname(newPath), { recursive: true });
|
||||||
|
|
||||||
|
// use reflink if possible, in order to not duplicate files at the block layer...
|
||||||
|
fs.copyFileSync(path, newPath, fs.constants.COPYFILE_FICLONE)
|
||||||
|
}
|
||||||
|
|
||||||
async set(path: string, value: Buffer) {
|
async set(path: string, value: Buffer) {
|
||||||
path = getPath(path);
|
path = getPath(path);
|
||||||
if (!fs.existsSync(dirname(path)))
|
if (!fs.existsSync(dirname(path)))
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
Copyright (C) 2025 Spacebar and Spacebar Contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@ -50,6 +50,15 @@ export class S3Storage implements Storage {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clone(path: string, newPath: string): Promise<void> {
|
||||||
|
// TODO: does this even work?
|
||||||
|
await this.client.copyObject({
|
||||||
|
Bucket: this.bucket,
|
||||||
|
CopySource: `/${this.bucket}/${this.bucketBasePath}${path}`,
|
||||||
|
Key: `${this.bucketBasePath}${newPath}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async get(path: string): Promise<Buffer | null> {
|
async get(path: string): Promise<Buffer | null> {
|
||||||
try {
|
try {
|
||||||
const s3Object = await this.client.getObject({
|
const s3Object = await this.client.getObject({
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
Copyright (C) 2025 Spacebar and Spacebar Contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@ -25,6 +25,7 @@ process.cwd();
|
|||||||
|
|
||||||
export interface Storage {
|
export interface Storage {
|
||||||
set(path: string, data: Buffer): Promise<void>;
|
set(path: string, data: Buffer): Promise<void>;
|
||||||
|
clone(path: string, newPath: string): Promise<void>;
|
||||||
get(path: string): Promise<Buffer | null>;
|
get(path: string): Promise<Buffer | null>;
|
||||||
delete(path: string): Promise<void>;
|
delete(path: string): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user