diff --git a/.gitignore b/.gitignore index dd94e6ef..d46e704e 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ public/uploads/* !public/uploads/.gitkeep /.nyc_output /coverage/ + +.vscode/settings.json \ No newline at end of file diff --git a/lib/auth/gitlab/index.js b/lib/auth/gitlab/index.js index 72ab0cde..ab4f6900 100644 --- a/lib/auth/gitlab/index.js +++ b/lib/auth/gitlab/index.js @@ -18,8 +18,8 @@ const gitlabAuthStrategy = new GitlabStrategy({ callbackURL: config.serverURL + '/auth/gitlab/callback' }, passportGeneralCallback) -if (process.env['https_proxy']) { - const httpsProxyAgent = new HttpsProxyAgent(process.env['https_proxy']) +if (process.env.https_proxy) { + const httpsProxyAgent = new HttpsProxyAgent(process.env.https_proxy) gitlabAuthStrategy._oauth2.setAgent(httpsProxyAgent) } diff --git a/lib/history/index.js b/lib/history/index.js index 3826ce98..ab8b4232 100644 --- a/lib/history/index.js +++ b/lib/history/index.js @@ -131,7 +131,7 @@ function historyPost (req, res) { if (req.isAuthenticated()) { var noteId = req.params.noteId if (!noteId) { - if (typeof req.body['history'] === 'undefined') return response.errorBadRequest(req, res) + if (typeof req.body.history === 'undefined') return response.errorBadRequest(req, res) if (config.debug) { logger.info('SERVER received history from [' + req.user.id + ']: ' + req.body.history) } try { var history = JSON.parse(req.body.history) @@ -147,7 +147,7 @@ function historyPost (req, res) { return response.errorBadRequest(req, res) } } else { - if (typeof req.body['pinned'] === 'undefined') return response.errorBadRequest(req, res) + if (typeof req.body.pinned === 'undefined') return response.errorBadRequest(req, res) getHistory(req.user.id, function (err, history) { if (err) return response.errorInternalError(req, res) if (!history) return response.errorNotFound(req, res) diff --git a/lib/note/index.js b/lib/note/index.js index f6820531..a387b59d 100644 --- a/lib/note/index.js +++ b/lib/note/index.js @@ -2,10 +2,9 @@ const config = require('../config') const logger = require('../logger') - const { Note, User } = require('../models') -const { newCheckViewPermission, errorForbidden, responseCodiMD, errorNotFound } = require('../response') +const { newCheckViewPermission, errorForbidden, responseCodiMD, errorNotFound, errorInternalError } = require('../response') const { updateHistory } = require('../history') const { actionPublish, actionSlide, actionInfo, actionDownload, actionPDF, actionGist, actionRevision, actionPandoc } = require('./noteActions') @@ -191,6 +190,49 @@ async function noteActions (req, res) { } } +async function getMyNoteList (userId, callback) { + const myNotes = await Note.findAll({ + where: { + ownerId: userId + } + }) + if (!myNotes) { + return callback(null, null) + } + try { + const myNoteList = myNotes.map(note => ({ + id: Note.encodeNoteId(note.id), + text: note.title, + tags: Note.parseNoteInfo(note.content).tags, + createdAt: note.createdAt, + lastchangeAt: note.lastchangeAt, + shortId: note.shortid + })) + if (config.debug) { + logger.info('Parse myNoteList success: ' + userId) + } + return callback(null, myNoteList) + } catch (err) { + logger.error('Parse myNoteList failed') + return callback(err, null) + } +} + +function listMyNotes (req, res) { + if (req.isAuthenticated()) { + getMyNoteList(req.user.id, (err, myNoteList) => { + if (err) return errorInternalError(req, res) + if (!myNoteList) return errorNotFound(req, res) + res.send({ + myNotes: myNoteList + }) + }) + } else { + return errorForbidden(req, res) + } +} + exports.showNote = showNote exports.showPublishNote = showPublishNote exports.noteActions = noteActions +exports.listMyNotes = listMyNotes diff --git a/lib/routes.js b/lib/routes.js index f4345039..48ac61f3 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -70,6 +70,8 @@ appRouter.get('/s/:shortid/:action', response.publishNoteActions) appRouter.get('/p/:shortid', response.showPublishSlide) // publish slide actions appRouter.get('/p/:shortid/:action', response.publishSlideActions) +// gey my note list +appRouter.get('/api/notes/myNotes', noteController.listMyNotes) // get note by id appRouter.get('/:noteId', wrap(noteController.showNote)) // note actions diff --git a/public/js/extra.js b/public/js/extra.js index 10e163d2..954a161c 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -474,7 +474,7 @@ export function finishView (view) { const { lat, lon } = data[0] position = [lat, lon] } - $elem.html(`
`) + $elem.html('
') const map = L.map($elem.find('.geo-map')[0]).setView(position, zoom || 16) L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { @@ -1017,7 +1017,7 @@ export function deduplicatedHeaderId (view) { if (window.linkifyHeaderStyle === 'gfm') { // consistent with GitHub, GitLab, Pandoc & co. // all headers contained in the document, in order of appearance - const allHeaders = view.find(`:header`).toArray() + const allHeaders = view.find(':header').toArray() // list of finaly assigned header IDs const headerIds = new Set() for (let j = 0; j < allHeaders.length; j++) { @@ -1177,7 +1177,7 @@ md.use(markdownitContainer, 'spoiler', { if (summary) { return `
${md.renderInline(summary)}\n` } else { - return `
\n` + return '
\n' } } else { // closing tag diff --git a/public/js/index.js b/public/js/index.js index f5010960..c736cb7f 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1789,7 +1789,7 @@ socket.on('reconnect', function (data) { socket.on('connect', function (data) { clearInterval(retryTimer) retryTimer = null - personalInfo['id'] = socket.id + personalInfo.id = socket.id showStatus(statusType.connected) socket.emit('version') }) @@ -2359,8 +2359,8 @@ function emitUserStatus (force) { var type = null if (visibleXS) { type = 'xs' } else if (visibleSM) { type = 'sm' } else if (visibleMD) { type = 'md' } else if (visibleLG) { type = 'lg' } - personalInfo['idle'] = idle.isAway - personalInfo['type'] = type + personalInfo.idle = idle.isAway + personalInfo.type = type for (var i = 0; i < onlineUsers.length; i++) { if (onlineUsers[i].id === personalInfo.id) { @@ -2637,7 +2637,7 @@ editorInstance.on('focus', function (editor) { onlineUsers[i].cursor = editor.getCursor() } } - personalInfo['cursor'] = editor.getCursor() + personalInfo.cursor = editor.getCursor() socket.emit('cursor focus', editor.getCursor()) }) @@ -2650,7 +2650,7 @@ function cursorActivityInner (editor) { onlineUsers[i].cursor = editor.getCursor() } } - personalInfo['cursor'] = editor.getCursor() + personalInfo.cursor = editor.getCursor() socket.emit('cursor activity', editor.getCursor()) } } @@ -2697,7 +2697,7 @@ editorInstance.on('blur', function (cm) { onlineUsers[i].cursor = null } } - personalInfo['cursor'] = null + personalInfo.cursor = null socket.emit('cursor blur') }) diff --git a/public/js/lib/editor/constants.js b/public/js/lib/editor/constants.js index 697f4514..726c4402 100644 --- a/public/js/lib/editor/constants.js +++ b/public/js/lib/editor/constants.js @@ -16,4 +16,4 @@ export const availableThemes = [ { name: 'Tomorror Night Eighties', value: 'tomorrow-night-eighties' } ] -export const emojifyImageDir = window.USE_CDN ? `https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/images/basic` : `${serverurl}/build/emojify.js/dist/images/basic` +export const emojifyImageDir = window.USE_CDN ? 'https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/images/basic' : `${serverurl}/build/emojify.js/dist/images/basic` diff --git a/public/js/lib/editor/index.js b/public/js/lib/editor/index.js index 5b7e4249..1d8a0dc7 100644 --- a/public/js/lib/editor/index.js +++ b/public/js/lib/editor/index.js @@ -592,7 +592,7 @@ export default class Editor { if (lang) { this.statusIndicators.find(`.status-spellcheck li[value="${lang}"]`).addClass('active') } else { - this.statusIndicators.find(`.status-spellcheck li[value="disabled"]`).addClass('active') + this.statusIndicators.find('.status-spellcheck li[value="disabled"]').addClass('active') } } @@ -632,7 +632,7 @@ export default class Editor { } const self = this - this.statusIndicators.find(`.status-spellcheck li`).click(function () { + this.statusIndicators.find('.status-spellcheck li').click(function () { const lang = $(this).attr('value') if (lang === 'disabled') { diff --git a/public/js/lib/editor/spellcheck.js b/public/js/lib/editor/spellcheck.js index 7ae52e61..c3d619a5 100644 --- a/public/js/lib/editor/spellcheck.js +++ b/public/js/lib/editor/spellcheck.js @@ -23,11 +23,11 @@ export const supportLanguages = [ value: 'de', aff: { url: `${serverurl}/build/dictionary-de/index.aff`, - cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de@2.0.3/index.aff` + cdnUrl: 'https://cdn.jsdelivr.net/npm/dictionary-de@2.0.3/index.aff' }, dic: { url: `${serverurl}/build/dictionary-de/index.dic`, - cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de@2.0.3/index.dic` + cdnUrl: 'https://cdn.jsdelivr.net/npm/dictionary-de@2.0.3/index.dic' } }, { @@ -35,11 +35,11 @@ export const supportLanguages = [ value: 'de_AT', aff: { url: `${serverurl}/build/dictionary-de-at/index.aff`, - cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de-at@2.0.3/index.aff` + cdnUrl: 'https://cdn.jsdelivr.net/npm/dictionary-de-at@2.0.3/index.aff' }, dic: { url: `${serverurl}/build/dictionary-de-at/index.dic`, - cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de-at@2.0.3/index.dic` + cdnUrl: 'https://cdn.jsdelivr.net/npm/dictionary-de-at@2.0.3/index.dic' } }, { @@ -47,11 +47,11 @@ export const supportLanguages = [ value: 'de_CH', aff: { url: `${serverurl}/build/dictionary-de-ch/index.aff`, - cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de-ch@2.0.3/index.aff` + cdnUrl: 'https://cdn.jsdelivr.net/npm/dictionary-de-ch@2.0.3/index.aff' }, dic: { url: `${serverurl}/build/dictionary-de-ch/index.dic`, - cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de-ch@2.0.3/index.dic` + cdnUrl: 'https://cdn.jsdelivr.net/npm/dictionary-de-ch@2.0.3/index.dic' } } ] diff --git a/public/js/lib/markdown/utils.js b/public/js/lib/markdown/utils.js index 3aeb646c..bc5ee6e9 100644 --- a/public/js/lib/markdown/utils.js +++ b/public/js/lib/markdown/utils.js @@ -7,10 +7,10 @@ export function parseFenceCodeParams (lang) { paraMatch && paraMatch.forEach(param => { param = param.trim() if (param[0] === '#') { - params['id'] = param.slice(1) + params.id = param.slice(1) } else if (param[0] === '.') { - if (params['class']) params['class'] = [] - params['class'] = params['class'].concat(param.slice(1)) + if (params.class) params.class = [] + params.class = params.class.concat(param.slice(1)) } else { const offset = param.indexOf('=') const id = param.substring(0, offset).trim().toLowerCase() @@ -21,8 +21,8 @@ export function parseFenceCodeParams (lang) { val = val.substring(1, val.length - 1) } if (id === 'class') { - if (params['class']) params['class'] = [] - params['class'] = params['class'].concat(val) + if (params.class) params.class = [] + params.class = params.class.concat(val) } else { params[id] = val } diff --git a/public/js/render.js b/public/js/render.js index ebda2984..4a9c3b25 100644 --- a/public/js/render.js +++ b/public/js/render.js @@ -12,27 +12,27 @@ var dataUriRegex = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base // custom white list var whiteList = filterXSS.whiteList // allow ol specify start number -whiteList['ol'] = ['start'] +whiteList.ol = ['start'] // allow li specify value number -whiteList['li'] = ['value'] +whiteList.li = ['value'] // allow style tag -whiteList['style'] = [] +whiteList.style = [] // allow kbd tag -whiteList['kbd'] = [] +whiteList.kbd = [] // allow ifram tag with some safe attributes -whiteList['iframe'] = ['allowfullscreen', 'name', 'referrerpolicy', 'src', 'width', 'height'] +whiteList.iframe = ['allowfullscreen', 'name', 'referrerpolicy', 'src', 'width', 'height'] // allow summary tag -whiteList['summary'] = [] +whiteList.summary = [] // allow ruby tag -whiteList['ruby'] = [] +whiteList.ruby = [] // allow rp tag for ruby -whiteList['rp'] = [] +whiteList.rp = [] // allow rt tag for ruby -whiteList['rt'] = [] +whiteList.rt = [] // allow figure tag -whiteList['figure'] = [] +whiteList.figure = [] // allow figcaption tag -whiteList['figcaption'] = [] +whiteList.figcaption = [] var filterXSSOptions = { allowCommentTag: true, diff --git a/test/realtime/dirtyNoteUpdate.test.js b/test/realtime/dirtyNoteUpdate.test.js index 0ba65131..7da1c7f4 100644 --- a/test/realtime/dirtyNoteUpdate.test.js +++ b/test/realtime/dirtyNoteUpdate.test.js @@ -50,7 +50,7 @@ describe('realtime#update note is dirty timer', function () { callback(null, note) }) - realtime.notes['note1'] = { + realtime.notes.note1 = { server: { isDirty: false }, @@ -64,7 +64,7 @@ describe('realtime#update note is dirty timer', function () { socks: [] } - realtime.notes['note2'] = note2 + realtime.notes.note2 = note2 clock.tick(1000) setTimeout(() => { @@ -75,7 +75,7 @@ describe('realtime#update note is dirty timer', function () { it('should not do anything when note missing', function (done) { sinon.stub(realtime, 'updateNote').callsFake(function (note, callback) { - delete realtime.notes['note'] + delete realtime.notes.note callback(null, note) }) @@ -85,7 +85,7 @@ describe('realtime#update note is dirty timer', function () { }, socks: [makeMockSocket()] } - realtime.notes['note'] = note + realtime.notes.note = note clock.tick(1000) @@ -115,7 +115,7 @@ describe('realtime#update note is dirty timer', function () { }, socks: [makeMockSocket(), undefined, makeMockSocket()] } - realtime.notes['note'] = note + realtime.notes.note = note clock.tick(1000) diff --git a/utils/string.js b/utils/string.js index 96f5e56e..23a308a4 100644 --- a/utils/string.js +++ b/utils/string.js @@ -1,7 +1,7 @@ 'use strict' function stripTags (s) { - return s.replace(RegExp(`]*>`, 'gi'), '') + return s.replace(RegExp(']*>', 'gi'), '') } exports.stripTags = stripTags