attachment upload and download now works for browser

This commit is contained in:
azivner 2018-02-18 21:28:24 -05:00
parent fda4146150
commit 78e8c15786
10 changed files with 98 additions and 19 deletions

View file

@ -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();

View file

@ -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();

View file

@ -116,6 +116,7 @@ const server = (function() {
put,
remove,
exec,
ajax,
// don't remove, used from CKEditor image upload!
getHeaders
}

View file

@ -268,4 +268,9 @@ div.ui-tooltip {
#attribute-list button {
padding: 2px;
margin-right: 5px;
}
#attachment-table th, #attachment-table td {
padding: 10px;
font-size: large;
}

View file

@ -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.`);
}
const noteId = (await notes.createNewNote(parentNoteId, {
title: "attachment",
content: file.buffer,
target: 'into',
isProtected: false,
type: 'file',
mime: ''
})).noteId;
await sql.doInTransaction(async () => {
const noteId = (await notes.createNewNote(parentNoteId, {
title: originalName,
content: file.buffer,
target: 'into',
isProtected: false,
type: 'file',
mime: file.mimetype
}, req, sourceId)).noteId;
res.send({
noteId: 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;

View file

@ -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
});
}));

View file

@ -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) {

View file

@ -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) {

View file

@ -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);

View file

@ -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" />