uploading new file revisions

This commit is contained in:
zadam 2019-11-09 11:58:52 +01:00
parent 7c7beb5502
commit 60ac1a04f4
11 changed files with 132 additions and 60 deletions

View File

@ -77,6 +77,19 @@ $list.on('change', async () => {
.attr("src", `data:${note.mime};base64,` + fullNoteRevision.content) .attr("src", `data:${note.mime};base64,` + fullNoteRevision.content)
.css("width", "100%")); .css("width", "100%"));
} }
else if (note.type === 'file') {
$content.html(
$("<table cellpadding='10'>")
.append($("<tr>").append(
$("<th>").text("MIME: "),
$("<td>").text(revisionItem.mime)
))
.append($("<tr>").append(
$("<th>").text("File size:"),
$("<td>").text(revisionItem.contentLength + " bytes")
))
);
}
else { else {
$content.text("Preview isn't available for this note type."); $content.text("Preview isn't available for this note type.");
} }

View File

@ -1,5 +1,7 @@
import utils from "./utils.js"; import utils from "./utils.js";
import server from "./server.js"; import server from "./server.js";
import toastService from "./toast.js";
import noteDetailService from "./note_detail.js";
class NoteDetailFile { class NoteDetailFile {
/** /**
@ -16,10 +18,12 @@ class NoteDetailFile {
this.$previewContent = ctx.$tabContent.find(".file-preview-content"); this.$previewContent = ctx.$tabContent.find(".file-preview-content");
this.$downloadButton = ctx.$tabContent.find(".file-download"); this.$downloadButton = ctx.$tabContent.find(".file-download");
this.$openButton = ctx.$tabContent.find(".file-open"); this.$openButton = ctx.$tabContent.find(".file-open");
this.$uploadNewRevisionButton = ctx.$tabContent.find(".file-upload-new-revision");
this.$uploadNewRevisionInput = ctx.$tabContent.find(".file-upload-new-revision-input");
this.$downloadButton.click(() => utils.download(this.getFileUrl())); this.$downloadButton.on('click', () => utils.download(this.getFileUrl()));
this.$openButton.click(() => { this.$openButton.on('click', () => {
if (utils.isElectron()) { if (utils.isElectron()) {
const open = require("open"); const open = require("open");
@ -29,6 +33,34 @@ class NoteDetailFile {
window.location.href = this.getFileUrl(); window.location.href = this.getFileUrl();
} }
}); });
this.$uploadNewRevisionButton.on("click", () => {
this.$uploadNewRevisionInput.trigger("click");
});
this.$uploadNewRevisionInput.on('change', async () => {
const formData = new FormData();
formData.append('upload', this.$uploadNewRevisionInput[0].files[0]);
const result = await $.ajax({
url: baseApiUrl + 'notes/' + this.ctx.note.noteId + '/file',
headers: server.getHeaders(),
data: formData,
type: 'PUT',
timeout: 60 * 60 * 1000,
contentType: false, // NEEDED, DON'T REMOVE THIS
processData: false, // NEEDED, DON'T REMOVE THIS
});
if (result.uploaded) {
toastService.showMessage("New file revision has been uploaded.");
await noteDetailService.reload();
}
else {
toastService.showError("Upload of a new file revision failed.");
}
});
} }
async render() { async render() {

View File

@ -62,14 +62,14 @@ class NoteDetailImage {
}); });
if (result.uploaded) { if (result.uploaded) {
toastService.showMessage("New revision of the image has been uploaded.") toastService.showMessage("New image revision has been uploaded.");
await utils.clearBrowserCache(); await utils.clearBrowserCache();
await noteDetailService.reload(); await noteDetailService.reload();
} }
else { else {
toastService.showError("Could not upload new revision of the image: " + result.message); toastService.showError("Upload of a new image revision failed: " + result.message);
} }
}); });
} }

View File

@ -4,30 +4,30 @@ const noteService = require('../../services/notes');
const protectedSessionService = require('../../services/protected_session'); const protectedSessionService = require('../../services/protected_session');
const repository = require('../../services/repository'); const repository = require('../../services/repository');
const utils = require('../../services/utils'); const utils = require('../../services/utils');
const noteRevisionService = require('../../services/note_revisions');
async function uploadFile(req) { async function updateFile(req) {
const parentNoteId = req.params.parentNoteId; const {noteId} = req.params;
const file = req.file; const file = req.file;
const originalName = file.originalname;
const size = file.size;
const mime = file.mimetype.toLowerCase();
const parentNote = await repository.getNote(parentNoteId); const note = await repository.getNote(noteId);
if (!parentNote) { if (!note) {
return [404, `Note ${parentNoteId} doesn't exist.`]; return [404, `Note ${noteId} doesn't exist.`];
} }
const {note} = await noteService.createNote(parentNoteId, originalName, file.buffer, { await noteRevisionService.createNoteRevision(note);
target: 'into',
isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(), note.mime = file.mimetype.toLowerCase();
type: mime.startsWith("image/") ? 'image' : 'file',
mime: file.mimetype, await note.setContent(file.buffer);
attributes: [{ type: "label", name: "originalFileName", value: originalName }]
}); await note.setLabel('originalFileName', file.originalname);
await noteRevisionService.protectNoteRevisions(note);
return { return {
noteId: note.noteId uploaded: true
}; };
} }
@ -58,7 +58,7 @@ async function downloadFile(req, res) {
} }
module.exports = { module.exports = {
uploadFile, updateFile,
downloadFile, downloadFile,
downloadNoteFile downloadNoteFile
}; };

View File

@ -1,6 +1,6 @@
const repository = require('../services/repository'); const repository = require('../services/repository');
const log = require('../services/log'); const log = require('../services/log');
const fileUploadService = require('./api/file_upload'); const fileUploadService = require('./api/files.js');
const scriptService = require('../services/script'); const scriptService = require('../services/script');
function register(router) { function register(router) {

View File

@ -28,7 +28,7 @@ const imageRoute = require('./api/image');
const attributesRoute = require('./api/attributes'); const attributesRoute = require('./api/attributes');
const scriptRoute = require('./api/script'); const scriptRoute = require('./api/script');
const senderRoute = require('./api/sender'); const senderRoute = require('./api/sender');
const filesRoute = require('./api/file_upload'); const filesRoute = require('./api/files');
const searchRoute = require('./api/search'); const searchRoute = require('./api/search');
const dateNotesRoute = require('./api/date_notes'); const dateNotesRoute = require('./api/date_notes');
const linkMapRoute = require('./api/link_map'); const linkMapRoute = require('./api/link_map');
@ -146,8 +146,8 @@ function register(app) {
route(GET, '/api/notes/:branchId/export/:type/:format/:version/:taskId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch); route(GET, '/api/notes/:branchId/export/:type/:format/:version/:taskId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch);
route(POST, '/api/notes/:parentNoteId/import', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], importRoute.importToBranch, apiResultHandler); route(POST, '/api/notes/:parentNoteId/import', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], importRoute.importToBranch, apiResultHandler);
route(POST, '/api/notes/:parentNoteId/upload', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], route(PUT, '/api/notes/:noteId/file', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware],
filesRoute.uploadFile, apiResultHandler); filesRoute.updateFile, apiResultHandler);
route(GET, '/api/notes/:noteId/download', [auth.checkApiAuthOrElectron], filesRoute.downloadFile); route(GET, '/api/notes/:noteId/download', [auth.checkApiAuthOrElectron], filesRoute.downloadFile);
// this "hacky" path is used for easier referencing of CSS resources // this "hacky" path is used for easier referencing of CSS resources

View File

@ -13,6 +13,7 @@ const jimp = require('jimp');
const imageType = require('image-type'); const imageType = require('image-type');
const sanitizeFilename = require('sanitize-filename'); const sanitizeFilename = require('sanitize-filename');
const dateUtils = require('./date_utils'); const dateUtils = require('./date_utils');
const noteRevisionService = require('./note_revisions.js');
const NoteRevision = require("../entities/note_revision"); const NoteRevision = require("../entities/note_revision");
async function processImage(uploadBuffer, originalName, shrinkImageSwitch) { async function processImage(uploadBuffer, originalName, shrinkImageSwitch) {
@ -38,22 +39,7 @@ async function updateImage(noteId, uploadBuffer, originalName) {
const note = await repository.getNote(noteId); const note = await repository.getNote(noteId);
const noteRevision = await new NoteRevision({ await noteRevisionService.createNoteRevision(note);
noteId: note.noteId,
// title and text should be decrypted now
title: note.title,
contentLength: -1, // will be updated in .setContent()
type: note.type,
mime: note.mime,
isProtected: false, // will be fixed in the protectNoteRevisions() call
utcDateLastEdited: note.utcDateModified,
utcDateCreated: dateUtils.utcNowDateTime(),
utcDateModified: dateUtils.utcNowDateTime(),
dateLastEdited: note.dateModified,
dateCreated: dateUtils.localNowDateTime()
}).save();
await noteRevision.setContent(await note.getContent());
note.mime = 'image/' + imageFormat.ext.toLowerCase(); note.mime = 'image/' + imageFormat.ext.toLowerCase();
@ -61,7 +47,7 @@ async function updateImage(noteId, uploadBuffer, originalName) {
await note.setLabel('originalFileName', originalName); await note.setLabel('originalFileName', originalName);
await noteService.protectNoteRevisions(note); await noteRevisionService.protectNoteRevisions(note);
} }
async function saveImage(parentNoteId, uploadBuffer, originalName, shrinkImageSwitch) { async function saveImage(parentNoteId, uploadBuffer, originalName, shrinkImageSwitch) {

View File

@ -0,0 +1,47 @@
"use strict";
const NoteRevision = require('../entities/note_revision');
const dateUtils = require('../services/date_utils');
/**
* @param {Note} note
*/
async function protectNoteRevisions(note) {
for (const revision of await note.getRevisions()) {
if (note.isProtected !== revision.isProtected) {
revision.isProtected = note.isProtected;
await revision.save();
}
}
}
/**
* @param {Note} note
* @return {NoteRevision}
*/
async function createNoteRevision(note) {
const noteRevision = await new NoteRevision({
noteId: note.noteId,
// title and text should be decrypted now
title: note.title,
contentLength: -1, // will be updated in .setContent()
type: note.type,
mime: note.mime,
isProtected: false, // will be fixed in the protectNoteRevisions() call
utcDateLastEdited: note.utcDateModified,
utcDateCreated: dateUtils.utcNowDateTime(),
utcDateModified: dateUtils.utcNowDateTime(),
dateLastEdited: note.dateModified,
dateCreated: dateUtils.localNowDateTime()
}).save();
await noteRevision.setContent(await note.getContent());
return noteRevision;
}
module.exports = {
protectNoteRevisions,
createNoteRevision
};

View File

@ -14,6 +14,7 @@ const Attribute = require('../entities/attribute');
const hoistedNoteService = require('../services/hoisted_note'); const hoistedNoteService = require('../services/hoisted_note');
const protectedSessionService = require('../services/protected_session'); const protectedSessionService = require('../services/protected_session');
const log = require('../services/log'); const log = require('../services/log');
const noteRevisionService = require('../services/note_revisions');
async function getNewNotePosition(parentNoteId, noteData) { async function getNewNotePosition(parentNoteId, noteData) {
let newNotePos = 0; let newNotePos = 0;
@ -199,17 +200,7 @@ async function protectNote(note, protect) {
await note.save(); await note.save();
} }
await protectNoteRevisions(note); await noteRevisionService.protectNoteRevisions(note);
}
async function protectNoteRevisions(note) {
for (const revision of await note.getRevisions()) {
if (note.isProtected !== revision.isProtected) {
revision.isProtected = note.isProtected;
await revision.save();
}
}
} }
function findImageLinks(content, foundLinks) { function findImageLinks(content, foundLinks) {
@ -383,7 +374,7 @@ async function updateNote(noteId, noteUpdates) {
await triggerNoteTitleChanged(note); await triggerNoteTitleChanged(note);
} }
await protectNoteRevisions(note); await noteRevisionService.protectNoteRevisions(note);
return { return {
dateModified: note.dateModified, dateModified: note.dateModified,
@ -538,6 +529,5 @@ module.exports = {
deleteBranch, deleteBranch,
protectNoteRecursively, protectNoteRecursively,
scanForLinks, scanForLinks,
duplicateNote, duplicateNote
protectNoteRevisions
}; };

View File

@ -24,10 +24,14 @@
</tr> </tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<button class="file-download btn btn-primary" type="button">Download</button> <button class="file-download btn btn-sm btn-primary" type="button">Download</button>
&nbsp; &nbsp;
<button class="file-open btn btn-primary" type="button">Open</button> <button class="file-open btn btn-sm btn-primary" type="button">Open</button>
&nbsp;
<button class="file-upload-new-revision btn btn-sm btn-primary">Upload new revision</button>
</td> </td>
</tr> </tr>
</table> </table>
<input type="file" class="file-upload-new-revision-input" style="display: none">
</div> </div>

View File

@ -27,6 +27,6 @@
<span class="image-filesize"></span> <span class="image-filesize"></span>
</span> </span>
</div> </div>
</div>
<input type="file" class="image-upload-new-revision-input" style="display: none"> <input type="file" class="image-upload-new-revision-input" style="display: none">
</div>