From 10c9811fc534a2738c19d8f74a447ed500b730a2 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Thu, 2 Jul 2015 00:10:20 +0800 Subject: Jump to 0.3.1 --- lib/auth.js | 13 +-- lib/db.js | 35 +++--- lib/logger.js | 3 +- lib/note.js | 153 ++++++++++++++++++++++++-- lib/realtime.js | 328 ++++++++++++++++++++++++++++++++++++++++---------------- lib/response.js | 177 ++++++++++++++++++++++++++---- lib/temp.js | 13 +-- lib/user.js | 11 +- 8 files changed, 579 insertions(+), 154 deletions(-) (limited to 'lib') diff --git a/lib/auth.js b/lib/auth.js index 456c9dff..dc8b94ca 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -7,17 +7,18 @@ var GithubStrategy = require('passport-github').Strategy; var DropboxStrategy = require('passport-dropbox-oauth2').Strategy; //core -var User = require('./user.js') -var config = require('../config.js') +var User = require('./user.js'); +var config = require('../config.js'); +var logger = require("./logger.js"); function callback(accessToken, refreshToken, profile, done) { - //console.log(profile.displayName || profile.username); + //logger.info(profile.displayName || profile.username); User.findOrNewUser(profile.id, profile, function (err, user) { if (err || user == null) { - console.log('auth callback failed: ' + err); + logger.error('auth callback failed: ' + err); } else { - if(config.debug && user) - console.log('user login: ' + user._id); + if (config.debug && user) + logger.info('user login: ' + user._id); done(null, user); } }); diff --git a/lib/db.js b/lib/db.js index d924cdf8..e0f873e5 100644 --- a/lib/db.js +++ b/lib/db.js @@ -6,6 +6,7 @@ var util = require('util'); //core var config = require("../config.js"); +var logger = require("./logger.js"); //public var db = { @@ -48,18 +49,18 @@ function newToDB(id, owner, body, callback) { if (err) { client.end(); callback(err, null); - return console.error('could not connect to postgres', err); + return logger.error('could not connect to postgres', err); } var newnotequery = util.format(insertquery, id, owner, body); - //console.log(newnotequery); + //logger.info(newnotequery); client.query(newnotequery, function (err, result) { client.end(); if (err) { callback(err, null); - return console.error("new note to db failed: " + err); + return logger.error("new note to db failed: " + err); } else { if (config.debug) - console.log("new note to db success"); + logger.info("new note to db success"); callback(null, result); } }); @@ -72,22 +73,22 @@ function readFromDB(id, callback) { if (err) { client.end(); callback(err, null); - return console.error('could not connect to postgres', err); + return logger.error('could not connect to postgres', err); } var readquery = util.format(selectquery, id); - //console.log(readquery); + //logger.info(readquery); client.query(readquery, function (err, result) { client.end(); if (err) { callback(err, null); - return console.error("read from db failed: " + err); + return logger.error("read from db failed: " + err); } else { - //console.log(result.rows); + //logger.info(result.rows); if (result.rows.length <= 0) { callback("not found note in db: " + id, null); } else { if(config.debug) - console.log("read from db success"); + logger.info("read from db success"); callback(null, result); } } @@ -101,18 +102,18 @@ function saveToDB(id, title, data, callback) { if (err) { client.end(); callback(err, null); - return console.error('could not connect to postgres', err); + return logger.error('could not connect to postgres', err); } var savequery = util.format(updatequery, title, data, id); - //console.log(savequery); + //logger.info(savequery); client.query(savequery, function (err, result) { client.end(); if (err) { callback(err, null); - return console.error("save to db failed: " + err); + return logger.error("save to db failed: " + err); } else { if (config.debug) - console.log("save to db success"); + logger.info("save to db success"); callback(null, result); } }); @@ -125,20 +126,20 @@ function countFromDB(callback) { if (err) { client.end(); callback(err, null); - return console.error('could not connect to postgres', err); + return logger.error('could not connect to postgres', err); } client.query(countquery, function (err, result) { client.end(); if (err) { callback(err, null); - return console.error("count from db failed: " + err); + return logger.error("count from db failed: " + err); } else { - //console.log(result.rows); + //logger.info(result.rows); if (result.rows.length <= 0) { callback("not found note in db", null); } else { if(config.debug) - console.log("count from db success"); + logger.info("count from db success"); callback(null, result); } } diff --git a/lib/logger.js b/lib/logger.js index c843330b..61299c10 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -7,7 +7,8 @@ var logger = new winston.Logger({ level: 'debug', handleExceptions: true, json: false, - colorize: true + colorize: true, + timestamp: true }) ], exitOnError: false diff --git a/lib/note.js b/lib/note.js index 1212e1a6..dc384b7f 100644 --- a/lib/note.js +++ b/lib/note.js @@ -1,22 +1,56 @@ //note //external modules +var mongoose = require('mongoose'); +var Schema = mongoose.Schema; var LZString = require('lz-string'); var marked = require('marked'); var cheerio = require('cheerio'); +var shortId = require('shortid'); //others var db = require("./db.js"); +var logger = require("./logger.js"); + +//permission types +permissionTypes = ["freely", "editable", "locked"]; + +// create a note model +var model = mongoose.model('note', { + id: String, + shortid: { + type: String, + unique: true, + default: shortId.generate + }, + permission: { + type: String, + enum: permissionTypes + }, + viewcount: { + type: Number, + default: 0 + }, + updated: Date, + created: Date +}); //public var note = { + model: model, + findNote: findNote, + newNote: newNote, + findOrNewNote: findOrNewNote, checkNoteIdValid: checkNoteIdValid, checkNoteExist: checkNoteExist, - getNoteTitle: getNoteTitle + getNoteTitle: getNoteTitle, + generateWebTitle: generateWebTitle, + increaseViewCount: increaseViewCount, + updatePermission: updatePermission }; function checkNoteIdValid(noteId) { try { - //console.log(noteId); + //logger.info(noteId); var id = LZString.decompressFromBase64(noteId); if (!id) return false; var uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; @@ -26,21 +60,21 @@ function checkNoteIdValid(noteId) { else return false; } catch (err) { - console.error(err); + logger.error(err); return false; } } function checkNoteExist(noteId) { try { - //console.log(noteId); + //logger.info(noteId); var id = LZString.decompressFromBase64(noteId); db.readFromDB(id, function (err, result) { if (err) return false; return true; }); } catch (err) { - console.error(err); + logger.error(err); return false; } } @@ -50,11 +84,118 @@ function getNoteTitle(body) { var $ = cheerio.load(marked(body)); var h1s = $("h1"); var title = ""; - if (h1s.length > 0) + if (h1s.length > 0 && h1s.first().text().split('\n').length == 1) title = h1s.first().text(); else title = "Untitled"; return title; } +//generate note web page title +function generateWebTitle(title) { + title = !title || title == "Untitled" ? "HackMD - Collaborative notes" : title + " - HackMD"; + return title; +} + +function findNote(id, callback) { + model.findOne({ + $or: [ + { + id: id + }, + { + shortid: id + } + ] + }, function (err, note) { + if (err) { + logger.error('find note failed: ' + err); + callback(err, null); + } + if (!err && note) { + callback(null, note); + } else { + logger.error('find note failed: ' + err); + callback(err, null); + }; + }); +} + +function newNote(id, permission, callback) { + var note = new model({ + id: id, + permission: permission, + updated: Date.now(), + created: Date.now() + }); + note.save(function (err) { + if (err) { + logger.error('new note failed: ' + err); + callback(err, null); + } else { + logger.info("new note success: " + note.id); + callback(null, note); + }; + }); +} + +function findOrNewNote(id, permission, callback) { + findNote(id, function (err, note) { + if (err || !note) { + newNote(id, permission, function (err, note) { + if (err) { + logger.error('find or new note failed: ' + err); + callback(err, null); + } else { + callback(null, note); + } + }); + } else { + if (!note.permission) { + note.permission = permission; + note.updated = Date.now(); + note.save(function (err) { + if (err) { + logger.error('add note permission failed: ' + err); + callback(err, null); + } else { + logger.info("add note permission success: " + note.id); + callback(null, note); + }; + }); + } else { + callback(null, note); + } + } + }); +} + +function increaseViewCount(note, callback) { + note.viewcount++; + note.updated = Date.now(); + note.save(function (err) { + if (err) { + logger.error('increase note viewcount failed: ' + err); + callback(err, null); + } else { + logger.info("increase note viewcount success: " + note.id); + callback(null, note); + }; + }); +} + +function updatePermission(note, permission, callback) { + note.permission = permission; + note.updated = Date.now(); + note.save(function (err) { + if (err) { + logger.error('update note permission failed: ' + err); + callback(err, null); + } else { + logger.info("update note permission success: " + note.id); + callback(null, note); + }; + }); +} + module.exports = note; \ No newline at end of file diff --git a/lib/realtime.js b/lib/realtime.js index 1a57c77e..57038b72 100644 --- a/lib/realtime.js +++ b/lib/realtime.js @@ -9,9 +9,12 @@ var shortId = require('shortid'); var randomcolor = require("randomcolor"); var Chance = require('chance'), chance = new Chance(); +var md5 = require("blueimp-md5").md5; +var moment = require('moment'); //core var config = require("../config.js"); +var logger = require("./logger.js"); //others var db = require("./db.js"); @@ -49,7 +52,7 @@ function secure(socket, next) { next(new Error('AUTH failed: No cookie transmitted.')); } if (config.debug) - console.log("AUTH success cookie: " + handshakeData.sessionID); + logger.info("AUTH success cookie: " + handshakeData.sessionID); next(); } catch (ex) { @@ -65,9 +68,10 @@ var updater = setInterval(function () { var note = notes[key]; if (note.isDirty) { if (config.debug) - console.log("updater found dirty note: " + key); + logger.info("updater found dirty note: " + key); var body = LZString.decompressFromUTF16(note.body); var title = Note.getNoteTitle(body); + title = LZString.compressToBase64(title); body = LZString.compressToBase64(body); db.saveToDB(key, title, body, function (err, result) {}); @@ -75,36 +79,45 @@ var updater = setInterval(function () { } callback(); }, function (err) { - if (err) return console.error('updater error', err); + if (err) return logger.error('updater error', err); }); }, 5000); function getStatus(callback) { db.countFromDB(function (err, data) { - if (err) return console.log(err); - var regusers = 0; - var distinctregusers = 0; + if (err) return logger.info(err); var distinctaddresses = []; + var regaddresses = []; + var distinctregaddresses = []; Object.keys(users).forEach(function (key) { - var value = users[key]; - if (value.login) - regusers++; + var user = users[key]; var found = false; for (var i = 0; i < distinctaddresses.length; i++) { - if (value.address == distinctaddresses[i]) { + if (user.address == distinctaddresses[i]) { found = true; break; } } if (!found) { - distinctaddresses.push(value.address); - if (value.login) - distinctregusers++; + distinctaddresses.push(user.address); + } + if (user.login) { + regaddresses.push(user.address); + var found = false; + for (var i = 0; i < distinctregaddresses.length; i++) { + if (user.address == distinctregaddresses[i]) { + found = true; + break; + } + } + if (!found) { + distinctregaddresses.push(user.address); + } } }); User.getUserCount(function (err, regcount) { if (err) { - console.log('get status failed: ' + err); + logger.error('get status failed: ' + err); return; } if (callback) @@ -114,8 +127,8 @@ function getStatus(callback) { distinctOnlineUsers: distinctaddresses.length, notesCount: data.rows[0].count, registeredUsers: regcount, - onlineRegisteredUsers: regusers, - distinctOnlineRegisteredUsers: distinctregusers + onlineRegisteredUsers: regaddresses.length, + distinctOnlineRegisteredUsers: distinctregaddresses.length }); }); }); @@ -146,23 +159,40 @@ function emitOnlineUsers(socket) { if (user) users.push(buildUserOutData(user)); }); - notes[notename].socks.forEach(function (sock) { - var out = { - users: users - }; - out = LZString.compressToUTF16(JSON.stringify(out)); - sock.emit('online users', out); - }); + var out = { + users: users + }; + out = LZString.compressToUTF16(JSON.stringify(out)); + for (var i = 0, l = notes[notename].socks.length; i < l; i++) { + var sock = notes[notename].socks[i]; + if (sock && out) + sock.emit('online users', out); + }; } function emitUserStatus(socket) { var notename = getNotenameFromSocket(socket); if (!notename || !notes[notename]) return; - notes[notename].socks.forEach(function (sock) { + var out = buildUserOutData(users[socket.id]); + for (var i = 0, l = notes[notename].socks.length; i < l; i++) { + var sock = notes[notename].socks[i]; if (sock != socket) { - var out = buildUserOutData(users[socket.id]); sock.emit('user status', out); } + }; +} + +function emitRefresh(socket) { + var notename = getNotenameFromSocket(socket); + if (!notename || !notes[notename]) return; + var note = notes[notename]; + socket.emit('refresh', { + owner: note.owner, + permission: note.permission, + body: note.body, + otk: note.otk, + hash: note.hash, + updatetime: note.updatetime }); } @@ -175,9 +205,7 @@ function finishConnection(socket, notename) { notes[notename].users[socket.id] = users[socket.id]; notes[notename].socks.push(socket); emitOnlineUsers(socket); - socket.emit('refresh', { - body: notes[notename].body - }); + emitRefresh(socket); //clear finished socket in queue for (var i = 0; i < connectionSocketQueue.length; i++) { @@ -190,11 +218,11 @@ function finishConnection(socket, notename) { startConnection(connectionSocketQueue[0]); if (config.debug) { - console.log('SERVER connected a client to [' + notename + ']:'); - console.log(JSON.stringify(users[socket.id])); - //console.log(notes); + logger.info('SERVER connected a client to [' + notename + ']:'); + logger.info(JSON.stringify(users[socket.id])); + //logger.info(notes); getStatus(function (data) { - console.log(JSON.stringify(data)); + logger.info(JSON.stringify(data)); }); } } @@ -219,17 +247,34 @@ function startConnection(socket) { connectionSocketQueue.splice(i, 1); } isConnectionBusy = false; - return console.error(err); + return logger.error(err); } - var body = LZString.decompressFromBase64(data.rows[0].content); - body = LZString.compressToUTF16(body); - notes[notename] = { - socks: [], - body: body, - isDirty: false, - users: {} - }; - finishConnection(socket, notename); + var owner = data.rows[0].owner; + var permission = "freely"; + if (owner && owner != "null") { + permission = "editable"; + } + Note.findOrNewNote(notename, permission, function (err, note) { + if (err) { + responseError(res, "404", "Not Found", "oops."); + return; + } + var body = LZString.decompressFromBase64(data.rows[0].content); + body = LZString.compressToUTF16(body); + var updatetime = data.rows[0].update_time; + notes[notename] = { + owner: owner, + permission: note.permission, + socks: [], + body: body, + isDirty: false, + users: {}, + otk: shortId.generate(), + hash: md5(body), + updatetime: moment(updatetime).valueOf() + }; + finishConnection(socket, notename); + }); }); } else { finishConnection(socket, notename); @@ -241,8 +286,8 @@ function disconnect(socket) { isDisconnectBusy = true; if (config.debug) { - console.log("SERVER disconnected a client"); - console.log(JSON.stringify(users[socket.id])); + logger.info("SERVER disconnected a client"); + logger.info(JSON.stringify(users[socket.id])); } var notename = getNotenameFromSocket(socket); if (!notename) return; @@ -251,24 +296,31 @@ function disconnect(socket) { } if (notes[notename]) { delete notes[notename].users[socket.id]; - var index = notes[notename].socks.indexOf(socket); - if (index > -1) { - notes[notename].socks.splice(index, 1); - } + do { + var index = notes[notename].socks.indexOf(socket); + if (index != -1) { + notes[notename].socks.splice(index, 1); + } + } while (index != -1); if (Object.keys(notes[notename].users).length <= 0) { - var body = LZString.decompressFromUTF16(notes[notename].body); - var title = Note.getNoteTitle(body); - body = LZString.compressToBase64(body); - db.saveToDB(notename, title, body, - function (err, result) { - delete notes[notename]; - if (config.debug) { - //console.log(notes); - getStatus(function (data) { - console.log(JSON.stringify(data)); - }); - } - }); + if (notes[notename].isDirty) { + var body = LZString.decompressFromUTF16(notes[notename].body); + var title = Note.getNoteTitle(body); + title = LZString.compressToBase64(title); + body = LZString.compressToBase64(body); + db.saveToDB(notename, title, body, + function (err, result) { + delete notes[notename]; + if (config.debug) { + //logger.info(notes); + getStatus(function (data) { + logger.info(JSON.stringify(data)); + }); + } + }); + } else { + delete notes[notename]; + } } } emitOnlineUsers(socket); @@ -284,9 +336,9 @@ function disconnect(socket) { disconnect(disconnectSocketQueue[0]); if (config.debug) { - //console.log(notes); + //logger.info(notes); getStatus(function (data) { - console.log(JSON.stringify(data)); + logger.info(JSON.stringify(data)); }); } } @@ -309,6 +361,24 @@ function updateUserData(socket, user) { //retrieve user data from passport if (socket.request.user && socket.request.user.logged_in) { var profile = JSON.parse(socket.request.user.profile); + /* + var photo = null; + switch(profile.provider) { + case "facebook": + console.log(profile); + break; + case "twitter": + photo = profile.photos[0]; + break; + case "github": + photo = profile.avatar_url; + break; + case "dropbox": + //not image api provided + break; + } + user.photo = photo; + */ user.name = profile.displayName || profile.username; user.userid = socket.request.user._id; user.login = true; @@ -353,7 +423,6 @@ function connection(socket) { id: socket.id, address: socket.handshake.address, 'user-agent': socket.handshake.headers['user-agent'], - otk: shortId.generate(), color: color, cursor: null, login: false, @@ -368,24 +437,41 @@ function connection(socket) { connectionSocketQueue.push(socket); startConnection(socket); - //when a new client coming or received a client refresh request - socket.on('refresh', function (body_) { + //received client refresh request + socket.on('refresh', function () { + emitRefresh(socket); + }); + + //received client data updated + socket.on('update', function (body_) { var notename = getNotenameFromSocket(socket); - if (!notename) return; + if (!notename || !notes[notename]) return; if (config.debug) - console.log('SERVER received [' + notename + '] data updated: ' + socket.id); - if (notes[notename].body != body_) { - notes[notename].body = body_; - notes[notename].isDirty = true; + logger.info('SERVER received [' + notename + '] data updated: ' + socket.id); + var note = notes[notename]; + if (note.body != body_) { + note.body = body_; + note.hash = md5(body_); + note.updatetime = Date.now(); + note.isDirty = true; } + var out = { + id: socket.id, + hash: note.hash, + updatetime: note.updatetime + }; + for (var i = 0, l = note.socks.length; i < l; i++) { + var sock = note.socks[i]; + sock.emit('check', out); + }; }); //received user status socket.on('user status', function (data) { var notename = getNotenameFromSocket(socket); - if (!notename) return; + if (!notename || !notes[notename]) return; if (config.debug) - console.log('SERVER received [' + notename + '] user status from [' + socket.id + ']: ' + JSON.stringify(data)); + logger.info('SERVER received [' + notename + '] user status from [' + socket.id + ']: ' + JSON.stringify(data)); if (data) { var user = users[socket.id]; user.idle = data.idle; @@ -394,9 +480,40 @@ function connection(socket) { emitUserStatus(socket); }); + //received note permission change request + socket.on('permission', function (permission) { + //need login to do more actions + if (socket.request.user && socket.request.user.logged_in) { + var notename = getNotenameFromSocket(socket); + if (!notename || !notes[notename]) return; + var note = notes[notename]; + //Only owner can change permission + if (note.owner == socket.request.user._id) { + note.permission = permission; + Note.findNote(notename, function (err, _note) { + if (err || !_note) { + return; + } + Note.updatePermission(_note, permission, function (err, _note) { + if (err || !_note) { + return; + } + var out = { + permission: permission + }; + for (var i = 0, l = note.socks.length; i < l; i++) { + var sock = note.socks[i]; + sock.emit('permission', out); + }; + }); + }); + } + } + }); + //reveiced when user logout or changed socket.on('user changed', function () { - console.log('user changed'); + logger.info('user changed'); var notename = getNotenameFromSocket(socket); if (!notename || !notes[notename]) return; updateUserData(socket, notes[notename].users[socket.id]); @@ -431,11 +548,12 @@ function connection(socket) { if (!notename || !notes[notename]) return; users[socket.id].cursor = data; var out = buildUserOutData(users[socket.id]); - notes[notename].socks.forEach(function (sock) { + for (var i = 0, l = notes[notename].socks.length; i < l; i++) { + var sock = notes[notename].socks[i]; if (sock != socket) { sock.emit('cursor focus', out); } - }); + }; }); //received cursor activity @@ -444,11 +562,12 @@ function connection(socket) { if (!notename || !notes[notename]) return; users[socket.id].cursor = data; var out = buildUserOutData(users[socket.id]); - notes[notename].socks.forEach(function (sock) { + for (var i = 0, l = notes[notename].socks.length; i < l; i++) { + var sock = notes[notename].socks[i]; if (sock != socket) { sock.emit('cursor activity', out); } - }); + }; }); //received cursor blur @@ -459,13 +578,12 @@ function connection(socket) { var out = { id: socket.id }; - notes[notename].socks.forEach(function (sock) { + for (var i = 0, l = notes[notename].socks.length; i < l; i++) { + var sock = notes[notename].socks[i]; if (sock != socket) { - if (sock != socket) { - sock.emit('cursor blur', out); - } + sock.emit('cursor blur', out); } - }); + }; }); //when a new client disconnect @@ -477,12 +595,30 @@ function connection(socket) { //when received client change data request socket.on('change', function (op) { var notename = getNotenameFromSocket(socket); - if (!notename) return; + if (!notename || !notes[notename]) return; + var note = notes[notename]; + switch (note.permission) { + case "freely": + //not blocking anyone + break; + case "editable": + //only login user can change + if (!socket.request.user || !socket.request.user.logged_in) + return; + break; + case "locked": + //only owner can change + if (note.owner != socket.request.user._id) + return; + break; + } op = LZString.decompressFromUTF16(op); if (op) op = JSON.parse(op); + else + return; if (config.debug) - console.log('SERVER received [' + notename + '] data changed: ' + socket.id + ', op:' + JSON.stringify(op)); + logger.info('SERVER received [' + notename + '] data changed: ' + socket.id + ', op:' + JSON.stringify(op)); switch (op.origin) { case '+input': case '+delete': @@ -499,16 +635,20 @@ function connection(socket) { case '+joinLines': case '+duplicateLine': case '+sortLines': - notes[notename].socks.forEach(function (sock) { - if (sock != socket) { - if (config.debug) - console.log('SERVER emit sync data out [' + notename + ']: ' + sock.id + ', op:' + JSON.stringify(op)); - sock.emit('change', LZString.compressToUTF16(JSON.stringify(op))); - } - }); + op.id = socket.id; + op.otk = note.otk; + op.nextotk = note.otk = shortId.generate(); + var stringop = JSON.stringify(op); + var compressstringop = LZString.compressToUTF16(stringop); + for (var i = 0, l = note.socks.length; i < l; i++) { + var sock = note.socks[i]; + if (config.debug) + logger.info('SERVER emit sync data out [' + notename + ']: ' + sock.id + ', op:' + stringop); + sock.emit('change', compressstringop); + }; break; - default: - console.log('SERVER received uncaught [' + notename + '] data changed: ' + socket.id + ', op:' + JSON.stringify(op)); + default: + logger.info('SERVER received uncaught [' + notename + '] data changed: ' + socket.id + ', op:' + JSON.stringify(op)); } }); } diff --git a/lib/response.js b/lib/response.js index a7dcc023..d3b011bf 100644 --- a/lib/response.js +++ b/lib/response.js @@ -6,6 +6,8 @@ var path = require('path'); var uuid = require('node-uuid'); var markdownpdf = require("markdown-pdf"); var LZString = require('lz-string'); +var S = require('string'); +var shortId = require('shortid'); //core var config = require("../config.js"); @@ -31,16 +33,20 @@ var response = { newNote: newNote, showFeatures: showFeatures, showNote: showNote, - noteActions: noteActions + showShareNote: showShareNote, + noteActions: noteActions, + shareNoteActions: shareNoteActions }; function responseError(res, code, detail, msg) { res.writeHead(code, { 'Content-Type': 'text/html' }); - var content = ejs.render(fs.readFileSync(config.errorpath, 'utf8'), { + var template = config.errorpath; + var content = ejs.render(fs.readFileSync(template, 'utf8'), { + title: code + ' ' + detail + ' ' + msg, cache: !config.debug, - filename: config.errorpath, + filename: template, code: code, detail: detail, msg: msg @@ -49,16 +55,44 @@ function responseError(res, code, detail, msg) { res.end(); } -function responseHackMD(res) { - res.writeHead(200, { - 'Content-Type': 'text/html' - }); - var content = ejs.render(fs.readFileSync(config.hackmdpath, 'utf8'), { - cache: !config.debug, - filename: config.hackmdpath +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) { + if (err) { + responseError(res, "404", "Not Found", "oops."); + return; + } + var title = data.rows[0].title; + var decodedTitle = LZString.decompressFromBase64(title); + if (decodedTitle) title = decodedTitle; + title = Note.generateWebTitle(title); + var template = config.hackmdpath; + var options = { + cache: !config.debug, + filename: template + }; + var compiled = ejs.compile(fs.readFileSync(template, 'utf8'), options); + var html = compiled({ + title: title + }); + var buf = html; + res.writeHead(200, { + 'Content-Type': 'text/html; charset=UTF-8', + 'Cache-Control': 'private', + 'Content-Length': buf.length + }); + res.end(buf); }); - res.write(content); - res.end(); } function newNote(req, res, next) { @@ -88,10 +122,10 @@ function showFeatures(req, res, next) { responseError(res, "500", "Internal Error", "wtf."); return; } - responseHackMD(res); + responseHackMD(res, config.featuresnotename); }); } else { - responseHackMD(res); + responseHackMD(res, config.featuresnotename); } }); } @@ -102,22 +136,105 @@ function showNote(req, res, next) { responseError(res, "404", "Not Found", "oops."); return; } - responseHackMD(res); + responseHackMD(res, noteId); } +function showShareNote(req, res, next) { + var shortid = req.params.shortid; + if (shortId.isValid(shortid)) { + Note.findNote(shortid, function (err, note) { + if (err || !note) { + responseError(res, "404", "Not Found", "oops."); + return; + } + //increase note viewcount + Note.increaseViewCount(note, function (err, note) { + if (err || !note) { + responseError(res, "404", "Not Found", "oops."); + return; + } + db.readFromDB(note.id, function (err, data) { + if (err) { + responseError(res, "404", "Not Found", "oops."); + return; + } + var body = LZString.decompressFromBase64(data.rows[0].content); + var updatetime = data.rows[0].update_time; + var text = S(body).escapeHTML().s; + var title = data.rows[0].title; + var decodedTitle = LZString.decompressFromBase64(title); + if (decodedTitle) title = decodedTitle; + title = Note.generateWebTitle(title); + var template = config.prettypath; + var options = { + cache: !config.debug, + filename: template + }; + var compiled = ejs.compile(fs.readFileSync(template, 'utf8'), options); + var origin = "//" + req.headers.host; + var html = compiled({ + title: title, + viewcount: note.viewcount, + updatetime: updatetime, + url: origin, + body: text + }); + var buf = html; + res.writeHead(200, { + 'Content-Type': 'text/html; charset=UTF-8', + 'Cache-Control': 'private', + 'Content-Length': buf.length + }); + res.end(buf); + }); + }); + }); + } else { + responseError(res, "404", "Not Found", "oops."); + } +} + +function actionShare(req, res, noteId) { + db.readFromDB(noteId, function (err, data) { + if (err) { + responseError(res, "404", "Not Found", "oops."); + return; + } + var owner = data.rows[0].owner; + var permission = "freely"; + if (owner && owner != "null") { + permission = "editable"; + } + Note.findOrNewNote(noteId, permission, function (err, note) { + if (err) { + responseError(res, "404", "Not Found", "oops."); + return; + } + res.redirect("/s/" + note.shortid); + }); + }); +} + +//pretty api is deprecated function actionPretty(req, res, noteId) { db.readFromDB(noteId, function (err, data) { if (err) { responseError(res, "404", "Not Found", "oops."); return; } - var body = data.rows[0].content; + var body = LZString.decompressFromBase64(data.rows[0].content); + var text = S(body).escapeHTML().s; + var title = data.rows[0].title; + var decodedTitle = LZString.decompressFromBase64(title); + if (decodedTitle) title = decodedTitle; + title = Note.generateWebTitle(title); var template = config.prettypath; var compiled = ejs.compile(fs.readFileSync(template, 'utf8')); var origin = "//" + req.headers.host; var html = compiled({ + title: title, url: origin, - body: body + body: text }); var buf = html; res.writeHead(200, { @@ -190,8 +307,9 @@ function noteActions(req, res, next) { } var action = req.params.action; switch (action) { - case "pretty": - actionPretty(req, res, noteId); + case "share": + case "pretty": //pretty deprecated + actionShare(req, res, noteId); break; case "download": actionDownload(req, res, noteId); @@ -208,4 +326,25 @@ function noteActions(req, res, next) { } } +function shareNoteActions(req, res, next) { + var action = req.params.action; + switch (action) { + case "edit": + var shortid = req.params.shortid; + if (shortId.isValid(shortid)) { + Note.findNote(shortid, function (err, note) { + if (err || !note) { + responseError(res, "404", "Not Found", "oops."); + return; + } + if (note.id != config.featuresnotename) + res.redirect('/' + LZString.compressToBase64(note.id)); + else + res.redirect('/' + note.id); + }); + } + break; + } +} + module.exports = response; \ No newline at end of file diff --git a/lib/temp.js b/lib/temp.js index 90d9343f..b635644d 100644 --- a/lib/temp.js +++ b/lib/temp.js @@ -4,6 +4,7 @@ var mongoose = require('mongoose'); //core var config = require("../config.js"); +var logger = require("./logger.js"); // create a temp model var model = mongoose.model('temp', { @@ -33,13 +34,13 @@ function findTemp(id, callback) { id: id }, function (err, temp) { if (err) { - console.log('find temp failed: ' + err); + logger.error('find temp failed: ' + err); callback(err, null); } if (!err && temp) { callback(null, temp); } else { - console.log('find temp failed: ' + err); + logger.error('find temp failed: ' + err); callback(err, null); }; }); @@ -53,10 +54,10 @@ function newTemp(id, data, callback) { }); temp.save(function (err) { if (err) { - console.log('new temp failed: ' + err); + logger.error('new temp failed: ' + err); callback(err, null); } else { - console.log("new temp success: " + temp.id); + logger.info("new temp success: " + temp.id); callback(null, temp); }; }); @@ -67,14 +68,14 @@ function removeTemp(id, callback) { if(!err && temp) { temp.remove(function(err) { if(err) { - console.log('remove temp failed: ' + err); + logger.error('remove temp failed: ' + err); callback(err, null); } else { callback(null, null); } }); } else { - console.log('remove temp failed: ' + err); + logger.error('remove temp failed: ' + err); callback(err, null); } }); diff --git a/lib/user.js b/lib/user.js index 11064506..f89f7def 100644 --- a/lib/user.js +++ b/lib/user.js @@ -4,6 +4,7 @@ var mongoose = require('mongoose'); //core var config = require("../config.js"); +var logger = require("./logger.js"); // create a user model var model = mongoose.model('user', { @@ -34,13 +35,13 @@ function findUser(id, callback) { id: id }, function (err, user) { if (err) { - console.log('find user failed: ' + err); + logger.error('find user failed: ' + err); callback(err, null); } if (!err && user) { callback(null, user); } else { - console.log('find user failed: ' + err); + logger.error('find user failed: ' + err); callback(err, null); }; }); @@ -54,10 +55,10 @@ function newUser(id, profile, callback) { }); user.save(function (err) { if (err) { - console.log('new user failed: ' + err); + logger.error('new user failed: ' + err); callback(err, null); } else { - console.log("new user success: " + user.id); + logger.info("new user success: " + user.id); callback(null, user); }; }); @@ -68,7 +69,7 @@ function findOrNewUser(id, profile, callback) { if(err || !user) { newUser(id, profile, function(err, user) { if(err) { - console.log('find or new user failed: ' + err); + logger.error('find or new user failed: ' + err); callback(err, null); } else { callback(null, user); -- cgit v1.2.3