mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-28 17:20:55 -05:00
Added private permission and clean up codes, solved potential race condition in realtime.js
This commit is contained in:
parent
473212676a
commit
49c7dded45
6 changed files with 297 additions and 199 deletions
|
@ -12,7 +12,7 @@ var db = require("./db.js");
|
||||||
var logger = require("./logger.js");
|
var logger = require("./logger.js");
|
||||||
|
|
||||||
//permission types
|
//permission types
|
||||||
permissionTypes = ["freely", "editable", "locked"];
|
permissionTypes = ["freely", "editable", "locked", "private"];
|
||||||
|
|
||||||
// create a note model
|
// create a note model
|
||||||
var model = mongoose.model('note', {
|
var model = mongoose.model('note', {
|
||||||
|
@ -126,7 +126,11 @@ function findNote(id, callback) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function newNote(id, permission, callback) {
|
function newNote(id, owner, callback) {
|
||||||
|
var permission = "freely";
|
||||||
|
if (owner && owner != "null") {
|
||||||
|
permission = "editable";
|
||||||
|
}
|
||||||
var note = new model({
|
var note = new model({
|
||||||
id: id,
|
id: id,
|
||||||
permission: permission,
|
permission: permission,
|
||||||
|
|
|
@ -43,6 +43,7 @@ EditorSocketIOServer.prototype.addClient = function (socket) {
|
||||||
socket.on('operation', function (revision, operation, selection) {
|
socket.on('operation', function (revision, operation, selection) {
|
||||||
operation = LZString.decompressFromUTF16(operation);
|
operation = LZString.decompressFromUTF16(operation);
|
||||||
operation = JSON.parse(operation);
|
operation = JSON.parse(operation);
|
||||||
|
socket.origin = 'operation';
|
||||||
self.mayWrite(socket, function (mayWrite) {
|
self.mayWrite(socket, function (mayWrite) {
|
||||||
if (!mayWrite) {
|
if (!mayWrite) {
|
||||||
console.log("User doesn't have the right to edit.");
|
console.log("User doesn't have the right to edit.");
|
||||||
|
@ -59,6 +60,7 @@ EditorSocketIOServer.prototype.addClient = function (socket) {
|
||||||
self.onGetOperations(socket, base, head);
|
self.onGetOperations(socket, base, head);
|
||||||
});
|
});
|
||||||
socket.on('selection', function (obj) {
|
socket.on('selection', function (obj) {
|
||||||
|
socket.origin = 'selection';
|
||||||
self.mayWrite(socket, function (mayWrite) {
|
self.mayWrite(socket, function (mayWrite) {
|
||||||
if (!mayWrite) {
|
if (!mayWrite) {
|
||||||
console.log("User doesn't have the right to edit.");
|
console.log("User doesn't have the right to edit.");
|
||||||
|
@ -104,6 +106,7 @@ EditorSocketIOServer.prototype.onOperation = function (socket, revision, operati
|
||||||
'operation', clientId, revision,
|
'operation', clientId, revision,
|
||||||
wrappedPrime.wrapped.toJSON(), wrappedPrime.meta
|
wrappedPrime.wrapped.toJSON(), wrappedPrime.meta
|
||||||
);
|
);
|
||||||
|
//set document is dirty
|
||||||
this.isDirty = true;
|
this.isDirty = true;
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
logger.error(exc);
|
logger.error(exc);
|
||||||
|
|
204
lib/realtime.js
204
lib/realtime.js
|
@ -90,46 +90,10 @@ var updater = setInterval(function () {
|
||||||
if (note.server.isDirty) {
|
if (note.server.isDirty) {
|
||||||
if (config.debug)
|
if (config.debug)
|
||||||
logger.info("updater found dirty note: " + key);
|
logger.info("updater found dirty note: " + key);
|
||||||
Note.findNote(note.id, function (err, _note) {
|
updaterUpdateMongo(note, function(err, result) {
|
||||||
if (err || !_note) return callback(err, null);
|
if (err) return callback(err, null);
|
||||||
//mongo update
|
updaterUpdatePostgres(note, function(err, result) {
|
||||||
if (note.lastchangeuser && _note.lastchangeuser != note.lastchangeuser) {
|
|
||||||
var lastchangeuser = note.lastchangeuser;
|
|
||||||
var lastchangeuserprofile = null;
|
|
||||||
User.findUser(lastchangeuser, function (err, user) {
|
|
||||||
if (err) return callback(err, null);
|
|
||||||
if (user && user.profile) {
|
|
||||||
var profile = JSON.parse(user.profile);
|
|
||||||
if (profile) {
|
|
||||||
lastchangeuserprofile = {
|
|
||||||
name: profile.displayName || profile.username,
|
|
||||||
photo: User.parsePhotoByProfile(profile)
|
|
||||||
}
|
|
||||||
note.lastchangeuser = lastchangeuser;
|
|
||||||
note.lastchangeuserprofile = lastchangeuserprofile;
|
|
||||||
Note.updateLastChangeUser(_note, lastchangeuser, function (err, result) {
|
|
||||||
if (err) return callback(err, null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
note.lastchangeuser = null;
|
|
||||||
note.lastchangeuserprofile = null;
|
|
||||||
Note.updateLastChangeUser(_note, null, function (err, result) {
|
|
||||||
if (err) return callback(err, null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//postgres update
|
|
||||||
var body = note.server.document;
|
|
||||||
var title = Note.getNoteTitle(body);
|
|
||||||
title = LZString.compressToBase64(title);
|
|
||||||
body = LZString.compressToBase64(body);
|
|
||||||
db.saveToDB(key, title, body, function (err, result) {
|
|
||||||
if (err) return callback(err, null);
|
if (err) return callback(err, null);
|
||||||
note.server.isDirty = false;
|
|
||||||
note.updatetime = Date.now();
|
|
||||||
emitCheck(note);
|
|
||||||
callback(null, null);
|
callback(null, null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -140,6 +104,56 @@ var updater = setInterval(function () {
|
||||||
if (err) return logger.error('updater error', err);
|
if (err) return logger.error('updater error', err);
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
function updaterUpdateMongo(note, callback) {
|
||||||
|
Note.findNote(note.id, function (err, _note) {
|
||||||
|
if (err || !_note) return callback(err, null);
|
||||||
|
if (note.lastchangeuser) {
|
||||||
|
if (_note.lastchangeuser != note.lastchangeuser) {
|
||||||
|
var lastchangeuser = note.lastchangeuser;
|
||||||
|
var lastchangeuserprofile = null;
|
||||||
|
User.findUser(lastchangeuser, function (err, user) {
|
||||||
|
if (err) return callback(err, null);
|
||||||
|
if (user && user.profile) {
|
||||||
|
var profile = JSON.parse(user.profile);
|
||||||
|
if (profile) {
|
||||||
|
lastchangeuserprofile = {
|
||||||
|
name: profile.displayName || profile.username,
|
||||||
|
photo: User.parsePhotoByProfile(profile)
|
||||||
|
}
|
||||||
|
_note.lastchangeuser = lastchangeuser;
|
||||||
|
note.lastchangeuserprofile = lastchangeuserprofile;
|
||||||
|
Note.updateLastChangeUser(_note, lastchangeuser, function (err, result) {
|
||||||
|
if (err) return callback(err, null);
|
||||||
|
callback(null, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_note.lastchangeuser = null;
|
||||||
|
note.lastchangeuserprofile = null;
|
||||||
|
Note.updateLastChangeUser(_note, null, function (err, result) {
|
||||||
|
if (err) return callback(err, null);
|
||||||
|
callback(null, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function updaterUpdatePostgres(note, callback) {
|
||||||
|
//postgres update
|
||||||
|
var body = note.server.document;
|
||||||
|
var title = Note.getNoteTitle(body);
|
||||||
|
title = LZString.compressToBase64(title);
|
||||||
|
body = LZString.compressToBase64(body);
|
||||||
|
db.saveToDB(note.id, title, body, function (err, result) {
|
||||||
|
if (err) return callback(err, null);
|
||||||
|
note.server.isDirty = false;
|
||||||
|
note.updatetime = Date.now();
|
||||||
|
emitCheck(note);
|
||||||
|
callback(null, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
//clean when user not in any rooms or user not in connected list
|
//clean when user not in any rooms or user not in connected list
|
||||||
var cleaner = setInterval(function () {
|
var cleaner = setInterval(function () {
|
||||||
async.each(Object.keys(users), function (key, callback) {
|
async.each(Object.keys(users), function (key, callback) {
|
||||||
|
@ -310,6 +324,19 @@ var disconnectSocketQueue = [];
|
||||||
|
|
||||||
function finishConnection(socket, note, user) {
|
function finishConnection(socket, note, user) {
|
||||||
if (!socket || !note || !user) return;
|
if (!socket || !note || !user) return;
|
||||||
|
//check view permission
|
||||||
|
if (note.permission == 'private') {
|
||||||
|
if (socket.request.user && socket.request.user.logged_in && socket.request.user._id == note.owner) {
|
||||||
|
//na
|
||||||
|
} else {
|
||||||
|
socket.emit('info', {
|
||||||
|
code: 403
|
||||||
|
});
|
||||||
|
clearSocketQueue(connectionSocketQueue, socket);
|
||||||
|
isConnectionBusy = false;
|
||||||
|
return socket.disconnect(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
note.users[socket.id] = user;
|
note.users[socket.id] = user;
|
||||||
note.socks.push(socket);
|
note.socks.push(socket);
|
||||||
note.server.addClient(socket);
|
note.server.addClient(socket);
|
||||||
|
@ -363,13 +390,9 @@ function startConnection(socket) {
|
||||||
|
|
||||||
var owner = data.rows[0].owner;
|
var owner = data.rows[0].owner;
|
||||||
var ownerprofile = null;
|
var ownerprofile = null;
|
||||||
var permission = "freely";
|
|
||||||
if (owner && owner != "null") {
|
|
||||||
permission = "editable";
|
|
||||||
}
|
|
||||||
|
|
||||||
//find or new note
|
//find or new note
|
||||||
Note.findOrNewNote(notename, permission, function (err, note) {
|
Note.findOrNewNote(notename, owner, function (err, note) {
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
responseError(res, "404", "Not Found", "oops.");
|
||||||
clearSocketQueue(connectionSocketQueue, socket);
|
clearSocketQueue(connectionSocketQueue, socket);
|
||||||
|
@ -399,41 +422,52 @@ function startConnection(socket) {
|
||||||
updatetime: moment(updatetime).valueOf(),
|
updatetime: moment(updatetime).valueOf(),
|
||||||
server: server
|
server: server
|
||||||
};
|
};
|
||||||
|
|
||||||
if (lastchangeuser) {
|
async.parallel([
|
||||||
//find last change user profile if lastchangeuser exists
|
function getlastchangeuser(callback) {
|
||||||
User.findUser(lastchangeuser, function (err, user) {
|
if (lastchangeuser) {
|
||||||
if (!err && user && user.profile) {
|
//find last change user profile if lastchangeuser exists
|
||||||
var profile = JSON.parse(user.profile);
|
User.findUser(lastchangeuser, function (err, user) {
|
||||||
if (profile) {
|
if (!err && user && user.profile) {
|
||||||
lastchangeuserprofile = {
|
var profile = JSON.parse(user.profile);
|
||||||
name: profile.displayName || profile.username,
|
if (profile) {
|
||||||
photo: User.parsePhotoByProfile(profile)
|
lastchangeuserprofile = {
|
||||||
|
name: profile.displayName || profile.username,
|
||||||
|
photo: User.parsePhotoByProfile(profile)
|
||||||
|
}
|
||||||
|
notes[notename].lastchangeuserprofile = lastchangeuserprofile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
notes[notename].lastchangeuserprofile = lastchangeuserprofile;
|
callback(null, null);
|
||||||
}
|
});
|
||||||
|
} else {
|
||||||
|
callback(null, null);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
}
|
function getowner(callback) {
|
||||||
|
if (owner && owner != "null") {
|
||||||
if (owner && owner != "null") {
|
//find owner profile if owner exists
|
||||||
//find owner profile if owner exists
|
User.findUser(owner, function (err, user) {
|
||||||
User.findUser(owner, function (err, user) {
|
if (!err && user && user.profile) {
|
||||||
if (!err && user && user.profile) {
|
var profile = JSON.parse(user.profile);
|
||||||
var profile = JSON.parse(user.profile);
|
if (profile) {
|
||||||
if (profile) {
|
ownerprofile = {
|
||||||
ownerprofile = {
|
name: profile.displayName || profile.username,
|
||||||
name: profile.displayName || profile.username,
|
photo: User.parsePhotoByProfile(profile)
|
||||||
photo: User.parsePhotoByProfile(profile)
|
}
|
||||||
|
notes[notename].ownerprofile = ownerprofile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
notes[notename].ownerprofile = ownerprofile;
|
callback(null, null);
|
||||||
}
|
});
|
||||||
|
} else {
|
||||||
|
callback(null, null);
|
||||||
}
|
}
|
||||||
finishConnection(socket, notes[notename], users[socket.id]);
|
}
|
||||||
});
|
], function(err, results){
|
||||||
} else {
|
if (err) return;
|
||||||
finishConnection(socket, notes[notename], users[socket.id]);
|
finishConnection(socket, notes[notename], users[socket.id]);
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -545,14 +579,14 @@ function ifMayEdit(socket, callback) {
|
||||||
if (!socket.request.user || !socket.request.user.logged_in)
|
if (!socket.request.user || !socket.request.user.logged_in)
|
||||||
mayEdit = false;
|
mayEdit = false;
|
||||||
break;
|
break;
|
||||||
case "locked":
|
case "locked": case "private":
|
||||||
//only owner can change
|
//only owner can change
|
||||||
if (note.owner != socket.request.user._id)
|
if (note.owner != socket.request.user._id)
|
||||||
mayEdit = false;
|
mayEdit = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//if user may edit and this note have owner (not anonymous usage)
|
//if user may edit and this note have owner (not anonymous usage)
|
||||||
if (mayEdit && note.owner && note.owner != "null") {
|
if (socket.origin == 'operation' && mayEdit && note.owner && note.owner != "null") {
|
||||||
//save for the last change user id
|
//save for the last change user id
|
||||||
if (socket.request.user && socket.request.user.logged_in) {
|
if (socket.request.user && socket.request.user.logged_in) {
|
||||||
note.lastchangeuser = socket.request.user._id;
|
note.lastchangeuser = socket.request.user._id;
|
||||||
|
@ -652,12 +686,22 @@ function connection(socket) {
|
||||||
permission: permission
|
permission: permission
|
||||||
};
|
};
|
||||||
realtime.io.to(note.id).emit('permission', out);
|
realtime.io.to(note.id).emit('permission', out);
|
||||||
/*
|
|
||||||
for (var i = 0, l = note.socks.length; i < l; i++) {
|
for (var i = 0, l = note.socks.length; i < l; i++) {
|
||||||
var sock = note.socks[i];
|
var sock = note.socks[i];
|
||||||
sock.emit('permission', out);
|
if (typeof sock !== 'undefined' && sock) {
|
||||||
};
|
//check view permission
|
||||||
*/
|
if (permission == 'private') {
|
||||||
|
if (sock.request.user && sock.request.user.logged_in && sock.request.user._id == note.owner) {
|
||||||
|
//na
|
||||||
|
} else {
|
||||||
|
sock.emit('info', {
|
||||||
|
code: 403
|
||||||
|
});
|
||||||
|
return sock.disconnect(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
258
lib/response.js
258
lib/response.js
|
@ -90,21 +90,9 @@ function showIndex(req, res, next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function responseHackMD(res, noteId) {
|
function responseHackMD(res, noteId) {
|
||||||
if (noteId != config.featuresnotename) {
|
|
||||||
if (!Note.checkNoteIdValid(noteId)) {
|
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
noteId = LZString.decompressFromBase64(noteId);
|
|
||||||
if (!noteId) {
|
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
db.readFromDB(noteId, function (err, data) {
|
db.readFromDB(noteId, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var body = LZString.decompressFromBase64(data.rows[0].content);
|
var body = LZString.decompressFromBase64(data.rows[0].content);
|
||||||
var meta = null;
|
var meta = null;
|
||||||
|
@ -144,14 +132,18 @@ function newNote(req, res, next) {
|
||||||
body = LZString.compressToBase64(body);
|
body = LZString.compressToBase64(body);
|
||||||
var owner = null;
|
var owner = null;
|
||||||
if (req.isAuthenticated()) {
|
if (req.isAuthenticated()) {
|
||||||
owner = req.session.passport.user;
|
owner = req.user._id;
|
||||||
}
|
}
|
||||||
db.newToDB(newId, owner, body, function (err, result) {
|
db.newToDB(newId, owner, body, function (err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "500", "Internal Error", "wtf.");
|
return response.errorInternalError(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
res.redirect("/" + LZString.compressToBase64(newId));
|
Note.newNote(newId, owner, function(err, result) {
|
||||||
|
if (err) {
|
||||||
|
return response.errorInternalError(res);
|
||||||
|
}
|
||||||
|
res.redirect("/" + LZString.compressToBase64(newId));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,8 +154,7 @@ function showFeatures(req, res, next) {
|
||||||
body = LZString.compressToBase64(body);
|
body = LZString.compressToBase64(body);
|
||||||
db.newToDB(config.featuresnotename, null, body, function (err, result) {
|
db.newToDB(config.featuresnotename, null, body, function (err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "500", "Internal Error", "wtf.");
|
return response.errorInternalError(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
responseHackMD(res, config.featuresnotename);
|
responseHackMD(res, config.featuresnotename);
|
||||||
});
|
});
|
||||||
|
@ -175,11 +166,32 @@ function showFeatures(req, res, next) {
|
||||||
|
|
||||||
function showNote(req, res, next) {
|
function showNote(req, res, next) {
|
||||||
var noteId = req.params.noteId;
|
var noteId = req.params.noteId;
|
||||||
if (!Note.checkNoteIdValid(noteId)) {
|
if (noteId != config.featuresnotename) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
if (!Note.checkNoteIdValid(noteId)) {
|
||||||
return;
|
return response.errorNotFound(res);
|
||||||
|
}
|
||||||
|
noteId = LZString.decompressFromBase64(noteId);
|
||||||
|
if (!noteId) {
|
||||||
|
return response.errorNotFound(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
responseHackMD(res, noteId);
|
Note.findNote(noteId, function (err, note) {
|
||||||
|
if (err || !note) {
|
||||||
|
return response.errorNotFound(res);
|
||||||
|
}
|
||||||
|
db.readFromDB(note.id, function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
return response.errorNotFound(res);
|
||||||
|
}
|
||||||
|
var notedata = data.rows[0];
|
||||||
|
//check view permission
|
||||||
|
if (note.permission == 'private') {
|
||||||
|
if (!req.isAuthenticated() || notedata.owner != req.user._id)
|
||||||
|
return response.errorForbidden(res);
|
||||||
|
}
|
||||||
|
responseHackMD(res, noteId);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPublishNote(req, res, next) {
|
function showPublishNote(req, res, next) {
|
||||||
|
@ -187,30 +199,33 @@ function showPublishNote(req, res, next) {
|
||||||
if (shortId.isValid(shortid)) {
|
if (shortId.isValid(shortid)) {
|
||||||
Note.findNote(shortid, function (err, note) {
|
Note.findNote(shortid, function (err, note) {
|
||||||
if (err || !note) {
|
if (err || !note) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
//increase note viewcount
|
db.readFromDB(note.id, function (err, data) {
|
||||||
Note.increaseViewCount(note, function (err, note) {
|
if (err) {
|
||||||
if (err || !note) {
|
return response.errorNotFound(res);
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
db.readFromDB(note.id, function (err, data) {
|
var notedata = data.rows[0];
|
||||||
if (err) {
|
//check view permission
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
if (note.permission == 'private') {
|
||||||
return;
|
if (!req.isAuthenticated() || notedata.owner != req.user._id)
|
||||||
|
return response.errorForbidden(res);
|
||||||
|
}
|
||||||
|
//increase note viewcount
|
||||||
|
Note.increaseViewCount(note, function (err, note) {
|
||||||
|
if (err || !note) {
|
||||||
|
return response.errorNotFound(res);
|
||||||
}
|
}
|
||||||
var body = LZString.decompressFromBase64(data.rows[0].content);
|
var body = LZString.decompressFromBase64(notedata.content);
|
||||||
var meta = null;
|
var meta = null;
|
||||||
try {
|
try {
|
||||||
meta = metaMarked(body).meta;
|
meta = metaMarked(body).meta;
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
//na
|
//na
|
||||||
}
|
}
|
||||||
var updatetime = data.rows[0].update_time;
|
var updatetime = notedata.update_time;
|
||||||
var text = S(body).escapeHTML().s;
|
var text = S(body).escapeHTML().s;
|
||||||
var title = data.rows[0].title;
|
var title = notedata.title;
|
||||||
var decodedTitle = LZString.decompressFromBase64(title);
|
var decodedTitle = LZString.decompressFromBase64(title);
|
||||||
if (decodedTitle) title = decodedTitle;
|
if (decodedTitle) title = decodedTitle;
|
||||||
title = Note.generateWebTitle(title);
|
title = Note.generateWebTitle(title);
|
||||||
|
@ -247,7 +262,7 @@ function showPublishNote(req, res, next) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,18 +286,12 @@ function renderPublish(data, res) {
|
||||||
function actionPublish(req, res, noteId) {
|
function actionPublish(req, res, noteId) {
|
||||||
db.readFromDB(noteId, function (err, data) {
|
db.readFromDB(noteId, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var owner = data.rows[0].owner;
|
var owner = data.rows[0].owner;
|
||||||
var permission = "freely";
|
Note.findOrNewNote(noteId, owner, function (err, note) {
|
||||||
if (owner && owner != "null") {
|
|
||||||
permission = "editable";
|
|
||||||
}
|
|
||||||
Note.findOrNewNote(noteId, permission, function (err, note) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
res.redirect("/s/" + note.shortid);
|
res.redirect("/s/" + note.shortid);
|
||||||
});
|
});
|
||||||
|
@ -292,18 +301,12 @@ function actionPublish(req, res, noteId) {
|
||||||
function actionSlide(req, res, noteId) {
|
function actionSlide(req, res, noteId) {
|
||||||
db.readFromDB(noteId, function (err, data) {
|
db.readFromDB(noteId, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var owner = data.rows[0].owner;
|
var owner = data.rows[0].owner;
|
||||||
var permission = "freely";
|
Note.findOrNewNote(noteId, owner, function (err, note) {
|
||||||
if (owner && owner != "null") {
|
|
||||||
permission = "editable";
|
|
||||||
}
|
|
||||||
Note.findOrNewNote(noteId, permission, function (err, note) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
res.redirect("/p/" + note.shortid);
|
res.redirect("/p/" + note.shortid);
|
||||||
});
|
});
|
||||||
|
@ -313,8 +316,7 @@ function actionSlide(req, res, noteId) {
|
||||||
function actionDownload(req, res, noteId) {
|
function actionDownload(req, res, noteId) {
|
||||||
db.readFromDB(noteId, function (err, data) {
|
db.readFromDB(noteId, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var body = LZString.decompressFromBase64(data.rows[0].content);
|
var body = LZString.decompressFromBase64(data.rows[0].content);
|
||||||
var title = Note.getNoteTitle(body);
|
var title = Note.getNoteTitle(body);
|
||||||
|
@ -331,8 +333,7 @@ function actionDownload(req, res, noteId) {
|
||||||
function actionPDF(req, res, noteId) {
|
function actionPDF(req, res, noteId) {
|
||||||
db.readFromDB(noteId, function (err, data) {
|
db.readFromDB(noteId, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var body = LZString.decompressFromBase64(data.rows[0].content);
|
var body = LZString.decompressFromBase64(data.rows[0].content);
|
||||||
try {
|
try {
|
||||||
|
@ -365,57 +366,81 @@ function noteActions(req, res, next) {
|
||||||
var noteId = req.params.noteId;
|
var noteId = req.params.noteId;
|
||||||
if (noteId != config.featuresnotename) {
|
if (noteId != config.featuresnotename) {
|
||||||
if (!Note.checkNoteIdValid(noteId)) {
|
if (!Note.checkNoteIdValid(noteId)) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
noteId = LZString.decompressFromBase64(noteId);
|
noteId = LZString.decompressFromBase64(noteId);
|
||||||
if (!noteId) {
|
if (!noteId) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var action = req.params.action;
|
Note.findNote(noteId, function (err, note) {
|
||||||
switch (action) {
|
if (err || !note) {
|
||||||
case "publish":
|
return response.errorNotFound(res);
|
||||||
case "pretty": //pretty deprecated
|
}
|
||||||
actionPublish(req, res, noteId);
|
db.readFromDB(note.id, function (err, data) {
|
||||||
break;
|
if (err) {
|
||||||
case "slide":
|
return response.errorNotFound(res);
|
||||||
actionSlide(req, res, noteId);
|
}
|
||||||
break;
|
var notedata = data.rows[0];
|
||||||
case "download":
|
//check view permission
|
||||||
actionDownload(req, res, noteId);
|
if (note.permission == 'private') {
|
||||||
break;
|
if (!req.isAuthenticated() || notedata.owner != req.user._id)
|
||||||
case "pdf":
|
return response.errorForbidden(res);
|
||||||
actionPDF(req, res, noteId);
|
}
|
||||||
break;
|
var action = req.params.action;
|
||||||
default:
|
switch (action) {
|
||||||
if (noteId != config.featuresnotename)
|
case "publish":
|
||||||
res.redirect('/' + LZString.compressToBase64(noteId));
|
case "pretty": //pretty deprecated
|
||||||
else
|
actionPublish(req, res, noteId);
|
||||||
res.redirect('/' + noteId);
|
break;
|
||||||
break;
|
case "slide":
|
||||||
}
|
actionSlide(req, res, noteId);
|
||||||
|
break;
|
||||||
|
case "download":
|
||||||
|
actionDownload(req, res, noteId);
|
||||||
|
break;
|
||||||
|
case "pdf":
|
||||||
|
actionPDF(req, res, noteId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (noteId != config.featuresnotename)
|
||||||
|
res.redirect('/' + LZString.compressToBase64(noteId));
|
||||||
|
else
|
||||||
|
res.redirect('/' + noteId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function publishNoteActions(req, res, next) {
|
function publishNoteActions(req, res, next) {
|
||||||
var action = req.params.action;
|
var shortid = req.params.shortid;
|
||||||
switch (action) {
|
if (shortId.isValid(shortid)) {
|
||||||
case "edit":
|
Note.findNote(shortid, function (err, note) {
|
||||||
var shortid = req.params.shortid;
|
if (err || !note) {
|
||||||
if (shortId.isValid(shortid)) {
|
return response.errorNotFound(res);
|
||||||
Note.findNote(shortid, function (err, note) {
|
}
|
||||||
if (err || !note) {
|
db.readFromDB(note.id, function (err, data) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
if (err) {
|
||||||
return;
|
return response.errorNotFound(res);
|
||||||
|
}
|
||||||
|
var notedata = data.rows[0];
|
||||||
|
//check view permission
|
||||||
|
if (note.permission == 'private') {
|
||||||
|
if (!req.isAuthenticated() || notedata.owner != req.user._id)
|
||||||
|
return response.errorForbidden(res);
|
||||||
|
}
|
||||||
|
var action = req.params.action;
|
||||||
|
switch (action) {
|
||||||
|
case "edit":
|
||||||
|
if (note.id != config.featuresnotename)
|
||||||
|
res.redirect('/' + LZString.compressToBase64(note.id));
|
||||||
|
else
|
||||||
|
res.redirect('/' + note.id);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (note.id != config.featuresnotename)
|
|
||||||
res.redirect('/' + LZString.compressToBase64(note.id));
|
|
||||||
else
|
|
||||||
res.redirect('/' + note.id);
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,27 +449,30 @@ function showPublishSlide(req, res, next) {
|
||||||
if (shortId.isValid(shortid)) {
|
if (shortId.isValid(shortid)) {
|
||||||
Note.findNote(shortid, function (err, note) {
|
Note.findNote(shortid, function (err, note) {
|
||||||
if (err || !note) {
|
if (err || !note) {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
//increase note viewcount
|
db.readFromDB(note.id, function (err, data) {
|
||||||
Note.increaseViewCount(note, function (err, note) {
|
if (err) {
|
||||||
if (err || !note) {
|
return response.errorNotFound(res);
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
db.readFromDB(note.id, function (err, data) {
|
var notedata = data.rows[0];
|
||||||
if (err) {
|
//check view permission
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
if (note.permission == 'private') {
|
||||||
return;
|
if (!req.isAuthenticated() || notedata.owner != req.user._id)
|
||||||
|
return response.errorForbidden(res);
|
||||||
|
}
|
||||||
|
//increase note viewcount
|
||||||
|
Note.increaseViewCount(note, function (err, note) {
|
||||||
|
if (err || !note) {
|
||||||
|
return response.errorNotFound(res);
|
||||||
}
|
}
|
||||||
var body = LZString.decompressFromBase64(data.rows[0].content);
|
var body = LZString.decompressFromBase64(notedata.content);
|
||||||
try {
|
try {
|
||||||
body = metaMarked(body).markdown;
|
body = metaMarked(body).markdown;
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
//na
|
//na
|
||||||
}
|
}
|
||||||
var title = data.rows[0].title;
|
var title = notedata.title;
|
||||||
var decodedTitle = LZString.decompressFromBase64(title);
|
var decodedTitle = LZString.decompressFromBase64(title);
|
||||||
if (decodedTitle) title = decodedTitle;
|
if (decodedTitle) title = decodedTitle;
|
||||||
title = Note.generateWebTitle(title);
|
title = Note.generateWebTitle(title);
|
||||||
|
@ -454,7 +482,7 @@ function showPublishSlide(req, res, next) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
responseError(res, "404", "Not Found", "oops.");
|
return response.errorNotFound(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -327,7 +327,8 @@ var ui = {
|
||||||
label: $(".ui-permission-label"),
|
label: $(".ui-permission-label"),
|
||||||
freely: $(".ui-permission-freely"),
|
freely: $(".ui-permission-freely"),
|
||||||
editable: $(".ui-permission-editable"),
|
editable: $(".ui-permission-editable"),
|
||||||
locked: $(".ui-permission-locked")
|
locked: $(".ui-permission-locked"),
|
||||||
|
private: $(".ui-permission-private")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toc: {
|
toc: {
|
||||||
|
@ -1067,6 +1068,10 @@ ui.infobar.permission.editable.click(function () {
|
||||||
ui.infobar.permission.locked.click(function () {
|
ui.infobar.permission.locked.click(function () {
|
||||||
emitPermission("locked");
|
emitPermission("locked");
|
||||||
});
|
});
|
||||||
|
//private
|
||||||
|
ui.infobar.permission.private.click(function () {
|
||||||
|
emitPermission("private");
|
||||||
|
});
|
||||||
|
|
||||||
function emitPermission(_permission) {
|
function emitPermission(_permission) {
|
||||||
if (_permission != permission) {
|
if (_permission != permission) {
|
||||||
|
@ -1094,6 +1099,10 @@ function updatePermission(newPermission) {
|
||||||
label = '<i class="fa fa-lock"></i> Locked';
|
label = '<i class="fa fa-lock"></i> Locked';
|
||||||
title = "Only owner can edit";
|
title = "Only owner can edit";
|
||||||
break;
|
break;
|
||||||
|
case "private":
|
||||||
|
label = '<i class="fa fa-hand-stop-o"></i> Private';
|
||||||
|
title = "Only owner can view & edit";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (personalInfo.userid == owner) {
|
if (personalInfo.userid == owner) {
|
||||||
label += ' <i class="fa fa-caret-down"></i>';
|
label += ' <i class="fa fa-caret-down"></i>';
|
||||||
|
@ -1118,6 +1127,7 @@ function havePermission() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "locked":
|
case "locked":
|
||||||
|
case "private":
|
||||||
if (personalInfo.userid != owner) {
|
if (personalInfo.userid != owner) {
|
||||||
bool = false;
|
bool = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1145,7 +1155,14 @@ socket.emit = function () {
|
||||||
};
|
};
|
||||||
socket.on('info', function (data) {
|
socket.on('info', function (data) {
|
||||||
console.error(data);
|
console.error(data);
|
||||||
location.href = "./404";
|
switch (data.code) {
|
||||||
|
case 404:
|
||||||
|
location.href = "./404";
|
||||||
|
break;
|
||||||
|
case 403:
|
||||||
|
location.href = "./403";
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
socket.on('error', function (data) {
|
socket.on('error', function (data) {
|
||||||
console.error(data);
|
console.error(data);
|
||||||
|
@ -1755,6 +1772,7 @@ editor.on('beforeChange', function (cm, change) {
|
||||||
$('.signin-modal').modal('show');
|
$('.signin-modal').modal('show');
|
||||||
break;
|
break;
|
||||||
case "locked":
|
case "locked":
|
||||||
|
case "private":
|
||||||
$('.locked-modal').modal('show');
|
$('.locked-modal').modal('show');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
<li class="ui-permission-freely"><a><i class="fa fa-leaf fa-fw"></i> Freely - Anyone can edit</a></li>
|
<li class="ui-permission-freely"><a><i class="fa fa-leaf fa-fw"></i> Freely - Anyone can edit</a></li>
|
||||||
<li class="ui-permission-editable"><a><i class="fa fa-shield fa-fw"></i> Editable - Signed people can edit</a></li>
|
<li class="ui-permission-editable"><a><i class="fa fa-shield fa-fw"></i> Editable - Signed people can edit</a></li>
|
||||||
<li class="ui-permission-locked"><a><i class="fa fa-lock fa-fw"></i> Locked - Only owner can edit</a></li>
|
<li class="ui-permission-locked"><a><i class="fa fa-lock fa-fw"></i> Locked - Only owner can edit</a></li>
|
||||||
|
<li class="ui-permission-private"><a><i class="fa fa-hand-stop-o fa-fw"></i> Private - Only owner can view & edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</span>
|
</span>
|
||||||
</small>
|
</small>
|
||||||
|
|
Loading…
Reference in a new issue