diff --git a/src/app.js b/src/app.js index 578517eb1..4becd4c67 100644 --- a/src/app.js +++ b/src/app.js @@ -56,7 +56,7 @@ app.use((req, res, next) => { // error handler app.use((err, req, res, next) => { - log.error(err.message); + log.info(err); res.status(err.status || 500); res.send({ diff --git a/src/entities/attribute.js b/src/entities/attribute.js index 2cecc29dd..0504a5696 100644 --- a/src/entities/attribute.js +++ b/src/entities/attribute.js @@ -4,7 +4,7 @@ const Entity = require('./entity'); class Attribute extends Entity { async getNote() { - return this.sql.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]); + return this.repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]); } } diff --git a/src/entities/entity.js b/src/entities/entity.js index 0228fab42..71e6dc1ea 100644 --- a/src/entities/entity.js +++ b/src/entities/entity.js @@ -1,8 +1,12 @@ "use strict"; +const utils = require('../services/utils'); + class Entity { - constructor(sql, row) { - this.sql = sql; + constructor(repository, row) { + utils.assertArguments(repository, row) + + this.repository = repository; for (const key in row) { this[key] = row[key]; diff --git a/src/entities/note.js b/src/entities/note.js index 35a0b0e3b..6409630e1 100644 --- a/src/entities/note.js +++ b/src/entities/note.js @@ -3,28 +3,32 @@ const Entity = require('./entity'); class Note extends Entity { - constructor(sql, row) { - super(sql, row); + constructor(repository, row) { + super(repository, row); - if (this.type === "code" && this.mime === "application/json") { + if (this.isJson()) { this.jsonContent = JSON.parse(this.content); } } + isJson() { + return this.type === "code" && this.mime === "application/json"; + } + async getAttributes() { - return this.sql.getEntities("SELECT * FROM attributes WHERE noteId = ?", [this.noteId]); + return this.repository.getEntities("SELECT * FROM attributes WHERE noteId = ?", [this.noteId]); } async getAttribute(name) { - return this.sql.getEntity("SELECT * FROM attributes WHERE noteId = ? AND name = ?", [this.noteId, name]); + return this.repository.getEntity("SELECT * FROM attributes WHERE noteId = ? AND name = ?", [this.noteId, name]); } async getRevisions() { - return this.sql.getEntities("SELECT * FROM note_revisions WHERE noteId = ?", [this.noteId]); + return this.repository.getEntities("SELECT * FROM note_revisions WHERE noteId = ?", [this.noteId]); } async getTrees() { - return this.sql.getEntities("SELECT * FROM note_tree WHERE isDeleted = 0 AND noteId = ?", [this.noteId]); + return this.repository.getEntities("SELECT * FROM note_tree WHERE isDeleted = 0 AND noteId = ?", [this.noteId]); } } diff --git a/src/entities/note_revision.js b/src/entities/note_revision.js index 17419b6e1..0e8c71f32 100644 --- a/src/entities/note_revision.js +++ b/src/entities/note_revision.js @@ -4,7 +4,7 @@ const Entity = require('./entity'); class NoteRevision extends Entity { async getNote() { - return this.sql.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]); + return this.repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]); } } diff --git a/src/entities/note_tree.js b/src/entities/note_tree.js index 391c4780b..94dee1834 100644 --- a/src/entities/note_tree.js +++ b/src/entities/note_tree.js @@ -4,11 +4,11 @@ const Entity = require('./entity'); class NoteTree extends Entity { async getNote() { - return this.sql.getEntity("SELECT * FROM note_tree WHERE isDeleted = 0 AND noteId = ?", [this.noteId]); + return this.repository.getEntity("SELECT * FROM note_tree WHERE isDeleted = 0 AND noteId = ?", [this.noteId]); } async getParentNote() { - return this.sql.getEntity("SELECT * FROM note_tree WHERE isDeleted = 0 AND parentNoteId = ?", [this.parentNoteId]); + return this.repository.getEntity("SELECT * FROM note_tree WHERE isDeleted = 0 AND parentNoteId = ?", [this.parentNoteId]); } } diff --git a/src/routes/api/script.js b/src/routes/api/script.js index 2782ccd4a..81d2b185c 100644 --- a/src/routes/api/script.js +++ b/src/routes/api/script.js @@ -4,11 +4,10 @@ const express = require('express'); const router = express.Router(); const auth = require('../../services/auth'); const wrap = require('express-promise-wrap').wrap; -const sql = require('../../services/sql'); const notes = require('../../services/notes'); -const protected_session = require('../../services/protected_session'); const attributes = require('../../services/attributes'); const script = require('../../services/script'); +const Repository = require('../../services/repository'); router.post('/exec/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { const noteId = req.params.noteId; @@ -33,9 +32,11 @@ router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => { router.get('/subtree/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { const noteId = req.params.noteId; - const noteScript = (await notes.getNoteById(noteId, req)).content; + const repository = new Repository(req); - const subTreeScripts = await getSubTreeScripts(noteId, [noteId], req); + const noteScript = (await repository.getNote(noteId)).content; + + const subTreeScripts = await getSubTreeScripts(noteId, [noteId], repository); res.send(subTreeScripts + noteScript); })); @@ -48,15 +49,14 @@ async function getNoteWithSubtreeScript(noteId, req) { return subTreeScripts + noteScript; } -async function getSubTreeScripts(parentId, includedNoteIds, dataKey) { - const children = await sql.getRows(`SELECT notes.noteId, notes.title, notes.content, notes.isProtected, notes.mime - FROM notes JOIN note_tree USING(noteId) - WHERE note_tree.isDeleted = 0 AND notes.isDeleted = 0 +async function getSubTreeScripts(parentId, includedNoteIds, repository) { + const children = await repository.getEntities(` + SELECT notes.* + FROM notes JOIN note_tree USING(noteId) + WHERE note_tree.isDeleted = 0 AND notes.isDeleted = 0 AND note_tree.parentNoteId = ? AND notes.type = 'code' AND (notes.mime = 'application/javascript' OR notes.mime = 'text/html')`, [parentId]); - protected_session.decryptNotes(dataKey, children); - let script = "\r\n"; for (const child of children) { @@ -66,7 +66,7 @@ async function getSubTreeScripts(parentId, includedNoteIds, dataKey) { includedNoteIds.push(child.noteId); - script += await getSubTreeScripts(child.noteId, includedNoteIds, dataKey); + script += await getSubTreeScripts(child.noteId, includedNoteIds, repository); if (child.mime === 'application/javascript') { child.content = ''; diff --git a/src/services/attributes.js b/src/services/attributes.js index 08419ef61..e365ecd04 100644 --- a/src/services/attributes.js +++ b/src/services/attributes.js @@ -3,7 +3,7 @@ const sql = require('./sql'); const utils = require('./utils'); const sync_table = require('./sync_table'); -const protected_session = require('./protected_session'); +const Repository = require('./repository'); async function getNoteAttributeMap(noteId) { return await sql.getMap(`SELECT name, value FROM attributes WHERE noteId = ?`, [noteId]); @@ -15,21 +15,19 @@ async function getNoteIdWithAttribute(name, value) { } async function getNotesWithAttribute(dataKey, name, value) { + const repository = new Repository(dataKey); + let notes; if (value !== undefined) { - notes = await sql.getEntities(`SELECT notes.* FROM notes JOIN attributes USING(noteId) + notes = await repository.getEntities(`SELECT notes.* FROM notes JOIN attributes USING(noteId) WHERE notes.isDeleted = 0 AND attributes.name = ? AND attributes.value = ?`, [name, value]); } else { - notes = await sql.getEntities(`SELECT notes.* FROM notes JOIN attributes USING(noteId) + notes = await repository.getEntities(`SELECT notes.* FROM notes JOIN attributes USING(noteId) WHERE notes.isDeleted = 0 AND attributes.name = ?`, [name]); } - for (const note of notes) { - protected_session.decryptNote(dataKey, note); - } - return notes; } diff --git a/src/services/notes.js b/src/services/notes.js index 010c533d0..38b1cf797 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -5,21 +5,6 @@ const sync_table = require('./sync_table'); const attributes = require('./attributes'); const protected_session = require('./protected_session'); -async function getNoteById(noteId, dataKey) { - const note = await sql.getEntity("SELECT * FROM notes WHERE noteId = ?", [noteId]); - - protected_session.decryptNote(dataKey, note); - - return note; -} - -async function getJsonNoteById(noteId, dataKey) { - const note = await getNoteById(noteId, dataKey); - note.data = JSON.parse(note.content); - - return note; -} - async function updateJsonNote(noteId, data) { const ret = await createNewNote(noteId, { title: name, @@ -329,7 +314,6 @@ async function deleteNote(noteTreeId, sourceId) { } module.exports = { - getNoteById, createNewNote, updateNote, deleteNote, diff --git a/src/services/repository.js b/src/services/repository.js new file mode 100644 index 000000000..b13a8c54b --- /dev/null +++ b/src/services/repository.js @@ -0,0 +1,62 @@ +const sql = require('./sql'); +const protected_session = require('./protected_session'); +const Note = require('../entities/note'); +const NoteRevision = require('../entities/note_revision'); +const NoteTree = require('../entities/note_tree'); +const Attribute = require('../entities/attribute'); + +class Repository { + constructor(dataKey) { + this.dataKey = protected_session.getDataKey(dataKey); + } + + async getEntities(query, params = []) { + const rows = await sql.getRows(query, params); + + for (const row of rows) { + row.dataKey = this.dataKey; + } + + return rows.map(row => this.createEntityFromRow(row)); + } + + async getEntity(query, params = []) { + const row = await sql.getRowOrNull(query, params); + + if (!row) { + return null; + } + + row.dataKey = this.dataKey; + + return this.createEntityFromRow(row); + } + + async getNote(noteId) { + return await this.getEntity("SELECT * FROM notes WHERE noteId = ?", [noteId]); + } + + createEntityFromRow(row) { + let entity; + + if (row.attributeId) { + entity = new Attribute(this, row); + } + else if (row.noteRevisionId) { + entity = new NoteRevision(this, row); + } + else if (row.noteTreeId) { + entity = new NoteTree(this, row); + } + else if (row.noteId) { + entity = new Note(this, row); + } + else { + throw new Error('Unknown entity type for row: ' + JSON.stringify(row)); + } + + return entity; + } +} + +module.exports = Repository; \ No newline at end of file diff --git a/src/services/script_context.js b/src/services/script_context.js index a6bddba48..98edb6a77 100644 --- a/src/services/script_context.js +++ b/src/services/script_context.js @@ -5,17 +5,19 @@ const attributes = require('./attributes'); const date_notes = require('./date_notes'); const sql = require('./sql'); const sync_table = require('./sync_table'); +const Repository = require('./repository'); function ScriptContext(noteId, dataKey) { this.scriptNoteId = noteId; this.dataKey = protected_session.getDataKey(dataKey); + this.repository = new Repository(dataKey); function serializePayload(payload) { return JSON.stringify(payload, null, '\t'); } this.getNoteById = async function(noteId) { - return notes.getNoteById(noteId, this.dataKey); + return this.repository.getNote(noteId); }; this.getNotesWithAttribute = async function (attrName, attrValue) { @@ -60,7 +62,7 @@ function ScriptContext(noteId, dataKey) { }; this.updateNote = async function (note) { - if (note.type === 'code' && note.mime === 'application/json') { + if (note.isJson()) { note.content = serializePayload(note.jsonContent); } diff --git a/src/services/sql.js b/src/services/sql.js index cbbd732d4..8b52df374 100644 --- a/src/services/sql.js +++ b/src/services/sql.js @@ -6,10 +6,6 @@ const fs = require('fs'); const sqlite = require('sqlite'); const app_info = require('./app_info'); const resource_dir = require('./resource_dir'); -const Note = require('../entities/note'); -const NoteRevision = require('../entities/note_revision'); -const NoteTree = require('../entities/note_tree'); -const Attribute = require('../entities/attribute'); async function createConnection() { return await sqlite.open(dataDir.DOCUMENT_PATH, {Promise}); @@ -137,45 +133,6 @@ async function getRows(query, params = []) { return await wrap(async db => db.all(query, ...params)); } -async function getEntities(query, params = []) { - const rows = await getRows(query, params); - - return rows.map(createEntityFromRow); -} - -async function getEntity(query, params = []) { - const row = await getRowOrNull(query, params); - - if (!row) { - return null; - } - - return createEntityFromRow(row); -} - -function createEntityFromRow(row) { - let entity; - let sql = module.exports; - - if (row.attributeId) { - entity = new Attribute(sql, row); - } - else if (row.noteRevisionId) { - entity = new NoteRevision(sql, row); - } - else if (row.noteTreeId) { - entity = new NoteTree(sql, row); - } - else if (row.noteId) { - entity = new Note(sql, row); - } - else { - throw new Error('Unknown entity type for row: ' + JSON.stringify(row)); - } - - return entity; -} - async function getMap(query, params = []) { const map = {}; const results = await getRows(query, params); @@ -309,8 +266,6 @@ module.exports = { getRow, getRowOrNull, getRows, - getEntities, - getEntity, getMap, getColumn, execute,