643 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			643 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| //response
 | |
| //external modules
 | |
| var ejs = require('ejs');
 | |
| var fs = require('fs');
 | |
| 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');
 | |
| var metaMarked = require('meta-marked');
 | |
| var querystring = require('querystring');
 | |
| var request = require('request');
 | |
| 
 | |
| //core
 | |
| var config = require("../config.js");
 | |
| 
 | |
| //others
 | |
| var db = require("./db.js");
 | |
| var Note = require("./note.js");
 | |
| var User = require("./user.js");
 | |
| 
 | |
| //slides
 | |
| var md = require('reveal.js/plugin/markdown/markdown');
 | |
| var Mustache = require('mustache');
 | |
| 
 | |
| //reveal.js
 | |
| var opts = {
 | |
|     userBasePath: process.cwd(),
 | |
|     revealBasePath: path.resolve(require.resolve('reveal.js'), '..', '..'),
 | |
|     template: fs.readFileSync(path.join('.', '/public/views/slide', 'reveal.hbs')).toString(),
 | |
|     templateListing: fs.readFileSync(path.join('.', '/public/views/slide', 'listing.hbs')).toString(),
 | |
|     theme: 'css/theme/black.css',
 | |
|     highlightTheme: 'zenburn',
 | |
|     separator: '^(\r\n?|\n)---(\r\n?|\n)$',
 | |
|     verticalSeparator: '^(\r\n?|\n)----(\r\n?|\n)$',
 | |
|     revealOptions: {}
 | |
| };
 | |
| 
 | |
| //public
 | |
| var response = {
 | |
|     errorForbidden: function (res) {
 | |
|         responseError(res, "403", "Forbidden", "oh no.");
 | |
|     },
 | |
|     errorNotFound: function (res) {
 | |
|         responseError(res, "404", "Not Found", "oops.");
 | |
|     },
 | |
|     errorInternalError: function (res) {
 | |
|         responseError(res, "500", "Internal Error", "wtf.");
 | |
|     },
 | |
|     errorServiceUnavailable: function (res) {
 | |
|         res.status(503).send("I'm busy right now, try again later.");
 | |
|     },
 | |
|     newNote: newNote,
 | |
|     showFeatures: showFeatures,
 | |
|     showNote: showNote,
 | |
|     showPublishNote: showPublishNote,
 | |
|     showPublishSlide: showPublishSlide,
 | |
| 	showIndex: showIndex,
 | |
|     noteActions: noteActions,
 | |
|     publishNoteActions: publishNoteActions,
 | |
|     githubActions: githubActions
 | |
| };
 | |
| 
 | |
| function responseError(res, code, detail, msg) {
 | |
|     res.writeHead(code, {
 | |
|         'Content-Type': 'text/html'
 | |
|     });
 | |
|     var template = config.errorpath;
 | |
|     var content = ejs.render(fs.readFileSync(template, 'utf8'), {
 | |
|         url: config.getserverurl(),
 | |
|         title: code + ' ' + detail + ' ' + msg,
 | |
|         cache: !config.debug,
 | |
|         filename: template,
 | |
|         code: code,
 | |
|         detail: detail,
 | |
|         msg: msg,
 | |
| 		useCDN: config.usecdn
 | |
|     });
 | |
|     res.write(content);
 | |
|     res.end();
 | |
| }
 | |
| 
 | |
| function showIndex(req, res, next) {
 | |
|     res.writeHead(200, {
 | |
|         'Content-Type': 'text/html'
 | |
|     });
 | |
|     var template = config.indexpath;
 | |
|     var content = ejs.render(fs.readFileSync(template, 'utf8'), {
 | |
|         url: config.getserverurl(),
 | |
|         useCDN: config.usecdn
 | |
|     });
 | |
|     res.write(content);
 | |
|     res.end();
 | |
| }
 | |
| 
 | |
| function responseHackMD(res, noteId) {
 | |
|     db.readFromDB(noteId, function (err, data) {
 | |
|         if (err) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         var notedata = data.rows[0];
 | |
|         var body = LZString.decompressFromBase64(notedata.content);
 | |
|         var meta = null;
 | |
|         try {
 | |
|             meta = metaMarked(body).meta;
 | |
|         } catch(err) {
 | |
|             //na
 | |
|         }
 | |
|         var title = Note.decodeTitle(notedata.title);
 | |
|         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({
 | |
|             url: config.getserverurl(),
 | |
|             title: title,
 | |
| 			useCDN: config.usecdn,
 | |
|             robots: (meta && meta.robots) || false //default allow robots
 | |
|         });
 | |
|         var buf = html;
 | |
|         res.writeHead(200, {
 | |
|             'Content-Type': 'text/html; charset=UTF-8',
 | |
|             'Cache-Control': 'private',
 | |
|             'Content-Length': buf.length
 | |
|         });
 | |
|         res.end(buf);
 | |
|     });
 | |
| }
 | |
| 
 | |
| function newNote(req, res, next) {
 | |
|     var newId = uuid.v4();
 | |
|     var body = fs.readFileSync(config.defaultnotepath, 'utf8');
 | |
|     body = LZString.compressToBase64(body);
 | |
|     var owner = null;
 | |
|     if (req.isAuthenticated()) {
 | |
|         owner = req.user._id;
 | |
|     }
 | |
|     db.newToDB(newId, owner, body, function (err, result) {
 | |
|         if (err) {
 | |
|             return response.errorInternalError(res);
 | |
|         }
 | |
|         Note.newNote(newId, owner, function(err, result) {
 | |
|             if (err) {
 | |
|                 return response.errorInternalError(res);
 | |
|             }
 | |
|             res.redirect(config.getserverurl() + "/" + LZString.compressToBase64(newId));
 | |
|         });
 | |
|     });
 | |
| }
 | |
| 
 | |
| function showFeatures(req, res, next) {
 | |
|     db.readFromDB(config.featuresnotename, function (err, data) {
 | |
|         if (err) {
 | |
|             var body = fs.readFileSync(config.defaultfeaturespath, 'utf8');
 | |
|             body = LZString.compressToBase64(body);
 | |
|             db.newToDB(config.featuresnotename, null, body, function (err, result) {
 | |
|                 if (err) {
 | |
|                     return response.errorInternalError(res);
 | |
|                 }
 | |
|                 responseHackMD(res, config.featuresnotename);
 | |
|             });
 | |
|         } else {
 | |
|             responseHackMD(res, config.featuresnotename);
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| function showNote(req, res, next) {
 | |
|     var noteId = req.params.noteId;
 | |
|     if (noteId != config.featuresnotename) {
 | |
|         if (!Note.checkNoteIdValid(noteId)) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         noteId = LZString.decompressFromBase64(noteId);
 | |
|         if (!noteId) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|     }
 | |
|     db.readFromDB(noteId, function (err, data) {
 | |
|         if (err) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         var notedata = data.rows[0];
 | |
|         Note.findOrNewNote(noteId, notedata.owner, function (err, note) {
 | |
|             if (err || !note) {
 | |
|                 return response.errorNotFound(res);
 | |
|             }
 | |
|             //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) {
 | |
|     var shortid = req.params.shortid;
 | |
|     if (shortId.isValid(shortid)) {
 | |
|         Note.findNote(shortid, 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);
 | |
|                 }
 | |
|                 //increase note viewcount
 | |
|                 Note.increaseViewCount(note, function (err, note) {
 | |
|                     if (err || !note) {
 | |
|                         return response.errorNotFound(res);
 | |
|                     }
 | |
|                     var body = LZString.decompressFromBase64(notedata.content);
 | |
|                     var meta = null;
 | |
|                     try {
 | |
|                         meta = metaMarked(body).meta;
 | |
|                     } catch(err) {
 | |
|                         //na
 | |
|                     }
 | |
|                     var updatetime = notedata.update_time;
 | |
|                     var text = S(body).escapeHTML().s;
 | |
|                     var title = Note.decodeTitle(notedata.title);
 | |
|                     title = Note.generateWebTitle(title);
 | |
|                     var origin = config.getserverurl();
 | |
|                     var data = {
 | |
|                         title: title,
 | |
|                         viewcount: note.viewcount,
 | |
|                         updatetime: updatetime,
 | |
|                         url: origin,
 | |
|                         body: text,
 | |
|                         useCDN: config.usecdn,
 | |
|                         lastchangeuserprofile: null,
 | |
|                         robots: (meta && meta.robots) || false //default allow robots
 | |
|                     };
 | |
|                     if (note.lastchangeuser) {
 | |
|                         //find last change user profile if lastchangeuser exists
 | |
|                         User.findUser(note.lastchangeuser, function (err, user) {
 | |
|                             if (!err && user && user.profile) {
 | |
|                                 var profile = JSON.parse(user.profile);
 | |
|                                 if (profile) {
 | |
|                                     data.lastchangeuserprofile = {
 | |
|                                         name: profile.displayName || profile.username,
 | |
|                                         photo: User.parsePhotoByProfile(profile)
 | |
|                                     }
 | |
|                                     renderPublish(data, res);
 | |
|                                 }
 | |
|                             }
 | |
|                         });
 | |
|                     } else {
 | |
|                         renderPublish(data, res);
 | |
|                     }
 | |
|                     
 | |
|                 });
 | |
|             });
 | |
|         });
 | |
|     } else {
 | |
|         return response.errorNotFound(res);
 | |
|     }
 | |
| }
 | |
| 
 | |
| function renderPublish(data, res) {
 | |
|     var template = config.prettypath;
 | |
|     var options = {
 | |
|         url: config.getserverurl(),
 | |
|         cache: !config.debug,
 | |
|         filename: template
 | |
|     };
 | |
|     var compiled = ejs.compile(fs.readFileSync(template, 'utf8'), options);
 | |
|     var html = compiled(data);
 | |
|     var buf = html;
 | |
|     res.writeHead(200, {
 | |
|         'Content-Type': 'text/html; charset=UTF-8',
 | |
|         'Cache-Control': 'private',
 | |
|         'Content-Length': buf.length
 | |
|     });
 | |
|     res.end(buf);
 | |
| }
 | |
| 
 | |
| function actionPublish(req, res, noteId) {
 | |
|     db.readFromDB(noteId, function (err, data) {
 | |
|         if (err) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         var owner = data.rows[0].owner;
 | |
|         Note.findOrNewNote(noteId, owner, function (err, note) {
 | |
|             if (err) {
 | |
|                 return response.errorNotFound(res);
 | |
|             }
 | |
|             res.redirect(config.getserverurl() + "/s/" + note.shortid);
 | |
|         });
 | |
|     });
 | |
| }
 | |
| 
 | |
| function actionSlide(req, res, noteId) {
 | |
|     db.readFromDB(noteId, function (err, data) {
 | |
|         if (err) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         var owner = data.rows[0].owner;
 | |
|         Note.findOrNewNote(noteId, owner, function (err, note) {
 | |
|             if (err) {
 | |
|                 return response.errorNotFound(res);
 | |
|             }
 | |
|             res.redirect(config.getserverurl() + "/p/" + note.shortid);
 | |
|         });
 | |
|     });
 | |
| }
 | |
| 
 | |
| function actionDownload(req, res, noteId) {
 | |
|     db.readFromDB(noteId, function (err, data) {
 | |
|         if (err) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         var notedata = data.rows[0];
 | |
|         var body = LZString.decompressFromBase64(notedata.content);
 | |
|         var title = Note.decodeTitle(notedata.title);
 | |
|         var filename = title;
 | |
|         filename = encodeURIComponent(filename);
 | |
|         res.writeHead(200, {
 | |
|             'Access-Control-Allow-Origin': '*', //allow CORS as API
 | |
|             'Access-Control-Allow-Headers': 'Range',
 | |
|             'Access-Control-Expose-Headers': 'Cache-Control, Content-Encoding, Content-Range',
 | |
|             'Content-Type': 'text/markdown; charset=UTF-8',
 | |
|             'Cache-Control': 'private',
 | |
|             'Content-disposition': 'attachment; filename=' + filename + '.md',
 | |
|             'Content-Length': body.length,
 | |
|             'X-Robots-Tag': 'noindex, nofollow' // prevent crawling
 | |
|         });
 | |
|         res.end(body);
 | |
|     });
 | |
| }
 | |
| 
 | |
| function actionPDF(req, res, noteId) {
 | |
|     db.readFromDB(noteId, function (err, data) {
 | |
|         if (err) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         var notedata = data.rows[0];
 | |
|         var body = LZString.decompressFromBase64(notedata.content);
 | |
|         try {
 | |
|             body = metaMarked(body).markdown;
 | |
|         } catch(err) {
 | |
|             //na
 | |
|         }
 | |
|         var title = Note.decodeTitle(notedata.title);
 | |
| 
 | |
|         if (!fs.existsSync(config.tmppath)) {
 | |
|             fs.mkdirSync(config.tmppath);
 | |
|         }
 | |
|         var path = config.tmppath + Date.now() + '.pdf';
 | |
|         markdownpdf().from.string(body).to(path, function () {
 | |
|             var stream = fs.createReadStream(path);
 | |
|             var filename = title;
 | |
|             // Be careful of special characters
 | |
|             filename = encodeURIComponent(filename);
 | |
|             // Ideally this should strip them
 | |
|             res.setHeader('Content-disposition', 'attachment; filename="' + filename + '.pdf"');
 | |
|             res.setHeader('Cache-Control', 'private');
 | |
|             res.setHeader('Content-Type', 'application/pdf; charset=UTF-8');
 | |
|             res.setHeader('X-Robots-Tag', 'noindex, nofollow'); // prevent crawling
 | |
|             stream.pipe(res);
 | |
|             fs.unlink(path);
 | |
|         });
 | |
|     });
 | |
| }
 | |
| 
 | |
| function actionGist(req, res, noteId) {
 | |
|     db.readFromDB(noteId, function (err, data) {
 | |
|         if (err) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         var owner = data.rows[0].owner;
 | |
|         Note.findOrNewNote(noteId, owner, function (err, note) {
 | |
|             if (err) {
 | |
|                 return response.errorNotFound(res);
 | |
|             }
 | |
|             var data = {
 | |
|                 client_id: config.github.clientID,
 | |
|                 redirect_uri: config.getserverurl() + '/auth/github/callback/' + LZString.compressToBase64(noteId) + '/gist',
 | |
|                 scope: "gist",
 | |
|                 state: shortId.generate()
 | |
|             };
 | |
|             var query = querystring.stringify(data);
 | |
|             res.redirect("https://github.com/login/oauth/authorize?" + query);
 | |
|         });
 | |
|     });
 | |
| }
 | |
| 
 | |
| function noteActions(req, res, next) {
 | |
|     var noteId = req.params.noteId;
 | |
|     if (noteId != config.featuresnotename) {
 | |
|         if (!Note.checkNoteIdValid(noteId)) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         noteId = LZString.decompressFromBase64(noteId);
 | |
|         if (!noteId) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|     }
 | |
|     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);
 | |
|             }
 | |
|             var action = req.params.action;
 | |
|             switch (action) {
 | |
|             case "publish":
 | |
|             case "pretty": //pretty deprecated
 | |
|                 actionPublish(req, res, noteId);
 | |
|                 break;
 | |
|             case "slide":
 | |
|                 actionSlide(req, res, noteId);
 | |
|                 break;
 | |
|             case "download":
 | |
|                 actionDownload(req, res, noteId);
 | |
|                 break;
 | |
|             case "pdf":
 | |
|                 actionPDF(req, res, noteId);
 | |
|                 break;
 | |
|             case "gist":
 | |
|                 actionGist(req, res, noteId);
 | |
|                 break;
 | |
|             default:
 | |
|                 if (noteId != config.featuresnotename)
 | |
|                     res.redirect(config.getserverurl() + '/' + LZString.compressToBase64(noteId));
 | |
|                 else
 | |
|                     res.redirect(config.getserverurl() + '/' + noteId);
 | |
|                 break;
 | |
|             }
 | |
|         });
 | |
|     });
 | |
| }
 | |
| 
 | |
| function publishNoteActions(req, res, next) {
 | |
|     var shortid = req.params.shortid;
 | |
|     if (shortId.isValid(shortid)) {
 | |
|         Note.findNote(shortid, 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);
 | |
|                 }
 | |
|                 var action = req.params.action;
 | |
|                 switch (action) {
 | |
|                 case "edit":
 | |
|                     if (note.id != config.featuresnotename)
 | |
|                         res.redirect(config.getserverurl() + '/' + LZString.compressToBase64(note.id));
 | |
|                     else
 | |
|                         res.redirect(config.getserverurl() + '/' + note.id);
 | |
|                     break;
 | |
|                 }
 | |
|             });
 | |
|         });
 | |
|     }
 | |
| }
 | |
| 
 | |
| function githubActions(req, res, next) {
 | |
|     var noteId = req.params.noteId;
 | |
|     if (noteId != config.featuresnotename) {
 | |
|         if (!Note.checkNoteIdValid(noteId)) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         noteId = LZString.decompressFromBase64(noteId);
 | |
|         if (!noteId) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|     }
 | |
|     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);
 | |
|             }
 | |
|             var action = req.params.action;
 | |
|             switch (action) {
 | |
|             case "gist":
 | |
|                 githubActionGist(req, res, noteId);
 | |
|                 break;
 | |
|             default:
 | |
|                 if (noteId != config.featuresnotename)
 | |
|                     res.redirect(config.getserverurl() + '/' + LZString.compressToBase64(noteId));
 | |
|                 else
 | |
|                     res.redirect(config.getserverurl() + '/' + noteId);
 | |
|                 break;
 | |
|             }
 | |
|         });
 | |
|     });
 | |
| }
 | |
| 
 | |
| function githubActionGist(req, res, noteId) {
 | |
|     db.readFromDB(noteId, function (err, data) {
 | |
|         if (err) {
 | |
|             return response.errorNotFound(res);
 | |
|         }
 | |
|         var notedata = data.rows[0];
 | |
|         var code = req.query.code;
 | |
|         var state = req.query.state;
 | |
|         if (!code || !state) {
 | |
|             return response.errorForbidden(res);
 | |
|         } else {
 | |
|             var data = {
 | |
|                 client_id: config.github.clientID,
 | |
|                 client_secret: config.github.clientSecret,
 | |
|                 code: code,
 | |
|                 state: state
 | |
|             }
 | |
|             var auth_url = 'https://github.com/login/oauth/access_token';
 | |
|             request({
 | |
|                     url: auth_url,
 | |
|                     method: "POST",
 | |
|                     json: data
 | |
|                 }, function (error, httpResponse, body) {
 | |
|                 if (!error && httpResponse.statusCode == 200) {
 | |
|                     var access_token = body.access_token;
 | |
|                     if (access_token) {
 | |
|                         var content = LZString.decompressFromBase64(notedata.content);
 | |
|                         var title = Note.decodeTitle(notedata.title);
 | |
|                         var filename = title.replace('/', ' ') + '.md';
 | |
|                         var gist = {
 | |
|                             "files": {}
 | |
|                         };
 | |
|                         gist.files[filename] = {
 | |
|                             "content": content
 | |
|                         };
 | |
|                         var gist_url = "https://api.github.com/gists";
 | |
|                         request({
 | |
|                             url: gist_url,
 | |
|                             headers: {
 | |
|                                 'User-Agent': 'HackMD',
 | |
|                                 'Authorization': 'token ' + access_token
 | |
|                             },
 | |
|                             method: "POST",
 | |
|                             json: gist
 | |
|                         }, function (error, httpResponse, body) {
 | |
|                             if (!error && httpResponse.statusCode == 201) {
 | |
|                                 res.setHeader('referer', '');
 | |
|                                 res.redirect(body.html_url);
 | |
|                             } else {
 | |
|                                 return response.errorForbidden(res);
 | |
|                             }
 | |
|                         });
 | |
|                     } else {
 | |
|                         return response.errorForbidden(res);
 | |
|                     }
 | |
|                 } else {
 | |
|                     return response.errorForbidden(res);
 | |
|                 }
 | |
|             })
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| function showPublishSlide(req, res, next) {
 | |
|     var shortid = req.params.shortid;
 | |
|     if (shortId.isValid(shortid)) {
 | |
|         Note.findNote(shortid, 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);
 | |
|                 }
 | |
|                 //increase note viewcount
 | |
|                 Note.increaseViewCount(note, function (err, note) {
 | |
|                     if (err || !note) {
 | |
|                         return response.errorNotFound(res);
 | |
|                     }
 | |
|                     var body = LZString.decompressFromBase64(notedata.content);
 | |
|                     try {
 | |
|                         body = metaMarked(body).markdown;
 | |
|                     } catch(err) {
 | |
|                         //na
 | |
|                     }
 | |
|                     var title = Note.decodeTitle(notedata.title);
 | |
|                     title = Note.generateWebTitle(title);
 | |
|                     var text = S(body).escapeHTML().s;
 | |
|                     render(res, title, text);
 | |
|                 });
 | |
|             });
 | |
|         });
 | |
|     } else {
 | |
|         return response.errorNotFound(res);
 | |
|     }
 | |
| }
 | |
| 
 | |
| //reveal.js render
 | |
| var render = function (res, title, markdown) {
 | |
|     var slides = md.slidify(markdown, opts);
 | |
| 
 | |
|     res.end(Mustache.to_html(opts.template, {
 | |
|         url: config.getserverurl(),
 | |
|         title: title,
 | |
|         theme: opts.theme,
 | |
|         highlightTheme: opts.highlightTheme,
 | |
|         slides: slides,
 | |
|         options: JSON.stringify(opts.revealOptions, null, 2)
 | |
|     }));
 | |
| };
 | |
| 
 | |
| module.exports = response; |