/
files.js
155 lines (118 loc) · 3.89 KB
/
files.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"use strict";
const protectedSessionService = require('../../services/protected_session');
const utils = require('../../services/utils');
const log = require('../../services/log');
const noteRevisionService = require('../../services/note_revisions');
const tmp = require('tmp');
const fs = require('fs');
const { Readable } = require('stream');
const chokidar = require('chokidar');
const ws = require('../../services/ws');
const becca = require("../../becca/becca");
function updateFile(req) {
const {noteId} = req.params;
const file = req.file;
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} doesn't exist.`];
}
note.saveNoteRevision();
noteRevisionService.protectNoteRevisions(note);
note.mime = file.mimetype.toLowerCase();
note.save();
note.setContent(file.buffer);
note.setLabel('originalFileName', file.originalname);
noteRevisionService.protectNoteRevisions(note);
return {
uploaded: true
};
}
function getFilename(note) {
// (one) reason we're not using the originFileName (available as label) is that it's not
// available for older note revisions and thus would be inconsistent
return utils.formatDownloadTitle(note.title, note.type, note.mime);
}
function downloadNoteFile(noteId, res, contentDisposition = true) {
const note = becca.getNote(noteId);
if (!note) {
return res.setHeader("Content-Type", "text/plain")
.status(404)
.send(`Note ${noteId} doesn't exist.`);
}
if (note.isProtected && !protectedSessionService.isProtectedSessionAvailable()) {
return res.status(401).send("Protected session not available");
}
if (contentDisposition) {
const filename = getFilename(note);
res.setHeader('Content-Disposition', utils.getContentDisposition(filename));
}
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
res.setHeader('Content-Type', note.mime);
res.send(note.getContent());
}
function downloadFile(req, res) {
const noteId = req.params.noteId;
return downloadNoteFile(noteId, res);
}
function openFile(req, res) {
const noteId = req.params.noteId;
return downloadNoteFile(noteId, res, false);
}
function fileContentProvider(req) {
// Read file name from route params.
const note = becca.getNote(req.params.noteId);
const fileName = getFilename(note);
let content = note.getContent();
if (typeof content === "string") {
content = Buffer.from(content, 'utf8');
}
const totalSize = content.byteLength;
const mimeType = note.mime;
const getStream = range => {
if (!range) {
// Request if for complete content.
return Readable.from(content);
}
// Partial content request.
const { start, end } = range;
return Readable.from(content.slice(start, end + 1));
}
return {
fileName,
totalSize,
mimeType,
getStream
};
}
function saveToTmpDir(req) {
const noteId = req.params.noteId;
const note = becca.getNote(noteId);
if (!note) {
return [404,`Note ${noteId} doesn't exist.`];
}
const tmpObj = tmp.fileSync({postfix: getFilename(note)});
fs.writeSync(tmpObj.fd, note.getContent());
fs.closeSync(tmpObj.fd);
log.info(`Saved temporary file for note ${noteId} into ${tmpObj.name}`);
if (utils.isElectron()) {
chokidar.watch(tmpObj.name).on('change', (path, stats) => {
ws.sendMessageToAllClients({
type: 'openedFileUpdated',
noteId: noteId,
lastModifiedMs: stats.atimeMs,
filePath: tmpObj.name
});
});
}
return {
tmpFilePath: tmpObj.name
};
}
module.exports = {
updateFile,
openFile,
fileContentProvider,
downloadFile,
downloadNoteFile,
saveToTmpDir
};