| 
									
										
										
										
											2018-02-14 23:31:20 -05:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | import protectedSessionService = require('../../services/protected_session'); | 
					
						
							|  |  |  | import utils = require('../../services/utils'); | 
					
						
							|  |  |  | import log = require('../../services/log'); | 
					
						
							|  |  |  | import noteService = require('../../services/notes'); | 
					
						
							|  |  |  | import tmp = require('tmp'); | 
					
						
							|  |  |  | import fs = require('fs'); | 
					
						
							|  |  |  | import { Readable } from 'stream'; | 
					
						
							|  |  |  | import chokidar = require('chokidar'); | 
					
						
							|  |  |  | import ws = require('../../services/ws'); | 
					
						
							|  |  |  | import becca = require('../../becca/becca'); | 
					
						
							|  |  |  | import ValidationError = require('../../errors/validation_error'); | 
					
						
							|  |  |  | import { Request, Response } from 'express'; | 
					
						
							|  |  |  | import BNote = require('../../becca/entities/bnote'); | 
					
						
							|  |  |  | import BAttachment = require('../../becca/entities/battachment'); | 
					
						
							| 
									
										
										
										
											2024-04-07 14:29:08 +03:00
										 |  |  | import { AppRequest } from '../route-interface'; | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-07 14:29:08 +03:00
										 |  |  | function updateFile(req: AppRequest) { | 
					
						
							| 
									
										
										
										
											2023-05-08 00:02:08 +02:00
										 |  |  |     const note = becca.getNoteOrThrow(req.params.noteId); | 
					
						
							| 
									
										
										
										
											2018-02-14 23:31:20 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-07 14:29:08 +03: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
										 |  |  |     }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-07 14:29:08 +03:00
										 |  |  | function updateAttachment(req: AppRequest) { | 
					
						
							| 
									
										
										
										
											2023-05-08 00:02:08 +02:00
										 |  |  |     const attachment = becca.getAttachmentOrThrow(req.params.attachmentId); | 
					
						
							| 
									
										
										
										
											2024-04-07 14:29:08 +03: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 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function downloadData(noteOrAttachment: BNote | BAttachment, res: Response, contentDisposition: boolean) { | 
					
						
							| 
									
										
										
										
											2023-05-03 10:23:20 +02:00
										 |  |  |     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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function downloadNoteInt(noteId: string, res: Response, 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function downloadAttachmentInt(attachmentId: string, res: Response, contentDisposition = true) { | 
					
						
							| 
									
										
										
										
											2023-05-03 10:23:20 +02:00
										 |  |  |     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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | const downloadFile = (req: Request, res: Response) => downloadNoteInt(req.params.noteId, res, true); | 
					
						
							|  |  |  | const openFile = (req: Request, res: Response) => downloadNoteInt(req.params.noteId, res, false); | 
					
						
							| 
									
										
										
										
											2019-01-27 15:47:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | const downloadAttachment = (req: Request, res: Response) => downloadAttachmentInt(req.params.attachmentId, res, true); | 
					
						
							|  |  |  | const openAttachment = (req: Request, res: Response) => downloadAttachmentInt(req.params.attachmentId, res, false); | 
					
						
							| 
									
										
										
										
											2020-03-08 18:06:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function fileContentProvider(req: Request) { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function attachmentContentProvider(req: Request) { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function streamContent(content: string | Buffer, fileName: string, mimeType: string) { | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  |     const getStream = (range: { start: number, end: number }) => { | 
					
						
							| 
									
										
										
										
											2021-04-17 22:35:47 +02:00
										 |  |  |         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 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function saveNoteToTmpDir(req: Request) { | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function saveAttachmentToTmpDir(req: Request) { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  |     if (!attachment.attachmentId) { | 
					
						
							|  |  |  |         throw new ValidationError("Missing attachment ID."); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-05-03 10:23:20 +02:00
										 |  |  |     return saveToTmpDir(fileName, content, 'attachments', attachment.attachmentId); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function saveToTmpDir(fileName: string, content: string | Buffer, entityType: string, entityId: string) { | 
					
						
							| 
									
										
										
										
											2023-05-03 10:23:20 +02:00
										 |  |  |     const tmpObj = tmp.fileSync({ postfix: fileName }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  |     if (typeof content === "string") { | 
					
						
							|  |  |  |         fs.writeSync(tmpObj.fd, content); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         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, | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  |                 lastModifiedMs: stats?.atimeMs, | 
					
						
							| 
									
										
										
										
											2021-04-24 11:39:59 +02:00
										 |  |  |                 filePath: tmpObj.name | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-13 22:50:45 +02:00
										 |  |  |     return { | 
					
						
							|  |  |  |         tmpFilePath: tmpObj.name | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function uploadModifiedFileToNote(req: Request) { | 
					
						
							| 
									
										
										
										
											2023-05-03 10:23:20 +02:00
										 |  |  |     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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | function uploadModifiedFileToAttachment(req: Request) { | 
					
						
							| 
									
										
										
										
											2023-05-03 10:23:20 +02:00
										 |  |  |     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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 22:22:18 +03:00
										 |  |  | export = { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | }; |