HackMD/lib/history.js
Sheogorath b5fc6db75d
Rework debug logging
We have various places with overly simple if statements that could be
handled by our logging library. Also a lot of those logs are not marked
as debug logs but as info logs, which can cause confusion during
debugging.

This patch removed unneeded if clauses around debug logging statements,
reworks debug log messages towards ECMA templates and add some new
logging statements which might be helpful in order to debug things like
image uploads.

Signed-off-by: Sheogorath <sheogorath@shivering-isles.com>
2019-06-08 21:27:29 +02:00

200 lines
5.8 KiB
JavaScript

'use strict'
// history
// external modules
var LZString = require('lz-string')
// core
var logger = require('./logger')
var response = require('./response')
var models = require('./models')
// public
var History = {
historyGet: historyGet,
historyPost: historyPost,
historyDelete: historyDelete,
updateHistory: updateHistory
}
function getHistory (userid, callback) {
models.User.findOne({
where: {
id: userid
}
}).then(function (user) {
if (!user) {
return callback(null, null)
}
var history = {}
if (user.history) {
history = JSON.parse(user.history)
// migrate LZString encoded note id to base64url encoded note id
for (let i = 0, l = history.length; i < l; i++) {
// Calculate minimal string length for an UUID that is encoded
// base64 encoded and optimize comparsion by using -1
// this should make a lot of LZ-String parsing errors obsolete
// as we can assume that a nodeId that is 48 chars or longer is a
// noteID.
const base64UuidLength = ((4 * 36) / 3) - 1
if (!(history[i].id.length > base64UuidLength)) {
continue
}
try {
let id = LZString.decompressFromBase64(history[i].id)
if (id && models.Note.checkNoteIdValid(id)) {
history[i].id = models.Note.encodeNoteId(id)
}
} catch (err) {
// most error here comes from LZString, ignore
if (err.message === 'Cannot read property \'charAt\' of undefined') {
logger.warning('Looks like we can not decode "' + history[i].id + '" with LZString. Can be ignored.')
} else {
logger.error(err)
}
}
}
history = parseHistoryToObject(history)
}
logger.debug(`read history success: ${user.id}`)
return callback(null, history)
}).catch(function (err) {
logger.error('read history failed: ' + err)
return callback(err, null)
})
}
function setHistory (userid, history, callback) {
models.User.update({
history: JSON.stringify(parseHistoryToArray(history))
}, {
where: {
id: userid
}
}).then(function (count) {
return callback(null, count)
}).catch(function (err) {
logger.error('set history failed: ' + err)
return callback(err, null)
})
}
function updateHistory (userid, noteId, document, time) {
if (userid && noteId && typeof document !== 'undefined') {
getHistory(userid, function (err, history) {
if (err || !history) return
if (!history[noteId]) {
history[noteId] = {}
}
var noteHistory = history[noteId]
var noteInfo = models.Note.parseNoteInfo(document)
noteHistory.id = noteId
noteHistory.text = noteInfo.title
noteHistory.time = time || Date.now()
noteHistory.tags = noteInfo.tags
setHistory(userid, history, function (err, count) {
if (err) {
logger.log(err)
}
})
})
}
}
function parseHistoryToArray (history) {
var _history = []
Object.keys(history).forEach(function (key) {
var item = history[key]
_history.push(item)
})
return _history
}
function parseHistoryToObject (history) {
var _history = {}
for (var i = 0, l = history.length; i < l; i++) {
var item = history[i]
_history[item.id] = item
}
return _history
}
function historyGet (req, res) {
if (req.isAuthenticated()) {
getHistory(req.user.id, function (err, history) {
if (err) return response.errorInternalError(res)
if (!history) return response.errorNotFound(res)
res.send({
history: parseHistoryToArray(history)
})
})
} else {
return response.errorForbidden(res)
}
}
function historyPost (req, res) {
if (req.isAuthenticated()) {
var noteId = req.params.noteId
if (!noteId) {
if (typeof req.body['history'] === 'undefined') return response.errorBadRequest(res)
logger.debug(`SERVER received history from [${req.user.id}]: ${req.body.history}`)
try {
var history = JSON.parse(req.body.history)
} catch (err) {
return response.errorBadRequest(res)
}
if (Array.isArray(history)) {
setHistory(req.user.id, history, function (err, count) {
if (err) return response.errorInternalError(res)
res.end()
})
} else {
return response.errorBadRequest(res)
}
} else {
if (typeof req.body['pinned'] === 'undefined') return response.errorBadRequest(res)
getHistory(req.user.id, function (err, history) {
if (err) return response.errorInternalError(res)
if (!history) return response.errorNotFound(res)
if (!history[noteId]) return response.errorNotFound(res)
if (req.body.pinned === 'true' || req.body.pinned === 'false') {
history[noteId].pinned = (req.body.pinned === 'true')
setHistory(req.user.id, history, function (err, count) {
if (err) return response.errorInternalError(res)
res.end()
})
} else {
return response.errorBadRequest(res)
}
})
}
} else {
return response.errorForbidden(res)
}
}
function historyDelete (req, res) {
if (req.isAuthenticated()) {
var noteId = req.params.noteId
if (!noteId) {
setHistory(req.user.id, [], function (err, count) {
if (err) return response.errorInternalError(res)
res.end()
})
} else {
getHistory(req.user.id, function (err, history) {
if (err) return response.errorInternalError(res)
if (!history) return response.errorNotFound(res)
delete history[noteId]
setHistory(req.user.id, history, function (err, count) {
if (err) return response.errorInternalError(res)
res.end()
})
})
}
} else {
return response.errorForbidden(res)
}
}
module.exports = History