summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/config.js19
-rw-r--r--lib/history.js2
-rw-r--r--lib/migrations/20160607060246-support-revision.js5
-rw-r--r--lib/models/index.js21
-rw-r--r--lib/models/note.js84
-rw-r--r--lib/models/revision.js43
-rwxr-xr-xlib/ot/editor-socketio-server.js8
-rw-r--r--lib/realtime.js62
-rwxr-xr-xlib/response.js94
-rw-r--r--lib/workers/dmpWorker.js14
10 files changed, 193 insertions, 159 deletions
diff --git a/lib/config.js b/lib/config.js
index 053d083b..2f6792b7 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -19,11 +19,13 @@ var urladdport = process.env.HMD_URL_ADDPORT ? (process.env.HMD_URL_ADDPORT ===
var usecdn = process.env.HMD_USECDN ? (process.env.HMD_USECDN === 'true') : ((typeof config.usecdn === 'boolean') ? config.usecdn : true);
+var allowanonymous = process.env.HMD_ALLOW_ANONYMOUS ? (process.env.HMD_ALLOW_ANONYMOUS === 'true') : ((typeof config.allowanonymous === 'boolean') ? config.allowanonymous : true);
+
+var allowfreeurl = process.env.HMD_ALLOW_FREEURL ? (process.env.HMD_ALLOW_FREEURL === 'true') : !!config.allowfreeurl;
+
// db
-var db = config.db || {
- dialect: 'sqlite',
- storage: './db.hackmd.sqlite'
-};
+var dburl = config.dburl || process.env.HMD_DB_URL || process.env.DATABASE_URL;
+var db = config.db || {};
// ssl path
var sslkeypath = config.sslkeypath || '';
@@ -125,7 +127,7 @@ if (process.env.HMD_LDAP_TLS_CA) {
ldap.tlsOptions = ldap.tlsOptions ? Object.assign(ldap.tlsOptions, ca) : ca
}
var imgur = process.env.HMD_IMGUR_CLIENTID || config.imgur || false;
-var email = process.env.HMD_EMAIL || config.email || false;
+var email = process.env.HMD_EMAIL ? (process.env.HMD_EMAIL === 'true') : !!config.email;
function getserverurl() {
var url = '';
@@ -140,8 +142,8 @@ function getserverurl() {
return url;
}
-var version = '0.4.5';
-var minimumCompatibleVersion = '0.4.5';
+var version = '0.5.0';
+var minimumCompatibleVersion = '0.5.0';
var maintenance = true;
var cwd = path.join(__dirname, '..');
@@ -156,6 +158,9 @@ module.exports = {
usessl: usessl,
serverurl: getserverurl(),
usecdn: usecdn,
+ allowanonymous: allowanonymous,
+ allowfreeurl: allowfreeurl,
+ dburl: dburl,
db: db,
sslkeypath: path.join(cwd, sslkeypath),
sslcertpath: path.join(cwd, sslcertpath),
diff --git a/lib/history.js b/lib/history.js
index 4a3bbe1e..2723422c 100644
--- a/lib/history.js
+++ b/lib/history.js
@@ -27,10 +27,10 @@ var updater = setInterval(function () {
if (cache.isDirty) {
if (config.debug) logger.info("history updater found dirty history: " + key);
var history = parseHistoryToArray(cache.history);
+ cache.isDirty = false;
finishUpdateHistory(key, history, function (err, count) {
if (err) return callback(err, null);
if (!count) return callback(null, null);
- cache.isDirty = false;
cache.updateAt = Date.now();
return callback(null, null);
});
diff --git a/lib/migrations/20160607060246-support-revision.js b/lib/migrations/20160607060246-support-revision.js
index 9721d7fc..fa647d93 100644
--- a/lib/migrations/20160607060246-support-revision.js
+++ b/lib/migrations/20160607060246-support-revision.js
@@ -4,7 +4,10 @@ module.exports = {
up: function (queryInterface, Sequelize) {
queryInterface.addColumn('Notes', 'savedAt', Sequelize.DATE);
queryInterface.createTable('Revisions', {
- id: Sequelize.UUID,
+ id: {
+ type: Sequelize.UUID,
+ primaryKey: true
+ },
noteId: Sequelize.UUID,
patch: Sequelize.TEXT,
lastContent: Sequelize.TEXT,
diff --git a/lib/models/index.js b/lib/models/index.js
index d52f5508..e83956e5 100644
--- a/lib/models/index.js
+++ b/lib/models/index.js
@@ -13,10 +13,25 @@ var dbconfig = config.db;
dbconfig.logging = config.debug ? logger.info : false;
var sequelize = null;
-if (dbconfig.hasOwnProperty('username') || dbconfig.hasOwnProperty('password'))
- sequelize = new Sequelize(dbconfig.database, dbconfig.username, dbconfig.password, dbconfig);
+
+// Heroku specific
+if (config.dburl)
+ sequelize = new Sequelize(config.dburl, dbconfig);
else
- sequelize = new Sequelize(dbconfig.database, dbconfig);
+ sequelize = new Sequelize(dbconfig.database, dbconfig.username, dbconfig.password, dbconfig);
+
+// [Postgres] Handling NULL bytes
+// https://github.com/sequelize/sequelize/issues/6485
+function stripNullByte(value) {
+ return value ? value.replace(/\u0000/g, "") : value;
+}
+sequelize.stripNullByte = stripNullByte;
+
+function processData(data, _default, process) {
+ if (data === undefined) return data;
+ else return data === null ? _default : (process ? process(data) : data);
+}
+sequelize.processData = processData;
var db = {};
diff --git a/lib/models/note.js b/lib/models/note.js
index 5727046c..132f8b1e 100644
--- a/lib/models/note.js
+++ b/lib/models/note.js
@@ -52,13 +52,31 @@ module.exports = function (sequelize, DataTypes) {
defaultValue: 0
},
title: {
- type: DataTypes.TEXT
+ type: DataTypes.TEXT,
+ get: function () {
+ return sequelize.processData(this.getDataValue('title'), "");
+ },
+ set: function (value) {
+ this.setDataValue('title', sequelize.stripNullByte(value));
+ }
},
content: {
- type: DataTypes.TEXT
+ type: DataTypes.TEXT,
+ get: function () {
+ return sequelize.processData(this.getDataValue('content'), "");
+ },
+ set: function (value) {
+ this.setDataValue('content', sequelize.stripNullByte(value));
+ }
},
authorship: {
- type: DataTypes.TEXT
+ type: DataTypes.TEXT,
+ get: function () {
+ return sequelize.processData(this.getDataValue('authorship'), [], JSON.parse);
+ },
+ set: function (value) {
+ this.setDataValue('authorship', JSON.stringify(value));
+ }
},
lastchangeAt: {
type: DataTypes.DATE
@@ -124,8 +142,6 @@ module.exports = function (sequelize, DataTypes) {
var body = fs.readFileSync(filePath, 'utf8');
var contentLength = body.length;
var title = Note.parseNoteTitle(body);
- body = LZString.compressToBase64(body);
- title = LZString.compressToBase64(title);
if (fsModifiedTime.isAfter(dbModifiedTime) && note.content !== body) {
note.update({
title: title,
@@ -135,14 +151,14 @@ module.exports = function (sequelize, DataTypes) {
sequelize.models.Revision.saveNoteRevision(note, function (err, revision) {
if (err) return _callback(err, null);
// update authorship on after making revision of docs
- var patch = dmp.patch_fromText(LZString.decompressFromBase64(revision.patch));
+ var patch = dmp.patch_fromText(revision.patch);
var operations = Note.transformPatchToOperations(patch, contentLength);
- var authorship = note.authorship ? JSON.parse(LZString.decompressFromBase64(note.authorship)) : [];
+ var authorship = note.authorship;
for (var i = 0; i < operations.length; i++) {
authorship = Note.updateAuthorshipByOperation(operations[i], null, authorship);
}
note.update({
- authorship: LZString.compressToBase64(JSON.stringify(authorship))
+ authorship: JSON.stringify(authorship)
}).then(function (note) {
return callback(null, note.id);
}).catch(function (err) {
@@ -220,33 +236,17 @@ module.exports = function (sequelize, DataTypes) {
});
},
parseNoteInfo: function (body) {
- var meta = null;
- try {
- var obj = metaMarked(body);
- body = obj.markdown;
- meta = obj.meta;
- } catch (err) {
- //na
- }
- if (!meta) meta = {};
- var $ = cheerio.load(md.render(body));
+ var parsed = Note.extractMeta(body);
+ var $ = cheerio.load(md.render(parsed.markdown));
return {
- title: Note.extractNoteTitle(meta, $),
- tags: Note.extractNoteTags(meta, $)
+ title: Note.extractNoteTitle(parsed.meta, $),
+ tags: Note.extractNoteTags(parsed.meta, $)
};
},
parseNoteTitle: function (body) {
- var meta = null;
- try {
- var obj = metaMarked(body);
- body = obj.markdown;
- meta = obj.meta;
- } catch (err) {
- //na
- }
- if (!meta) meta = {};
- var $ = cheerio.load(md.render(body));
- return Note.extractNoteTitle(meta, $);
+ var parsed = Note.extractMeta(body);
+ var $ = cheerio.load(md.render(parsed.markdown));
+ return Note.extractNoteTitle(parsed.meta, $);
},
extractNoteTitle: function (meta, $) {
var title = "";
@@ -264,10 +264,7 @@ module.exports = function (sequelize, DataTypes) {
return markdown.substr(0, 100).replace(/(?:\r\n|\r|\n)/g, ' ');
},
decodeTitle: function (title) {
- var decodedTitle = LZString.decompressFromBase64(title);
- if (decodedTitle) title = decodedTitle;
- else title = 'Untitled';
- return title;
+ return title ? title : 'Untitled';
},
generateWebTitle: function (title) {
title = !title || title == "Untitled" ? "HackMD - Collaborative markdown notes" : title + " - HackMD";
@@ -307,6 +304,19 @@ module.exports = function (sequelize, DataTypes) {
}
return tags;
},
+ extractMeta: function (content) {
+ try {
+ var obj = metaMarked(content);
+ if (!obj.markdown) obj.markdown = "";
+ if (!obj.meta) obj.meta = {};
+ } catch (err) {
+ var obj = {
+ markdown: content,
+ meta: {}
+ };
+ }
+ return obj;
+ },
parseMeta: function (meta) {
var _meta = {};
if (meta) {
@@ -496,8 +506,8 @@ module.exports = function (sequelize, DataTypes) {
if (Note.checkFileExist(filePath)) {
var fsCreatedTime = moment(fs.statSync(filePath).ctime);
body = fs.readFileSync(filePath, 'utf8');
- note.title = LZString.compressToBase64(Note.parseNoteTitle(body));
- note.content = LZString.compressToBase64(body);
+ note.title = Note.parseNoteTitle(body);
+ note.content = body;
if (filePath !== config.defaultnotepath) {
note.createdAt = fsCreatedTime;
}
diff --git a/lib/models/revision.js b/lib/models/revision.js
index 8b8eba94..c7360fed 100644
--- a/lib/models/revision.js
+++ b/lib/models/revision.js
@@ -2,7 +2,6 @@
// external modules
var Sequelize = require("sequelize");
-var LZString = require('lz-string');
var async = require('async');
var moment = require('moment');
var childProcess = require('child_process');
@@ -60,19 +59,43 @@ module.exports = function (sequelize, DataTypes) {
defaultValue: Sequelize.UUIDV4
},
patch: {
- type: DataTypes.TEXT
+ type: DataTypes.TEXT,
+ get: function () {
+ return sequelize.processData(this.getDataValue('patch'), "");
+ },
+ set: function (value) {
+ this.setDataValue('patch', sequelize.stripNullByte(value));
+ }
},
lastContent: {
- type: DataTypes.TEXT
+ type: DataTypes.TEXT,
+ get: function () {
+ return sequelize.processData(this.getDataValue('lastContent'), "");
+ },
+ set: function (value) {
+ this.setDataValue('lastContent', sequelize.stripNullByte(value));
+ }
},
content: {
- type: DataTypes.TEXT
+ type: DataTypes.TEXT,
+ get: function () {
+ return sequelize.processData(this.getDataValue('content'), "");
+ },
+ set: function (value) {
+ this.setDataValue('content', sequelize.stripNullByte(value));
+ }
},
length: {
type: DataTypes.INTEGER
},
authorship: {
- type: DataTypes.TEXT
+ type: DataTypes.TEXT,
+ get: function () {
+ return sequelize.processData(this.getDataValue('authorship'), [], JSON.parse);
+ },
+ set: function (value) {
+ this.setDataValue('authorship', value ? JSON.stringify(value) : value);
+ }
}
}, {
classMethods: {
@@ -214,7 +237,7 @@ module.exports = function (sequelize, DataTypes) {
Revision.create({
noteId: note.id,
lastContent: note.content,
- length: LZString.decompressFromBase64(note.content).length,
+ length: note.content.length,
authorship: note.authorship
}).then(function (revision) {
Revision.finishSaveNoteRevision(note, revision, callback);
@@ -223,8 +246,8 @@ module.exports = function (sequelize, DataTypes) {
});
} else {
var latestRevision = revisions[0];
- var lastContent = LZString.decompressFromBase64(latestRevision.content || latestRevision.lastContent);
- var content = LZString.decompressFromBase64(note.content);
+ var lastContent = latestRevision.content || latestRevision.lastContent;
+ var content = note.content;
sendDmpWorker({
msg: 'create patch',
lastDoc: lastContent,
@@ -244,9 +267,9 @@ module.exports = function (sequelize, DataTypes) {
} else {
Revision.create({
noteId: note.id,
- patch: LZString.compressToBase64(patch),
+ patch: patch,
content: note.content,
- length: LZString.decompressFromBase64(note.content).length,
+ length: note.content.length,
authorship: note.authorship
}).then(function (revision) {
// clear last revision content to reduce db size
diff --git a/lib/ot/editor-socketio-server.js b/lib/ot/editor-socketio-server.js
index d062fa19..7b204539 100755
--- a/lib/ot/editor-socketio-server.js
+++ b/lib/ot/editor-socketio-server.js
@@ -7,7 +7,6 @@ var Server = require('./server');
var Selection = require('./selection');
var util = require('util');
-var LZString = require('lz-string');
var logger = require('../logger');
function EditorSocketIOServer(document, operations, docId, mayWrite, operationCallback) {
@@ -40,10 +39,8 @@ EditorSocketIOServer.prototype.addClient = function (socket) {
revision: this.operations.length,
clients: this.users
};
- socket.emit('doc', LZString.compressToUTF16(JSON.stringify(docOut)));
+ socket.emit('doc', docOut);
socket.on('operation', function (revision, operation, selection) {
- operation = LZString.decompressFromUTF16(operation);
- operation = JSON.parse(operation);
socket.origin = 'operation';
self.mayWrite(socket, function (mayWrite) {
if (!mayWrite) {
@@ -62,7 +59,7 @@ EditorSocketIOServer.prototype.addClient = function (socket) {
clients: self.users,
force: true
};
- socket.emit('doc', LZString.compressToUTF16(JSON.stringify(docOut)));
+ socket.emit('doc', docOut);
}, 100);
}
});
@@ -129,7 +126,6 @@ EditorSocketIOServer.prototype.onGetOperations = function (socket, base, head) {
var operations = this.operations.slice(base, head).map(function (op) {
return op.wrapped.toJSON();
});
- operations = LZString.compressToUTF16(JSON.stringify(operations));
socket.emit('operations', head, operations);
};
diff --git a/lib/realtime.js b/lib/realtime.js
index 73f831f4..a662deeb 100644
--- a/lib/realtime.js
+++ b/lib/realtime.js
@@ -71,7 +71,6 @@ function emitCheck(note) {
authors: note.authors,
authorship: note.authorship
};
- out = LZString.compressToUTF16(JSON.stringify(out));
realtime.io.to(note.id).emit('check', out);
}
@@ -84,6 +83,7 @@ var updater = setInterval(function () {
var note = notes[key];
if (note.server.isDirty) {
if (config.debug) logger.info("updater found dirty note: " + key);
+ note.server.isDirty = false;
updateNote(note, function(err, _note) {
// handle when note already been clean up
if (!notes[key] || !notes[key].server) return callback(null, null);
@@ -104,7 +104,6 @@ var updater = setInterval(function () {
}
return callback(err, null);
}
- note.server.isDirty = false;
note.updatetime = moment(_note.lastchangeAt).valueOf();
emitCheck(note);
return callback(null, null);
@@ -153,12 +152,10 @@ function finishUpdateNote(note, _note, callback) {
if (!note || !note.server) return callback(null, null);
var body = note.server.document;
var title = note.title = models.Note.parseNoteTitle(body);
- title = LZString.compressToBase64(title);
- body = LZString.compressToBase64(body);
var values = {
title: title,
content: body,
- authorship: LZString.compressToBase64(JSON.stringify(note.authorship)),
+ authorship: note.authorship,
lastchangeuserId: note.lastchangeuser,
lastchangeAt: Date.now()
};
@@ -211,6 +208,7 @@ function getStatus(callback) {
var distinctregaddresses = [];
Object.keys(users).forEach(function (key) {
var user = users[key];
+ if (!user) return;
var found = false;
for (var i = 0; i < distinctaddresses.length; i++) {
if (user.address == distinctaddresses[i]) {
@@ -300,14 +298,14 @@ function emitOnlineUsers(socket) {
var out = {
users: users
};
- out = LZString.compressToUTF16(JSON.stringify(out));
realtime.io.to(noteId).emit('online users', out);
}
function emitUserStatus(socket) {
var noteId = socket.noteId;
- if (!noteId || !notes[noteId]) return;
- var out = buildUserOutData(users[socket.id]);
+ var user = users[socket.id];
+ if (!noteId || !notes[noteId] || !user) return;
+ var out = buildUserOutData(user);
socket.broadcast.to(noteId).emit('user status', out);
}
@@ -328,7 +326,6 @@ function emitRefresh(socket) {
createtime: note.createtime,
updatetime: note.updatetime
};
- out = LZString.compressToUTF16(JSON.stringify(out));
socket.emit('refresh', out);
}
@@ -460,7 +457,7 @@ function startConnection(socket) {
var lastchangeuser = note.lastchangeuserId;
var lastchangeuserprofile = note.lastchangeuser ? models.User.getProfile(note.lastchangeuser) : null;
- var body = LZString.decompressFromBase64(note.content);
+ var body = note.content;
var createtime = note.createdAt;
var updatetime = note.lastchangeAt;
var server = new ot.EditorSocketIOServer(body, [], noteId, ifMayEdit, operationCallback);
@@ -480,7 +477,7 @@ function startConnection(socket) {
notes[noteId] = {
id: noteId,
alias: note.alias,
- title: LZString.decompressFromBase64(note.title),
+ title: note.title,
owner: owner,
ownerprofile: ownerprofile,
permission: note.permission,
@@ -492,7 +489,7 @@ function startConnection(socket) {
updatetime: moment(updatetime).valueOf(),
server: server,
authors: authors,
- authorship: note.authorship ? JSON.parse(LZString.decompressFromBase64(note.authorship)) : []
+ authorship: note.authorship
};
return finishConnection(socket, notes[noteId], users[socket.id]);
@@ -532,7 +529,9 @@ function disconnect(socket) {
var note = notes[noteId];
if (note) {
// delete user in users
- delete note.users[socket.id];
+ if (note.users[socket.id]) {
+ delete note.users[socket.id];
+ }
// remove sockets in the note socks
do {
var index = note.socks.indexOf(socket);
@@ -649,14 +648,14 @@ function operationCallback(socket, operation) {
var userId = null;
// save authors
if (socket.request.user && socket.request.user.logged_in) {
- var socketId = socket.id;
- var user = users[socketId];
+ var user = users[socket.id];
+ if (!user) return;
userId = socket.request.user.id;
if (!note.authors[userId]) {
models.Author.create({
noteId: noteId,
userId: userId,
- color: users[socketId].color
+ color: user.color
}).then(function (author) {
note.authors[author.userId] = {
userid: author.userId,
@@ -743,11 +742,11 @@ function connection(socket) {
//received user status
socket.on('user status', function (data) {
var noteId = socket.noteId;
- if (!noteId || !notes[noteId]) return;
+ var user = users[socket.id];
+ if (!noteId || !notes[noteId] || !user) return;
if (config.debug)
logger.info('SERVER received [' + noteId + '] user status from [' + socket.id + ']: ' + JSON.stringify(data));
if (data) {
- var user = users[socket.id];
user.idle = data.idle;
user.type = data.type;
}
@@ -763,6 +762,7 @@ function connection(socket) {
var note = notes[noteId];
//Only owner can change permission
if (note.owner && note.owner == socket.request.user.id) {
+ if (permission == 'freely' && !config.allowanonymous) return;
note.permission = permission;
models.Note.update({
permission: permission
@@ -839,7 +839,9 @@ function connection(socket) {
logger.info('user changed');
var noteId = socket.noteId;
if (!noteId || !notes[noteId]) return;
- updateUserData(socket, notes[noteId].users[socket.id]);
+ var user = notes[noteId].users[socket.id];
+ if (!user) return;
+ updateUserData(socket, user);
emitOnlineUsers(socket);
});
@@ -856,7 +858,6 @@ function connection(socket) {
var out = {
users: users
};
- out = LZString.compressToUTF16(JSON.stringify(out));
socket.emit('online users', out);
});
@@ -871,26 +872,29 @@ function connection(socket) {
//received cursor focus
socket.on('cursor focus', function (data) {
var noteId = socket.noteId;
- if (!noteId || !notes[noteId]) return;
- users[socket.id].cursor = data;
- var out = buildUserOutData(users[socket.id]);
+ var user = users[socket.id];
+ if (!noteId || !notes[noteId] || !user) return;
+ user.cursor = data;
+ var out = buildUserOutData(user);
socket.broadcast.to(noteId).emit('cursor focus', out);
});
//received cursor activity
socket.on('cursor activity', function (data) {
var noteId = socket.noteId;
- if (!noteId || !notes[noteId]) return;
- users[socket.id].cursor = data;
- var out = buildUserOutData(users[socket.id]);
+ var user = users[socket.id];
+ if (!noteId || !notes[noteId] || !user) return;
+ user.cursor = data;
+ var out = buildUserOutData(user);
socket.broadcast.to(noteId).emit('cursor activity', out);
});
//received cursor blur
socket.on('cursor blur', function () {
var noteId = socket.noteId;
- if (!noteId || !notes[noteId]) return;
- users[socket.id].cursor = null;
+ var user = users[socket.id];
+ if (!noteId || !notes[noteId] || !user) return;
+ user.cursor = null;
var out = {
id: socket.id
};
@@ -905,4 +909,4 @@ function connection(socket) {
});
}
-module.exports = realtime; \ No newline at end of file
+module.exports = realtime;
diff --git a/lib/response.js b/lib/response.js
index f0f49181..cedee3de 100755
--- a/lib/response.js
+++ b/lib/response.js
@@ -6,7 +6,6 @@ var markdownpdf = require("markdown-pdf");
var LZString = require('lz-string');
var S = require('string');
var shortId = require('shortid');
-var metaMarked = require('meta-marked');
var querystring = require('querystring');
var request = require('request');
var moment = require('moment');
@@ -60,6 +59,7 @@ function showIndex(req, res, next) {
res.render(config.indexpath, {
url: config.serverurl,
useCDN: config.usecdn,
+ allowAnonymous: config.allowanonymous,
facebook: config.facebook,
twitter: config.twitter,
github: config.github,
@@ -75,14 +75,9 @@ function showIndex(req, res, next) {
}
function responseHackMD(res, note) {
- var body = LZString.decompressFromBase64(note.content);
- var meta = null;
- try {
- meta = models.Note.parseMeta(metaMarked(body).meta);
- } catch(err) {
- //na
- }
- if (!meta) meta = {};
+ var body = note.content;
+ var extracted = models.Note.extractMeta(body);
+ var meta = models.Note.parseMeta(extracted.meta);
var title = models.Note.decodeTitle(note.title);
title = models.Note.generateWebTitle(meta.title || title);
res.set({
@@ -93,6 +88,7 @@ function responseHackMD(res, note) {
url: config.serverurl,
title: title,
useCDN: config.usecdn,
+ allowAnonymous: config.allowanonymous,
facebook: config.facebook,
twitter: config.twitter,
github: config.github,
@@ -108,9 +104,12 @@ function newNote(req, res, next) {
var owner = null;
if (req.isAuthenticated()) {
owner = req.user.id;
+ } else if (!config.allowanonymous) {
+ return response.errorForbidden(res);
}
models.Note.create({
- ownerId: owner
+ ownerId: owner,
+ alias: req.alias ? req.alias : null
}).then(function (note) {
return res.redirect(config.serverurl + "/" + LZString.compressToBase64(note.id));
}).catch(function (err) {
@@ -131,6 +130,7 @@ function checkViewPermission(req, note) {
}
function findNote(req, res, callback, include) {
+ var noteId = req.params.noteId;
var id = req.params.noteId || req.params.shortid;
models.Note.parseNoteId(id, function (err, _id) {
models.Note.findOne({
@@ -140,7 +140,12 @@ function findNote(req, res, callback, include) {
include: include || null
}).then(function (note) {
if (!note) {
- return response.errorNotFound(res);
+ if (config.allowfreeurl && noteId) {
+ req.alias = noteId;
+ return newNote(req, res);
+ } else {
+ return response.errorNotFound(res);
+ }
}
if (!checkViewPermission(req, note)) {
return response.errorForbidden(res);
@@ -182,17 +187,10 @@ function showPublishNote(req, res, next) {
if (!note) {
return response.errorNotFound(res);
}
- var body = LZString.decompressFromBase64(note.content);
- var meta = null;
- var markdown = null;
- try {
- var obj = metaMarked(body);
- markdown = obj.markdown;
- meta = models.Note.parseMeta(obj.meta);
- } catch(err) {
- //na
- }
- if (!meta) meta = {};
+ var body = note.content;
+ var extracted = models.Note.extractMeta(body);
+ markdown = extracted.markdown;
+ meta = models.Note.parseMeta(extracted.meta);
var createtime = note.createdAt;
var updatetime = note.lastchangeAt;
var title = models.Note.decodeTitle(note.title);
@@ -200,7 +198,7 @@ function showPublishNote(req, res, next) {
var origin = config.serverurl;
var data = {
title: title,
- description: meta.description || markdown ? models.Note.generateDescription(markdown) : null,
+ description: meta.description || (markdown ? models.Note.generateDescription(markdown) : null),
viewcount: note.viewcount,
createtime: createtime,
updatetime: updatetime,
@@ -239,7 +237,7 @@ function actionSlide(req, res, note) {
}
function actionDownload(req, res, note) {
- var body = LZString.decompressFromBase64(note.content);
+ var body = note.content;
var title = models.Note.decodeTitle(note.title);
var filename = title;
filename = encodeURIComponent(filename);
@@ -256,23 +254,16 @@ function actionDownload(req, res, note) {
}
function actionInfo(req, res, note) {
- var body = LZString.decompressFromBase64(note.content);
- var meta = null;
- var markdown = null;
- try {
- var obj = metaMarked(body);
- markdown = obj.markdown;
- meta = models.Note.parseMeta(obj.meta);
- } catch(err) {
- //na
- }
- if (!meta) meta = {};
+ var body = note.content;
+ var extracted = models.Note.extractMeta(body);
+ var markdown = extracted.markdown;
+ var meta = models.Note.parseMeta(extracted.meta);
var createtime = note.createdAt;
var updatetime = note.lastchangeAt;
var title = models.Note.decodeTitle(note.title);
var data = {
title: meta.title || title,
- description: meta.description || markdown ? models.Note.generateDescription(markdown) : null,
+ description: meta.description || (markdown ? models.Note.generateDescription(markdown) : null),
viewcount: note.viewcount,
createtime: createtime,
updatetime: updatetime
@@ -288,19 +279,15 @@ function actionInfo(req, res, note) {
}
function actionPDF(req, res, note) {
- var body = LZString.decompressFromBase64(note.content);
- try {
- body = metaMarked(body).markdown;
- } catch(err) {
- //na
- }
+ var body = note.content;
+ var extracted = models.Note.extractMeta(body);
var title = models.Note.decodeTitle(note.title);
if (!fs.existsSync(config.tmppath)) {
fs.mkdirSync(config.tmppath);
}
var path = config.tmppath + '/' + Date.now() + '.pdf';
- markdownpdf().from.string(body).to(path, function () {
+ markdownpdf().from.string(extracted.markdown).to(path, function () {
var stream = fs.createReadStream(path);
var filename = title;
// Be careful of special characters
@@ -470,7 +457,7 @@ function githubActionGist(req, res, note) {
if (!error && httpResponse.statusCode == 200) {
var access_token = body.access_token;
if (access_token) {
- var content = LZString.decompressFromBase64(note.content);
+ var content = note.content;
var title = models.Note.decodeTitle(note.title);
var filename = title.replace('/', ' ') + '.md';
var gist = {
@@ -570,17 +557,10 @@ function showPublishSlide(req, res, next) {
if (!note) {
return response.errorNotFound(res);
}
- var body = LZString.decompressFromBase64(note.content);
- var meta = null;
- var markdown = null;
- try {
- var obj = metaMarked(body);
- markdown = obj.markdown;
- meta = models.Note.parseMeta(obj.meta);
- } catch(err) {
- //na
- }
- if (!meta) meta = {};
+ var body = note.content;
+ var extracted = models.Note.extractMeta(body);
+ markdown = extracted.markdown;
+ meta = models.Note.parseMeta(extracted.meta);
var createtime = note.createdAt;
var updatetime = note.lastchangeAt;
var title = models.Note.decodeTitle(note.title);
@@ -588,13 +568,13 @@ function showPublishSlide(req, res, next) {
var origin = config.serverurl;
var data = {
title: title,
- description: meta.description || markdown ? models.Note.generateDescription(markdown) : null,
+ description: meta.description || (markdown ? models.Note.generateDescription(markdown) : null),
viewcount: note.viewcount,
createtime: createtime,
updatetime: updatetime,
url: origin,
body: markdown,
- meta: JSON.stringify(obj.meta || {}),
+ meta: JSON.stringify(extracted.meta),
useCDN: config.usecdn,
owner: note.owner ? note.owner.id : null,
ownerprofile: note.owner ? models.User.getProfile(note.owner) : null,
diff --git a/lib/workers/dmpWorker.js b/lib/workers/dmpWorker.js
index fae36191..8e69636e 100644
--- a/lib/workers/dmpWorker.js
+++ b/lib/workers/dmpWorker.js
@@ -1,5 +1,4 @@
// external modules
-var LZString = require('lz-string');
var DiffMatchPatch = require('diff-match-patch');
var dmp = new DiffMatchPatch();
@@ -58,7 +57,6 @@ process.on('message', function(data) {
function createPatch(lastDoc, currDoc) {
var ms_start = (new Date()).getTime();
var diff = dmp.diff_main(lastDoc, currDoc);
- dmp.diff_cleanupSemantic(diff);
var patch = dmp.patch_make(lastDoc, diff);
patch = dmp.patch_toText(patch);
var ms_end = (new Date()).getTime();
@@ -80,10 +78,10 @@ function getRevision(revisions, count) {
for (var i = 0; i < count; i++) {
var revision = revisions[i];
if (i == 0) {
- startContent = LZString.decompressFromBase64(revision.content || revision.lastContent);
+ startContent = revision.content || revision.lastContent;
}
if (i != count - 1) {
- var patch = dmp.patch_fromText(LZString.decompressFromBase64(revision.patch));
+ var patch = dmp.patch_fromText(revision.patch);
applyPatches = applyPatches.concat(patch);
}
lastPatch = revision.patch;
@@ -105,11 +103,11 @@ function getRevision(revisions, count) {
for (var i = l; i >= count - 1; i--) {
var revision = revisions[i];
if (i == l) {
- startContent = LZString.decompressFromBase64(revision.lastContent);
+ startContent = revision.lastContent;
authorship = revision.authorship;
}
if (revision.patch) {
- var patch = dmp.patch_fromText(LZString.decompressFromBase64(revision.patch));
+ var patch = dmp.patch_fromText(revision.patch);
applyPatches = applyPatches.concat(patch);
}
lastPatch = revision.patch;
@@ -123,8 +121,8 @@ function getRevision(revisions, count) {
}
var data = {
content: finalContent,
- patch: dmp.patch_fromText(LZString.decompressFromBase64(lastPatch)),
- authorship: authorship ? JSON.parse(LZString.decompressFromBase64(authorship)) : null
+ patch: dmp.patch_fromText(lastPatch),
+ authorship: authorship
};
var ms_end = (new Date()).getTime();
if (config.debug) {