mirror of
https://github.com/zadam/trilium.git
synced 2025-06-05 17:38:47 +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)
|
||||
.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 {
|
||||
$content.text("Preview isn't available for this note type.");
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import utils from "./utils.js";
|
||||
import server from "./server.js";
|
||||
import toastService from "./toast.js";
|
||||
import noteDetailService from "./note_detail.js";
|
||||
|
||||
class NoteDetailFile {
|
||||
/**
|
||||
@ -16,10 +18,12 @@ class NoteDetailFile {
|
||||
this.$previewContent = ctx.$tabContent.find(".file-preview-content");
|
||||
this.$downloadButton = ctx.$tabContent.find(".file-download");
|
||||
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()) {
|
||||
const open = require("open");
|
||||
|
||||
@ -29,6 +33,34 @@ class NoteDetailFile {
|
||||
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() {
|
||||
|
@ -62,14 +62,14 @@ class NoteDetailImage {
|
||||
});
|
||||
|
||||
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 noteDetailService.reload();
|
||||
}
|
||||
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 repository = require('../../services/repository');
|
||||
const utils = require('../../services/utils');
|
||||
const noteRevisionService = require('../../services/note_revisions');
|
||||
|
||||
async function uploadFile(req) {
|
||||
const parentNoteId = req.params.parentNoteId;
|
||||
async function updateFile(req) {
|
||||
const {noteId} = req.params;
|
||||
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) {
|
||||
return [404, `Note ${parentNoteId} doesn't exist.`];
|
||||
if (!note) {
|
||||
return [404, `Note ${noteId} doesn't exist.`];
|
||||
}
|
||||
|
||||
const {note} = await noteService.createNote(parentNoteId, originalName, file.buffer, {
|
||||
target: 'into',
|
||||
isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(),
|
||||
type: mime.startsWith("image/") ? 'image' : 'file',
|
||||
mime: file.mimetype,
|
||||
attributes: [{ type: "label", name: "originalFileName", value: originalName }]
|
||||
});
|
||||
await noteRevisionService.createNoteRevision(note);
|
||||
|
||||
note.mime = file.mimetype.toLowerCase();
|
||||
|
||||
await note.setContent(file.buffer);
|
||||
|
||||
await note.setLabel('originalFileName', file.originalname);
|
||||
|
||||
await noteRevisionService.protectNoteRevisions(note);
|
||||
|
||||
return {
|
||||
noteId: note.noteId
|
||||
uploaded: true
|
||||
};
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ async function downloadFile(req, res) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
uploadFile,
|
||||
updateFile,
|
||||
downloadFile,
|
||||
downloadNoteFile
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
const repository = require('../services/repository');
|
||||
const log = require('../services/log');
|
||||
const fileUploadService = require('./api/file_upload');
|
||||
const fileUploadService = require('./api/files.js');
|
||||
const scriptService = require('../services/script');
|
||||
|
||||
function register(router) {
|
||||
|
@ -28,7 +28,7 @@ const imageRoute = require('./api/image');
|
||||
const attributesRoute = require('./api/attributes');
|
||||
const scriptRoute = require('./api/script');
|
||||
const senderRoute = require('./api/sender');
|
||||
const filesRoute = require('./api/file_upload');
|
||||
const filesRoute = require('./api/files');
|
||||
const searchRoute = require('./api/search');
|
||||
const dateNotesRoute = require('./api/date_notes');
|
||||
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(POST, '/api/notes/:parentNoteId/import', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], importRoute.importToBranch, apiResultHandler);
|
||||
|
||||
route(POST, '/api/notes/:parentNoteId/upload', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware],
|
||||
filesRoute.uploadFile, apiResultHandler);
|
||||
route(PUT, '/api/notes/:noteId/file', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware],
|
||||
filesRoute.updateFile, apiResultHandler);
|
||||
|
||||
route(GET, '/api/notes/:noteId/download', [auth.checkApiAuthOrElectron], filesRoute.downloadFile);
|
||||
// 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 sanitizeFilename = require('sanitize-filename');
|
||||
const dateUtils = require('./date_utils');
|
||||
const noteRevisionService = require('./note_revisions.js');
|
||||
const NoteRevision = require("../entities/note_revision");
|
||||
|
||||
async function processImage(uploadBuffer, originalName, shrinkImageSwitch) {
|
||||
@ -38,22 +39,7 @@ async function updateImage(noteId, uploadBuffer, originalName) {
|
||||
|
||||
const note = await repository.getNote(noteId);
|
||||
|
||||
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());
|
||||
await noteRevisionService.createNoteRevision(note);
|
||||
|
||||
note.mime = 'image/' + imageFormat.ext.toLowerCase();
|
||||
|
||||
@ -61,7 +47,7 @@ async function updateImage(noteId, uploadBuffer, originalName) {
|
||||
|
||||
await note.setLabel('originalFileName', originalName);
|
||||
|
||||
await noteService.protectNoteRevisions(note);
|
||||
await noteRevisionService.protectNoteRevisions(note);
|
||||
}
|
||||
|
||||
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 protectedSessionService = require('../services/protected_session');
|
||||
const log = require('../services/log');
|
||||
const noteRevisionService = require('../services/note_revisions');
|
||||
|
||||
async function getNewNotePosition(parentNoteId, noteData) {
|
||||
let newNotePos = 0;
|
||||
@ -199,17 +200,7 @@ async function protectNote(note, protect) {
|
||||
await note.save();
|
||||
}
|
||||
|
||||
await 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();
|
||||
}
|
||||
}
|
||||
await noteRevisionService.protectNoteRevisions(note);
|
||||
}
|
||||
|
||||
function findImageLinks(content, foundLinks) {
|
||||
@ -383,7 +374,7 @@ async function updateNote(noteId, noteUpdates) {
|
||||
await triggerNoteTitleChanged(note);
|
||||
}
|
||||
|
||||
await protectNoteRevisions(note);
|
||||
await noteRevisionService.protectNoteRevisions(note);
|
||||
|
||||
return {
|
||||
dateModified: note.dateModified,
|
||||
@ -538,6 +529,5 @@ module.exports = {
|
||||
deleteBranch,
|
||||
protectNoteRecursively,
|
||||
scanForLinks,
|
||||
duplicateNote,
|
||||
protectNoteRevisions
|
||||
duplicateNote
|
||||
};
|
@ -24,10 +24,14 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<input type="file" class="file-upload-new-revision-input" style="display: none">
|
||||
</div>
|
@ -27,6 +27,6 @@
|
||||
<span class="image-filesize"></span>
|
||||
</span>
|
||||
</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