mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-30 18:05:55 +01:00 
			
		
		
		
	exposing blobs in APIs
This commit is contained in:
		| @@ -139,8 +139,7 @@ class Becca { | |||||||
|  |  | ||||||
|     /** @returns {BBlob|null} */ |     /** @returns {BBlob|null} */ | ||||||
|     getBlob(blobId) { |     getBlob(blobId) { | ||||||
|         const row = sql.getRow("SELECT *, LENGTH(content) AS contentLength " + |         const row = sql.getRow("SELECT *, LENGTH(content) AS contentLength FROM blobs WHERE blobId = ?", [blobId]); | ||||||
|                                      "FROM blob WHERE blobId = ?", [blobId]); |  | ||||||
|  |  | ||||||
|         const BBlob = require("./entities/bblob"); // avoiding circular dependency problems |         const BBlob = require("./entities/bblob"); // avoiding circular dependency problems | ||||||
|         return row ? new BBlob(row) : null; |         return row ? new BBlob(row) : null; | ||||||
|   | |||||||
| @@ -212,15 +212,9 @@ class BNote extends AbstractBeccaEntity { | |||||||
|         return this._getContent(); |         return this._getContent(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @returns {{contentLength, dateModified, utcDateModified}} */ |     /** @returns {{dateModified, utcDateModified}} */ | ||||||
|     getContentMetadata() { |     getContentMetadata() { | ||||||
|         return sql.getRow(` |         return sql.getRow(`SELECT dateModified, utcDateModified FROM blobs WHERE blobId = ?`, [this.blobId]); | ||||||
|             SELECT  |  | ||||||
|                 LENGTH(content) AS contentLength,  |  | ||||||
|                 dateModified, |  | ||||||
|                 utcDateModified  |  | ||||||
|             FROM blobs  |  | ||||||
|             WHERE blobId = ?`, [this.blobId]); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @returns {*} */ |     /** @returns {*} */ | ||||||
|   | |||||||
| @@ -207,6 +207,7 @@ class NoteContext extends Component { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** @returns {Promise<boolean>} */ | ||||||
|     async isReadOnly() { |     async isReadOnly() { | ||||||
|         if (this.viewScope.readOnlyTemporarilyDisabled) { |         if (this.viewScope.readOnlyTemporarilyDisabled) { | ||||||
|             return false; |             return false; | ||||||
| @@ -221,14 +222,13 @@ class NoteContext extends Component { | |||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const noteComplement = await this.getNoteComplement(); |         const blob = await this.note.getBlob(); | ||||||
|  |  | ||||||
|         const sizeLimit = this.note.type === 'text' |         const sizeLimit = this.note.type === 'text' | ||||||
|             ? options.getInt('autoReadonlySizeText') |             ? options.getInt('autoReadonlySizeText') | ||||||
|             : options.getInt('autoReadonlySizeCode'); |             : options.getInt('autoReadonlySizeCode'); | ||||||
|  |  | ||||||
|         return noteComplement.content |         return blob.contentLength > sizeLimit | ||||||
|             && noteComplement.content.length > sizeLimit |  | ||||||
|             && !this.note.hasLabel('autoReadOnlyDisabled'); |             && !this.note.hasLabel('autoReadOnlyDisabled'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ class FAttachment { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @param [opts.full=false] - force retrieval of the full note |      * @param [opts.preview=false] - retrieve only first 10 000 characters for a preview | ||||||
|      * @return {FBlob} |      * @return {FBlob} | ||||||
|      */ |      */ | ||||||
|     async getBlob(opts = {}) { |     async getBlob(opts = {}) { | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| class FBlob { | export default class FBlob { | ||||||
|     constructor(row) { |     constructor(row) { | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.blobId = row.blobId; |         this.blobId = row.blobId; | ||||||
| @@ -8,6 +8,7 @@ class FBlob { | |||||||
|          * @type {string} |          * @type {string} | ||||||
|          */ |          */ | ||||||
|         this.content = row.content; |         this.content = row.content; | ||||||
|  |         this.contentLength = row.contentLength; | ||||||
|  |  | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.dateModified = row.dateModified; |         this.dateModified = row.dateModified; | ||||||
|   | |||||||
| @@ -843,7 +843,7 @@ class FNote { | |||||||
|     /** |     /** | ||||||
|      * Get relations which target this note |      * Get relations which target this note | ||||||
|      * |      * | ||||||
|      * @returns {FNote[]} |      * @returns {Promise<FNote[]>} | ||||||
|      */ |      */ | ||||||
|     async getTargetRelationSourceNotes() { |     async getTargetRelationSourceNotes() { | ||||||
|         const targetRelations = this.getTargetRelations(); |         const targetRelations = this.getTargetRelations(); | ||||||
| @@ -851,14 +851,17 @@ class FNote { | |||||||
|         return await this.froca.getNotes(targetRelations.map(tr => tr.noteId)); |         return await this.froca.getNotes(targetRelations.map(tr => tr.noteId)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @deprecated use getBlob() instead */ |     /** | ||||||
|  |      * @deprecated use getBlob() instead | ||||||
|  |      * @return {Promise<FBlob>} | ||||||
|  |      */ | ||||||
|     async getNoteComplement() { |     async getNoteComplement() { | ||||||
|         return this.getBlob({ full: true }); |         return this.getBlob(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @param [opts.full=false] - force retrieval of the full note |      * @param [opts.preview=false] - retrieve only first 10 000 characters for a preview | ||||||
|      * @return {FBlob} |      * @return {Promise<FBlob>} | ||||||
|      */ |      */ | ||||||
|     async getBlob(opts = {}) { |     async getBlob(opts = {}) { | ||||||
|         return await this.froca.getBlob('notes', this.noteId, opts); |         return await this.froca.getBlob('notes', this.noteId, opts); | ||||||
|   | |||||||
| @@ -320,12 +320,13 @@ class Froca { | |||||||
|         return attachmentRow ? new FAttachment(this, attachmentRow) : null; |         return attachmentRow ? new FAttachment(this, attachmentRow) : null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** @returns {Promise<FBlob>} */ | ||||||
|     async getBlob(entityType, entityId, opts = {}) { |     async getBlob(entityType, entityId, opts = {}) { | ||||||
|         opts.full = !!opts.full; |         opts.preview = !!opts.preview; | ||||||
|         const key = `${entityType}-${entityId}`; |         const key = `${entityType}-${entityId}-${opts.preview}`; | ||||||
|  |  | ||||||
|         if (!this.blobPromises[key]) { |         if (!this.blobPromises[key]) { | ||||||
|             this.blobPromises[key] = server.get(`${entityType}/${entityId}/blob?full=${opts.full}`) |             this.blobPromises[key] = server.get(`${entityType}/${entityId}/blob?preview=${opts.preview}`) | ||||||
|                 .then(row => new FBlob(row)) |                 .then(row => new FBlob(row)) | ||||||
|                 .catch(e => console.error(`Cannot get blob for ${entityType} '${entityId}'`)); |                 .catch(e => console.error(`Cannot get blob for ${entityType} '${entityId}'`)); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,6 +11,11 @@ import treeService from "./tree.js"; | |||||||
|  |  | ||||||
| let idCounter = 1; | let idCounter = 1; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param {FNote} note | ||||||
|  |  * @param {object} options | ||||||
|  |  * @return {Promise<{type: string, $renderedContent: jQuery}>} | ||||||
|  |  */ | ||||||
| async function getRenderedContent(note, options = {}) { | async function getRenderedContent(note, options = {}) { | ||||||
|     options = Object.assign({ |     options = Object.assign({ | ||||||
|         trim: false, |         trim: false, | ||||||
| @@ -22,10 +27,10 @@ async function getRenderedContent(note, options = {}) { | |||||||
|     const $renderedContent = $('<div class="rendered-note-content">'); |     const $renderedContent = $('<div class="rendered-note-content">'); | ||||||
|  |  | ||||||
|     if (type === 'text') { |     if (type === 'text') { | ||||||
|         const noteComplement = await froca.getNoteComplement(note.noteId); |         const blob = await note.getBlob({ preview: options.trim }); | ||||||
|  |  | ||||||
|         if (!utils.isHtmlEmpty(noteComplement.content)) { |         if (!utils.isHtmlEmpty(blob.content)) { | ||||||
|             $renderedContent.append($('<div class="ck-content">').html(trim(noteComplement.content, options.trim))); |             $renderedContent.append($('<div class="ck-content">').html(trim(blob.content, options.trim))); | ||||||
|  |  | ||||||
|             if ($renderedContent.find('span.math-tex').length > 0) { |             if ($renderedContent.find('span.math-tex').length > 0) { | ||||||
|                 await libraryLoader.requireLibrary(libraryLoader.KATEX); |                 await libraryLoader.requireLibrary(libraryLoader.KATEX); | ||||||
| @@ -108,8 +113,8 @@ async function getRenderedContent(note, options = {}) { | |||||||
|     else if (type === 'mermaid') { |     else if (type === 'mermaid') { | ||||||
|         await libraryLoader.requireLibrary(libraryLoader.MERMAID); |         await libraryLoader.requireLibrary(libraryLoader.MERMAID); | ||||||
|  |  | ||||||
|         const noteComplement = await froca.getNoteComplement(note.noteId); |         const blob = await note.getBlob(); | ||||||
|         const content = noteComplement.content || ""; |         const content = blob.content || ""; | ||||||
|  |  | ||||||
|         $renderedContent |         $renderedContent | ||||||
|             .css("display", "flex") |             .css("display", "flex") | ||||||
| @@ -140,8 +145,8 @@ async function getRenderedContent(note, options = {}) { | |||||||
|         // make sure surrounding container has size of what is visible. Then image is shrinked to its boundaries |         // make sure surrounding container has size of what is visible. Then image is shrinked to its boundaries | ||||||
|         $renderedContent.css({height: "100%", width:"100%"}); |         $renderedContent.css({height: "100%", width:"100%"}); | ||||||
|  |  | ||||||
|         const noteComplement = await froca.getNoteComplement(note.noteId); |         const blob = await note.getBlob(); | ||||||
|         const content = noteComplement.content || ""; |         const content = blob.content || ""; | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             const placeHolderSVG = "<svg />"; |             const placeHolderSVG = "<svg />"; | ||||||
|   | |||||||
| @@ -99,8 +99,8 @@ export default class MermaidWidget extends NoteContextAwareWidget { | |||||||
|     async renderSvg(cb) { |     async renderSvg(cb) { | ||||||
|         idCounter++; |         idCounter++; | ||||||
|  |  | ||||||
|         const noteComplement = await froca.getNoteComplement(this.noteId); |         const blob = await this.note.getBlob(); | ||||||
|         const content = noteComplement.content || ""; |         const content = blob.content || ""; | ||||||
|  |  | ||||||
|         // this can't be promisified since in case of error this both calls callback with error SVG and throws exception |         // this can't be promisified since in case of error this both calls callback with error SVG and throws exception | ||||||
|         // with error details |         // with error details | ||||||
|   | |||||||
| @@ -19,18 +19,22 @@ export default class NoteContextAwareWidget extends BasicWidget { | |||||||
|         return this.noteId === noteId; |         return this.noteId === noteId; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** @returns {FNote|undefined} */ | ||||||
|     get note() { |     get note() { | ||||||
|         return this.noteContext?.note; |         return this.noteContext?.note; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** @returns {string|undefined} */ | ||||||
|     get noteId() { |     get noteId() { | ||||||
|         return this.note?.noteId; |         return this.note?.noteId; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** @returns {string|undefined} */ | ||||||
|     get notePath() { |     get notePath() { | ||||||
|         return this.noteContext?.notePath; |         return this.noteContext?.notePath; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** @returns {string} */ | ||||||
|     get hoistedNoteId() { |     get hoistedNoteId() { | ||||||
|         return this.noteContext?.hoistedNoteId; |         return this.noteContext?.hoistedNoteId; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -143,9 +143,9 @@ export default class NoteTypeWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async confirmChangeIfContent() { |     async confirmChangeIfContent() { | ||||||
|         const noteComplement = await this.noteContext.getNoteComplement(); |         const blob = await this.note.getBlob(); | ||||||
|  |  | ||||||
|         if (!noteComplement.content || !noteComplement.content.trim().length) { |         if (!blob.content || !blob.content.trim().length) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -134,9 +134,9 @@ export default class FilePropertiesWidget extends NoteContextAwareWidget { | |||||||
|         this.$fileName.text(attributeMap.originalFileName || "?"); |         this.$fileName.text(attributeMap.originalFileName || "?"); | ||||||
|         this.$fileType.text(note.mime); |         this.$fileType.text(note.mime); | ||||||
|  |  | ||||||
|         const noteComplement = await this.noteContext.getNoteComplement(); |         const blob = await this.note.getBlob(); | ||||||
|  |  | ||||||
|         this.$fileSize.text(`${noteComplement.contentLength} bytes`); |         this.$fileSize.text(`${blob.contentLength} bytes`); | ||||||
|  |  | ||||||
|         // open doesn't work for protected notes since it works through browser which isn't in protected session |         // open doesn't work for protected notes since it works through browser which isn't in protected session | ||||||
|         this.$openButton.toggle(!note.isProtected); |         this.$openButton.toggle(!note.isProtected); | ||||||
|   | |||||||
| @@ -116,10 +116,10 @@ export default class ImagePropertiesWidget extends NoteContextAwareWidget { | |||||||
|  |  | ||||||
|         this.$widget.show(); |         this.$widget.show(); | ||||||
|  |  | ||||||
|         const noteComplement = await this.noteContext.getNoteComplement(); |         const blob = await this.note.getBlob(); | ||||||
|  |  | ||||||
|         this.$fileName.text(attributeMap.originalFileName || "?"); |         this.$fileName.text(attributeMap.originalFileName || "?"); | ||||||
|         this.$fileSize.text(`${noteComplement.contentLength} bytes`); |         this.$fileSize.text(`${blob.contentLength} bytes`); | ||||||
|         this.$fileType.text(note.mime); |         this.$fileType.text(note.mime); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -120,23 +120,22 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async refreshWithNote(note) { |     async refreshWithNote(note) { | ||||||
|         const noteComplement = await this.noteContext.getNoteComplement(); |         const metadata = await server.get(`notes/${this.noteId}/metadata`); | ||||||
|  |  | ||||||
|         this.$noteId.text(note.noteId); |         this.$noteId.text(note.noteId); | ||||||
|         this.$dateCreated |         this.$dateCreated | ||||||
|             .text(noteComplement.dateCreated.substr(0, 16)) |             .text(metadata.dateCreated.substr(0, 16)) | ||||||
|             .attr("title", noteComplement.dateCreated); |             .attr("title", metadata.dateCreated); | ||||||
|  |  | ||||||
|         this.$dateModified |         this.$dateModified | ||||||
|             .text(noteComplement.combinedDateModified.substr(0, 16)) |             .text(metadata.combinedDateModified.substr(0, 16)) | ||||||
|             .attr("title", noteComplement.combinedDateModified); |             .attr("title", metadata.combinedDateModified); | ||||||
|  |  | ||||||
|         this.$type.text(note.type); |         this.$type.text(note.type); | ||||||
|  |  | ||||||
|         if (note.mime) { |         if (note.mime) { | ||||||
|             this.$mime.text(`(${note.mime})`); |             this.$mime.text(`(${note.mime})`); | ||||||
|         } |         } else { | ||||||
|         else { |  | ||||||
|             this.$mime.empty(); |             this.$mime.empty(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -156,7 +156,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | |||||||
|         this.currentNoteId = note.noteId; |         this.currentNoteId = note.noteId; | ||||||
|  |  | ||||||
|         // get note from backend and put into canvas |         // get note from backend and put into canvas | ||||||
|         const noteComplement = await froca.getNoteComplement(note.noteId); |         const blob = await note.getBlob(); | ||||||
|  |  | ||||||
|         // before we load content into excalidraw, make sure excalidraw has loaded |         // before we load content into excalidraw, make sure excalidraw has loaded | ||||||
|         while (!this.excalidrawRef || !this.excalidrawRef.current) { |         while (!this.excalidrawRef || !this.excalidrawRef.current) { | ||||||
| @@ -170,7 +170,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | |||||||
|          * note into this fresh note. Probably due to that this note-instance does not get |          * note into this fresh note. Probably due to that this note-instance does not get | ||||||
|          * newly instantiated? |          * newly instantiated? | ||||||
|          */ |          */ | ||||||
|         if (this.excalidrawRef.current && noteComplement.content?.trim() === "") { |         if (this.excalidrawRef.current && blob.content?.trim() === "") { | ||||||
|             const sceneData = { |             const sceneData = { | ||||||
|                 elements: [], |                 elements: [], | ||||||
|                 appState: { |                 appState: { | ||||||
| @@ -181,16 +181,16 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | |||||||
|  |  | ||||||
|             this.excalidrawRef.current.updateScene(sceneData); |             this.excalidrawRef.current.updateScene(sceneData); | ||||||
|         } |         } | ||||||
|         else if (this.excalidrawRef.current && noteComplement.content) { |         else if (this.excalidrawRef.current && blob.content) { | ||||||
|             // load saved content into excalidraw canvas |             // load saved content into excalidraw canvas | ||||||
|             let content; |             let content; | ||||||
|  |  | ||||||
|             try { |             try { | ||||||
|                 content = JSON.parse(noteComplement.content || ""); |                 content = JSON.parse(blob.content || ""); | ||||||
|             } catch(err) { |             } catch(err) { | ||||||
|                 console.error("Error parsing content. Probably note.type changed", |                 console.error("Error parsing content. Probably note.type changed", | ||||||
|                               "Starting with empty canvas" |                               "Starting with empty canvas" | ||||||
|                               , note, noteComplement, err); |                               , note, blob, err); | ||||||
|  |  | ||||||
|                 content = { |                 content = { | ||||||
|                     elements: [], |                     elements: [], | ||||||
|   | |||||||
| @@ -69,12 +69,12 @@ export default class EditableCodeTypeWidget extends TypeWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async doRefresh(note) { |     async doRefresh(note) { | ||||||
|         const noteComplement = await this.noteContext.getNoteComplement(); |         const blob = await this.note.getBlob(); | ||||||
|  |  | ||||||
|         await this.spacedUpdate.allowUpdateWithoutChange(() => { |         await this.spacedUpdate.allowUpdateWithoutChange(() => { | ||||||
|             // CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check) |             // CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check) | ||||||
|             // we provide fallback |             // we provide fallback | ||||||
|             this.codeEditor.setValue(noteComplement.content || ""); |             this.codeEditor.setValue(blob.content || ""); | ||||||
|             this.codeEditor.clearHistory(); |             this.codeEditor.clearHistory(); | ||||||
|  |  | ||||||
|             let info = CodeMirror.findModeByMIME(note.mime); |             let info = CodeMirror.findModeByMIME(note.mime); | ||||||
|   | |||||||
| @@ -183,10 +183,10 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async doRefresh(note) { |     async doRefresh(note) { | ||||||
|         const noteComplement = await froca.getNoteComplement(note.noteId); |         const blob = await note.getBlob(); | ||||||
|  |  | ||||||
|         await this.spacedUpdate.allowUpdateWithoutChange(() => { |         await this.spacedUpdate.allowUpdateWithoutChange(() => { | ||||||
|             this.watchdog.editor.setData(noteComplement.content || ""); |             this.watchdog.editor.setData(blob.content || ""); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ export default class FileTypeWidget extends TypeWidget { | |||||||
|     async doRefresh(note) { |     async doRefresh(note) { | ||||||
|         this.$widget.show(); |         this.$widget.show(); | ||||||
|  |  | ||||||
|         const noteComplement = await this.noteContext.getNoteComplement(); |         const blob = await this.note.getBlob(); | ||||||
|  |  | ||||||
|         this.$previewContent.empty().hide(); |         this.$previewContent.empty().hide(); | ||||||
|         this.$pdfPreview.attr('src', '').empty().hide(); |         this.$pdfPreview.attr('src', '').empty().hide(); | ||||||
| @@ -60,9 +60,9 @@ export default class FileTypeWidget extends TypeWidget { | |||||||
|         this.$videoPreview.hide(); |         this.$videoPreview.hide(); | ||||||
|         this.$audioPreview.hide(); |         this.$audioPreview.hide(); | ||||||
|  |  | ||||||
|         if (noteComplement.content) { |         if (blob.content) { | ||||||
|             this.$previewContent.show().scrollTop(0); |             this.$previewContent.show().scrollTop(0); | ||||||
|             this.$previewContent.text(noteComplement.content); |             this.$previewContent.text(blob.content); | ||||||
|         } |         } | ||||||
|         else if (note.mime === 'application/pdf') { |         else if (note.mime === 'application/pdf') { | ||||||
|             this.$pdfPreview.show().attr("src", openService.getUrlForDownload(`api/notes/${this.noteId}/open`)); |             this.$pdfPreview.show().attr("src", openService.getUrlForDownload(`api/notes/${this.noteId}/open`)); | ||||||
|   | |||||||
| @@ -27,9 +27,9 @@ export default class ReadOnlyCodeTypeWidget extends TypeWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async doRefresh(note) { |     async doRefresh(note) { | ||||||
|         const noteComplement = await this.noteContext.getNoteComplement(); |         const blob = await this.note.getBlob(); | ||||||
|  |  | ||||||
|         this.$content.text(noteComplement.content); |         this.$content.text(blob.content); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async executeWithContentElementEvent({resolve, ntxId}) { |     async executeWithContentElementEvent({resolve, ntxId}) { | ||||||
|   | |||||||
| @@ -93,9 +93,9 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget { | |||||||
|         // (see https://github.com/zadam/trilium/issues/1590 for example of such conflict) |         // (see https://github.com/zadam/trilium/issues/1590 for example of such conflict) | ||||||
|         await libraryLoader.requireLibrary(libraryLoader.CKEDITOR); |         await libraryLoader.requireLibrary(libraryLoader.CKEDITOR); | ||||||
|  |  | ||||||
|         const noteComplement = await froca.getNoteComplement(note.noteId); |         const blob = await note.getBlob(); | ||||||
|  |  | ||||||
|         this.$content.html(noteComplement.content); |         this.$content.html(blob.content); | ||||||
|  |  | ||||||
|         this.$content.find("a.reference-link").each(async (_, el) => { |         this.$content.find("a.reference-link").each(async (_, el) => { | ||||||
|             const notePath = $(el).attr('href'); |             const notePath = $(el).attr('href'); | ||||||
|   | |||||||
| @@ -197,11 +197,11 @@ export default class RelationMapTypeWidget extends TypeWidget { | |||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         const noteComplement = await this.noteContext.getNoteComplement(); |         const blob = await this.note.getBlob(); | ||||||
|  |  | ||||||
|         if (noteComplement.content) { |         if (blob.content) { | ||||||
|             try { |             try { | ||||||
|                 this.mapData = JSON.parse(noteComplement.content); |                 this.mapData = JSON.parse(blob.content); | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.log("Could not parse content: ", e); |                 console.log("Could not parse content: ", e); | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -4,9 +4,9 @@ const utils = require("../../services/utils"); | |||||||
| const blobService = require("../../services/blob.js"); | const blobService = require("../../services/blob.js"); | ||||||
|  |  | ||||||
| function getAttachmentBlob(req) { | function getAttachmentBlob(req) { | ||||||
|     const full = req.query.full === 'true'; |     const preview = req.query.preview === 'true'; | ||||||
|  |  | ||||||
|     return blobService.getBlobPojo('attachments', req.params.attachmentId, { full }); |     return blobService.getBlobPojo('attachments', req.params.attachmentId, { preview }); | ||||||
| } | } | ||||||
|  |  | ||||||
| function getAttachments(req) { | function getAttachments(req) { | ||||||
|   | |||||||
| @@ -10,9 +10,9 @@ const becca = require("../../becca/becca"); | |||||||
| const blobService = require("../../services/blob.js"); | const blobService = require("../../services/blob.js"); | ||||||
|  |  | ||||||
| function getNoteRevisionBlob(req) { | function getNoteRevisionBlob(req) { | ||||||
|     const full = req.query.full === 'true'; |     const preview = req.query.preview === 'true'; | ||||||
|  |  | ||||||
|     return blobService.getBlobPojo('note_revisions', req.params.noteRevisionId, { full }); |     return blobService.getBlobPojo('note_revisions', req.params.noteRevisionId, { preview }); | ||||||
| } | } | ||||||
|  |  | ||||||
| function getNoteRevisions(req) { | function getNoteRevisions(req) { | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ const sql = require('../../services/sql'); | |||||||
| const utils = require('../../services/utils'); | const utils = require('../../services/utils'); | ||||||
| const log = require('../../services/log'); | const log = require('../../services/log'); | ||||||
| const TaskContext = require('../../services/task_context'); | const TaskContext = require('../../services/task_context'); | ||||||
| const fs = require('fs'); |  | ||||||
| const becca = require("../../becca/becca"); | const becca = require("../../becca/becca"); | ||||||
| const ValidationError = require("../../errors/validation_error"); | const ValidationError = require("../../errors/validation_error"); | ||||||
| const NotFoundError = require("../../errors/not_found_error"); | const NotFoundError = require("../../errors/not_found_error"); | ||||||
| @@ -18,31 +17,27 @@ function getNote(req) { | |||||||
|         throw new NotFoundError(`Note '${req.params.noteId}' has not been found.`); |         throw new NotFoundError(`Note '${req.params.noteId}' has not been found.`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const pojo = note.getPojo(); |     return note; | ||||||
|  | } | ||||||
|  |  | ||||||
|     if (note.hasStringContent()) { | function getNoteBlob(req) { | ||||||
|         pojo.content = note.getContent(); |     const preview = req.query.preview === 'true'; | ||||||
|  |  | ||||||
|         // FIXME: use blobs instead |     return blobService.getBlobPojo('notes', req.params.noteId, { preview }); | ||||||
|         if (note.type === 'file' && pojo.content.length > 10000) { | } | ||||||
|             pojo.content = `${pojo.content.substr(0, 10000)}\r\n\r\n... and ${pojo.content.length - 10000} more characters.`; |  | ||||||
|         } | function getNoteMetadata(req) { | ||||||
|  |     const note = becca.getNote(req.params.noteId); | ||||||
|  |     if (!note) { | ||||||
|  |         throw new NotFoundError(`Note '${req.params.noteId}' has not been found.`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const contentMetadata = note.getContentMetadata(); |     const contentMetadata = note.getContentMetadata(); | ||||||
|  |  | ||||||
|     pojo.contentLength = contentMetadata.contentLength; |     return { | ||||||
|  |         dateCreated: note.dateCreated, | ||||||
|     pojo.combinedUtcDateModified = note.utcDateModified > contentMetadata.utcDateModified ? note.utcDateModified : contentMetadata.utcDateModified; |         combinedDateModified: note.utcDateModified > contentMetadata.utcDateModified ? note.dateModified : contentMetadata.dateModified | ||||||
|     pojo.combinedDateModified = note.utcDateModified > contentMetadata.utcDateModified ? note.dateModified : contentMetadata.dateModified; |     }; | ||||||
|  |  | ||||||
|     return pojo; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function getNoteBlob(req) { |  | ||||||
|     const full = req.query.full === 'true'; |  | ||||||
|  |  | ||||||
|     return blobService.getBlobPojo('notes', req.params.noteId, { full }); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function createNote(req) { | function createNote(req) { | ||||||
| @@ -266,6 +261,7 @@ function convertNoteToAttachment(req) { | |||||||
| module.exports = { | module.exports = { | ||||||
|     getNote, |     getNote, | ||||||
|     getNoteBlob, |     getNoteBlob, | ||||||
|  |     getNoteMetadata, | ||||||
|     updateNoteData, |     updateNoteData, | ||||||
|     deleteNote, |     deleteNote, | ||||||
|     undeleteNote, |     undeleteNote, | ||||||
|   | |||||||
| @@ -113,6 +113,7 @@ function register(app) { | |||||||
|  |  | ||||||
|     apiRoute(GET, '/api/notes/:noteId', notesApiRoute.getNote); |     apiRoute(GET, '/api/notes/:noteId', notesApiRoute.getNote); | ||||||
|     apiRoute(GET, '/api/notes/:noteId/blob', notesApiRoute.getNoteBlob); |     apiRoute(GET, '/api/notes/:noteId/blob', notesApiRoute.getNoteBlob); | ||||||
|  |     apiRoute(GET, '/api/notes/:noteId/metadata', notesApiRoute.getNoteMetadata); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/data', notesApiRoute.updateNoteData); |     apiRoute(PUT, '/api/notes/:noteId/data', notesApiRoute.updateNoteData); | ||||||
|     apiRoute(DEL, '/api/notes/:noteId', notesApiRoute.deleteNote); |     apiRoute(DEL, '/api/notes/:noteId', notesApiRoute.deleteNote); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/undelete', notesApiRoute.undeleteNote); |     apiRoute(PUT, '/api/notes/:noteId/undelete', notesApiRoute.undeleteNote); | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ const becca = require('../becca/becca'); | |||||||
| const NotFoundError = require("../errors/not_found_error"); | const NotFoundError = require("../errors/not_found_error"); | ||||||
|  |  | ||||||
| function getBlobPojo(entityName, entityId, opts = {}) { | function getBlobPojo(entityName, entityId, opts = {}) { | ||||||
|     opts.full = !!opts.full; |     opts.preview = !!opts.preview; | ||||||
|  |  | ||||||
|     const entity = becca.getEntity(entityName, entityId); |     const entity = becca.getEntity(entityName, entityId); | ||||||
|  |  | ||||||
| @@ -16,7 +16,7 @@ function getBlobPojo(entityName, entityId, opts = {}) { | |||||||
|  |  | ||||||
|     if (!entity.hasStringContent()) { |     if (!entity.hasStringContent()) { | ||||||
|         pojo.content = null; |         pojo.content = null; | ||||||
|     } else if (!opts.full && pojo.content.length > 10000) { |     } else if (opts.preview && pojo.content.length > 10000) { | ||||||
|         pojo.content = `${pojo.content.substr(0, 10000)}\r\n\r\n... and ${pojo.content.length - 10000} more characters.`; |         pojo.content = `${pojo.content.substr(0, 10000)}\r\n\r\n... and ${pojo.content.length - 10000} more characters.`; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user