2018-02-14 23:31:20 -05:00
|
|
|
"use strict";
|
|
|
|
|
2018-04-01 21:27:46 -04:00
|
|
|
const protectedSessionService = require('../../services/protected_session');
|
2019-01-13 10:22:17 +01:00
|
|
|
const utils = require('../../services/utils');
|
2021-04-24 21:56:44 +02:00
|
|
|
const log = require('../../services/log');
|
2023-01-26 20:32:27 +01:00
|
|
|
const noteService = require('../../services/notes');
|
2020-10-13 22:50:45 +02:00
|
|
|
const tmp = require('tmp');
|
|
|
|
const fs = require('fs');
|
2021-04-17 22:35:47 +02:00
|
|
|
const { Readable } = require('stream');
|
2021-04-24 11:39:59 +02:00
|
|
|
const chokidar = require('chokidar');
|
|
|
|
const ws = require('../../services/ws');
|
2021-06-29 22:15:57 +02:00
|
|
|
const becca = require("../../becca/becca");
|
2023-06-14 22:21:22 +02:00
|
|
|
const ValidationError = require("../../errors/validation_error");
|
2018-02-14 23:31:20 -05:00
|
|
|
|
2020-06-20 12:31:38 +02:00
|
|
|
function updateFile(req) {
|
2023-05-08 00:02:08 +02:00
|
|
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
2018-02-14 23:31:20 -05:00
|
|
|
|
2023-05-03 22:49:24 +02:00
|
|
|
const file = req.file;
|
2023-06-04 23:01:40 +02:00
|
|
|
note.saveRevision();
|
2019-11-09 11:58:52 +01:00
|
|
|
|
|
|
|
note.mime = file.mimetype.toLowerCase();
|
2020-08-18 22:20:47 +02:00
|
|
|
note.save();
|
2019-11-09 11:58:52 +01:00
|
|
|
|
2020-06-20 12:31:38 +02:00
|
|
|
note.setContent(file.buffer);
|
2019-11-09 11:58:52 +01:00
|
|
|
|
2020-06-20 12:31:38 +02:00
|
|
|
note.setLabel('originalFileName', file.originalname);
|
2019-11-09 11:58:52 +01:00
|
|
|
|
2023-01-26 20:32:27 +01:00
|
|
|
noteService.asyncPostProcessContent(note, file.buffer);
|
2023-01-22 23:36:05 +01:00
|
|
|
|
2018-03-30 17:29:13 -04:00
|
|
|
return {
|
2019-11-09 11:58:52 +01:00
|
|
|
uploaded: true
|
2018-03-30 17:29:13 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-05-03 22:49:24 +02:00
|
|
|
function updateAttachment(req) {
|
2023-05-08 00:02:08 +02:00
|
|
|
const attachment = becca.getAttachmentOrThrow(req.params.attachmentId);
|
2023-05-03 22:49:24 +02:00
|
|
|
const file = req.file;
|
2023-06-14 00:28:59 +02:00
|
|
|
|
2023-06-04 23:01:40 +02:00
|
|
|
attachment.getNote().saveRevision();
|
2023-05-03 22:49:24 +02:00
|
|
|
|
|
|
|
attachment.mime = file.mimetype.toLowerCase();
|
|
|
|
attachment.setContent(file.buffer, {forceSave: true});
|
|
|
|
|
|
|
|
return {
|
|
|
|
uploaded: true
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
/**
|
|
|
|
* @param {BNote|BAttachment} noteOrAttachment
|
|
|
|
* @param res
|
|
|
|
* @param {boolean} contentDisposition
|
|
|
|
*/
|
|
|
|
function downloadData(noteOrAttachment, res, contentDisposition) {
|
|
|
|
if (noteOrAttachment.isProtected && !protectedSessionService.isProtectedSessionAvailable()) {
|
|
|
|
return res.status(401).send("Protected session not available");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contentDisposition) {
|
|
|
|
const fileName = noteOrAttachment.getFileName();
|
|
|
|
|
|
|
|
res.setHeader('Content-Disposition', utils.getContentDisposition(fileName));
|
|
|
|
}
|
|
|
|
|
|
|
|
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
|
|
res.setHeader('Content-Type', noteOrAttachment.mime);
|
|
|
|
|
|
|
|
res.send(noteOrAttachment.getContent());
|
2020-10-13 22:50:45 +02:00
|
|
|
}
|
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
function downloadNoteInt(noteId, res, contentDisposition = true) {
|
2021-05-02 11:23:58 +02:00
|
|
|
const note = becca.getNote(noteId);
|
2018-02-18 21:28:24 -05:00
|
|
|
|
|
|
|
if (!note) {
|
2022-07-01 00:01:29 +02:00
|
|
|
return res.setHeader("Content-Type", "text/plain")
|
|
|
|
.status(404)
|
2023-05-03 10:23:20 +02:00
|
|
|
.send(`Note '${noteId}' doesn't exist.`);
|
2018-02-23 22:58:24 -05:00
|
|
|
}
|
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
return downloadData(note, res, contentDisposition);
|
|
|
|
}
|
2018-02-18 21:28:24 -05:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
function downloadAttachmentInt(attachmentId, res, contentDisposition = true) {
|
|
|
|
const attachment = becca.getAttachment(attachmentId);
|
2020-05-12 10:28:31 +02:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
if (!attachment) {
|
|
|
|
return res.setHeader("Content-Type", "text/plain")
|
|
|
|
.status(404)
|
|
|
|
.send(`Attachment '${attachmentId}' doesn't exist.`);
|
2020-03-08 18:06:24 +01:00
|
|
|
}
|
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
return downloadData(attachment, res, contentDisposition);
|
2018-03-30 17:29:13 -04:00
|
|
|
}
|
2018-02-18 21:28:24 -05:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
const downloadFile = (req, res) => downloadNoteInt(req.params.noteId, res, true);
|
|
|
|
const openFile = (req, res) => downloadNoteInt(req.params.noteId, res, false);
|
2019-01-27 15:47:40 +01:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
const downloadAttachment = (req, res) => downloadAttachmentInt(req.params.attachmentId, res, true);
|
|
|
|
const openAttachment = (req, res) => downloadAttachmentInt(req.params.attachmentId, res, false);
|
2020-03-08 18:06:24 +01:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
function fileContentProvider(req) {
|
2023-05-05 23:41:11 +02:00
|
|
|
// Read the file name from route params.
|
2023-05-08 00:02:08 +02:00
|
|
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
2019-01-27 15:47:40 +01:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
return streamContent(note.getContent(), note.getFileName(), note.mime);
|
2019-01-27 15:47:40 +01:00
|
|
|
}
|
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
function attachmentContentProvider(req) {
|
2023-05-05 23:41:11 +02:00
|
|
|
// Read the file name from route params.
|
2023-05-08 00:02:08 +02:00
|
|
|
const attachment = becca.getAttachmentOrThrow(req.params.attachmentId);
|
2023-05-03 10:23:20 +02:00
|
|
|
|
|
|
|
return streamContent(attachment.getContent(), attachment.getFileName(), attachment.mime);
|
|
|
|
}
|
2021-04-17 22:35:47 +02:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
function streamContent(content, fileName, mimeType) {
|
2021-04-17 22:35:47 +02:00
|
|
|
if (typeof content === "string") {
|
2023-05-03 10:23:20 +02:00
|
|
|
content = Buffer.from(content, 'utf8');
|
2021-04-17 22:35:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const totalSize = content.byteLength;
|
|
|
|
|
|
|
|
const getStream = range => {
|
|
|
|
if (!range) {
|
|
|
|
// Request if for complete content.
|
|
|
|
return Readable.from(content);
|
|
|
|
}
|
|
|
|
// Partial content request.
|
2023-05-03 10:23:20 +02:00
|
|
|
const {start, end} = range;
|
2021-04-17 22:35:47 +02:00
|
|
|
|
|
|
|
return Readable.from(content.slice(start, end + 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
fileName,
|
|
|
|
totalSize,
|
|
|
|
mimeType,
|
|
|
|
getStream
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
function saveNoteToTmpDir(req) {
|
2023-05-08 00:02:08 +02:00
|
|
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
2023-05-03 10:23:20 +02:00
|
|
|
const fileName = note.getFileName();
|
|
|
|
const content = note.getContent();
|
2020-10-13 22:50:45 +02:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
return saveToTmpDir(fileName, content, 'notes', note.noteId);
|
|
|
|
}
|
|
|
|
|
|
|
|
function saveAttachmentToTmpDir(req) {
|
2023-05-08 00:02:08 +02:00
|
|
|
const attachment = becca.getAttachmentOrThrow(req.params.attachmentId);
|
2023-05-03 10:23:20 +02:00
|
|
|
const fileName = attachment.getFileName();
|
|
|
|
const content = attachment.getContent();
|
2020-10-13 22:50:45 +02:00
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
return saveToTmpDir(fileName, content, 'attachments', attachment.attachmentId);
|
|
|
|
}
|
|
|
|
|
|
|
|
function saveToTmpDir(fileName, content, entityType, entityId) {
|
|
|
|
const tmpObj = tmp.fileSync({ postfix: fileName });
|
|
|
|
|
|
|
|
fs.writeSync(tmpObj.fd, content);
|
2020-10-13 22:50:45 +02:00
|
|
|
fs.closeSync(tmpObj.fd);
|
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
log.info(`Saved temporary file ${tmpObj.name}`);
|
2021-04-24 21:56:44 +02:00
|
|
|
|
2021-04-24 11:39:59 +02:00
|
|
|
if (utils.isElectron()) {
|
|
|
|
chokidar.watch(tmpObj.name).on('change', (path, stats) => {
|
|
|
|
ws.sendMessageToAllClients({
|
|
|
|
type: 'openedFileUpdated',
|
2023-05-03 10:23:20 +02:00
|
|
|
entityType: entityType,
|
|
|
|
entityId: entityId,
|
2021-04-24 11:39:59 +02:00
|
|
|
lastModifiedMs: stats.atimeMs,
|
|
|
|
filePath: tmpObj.name
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-10-13 22:50:45 +02:00
|
|
|
return {
|
|
|
|
tmpFilePath: tmpObj.name
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-05-03 10:23:20 +02:00
|
|
|
function uploadModifiedFileToNote(req) {
|
|
|
|
const noteId = req.params.noteId;
|
|
|
|
const {filePath} = req.body;
|
|
|
|
|
2023-05-08 00:02:08 +02:00
|
|
|
const note = becca.getNoteOrThrow(noteId);
|
2023-05-03 10:23:20 +02:00
|
|
|
|
|
|
|
log.info(`Updating note '${noteId}' with content from '${filePath}'`);
|
|
|
|
|
2023-06-04 23:01:40 +02:00
|
|
|
note.saveRevision();
|
2023-05-03 10:23:20 +02:00
|
|
|
|
|
|
|
const fileContent = fs.readFileSync(filePath);
|
|
|
|
|
|
|
|
if (!fileContent) {
|
|
|
|
throw new ValidationError(`File '${fileContent}' is empty`);
|
|
|
|
}
|
|
|
|
|
|
|
|
note.setContent(fileContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
function uploadModifiedFileToAttachment(req) {
|
|
|
|
const {attachmentId} = req.params;
|
|
|
|
const {filePath} = req.body;
|
|
|
|
|
2023-05-08 00:02:08 +02:00
|
|
|
const attachment = becca.getAttachmentOrThrow(attachmentId);
|
2023-05-03 10:23:20 +02:00
|
|
|
|
|
|
|
log.info(`Updating attachment '${attachmentId}' with content from '${filePath}'`);
|
|
|
|
|
2023-06-04 23:01:40 +02:00
|
|
|
attachment.getNote().saveRevision();
|
2023-05-03 10:23:20 +02:00
|
|
|
|
|
|
|
const fileContent = fs.readFileSync(filePath);
|
|
|
|
|
|
|
|
if (!fileContent) {
|
|
|
|
throw new ValidationError(`File '${fileContent}' is empty`);
|
|
|
|
}
|
|
|
|
|
|
|
|
attachment.setContent(fileContent);
|
|
|
|
}
|
|
|
|
|
2018-03-30 17:29:13 -04:00
|
|
|
module.exports = {
|
2019-11-09 11:58:52 +01:00
|
|
|
updateFile,
|
2023-05-03 22:49:24 +02:00
|
|
|
updateAttachment,
|
2020-03-08 18:06:24 +01:00
|
|
|
openFile,
|
2021-04-17 22:35:47 +02:00
|
|
|
fileContentProvider,
|
2019-01-27 15:47:40 +01:00
|
|
|
downloadFile,
|
2023-05-03 10:23:20 +02:00
|
|
|
downloadNoteInt,
|
|
|
|
saveNoteToTmpDir,
|
|
|
|
openAttachment,
|
|
|
|
downloadAttachment,
|
|
|
|
saveAttachmentToTmpDir,
|
|
|
|
attachmentContentProvider,
|
|
|
|
uploadModifiedFileToNote,
|
|
|
|
uploadModifiedFileToAttachment
|
2020-05-12 10:28:31 +02:00
|
|
|
};
|