mirror of
https://github.com/zadam/trilium.git
synced 2024-09-22 00:26:01 +08:00
attachment upload and download now works for browser
This commit is contained in:
parent
fda4146150
commit
78e8c15786
|
@ -14,6 +14,10 @@ const noteEditor = (function() {
|
|||
const $noteIdDisplay = $("#note-id-display");
|
||||
const $attributeList = $("#attribute-list");
|
||||
const $attributeListInner = $("#attribute-list-inner");
|
||||
const $attachmentFileName = $("#attachment-filename");
|
||||
const $attachmentFileType = $("#attachment-filetype");
|
||||
const $attachmentFileSize = $("#attachment-filesize");
|
||||
const $attachmentDownload = $("#attachment-download");
|
||||
|
||||
let editor = null;
|
||||
let codeEditor = null;
|
||||
|
@ -83,7 +87,7 @@ const noteEditor = (function() {
|
|||
else if (note.detail.type === 'code') {
|
||||
note.detail.content = codeEditor.getValue();
|
||||
}
|
||||
else if (note.detail.type === 'render') {
|
||||
else if (note.detail.type === 'render' || note.detail.type === 'file') {
|
||||
// nothing
|
||||
}
|
||||
else {
|
||||
|
@ -185,6 +189,10 @@ const noteEditor = (function() {
|
|||
}
|
||||
else if (currentNote.detail.type === 'file') {
|
||||
$noteDetailAttachment.show();
|
||||
|
||||
$attachmentFileName.text(currentNote.attributes.original_file_name);
|
||||
$attachmentFileSize.text(currentNote.attributes.file_size + " bytes");
|
||||
$attachmentFileType.text(currentNote.detail.mime);
|
||||
}
|
||||
else {
|
||||
setContent(currentNote.detail.content);
|
||||
|
@ -237,7 +245,7 @@ const noteEditor = (function() {
|
|||
else if (note.detail.type === 'code') {
|
||||
codeEditor.focus();
|
||||
}
|
||||
else if (note.detail.type === 'render') {
|
||||
else if (note.detail.type === 'render' || note.detail.type === 'file') {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
|
@ -262,6 +270,10 @@ const noteEditor = (function() {
|
|||
}
|
||||
}
|
||||
|
||||
$attachmentDownload.click(() => {
|
||||
window.location.href = "/api/attachments/download/" + getCurrentNoteId();
|
||||
});
|
||||
|
||||
$(document).ready(() => {
|
||||
$noteTitle.on('input', () => {
|
||||
noteChanged();
|
||||
|
|
|
@ -65,11 +65,18 @@ const noteType = (function() {
|
|||
else if (type === 'render') {
|
||||
return 'Render HTML note';
|
||||
}
|
||||
else if (type === 'file') {
|
||||
return 'Attachment';
|
||||
}
|
||||
else {
|
||||
throwError('Unrecognized type: ' + type);
|
||||
}
|
||||
};
|
||||
|
||||
this.isDisabled = function() {
|
||||
return self.type() === "file";
|
||||
};
|
||||
|
||||
async function save() {
|
||||
const note = noteEditor.getCurrentNote();
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ const server = (function() {
|
|||
put,
|
||||
remove,
|
||||
exec,
|
||||
ajax,
|
||||
// don't remove, used from CKEditor image upload!
|
||||
getHeaders
|
||||
}
|
||||
|
|
|
@ -269,3 +269,8 @@ div.ui-tooltip {
|
|||
padding: 2px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#attachment-table th, #attachment-table td {
|
||||
padding: 10px;
|
||||
font-size: large;
|
||||
}
|
|
@ -5,6 +5,7 @@ const router = express.Router();
|
|||
const sql = require('../../services/sql');
|
||||
const auth = require('../../services/auth');
|
||||
const notes = require('../../services/notes');
|
||||
const attributes = require('../../services/attributes');
|
||||
const multer = require('multer')();
|
||||
const wrap = require('express-promise-wrap').wrap;
|
||||
|
||||
|
@ -12,6 +13,8 @@ router.post('/upload/:parentNoteId', auth.checkApiAuthOrElectron, multer.single(
|
|||
const sourceId = req.headers.source_id;
|
||||
const parentNoteId = req.params.parentNoteId;
|
||||
const file = req.file;
|
||||
const originalName = file.originalname;
|
||||
const size = file.size;
|
||||
|
||||
const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [parentNoteId]);
|
||||
|
||||
|
@ -19,18 +22,40 @@ router.post('/upload/:parentNoteId', auth.checkApiAuthOrElectron, multer.single(
|
|||
return res.status(404).send(`Note ${parentNoteId} doesn't exist.`);
|
||||
}
|
||||
|
||||
await sql.doInTransaction(async () => {
|
||||
const noteId = (await notes.createNewNote(parentNoteId, {
|
||||
title: "attachment",
|
||||
title: originalName,
|
||||
content: file.buffer,
|
||||
target: 'into',
|
||||
isProtected: false,
|
||||
type: 'file',
|
||||
mime: ''
|
||||
})).noteId;
|
||||
mime: file.mimetype
|
||||
}, req, sourceId)).noteId;
|
||||
|
||||
await attributes.createAttribute(noteId, "original_file_name", originalName);
|
||||
await attributes.createAttribute(noteId, "file_size", size);
|
||||
|
||||
res.send({
|
||||
noteId: noteId
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
router.get('/download/:noteId', auth.checkApiAuthOrElectron, wrap(async (req, res, next) => {
|
||||
const noteId = req.params.noteId;
|
||||
const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]);
|
||||
|
||||
if (!note) {
|
||||
return res.status(404).send(`Note ${parentNoteId} doesn't exist.`);
|
||||
}
|
||||
|
||||
const attributeMap = await attributes.getNoteAttributeMap(noteId);
|
||||
const fileName = attributeMap.original_file_name ? attributeMap.original_file_name : note.title;
|
||||
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=' + fileName);
|
||||
res.setHeader('Content-Type', note.mime);
|
||||
|
||||
res.send(note.content);
|
||||
}));
|
||||
|
||||
module.exports = router;
|
|
@ -5,6 +5,7 @@ const router = express.Router();
|
|||
const auth = require('../../services/auth');
|
||||
const sql = require('../../services/sql');
|
||||
const notes = require('../../services/notes');
|
||||
const attributes = require('../../services/attributes');
|
||||
const log = require('../../services/log');
|
||||
const utils = require('../../services/utils');
|
||||
const protected_session = require('../../services/protected_session');
|
||||
|
@ -25,8 +26,19 @@ router.get('/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
|
|||
|
||||
protected_session.decryptNote(req, detail);
|
||||
|
||||
let attributeMap = null;
|
||||
|
||||
if (detail.type === 'file') {
|
||||
// no need to transfer attachment payload for this request
|
||||
detail.content = null;
|
||||
|
||||
// attributes contain important attachment metadata - filename and size
|
||||
attributeMap = await attributes.getNoteAttributeMap(noteId);
|
||||
}
|
||||
|
||||
res.send({
|
||||
detail: detail
|
||||
detail: detail,
|
||||
attributes: attributeMap
|
||||
});
|
||||
}));
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
$date.datepicker('setDate', new Date());
|
||||
|
||||
async function saveWeight() {
|
||||
await server.exec([$date.val(), $weight.val(), $comment.val()], async (date, weight, comment) => {
|
||||
await server.exec([$date.val(), parseFloat($weight.val()), $comment.val()], async (date, weight, comment) => {
|
||||
const dataNote = await this.getNoteWithAttribute('date_data', date);
|
||||
|
||||
if (dataNote) {
|
||||
|
|
|
@ -13,7 +13,7 @@ const BUILTIN_ATTRIBUTES = [
|
|||
];
|
||||
|
||||
async function getNoteAttributeMap(noteId) {
|
||||
return await sql.getMap(`SELECT name, value FROM attributes WHERE noteId = ?`, [noteId]);
|
||||
return await sql.getMap(`SELECT name, value FROM attributes WHERE noteId = ? AND isDeleted = 0`, [noteId]);
|
||||
}
|
||||
|
||||
async function getNoteIdWithAttribute(name, value) {
|
||||
|
|
|
@ -214,7 +214,7 @@ async function runAllChecks() {
|
|||
FROM
|
||||
notes
|
||||
WHERE
|
||||
type != 'text' AND type != 'code' AND type != 'render'`,
|
||||
type != 'text' AND type != 'code' AND type != 'render' AND type != 'file'`,
|
||||
"Note has invalid type", errorList);
|
||||
|
||||
await runSyncRowChecks("notes", "noteId", errorList);
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
onclick="noteEditor.executeCurrentNote()">Execute <kbd>Ctrl+Enter</kbd></button>
|
||||
|
||||
<div class="dropdown" id="note-type">
|
||||
<button id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-sm">
|
||||
<button data-bind="disable: isDisabled()" id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-sm">
|
||||
Type: <span data-bind="text: typeString()"></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
|
@ -144,8 +144,25 @@
|
|||
<div id="note-detail-render"></div>
|
||||
|
||||
<div id="note-detail-attachment">
|
||||
Attachment!!!
|
||||
|
||||
<table id="attachment-table">
|
||||
<tr>
|
||||
<th>File name:</th>
|
||||
<td id="attachment-filename"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File type:</th>
|
||||
<td id="attachment-filetype"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>File size:</th>
|
||||
<td id="attachment-filesize"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="attachment-download" class="btn btn-primary" type="button">Download</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<input type="file" id="file-upload" style="display: none" />
|
||||
|
|
Loading…
Reference in a new issue