Notes/src/routes/api/attachments.ts
Panagiotis Papadopoulos c8e36942fc chore(lint): get rid of "any" in attachments
req.file is of type "Express.Multer.File | undefined".
Returning with an "uploaded: false" type object -> same handling as in
image.ts
2025-03-06 23:09:24 +01:00

120 lines
3.5 KiB
TypeScript

import becca from "../../becca/becca.js";
import blobService from "../../services/blob.js";
import ValidationError from "../../errors/validation_error.js";
import imageService from "../../services/image.js";
import type { Request } from "express";
function getAttachmentBlob(req: Request) {
const preview = req.query.preview === "true";
return blobService.getBlobPojo("attachments", req.params.attachmentId, { preview });
}
function getAttachments(req: Request) {
const note = becca.getNoteOrThrow(req.params.noteId);
return note.getAttachments({ includeContentLength: true });
}
function getAttachment(req: Request) {
const { attachmentId } = req.params;
return becca.getAttachmentOrThrow(attachmentId, { includeContentLength: true });
}
function getAllAttachments(req: Request) {
const { attachmentId } = req.params;
// one particular attachment is requested, but return all note's attachments
const attachment = becca.getAttachmentOrThrow(attachmentId);
return attachment.getNote()?.getAttachments({ includeContentLength: true }) || [];
}
function saveAttachment(req: Request) {
const { noteId } = req.params;
const { attachmentId, role, mime, title, content } = req.body;
const matchByQuery = req.query.matchBy
const isValidMatchBy = (typeof matchByQuery === "string") && (matchByQuery === "attachmentId" || matchByQuery === "title");
const matchBy = isValidMatchBy ? matchByQuery : undefined;
const note = becca.getNoteOrThrow(noteId);
note.saveAttachment({ attachmentId, role, mime, title, content }, matchBy);
}
function uploadAttachment(req: Request) {
const { noteId } = req.params;
const { file } = req;
if (!file) {
return {
uploaded: false,
message: `Missing attachment data.`
};
}
const note = becca.getNoteOrThrow(noteId);
let url;
if (["image/png", "image/jpg", "image/jpeg", "image/gif", "image/webp", "image/svg+xml"].includes(file.mimetype)) {
const attachment = imageService.saveImageToAttachment(noteId, file.buffer, file.originalname, true, true);
url = `api/attachments/${attachment.attachmentId}/image/${encodeURIComponent(attachment.title)}`;
} else {
const attachment = note.saveAttachment({
role: "file",
mime: file.mimetype,
title: file.originalname,
content: file.buffer
});
url = `#root/${noteId}?viewMode=attachments&attachmentId=${attachment.attachmentId}`;
}
return {
uploaded: true,
url
};
}
function renameAttachment(req: Request) {
const { title } = req.body;
const { attachmentId } = req.params;
const attachment = becca.getAttachmentOrThrow(attachmentId);
if (!title?.trim()) {
throw new ValidationError("Title must not be empty");
}
attachment.title = title;
attachment.save();
}
function deleteAttachment(req: Request) {
const { attachmentId } = req.params;
const attachment = becca.getAttachment(attachmentId);
if (attachment) {
attachment.markAsDeleted();
}
}
function convertAttachmentToNote(req: Request) {
const { attachmentId } = req.params;
const attachment = becca.getAttachmentOrThrow(attachmentId);
return attachment.convertToNote();
}
export default {
getAttachmentBlob,
getAttachments,
getAttachment,
getAllAttachments,
saveAttachment,
uploadAttachment,
renameAttachment,
deleteAttachment,
convertAttachmentToNote
};