mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
uploading new file revisions
This commit is contained in:
parent
7c7beb5502
commit
60ac1a04f4
@ -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.");
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
};
|
};
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
47
src/services/note_revisions.js
Normal file
47
src/services/note_revisions.js
Normal 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
|
||||||
|
};
|
@ -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
|
|
||||||
};
|
};
|
@ -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>
|
||||||
|
|
||||||
<button class="file-open btn btn-primary" type="button">Open</button>
|
<button class="file-open btn btn-sm btn-primary" type="button">Open</button>
|
||||||
|
|
||||||
|
<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>
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user