Skip to content

Commit 3e75445

Browse files
authored
Merge pull request #1557 from hackmdio/release/2.2.0
2 parents 89a0de4 + fad1947 commit 3e75445

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+2090
-244
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ public/uploads/*
2828
!public/uploads/.gitkeep
2929
/.nyc_output
3030
/coverage/
31+
32+
.vscode/settings.json

.nvmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v10.20.1

app.js

+6
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,18 @@ models.sequelize.sync().then(function () {
280280
} else {
281281
throw new Error('server still not ready after db synced')
282282
}
283+
}).catch(err => {
284+
logger.error('Can\'t sync database')
285+
logger.error(err.stack)
286+
logger.error('Process will exit now.')
287+
process.exit(1)
283288
})
284289

285290
// log uncaught exception
286291
process.on('uncaughtException', function (err) {
287292
logger.error('An uncaught exception has occured.')
288293
logger.error(err)
294+
console.error(err)
289295
logger.error('Process will exit now.')
290296
process.exit(1)
291297
})

deployments/docker-compose.yml

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ services:
1010
- "database-data:/var/lib/postgresql/data"
1111
restart: always
1212
codimd:
13-
# you can use image or custom build below
14-
image: nabo.codimd.dev/hackmdio/hackmd:2.0.0
13+
# you can use image or custom build below,
14+
# if you need CJK character with exported PDF files,
15+
# please change the image tag with `cjk` postfix version
16+
image: nabo.codimd.dev/hackmdio/hackmd:2.1.0
17+
# image: nabo.codimd.dev/hackmdio/hackmd:2.1.0-cjk
1518
# build:
1619
# context: ..
1720
# dockerfile: ./deployments/Dockerfile

lib/auth/gitlab/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ const gitlabAuthStrategy = new GitlabStrategy({
1818
callbackURL: config.serverURL + '/auth/gitlab/callback'
1919
}, passportGeneralCallback)
2020

21-
if (process.env['https_proxy']) {
22-
const httpsProxyAgent = new HttpsProxyAgent(process.env['https_proxy'])
21+
if (process.env.https_proxy) {
22+
const httpsProxyAgent = new HttpsProxyAgent(process.env.https_proxy)
2323
gitlabAuthStrategy._oauth2.setAgent(httpsProxyAgent)
2424
}
2525

lib/history/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ function historyPost (req, res) {
131131
if (req.isAuthenticated()) {
132132
var noteId = req.params.noteId
133133
if (!noteId) {
134-
if (typeof req.body['history'] === 'undefined') return response.errorBadRequest(req, res)
134+
if (typeof req.body.history === 'undefined') return response.errorBadRequest(req, res)
135135
if (config.debug) { logger.info('SERVER received history from [' + req.user.id + ']: ' + req.body.history) }
136136
try {
137137
var history = JSON.parse(req.body.history)
@@ -147,7 +147,7 @@ function historyPost (req, res) {
147147
return response.errorBadRequest(req, res)
148148
}
149149
} else {
150-
if (typeof req.body['pinned'] === 'undefined') return response.errorBadRequest(req, res)
150+
if (typeof req.body.pinned === 'undefined') return response.errorBadRequest(req, res)
151151
getHistory(req.user.id, function (err, history) {
152152
if (err) return response.errorInternalError(req, res)
153153
if (!history) return response.errorNotFound(req, res)

lib/imageRouter/filesystem.js

+44-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,39 @@
11
'use strict'
2+
3+
const crypto = require('crypto')
4+
const fs = require('fs')
25
const URL = require('url').URL
36
const path = require('path')
47

58
const config = require('../config')
69
const logger = require('../logger')
710

11+
/**
12+
* generate a random filename for uploaded image
13+
*/
14+
function randomFilename () {
15+
const buf = crypto.randomBytes(16)
16+
return `upload_${buf.toString('hex')}`
17+
}
18+
19+
/**
20+
* pick a filename not exist in filesystem
21+
* maximum attempt 5 times
22+
*/
23+
function pickFilename (defaultFilename) {
24+
let retryCounter = 5
25+
let filename = defaultFilename
26+
const extname = path.extname(defaultFilename)
27+
while (retryCounter-- > 0) {
28+
if (fs.existsSync(path.join(config.uploadsPath, filename))) {
29+
filename = `${randomFilename()}${extname}`
30+
continue
31+
}
32+
return filename
33+
}
34+
throw new Error('file exists.')
35+
}
36+
837
exports.uploadImage = function (imagePath, callback) {
938
if (!imagePath || typeof imagePath !== 'string') {
1039
callback(new Error('Image path is missing or wrong'), null)
@@ -16,11 +45,24 @@ exports.uploadImage = function (imagePath, callback) {
1645
return
1746
}
1847

48+
let filename = path.basename(imagePath)
49+
try {
50+
filename = pickFilename(path.basename(imagePath))
51+
} catch (e) {
52+
return callback(e, null)
53+
}
54+
55+
try {
56+
fs.copyFileSync(imagePath, path.join(config.uploadsPath, filename))
57+
} catch (e) {
58+
return callback(e, null)
59+
}
60+
1961
let url
2062
try {
21-
url = (new URL(path.basename(imagePath), config.serverURL + '/uploads/')).href
63+
url = (new URL(filename, config.serverURL + '/uploads/')).href
2264
} catch (e) {
23-
url = config.serverURL + '/uploads/' + path.basename(imagePath)
65+
url = config.serverURL + '/uploads/' + filename
2466
}
2567

2668
callback(null, url)

lib/imageRouter/index.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict'
22

3+
const fs = require('fs')
34
const Router = require('express').Router
45
const formidable = require('formidable')
56

@@ -15,10 +16,6 @@ imageRouter.post('/uploadimage', function (req, res) {
1516

1617
form.keepExtensions = true
1718

18-
if (config.imageUploadType === 'filesystem') {
19-
form.uploadDir = config.uploadsPath
20-
}
21-
2219
form.parse(req, function (err, fields, files) {
2320
if (err || !files.image || !files.image.path) {
2421
response.errorForbidden(req, res)
@@ -29,6 +26,8 @@ imageRouter.post('/uploadimage', function (req, res) {
2926

3027
const uploadProvider = require('./' + config.imageUploadType)
3128
uploadProvider.uploadImage(files.image.path, function (err, url) {
29+
// remove temporary upload file, and ignore any error
30+
fs.unlink(files.image.path, () => {})
3231
if (err !== null) {
3332
logger.error(err)
3433
return res.status(500).end('upload image error')

lib/models/note.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,13 @@ module.exports = function (sequelize, DataTypes) {
367367
Note.extractNoteTags = function (meta, $) {
368368
var tags = []
369369
var rawtags = []
370+
var metaTags
370371
if (meta.tags && (typeof meta.tags === 'string' || typeof meta.tags === 'number')) {
371-
var metaTags = ('' + meta.tags).split(',')
372+
metaTags = ('' + meta.tags).split(',')
373+
} else if (meta.tags && (Array.isArray(meta.tags))) {
374+
metaTags = meta.tags
375+
}
376+
if (metaTags) {
372377
for (let i = 0; i < metaTags.length; i++) {
373378
var text = metaTags[i].trim()
374379
if (text) rawtags.push(text)

lib/note/index.js

+45-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
const config = require('../config')
44
const logger = require('../logger')
5-
65
const { Note, User } = require('../models')
76

8-
const { newCheckViewPermission, errorForbidden, responseCodiMD, errorNotFound } = require('../response')
7+
const { newCheckViewPermission, errorForbidden, responseCodiMD, errorNotFound, errorInternalError } = require('../response')
98
const { updateHistory } = require('../history')
109
const { actionPublish, actionSlide, actionInfo, actionDownload, actionPDF, actionGist, actionRevision, actionPandoc } = require('./noteActions')
1110

@@ -121,6 +120,7 @@ async function showPublishNote (req, res) {
121120
const data = {
122121
title: title,
123122
description: meta.description || (markdown ? Note.generateDescription(markdown) : null),
123+
image: meta.image,
124124
viewcount: note.viewcount,
125125
createtime: createTime,
126126
updatetime: updateTime,
@@ -190,6 +190,49 @@ async function noteActions (req, res) {
190190
}
191191
}
192192

193+
async function getMyNoteList (userId, callback) {
194+
const myNotes = await Note.findAll({
195+
where: {
196+
ownerId: userId
197+
}
198+
})
199+
if (!myNotes) {
200+
return callback(null, null)
201+
}
202+
try {
203+
const myNoteList = myNotes.map(note => ({
204+
id: Note.encodeNoteId(note.id),
205+
text: note.title,
206+
tags: Note.parseNoteInfo(note.content).tags,
207+
createdAt: note.createdAt,
208+
lastchangeAt: note.lastchangeAt,
209+
shortId: note.shortid
210+
}))
211+
if (config.debug) {
212+
logger.info('Parse myNoteList success: ' + userId)
213+
}
214+
return callback(null, myNoteList)
215+
} catch (err) {
216+
logger.error('Parse myNoteList failed')
217+
return callback(err, null)
218+
}
219+
}
220+
221+
function listMyNotes (req, res) {
222+
if (req.isAuthenticated()) {
223+
getMyNoteList(req.user.id, (err, myNoteList) => {
224+
if (err) return errorInternalError(req, res)
225+
if (!myNoteList) return errorNotFound(req, res)
226+
res.send({
227+
myNotes: myNoteList
228+
})
229+
})
230+
} else {
231+
return errorForbidden(req, res)
232+
}
233+
}
234+
193235
exports.showNote = showNote
194236
exports.showPublishNote = showPublishNote
195237
exports.noteActions = noteActions
238+
exports.listMyNotes = listMyNotes

lib/routes.js

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ appRouter.get('/s/:shortid/:action', response.publishNoteActions)
7070
appRouter.get('/p/:shortid', response.showPublishSlide)
7171
// publish slide actions
7272
appRouter.get('/p/:shortid/:action', response.publishSlideActions)
73+
// gey my note list
74+
appRouter.get('/api/notes/myNotes', noteController.listMyNotes)
7375
// get note by id
7476
appRouter.get('/:noteId', wrap(noteController.showNote))
7577
// note actions

0 commit comments

Comments
 (0)