diff --git a/src/routes/api/clipper.js b/src/routes/api/clipper.js index 53af2ab05..273591d7f 100644 --- a/src/routes/api/clipper.js +++ b/src/routes/api/clipper.js @@ -4,22 +4,70 @@ const noteService = require('../../services/notes'); const dateNoteService = require('../../services/date_notes'); const dateUtils = require('../../services/date_utils'); const imageService = require('../../services/image'); +const appInfo = require('../../services/app_info'); const messagingService = require('../../services/messaging'); const log = require('../../services/log'); const path = require('path'); const Link = require('../../entities/link'); +async function findClippingNote(todayNote, pageUrl) { + const notes = await todayNote.getDescendantNotesWithLabel('pageUrl', pageUrl); + + for (const note of notes) { + if (await note.getLabelValue('clipType') === 'clippings') { + return note; + } + } + + return null; +} + +async function addClipping(req) { + const {title, content, pageUrl, images} = req.body; + + const todayNote = await dateNoteService.getDateNote(dateUtils.localNowDate()); + + let clippingNote = await findClippingNote(todayNote, pageUrl); + + if (!clippingNote) { + clippingNote = (await noteService.createNote(todayNote.noteId, title, '')).note; + + await clippingNote.setLabel('clipType', 'clippings'); + await clippingNote.setLabel('pageUrl', pageUrl); + } + + const rewrittenContent = await addImagesToNote(images, clippingNote, content); + + await clippingNote.setContent(await clippingNote.getContent() + rewrittenContent); + + return { + noteId: clippingNote.noteId + }; +} + async function createNote(req) { - const {title, content, url, images} = req.body; + const {title, content, pageUrl, images} = req.body; const todayNote = await dateNoteService.getDateNote(dateUtils.localNowDate()); const {note} = await noteService.createNote(todayNote.noteId, title, content); - if (url) { - await note.setLabel('sourceUrl', url); + await note.setLabel('clipType', 'note'); + + if (pageUrl) { + await note.setLabel('pageUrl', pageUrl); } + const rewrittenContent = await addImagesToNote(images, note, content); + + await note.setContent(rewrittenContent); + + return { + noteId: note.noteId + }; +} + +async function addImagesToNote(images, note, content) { let rewrittenContent = content; if (images) { @@ -47,19 +95,16 @@ async function createNote(req) { } } - await note.setContent(rewrittenContent); - - return { - noteId: note.noteId - }; + return rewrittenContent; } async function createImage(req) { - let {dataUrl, title, sourceUrl, pageUrl} = req.body; + let {dataUrl, title, imageUrl, pageUrl} = req.body; if (!dataUrl) { - dataUrl = sourceUrl; - sourceUrl = null; + // this is image inlined into the src attribute so there isn't any source image URL + dataUrl = imageUrl; + imageUrl = null; } if (!dataUrl.startsWith("data:image/")) { @@ -69,8 +114,8 @@ async function createImage(req) { return [400, message]; } - if (!title && sourceUrl) { - title = path.basename(sourceUrl); + if (!title && imageUrl) { + title = path.basename(imageUrl); } if (!title) { @@ -83,8 +128,10 @@ async function createImage(req) { const {note} = await imageService.saveImage(buffer, title, todayNote.noteId, true); - if (sourceUrl) { - await note.setLabel('sourceUrl', sourceUrl); + await note.setLabel('clipType', 'image'); + + if (imageUrl) { + await note.setLabel('imageUrl', imageUrl); } if (pageUrl) { @@ -105,15 +152,17 @@ async function openNote(req) { return {}; } -async function ping(req, res) { - console.log("PING!!!!"); - - res.status(200).send("TriliumClipperServer"); +async function handshake() { + return { + appName: "trilium", + appVersion: appInfo.appVersion + } } module.exports = { createNote, createImage, + addClipping, openNote, - ping + handshake }; \ No newline at end of file diff --git a/src/routes/routes.js b/src/routes/routes.js index 232687057..eabb7319c 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -225,10 +225,11 @@ function register(app) { apiRoute(POST, '/api/login/protected', loginApiRoute.loginToProtectedSession); route(POST, '/api/login/token', [], loginApiRoute.token, apiResultHandler); + route(GET, '/api/clipper/handshake', [], clipperRoute.handshake, apiResultHandler); + route(POST, '/api/clipper/clippings', [], clipperRoute.addClipping, apiResultHandler); route(POST, '/api/clipper/notes', [], clipperRoute.createNote, apiResultHandler); route(POST, '/api/clipper/image', [], clipperRoute.createImage, apiResultHandler); route(POST, '/api/clipper/open/:noteId', [], clipperRoute.openNote, apiResultHandler); - route(GET, '/api/clipper/ping', [], clipperRoute.ping); app.use('', router); } diff --git a/src/services/app_info.js b/src/services/app_info.js index 6b59dc536..2787ba67c 100644 --- a/src/services/app_info.js +++ b/src/services/app_info.js @@ -6,7 +6,6 @@ const {TRILIUM_DATA_DIR} = require('./data_dir'); const APP_DB_VERSION = 136; const SYNC_VERSION = 9; -const CLIPPER_VERSION = 1; module.exports = { appVersion: packageJson.version, diff --git a/src/services/date_notes.js b/src/services/date_notes.js index d8b85f75e..89d282179 100644 --- a/src/services/date_notes.js +++ b/src/services/date_notes.js @@ -29,6 +29,7 @@ async function getNoteStartingWith(parentNoteId, startsWith) { AND branches.isDeleted = 0`, [parentNoteId]); } +/** @return {Promise} */ async function getRootCalendarNote() { // some caching here could be useful (e.g. in CLS) let rootNote = await attributeService.getNoteWithLabel(CALENDAR_ROOT_LABEL); @@ -47,6 +48,7 @@ async function getRootCalendarNote() { return rootNote; } +/** @return {Promise} */ async function getYearNote(dateStr, rootNote) { if (!rootNote) { rootNote = await getRootCalendarNote(); @@ -79,6 +81,7 @@ async function getMonthNoteTitle(rootNote, monthNumber, dateObj) { .replace(/{month}/g, monthName); } +/** @return {Promise} */ async function getMonthNote(dateStr, rootNote) { const monthStr = dateStr.substr(0, 7); const monthNumber = dateStr.substr(5, 2); @@ -116,6 +119,7 @@ async function getDateNoteTitle(rootNote, dayNumber, dateObj) { .replace(/{weekDay2}/g, weekDay.substr(0, 2)); } +/** @return {Promise} */ async function getDateNote(dateStr) { const rootNote = await getRootCalendarNote();