jsduck 3.10.0 → 3.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,366 +0,0 @@
1
-
2
- /**
3
- * JSDuck authentication / commenting server side element. Requires Node.js + MongoDB.
4
- *
5
- * Authentication assumes a vBulletin forum database, but could easily be adapted (see ForumUser.js)
6
- *
7
- * Expects a config file, config.js, that looks like this:
8
- *
9
- * exports.db = {
10
- * user: 'forumUsername',
11
- * password: 'forumPassword',
12
- * host: 'forumHost',
13
- * dbName: 'forumDb'
14
- * };
15
- *
16
- * exports.sessionSecret = 'random string for session cookie encryption';
17
- *
18
- * exports.mongoDb = 'mongodb://mongoHost:port/comments';
19
- *
20
- */
21
-
22
- var config = require('./config');
23
- require('./database');
24
-
25
- var mysql = require('mysql'),
26
- client = mysql.createClient({
27
- host: config.db.host,
28
- user: config.db.user,
29
- password: config.db.password,
30
- database: config.db.dbName
31
- }),
32
- express = require('express'),
33
- MongoStore = require('connect-mongo'),
34
- _ = require('underscore'),
35
- ForumUser = require('./ForumUser').ForumUser,
36
- forumUser = new ForumUser(client),
37
- util = require('./util'),
38
- crypto = require('crypto'),
39
- mongoose = require('mongoose');
40
-
41
- var app = express();
42
-
43
- app.configure(function() {
44
-
45
- // Headers for Cross Origin Resource Sharing (CORS)
46
- app.use(function (req, res, next) {
47
- res.setHeader('Access-Control-Allow-Origin', '*');
48
- res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
49
- res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
50
- next();
51
- });
52
-
53
- app.use(express.cookieParser(config.sessionSecret));
54
-
55
- // Hack to set session cookie if session ID is set as a URL param.
56
- // This is because not all browsers support sending cookies via CORS
57
- app.use(function(req, res, next) {
58
- if (req.query.sid && req.query.sid != 'null') {
59
- var sid = req.query.sid.replace(/ /g, '+');
60
- req.sessionID = sid;
61
- req.signedCookies = req.signedCookies || {};
62
- req.signedCookies['sencha_docs'] = sid;
63
- }
64
- next();
65
- });
66
-
67
- // Use MongoDB for session storage
68
- app.use(express.session({
69
- secret: config.sessionSecret,
70
- key: 'sencha_docs',
71
- store: new MongoStore({
72
- url: exports.mongoDb + "/sessions"
73
- })
74
- }));
75
-
76
- app.use(function(req, res, next) {
77
- // IE doesn't get content-type, so default to form encoded.
78
- if (!req.headers['content-type']) {
79
- req.headers['content-type'] = 'application/x-www-form-urlencoded';
80
- }
81
- next();
82
- });
83
-
84
- app.use(express.bodyParser());
85
- app.use(express.methodOverride());
86
-
87
- app.enable('jsonp callback');
88
- });
89
-
90
- app.configure('development', function(){
91
- app.use(express.logger('dev'));
92
- app.use(express.errorHandler());
93
- });
94
-
95
- /**
96
- * Authentication
97
- */
98
-
99
- app.get('/auth/session', function(req, res) {
100
- var result = req.session && req.session.user && forumUser.clientUser(req.session.user);
101
- res.json(result || false);
102
- });
103
-
104
- app.post('/auth/login', function(req, res){
105
-
106
- forumUser.login(req.body.username, req.body.password, function(err, result) {
107
-
108
- if (err) {
109
- res.json({ success: false, reason: err });
110
- return;
111
- }
112
-
113
- req.session = req.session || {};
114
- req.session.user = result;
115
-
116
- var response = _.extend(forumUser.clientUser(result), {
117
- sessionID: req.sessionID,
118
- success: true
119
- });
120
-
121
- res.json(response);
122
- });
123
- });
124
-
125
- // Remove session
126
- app.post('/auth/logout', function(req, res){
127
- req.session.user = null;
128
- res.json({ success: true });
129
- });
130
-
131
- /**
132
- * Handles comment unsubscription requests.
133
- */
134
- app.get('/auth/unsubscribe/:subscriptionId', function(req, res) {
135
-
136
- Subscription.findOne({ _id: req.params.subscriptionId }, function(err, subscription) {
137
- if (err) throw(err);
138
-
139
- if (subscription) {
140
- if (req.query.all == 'true') {
141
- Subscription.remove({ userId: subscription.userId }, function(err) {
142
- res.send("You have been unsubscribed from all threads.");
143
- });
144
- } else {
145
- Subscription.remove({ _id: req.params.subscriptionId }, function(err) {
146
- res.send("You have been unsubscribed from that thread.");
147
- });
148
- }
149
- } else {
150
- res.send("You are already unsubscribed.");
151
- }
152
- });
153
- });
154
-
155
-
156
- /**
157
- * Commenting
158
- */
159
-
160
- /**
161
- * Returns a list of comments for a particular target (eg class, guide, video)
162
- */
163
- app.get('/auth/:sdk/:version/comments', util.getCommentReads, function(req, res) {
164
-
165
- if (!req.query.startkey) {
166
- res.json({error: 'Invalid request'});
167
- return;
168
- }
169
-
170
- Comment.find({
171
- target: JSON.parse(req.query.startkey),
172
- deleted: { '$ne': true },
173
- sdk: req.params.sdk,
174
- version: req.params.version
175
- }).sort('createdAt', 1).run(function(err, comments){
176
- res.json(util.scoreComments(comments, req));
177
- });
178
- });
179
-
180
- /**
181
- * Returns n most recent comments.
182
- * Takes two parameters: offset and limit.
183
- *
184
- * The last comment object returned will contain `total_rows`,
185
- * `offset` and `limit` fields. I'd say it's a hack, but at least
186
- * it works for now.
187
- */
188
- app.get('/auth/:sdk/:version/comments_recent', util.getCommentReads, function(req, res) {
189
- var offset = parseInt(req.query.offset, 10) || 0;
190
- var limit = parseInt(req.query.limit, 10) || 100;
191
- var filter = {
192
- deleted: { '$ne': true },
193
- sdk: req.params.sdk,
194
- version: req.params.version
195
- };
196
-
197
- if (req.query.hideRead && req.commentMeta.reads.length > 0) {
198
- filter._id = { $nin: req.commentMeta.reads };
199
- }
200
-
201
- Comment.find(filter).sort('createdAt', -1).skip(offset).limit(limit).run(function(err, comments) {
202
- comments = util.scoreComments(comments, req);
203
- // Count all comments, store count to last comment
204
- Comment.count(filter).run(function(err, count) {
205
- var last = comments[comments.length-1];
206
- last.total_rows = count;
207
- last.offset = offset;
208
- last.limit = limit;
209
- res.json(comments);
210
- });
211
- });
212
- });
213
-
214
- /**
215
- * Returns number of comments for each class/member,
216
- * and a list of classes/members into which the user has subscribed.
217
- */
218
- app.get('/auth/:sdk/:version/comments_meta', util.getCommentCounts, util.getCommentSubscriptions, function(req, res) {
219
- res.send({ comments: req.commentCounts, subscriptions: req.commentSubscriptions || [] });
220
- });
221
-
222
- /**
223
- * Returns an individual comment (used when editing a comment)
224
- */
225
- app.get('/auth/:sdk/:version/comments/:commentId', util.findComment, function(req, res) {
226
- res.json({ success: true, content: req.comment.content });
227
- });
228
-
229
- /**
230
- * Creates a new comment
231
- */
232
- app.post('/auth/:sdk/:version/comments', util.requireLoggedInUser, function(req, res) {
233
-
234
- var target = JSON.parse(req.body.target);
235
-
236
- if (target.length === 2) {
237
- target.push('');
238
- }
239
-
240
- var comment = new Comment({
241
- author: req.session.user.username,
242
- userId: req.session.user.userid,
243
- content: req.body.comment,
244
- action: req.body.action,
245
- rating: Number(req.body.rating),
246
- contentHtml: util.markdown(req.body.comment),
247
- downVotes: [],
248
- upVotes: [],
249
- createdAt: new Date,
250
- target: target,
251
- emailHash: crypto.createHash('md5').update(req.session.user.email).digest("hex"),
252
- sdk: req.params.sdk,
253
- version: req.params.version,
254
- moderator: req.session.user.moderator,
255
- title: req.body.title,
256
- url: req.body.url
257
- });
258
-
259
- comment.save(function(err, response) {
260
- res.json({ success: true, id: response._id, action: req.body.action });
261
-
262
- util.sendEmailUpdates(comment);
263
- });
264
- });
265
-
266
- /**
267
- * Updates an existing comment (for voting or updating contents)
268
- */
269
- app.post('/auth/:sdk/:version/comments/:commentId', util.requireLoggedInUser, util.findComment, function(req, res) {
270
-
271
- var voteDirection,
272
- comment = req.comment;
273
-
274
- if (req.body.vote) {
275
- util.vote(req, res, comment);
276
- } else {
277
- util.requireOwner(req, res, function() {
278
- comment.content = req.body.content;
279
- comment.contentHtml = util.markdown(req.body.content);
280
-
281
- comment.updates = comment.updates || [];
282
- comment.updates.push({
283
- updatedAt: String(new Date()),
284
- author: req.session.user.username
285
- });
286
-
287
- comment.save(function(err, response) {
288
- res.json({ success: true, content: comment.contentHtml });
289
- });
290
- });
291
- }
292
- });
293
-
294
- /**
295
- * Deletes a comment
296
- */
297
- app.post('/auth/:sdk/:version/comments/:commentId/delete', util.requireLoggedInUser, util.findComment, util.requireOwner, function(req, res) {
298
- req.comment.deleted = true;
299
- req.comment.save(function(err, response) {
300
- res.send({ success: true });
301
- });
302
- });
303
-
304
- /**
305
- * Restores deleted comment
306
- */
307
- app.post('/auth/:sdk/:version/comments/:commentId/undo_delete', util.requireLoggedInUser, util.findComment, util.requireOwner, util.getCommentReads, function(req, res) {
308
- req.comment.deleted = false;
309
- req.comment.save(function(err, response) {
310
- res.send({ success: true, comment: util.scoreComments([req.comment], req)[0] });
311
- });
312
- });
313
-
314
- /**
315
- * Marks a comment 'read'
316
- */
317
- app.post('/auth/:sdk/:version/comments/:commentId/read', util.requireLoggedInUser, util.findCommentMeta, function(req, res) {
318
- req.commentMeta.metaType = 'read';
319
- req.commentMeta.save(function(err, response) {
320
- res.send({ success: true });
321
- });
322
- });
323
-
324
- /**
325
- * Get email subscriptions
326
- */
327
- app.get('/auth/:sdk/:version/subscriptions', util.getCommentSubscriptions, function(req, res) {
328
- res.json({ subscriptions: req.commentMeta.subscriptions });
329
- });
330
-
331
- /**
332
- * Subscibe / unsubscribe to a comment thread
333
- */
334
- app.post('/auth/:sdk/:version/subscribe', util.requireLoggedInUser, function(req, res) {
335
-
336
- var subscriptionBody = {
337
- sdk: req.params.sdk,
338
- version: req.params.version,
339
- target: JSON.parse(req.body.target),
340
- userId: req.session.user.userid
341
- };
342
-
343
- Subscription.findOne(subscriptionBody, function(err, subscription) {
344
-
345
- if (subscription && req.body.subscribed == 'false') {
346
-
347
- subscription.remove(function(err, ok) {
348
- res.send({ success: true });
349
- });
350
-
351
- } else if (!subscription && req.body.subscribed == 'true') {
352
-
353
- subscription = new Subscription(subscriptionBody);
354
- subscription.email = req.session.user.email;
355
-
356
- subscription.save(function(err, ok) {
357
- res.send({ success: true });
358
- });
359
- }
360
- });
361
- });
362
-
363
- var port = 3000;
364
- app.listen(port);
365
- console.log("Server started at port "+port+"...");
366
-
@@ -1,53 +0,0 @@
1
-
2
- /**
3
- * Defines comment schema and connects to database
4
- */
5
-
6
- var mongoose = require('mongoose'),
7
- config = require('./config');
8
-
9
- Comment = mongoose.model('Comment', new mongoose.Schema({
10
- sdk: String,
11
- version: String,
12
-
13
- action: String,
14
- author: String,
15
- userId: Number,
16
- content: String,
17
- contentHtml: String,
18
- createdAt: Date,
19
- downVotes: Array,
20
- emailHash: String,
21
- rating: Number,
22
- target: Array,
23
- upVotes: Array,
24
- deleted: Boolean,
25
- updates: Array,
26
- mod: Boolean,
27
- title: String,
28
- url: String
29
- }));
30
-
31
- Subscription = mongoose.model('Subscription', new mongoose.Schema({
32
- sdk: String,
33
- version: String,
34
-
35
- createdAt: Date,
36
- userId: Number,
37
- email: String,
38
- target: Array
39
- }));
40
-
41
- Meta = mongoose.model('Meta', new mongoose.Schema({
42
- sdk: String,
43
- version: String,
44
-
45
- createdAt: Date,
46
- userId: Number,
47
- commentId: String,
48
- metaType: String
49
- }));
50
-
51
- mongoose.connect(config.mongoDb, function(err, ok) {
52
- console.log("Connected to DB")
53
- });
@@ -1,19 +0,0 @@
1
- {
2
- "name": "jsduck_comments",
3
- "version": "0.5.0",
4
- "description": "Commenting backend for JSDuck Documentation",
5
- "author": "Nick Poudlen <nick@sencha.com>",
6
- "dependencies": {
7
- "express": "git://github.com/visionmedia/express.git",
8
- "express-namespace": "",
9
- "connect": "",
10
- "connect-mongo": "",
11
- "marked": "",
12
- "mongoose": "",
13
- "mysql": "",
14
- "sanitizer": "",
15
- "step": "",
16
- "underscore": "",
17
- "nodemailer": ""
18
- }
19
- }
@@ -1,396 +0,0 @@
1
-
2
- var marked = require('marked'),
3
- _ = require('underscore'),
4
- sanitizer = require('sanitizer'),
5
- nodemailer = require("nodemailer"),
6
- mongoose = require('mongoose');
7
-
8
- /**
9
- * Converts Markdown-formatted comment text into HTML.
10
- *
11
- * @param {String} content Markdown-formatted text
12
- * @return {String} HTML
13
- */
14
- exports.markdown = function(content) {
15
- var markdowned;
16
- try {
17
- markdowned = marked(content);
18
- } catch(e) {
19
- markdowned = content;
20
- }
21
-
22
- // Strip dangerous markup, but allow links to all URL-s
23
- var sanitized_output = sanitizer.sanitize(markdowned, function(str) {
24
- return str;
25
- });
26
-
27
- // IE does not support &apos;
28
- return sanitized_output.replace(/&apos;/g, '&#39;');
29
- };
30
-
31
- /**
32
- * Calculates up/down scores for each comment.
33
- *
34
- * Marks if the current user has already voted on the comment.
35
- * Ensures createdAt timestamp is a string.
36
- *
37
- * @param {Object[]} comments
38
- * @param {Object} req Containing username data
39
- * @return {Object[]}
40
- */
41
- exports.scoreComments = function(comments, req) {
42
- return _.map(comments, function(comment) {
43
- comment = _.extend(comment._doc, {
44
- score: comment.upVotes.length - comment.downVotes.length,
45
- createdAt: String(comment.createdAt)
46
- });
47
-
48
- if (req.commentMeta.reads.length > 0) {
49
- comment.read = _.include(req.commentMeta.reads, ""+comment._id);
50
- }
51
-
52
- if (req.session.user) {
53
- comment.upVote = _.contains(comment.upVotes, req.session.user.username);
54
- comment.downVote = _.contains(comment.downVotes, req.session.user.username);
55
- }
56
-
57
- return comment;
58
- });
59
- };
60
-
61
- /**
62
- * Performs voting on comment.
63
- *
64
- * @param {Object} req The request object.
65
- * @param {Object} res The response object where voting result is written.
66
- * @param {Comment} comment The comment to vote on.
67
- */
68
- exports.vote = function(req, res, comment) {
69
- var voteDirection;
70
- var username = req.session.user.username;
71
-
72
- if (username == comment.author) {
73
-
74
- // Ignore votes from the author
75
- res.json({success: false, reason: 'You cannot vote on your own content'});
76
- return;
77
-
78
- } else if (req.body.vote == 'up' && !_.include(comment.upVotes, username)) {
79
-
80
- var voted = _.include(comment.downVotes, username);
81
-
82
- comment.downVotes = _.reject(comment.downVotes, function(v) {
83
- return v == username;
84
- });
85
-
86
- if (!voted) {
87
- voteDirection = 'up';
88
- comment.upVotes.push(username);
89
- }
90
- } else if (req.body.vote == 'down' && !_.include(comment.downVotes, username)) {
91
-
92
- var voted = _.include(comment.upVotes, username);
93
-
94
- comment.upVotes = _.reject(comment.upVotes, function(v) {
95
- return v == username;
96
- });
97
-
98
- if (!voted) {
99
- voteDirection = 'down';
100
- comment.downVotes.push(username);
101
- }
102
- }
103
-
104
- comment.save(function(err, response) {
105
- res.json({
106
- success: true,
107
- direction: voteDirection,
108
- total: (comment.upVotes.length - comment.downVotes.length)
109
- });
110
- });
111
- };
112
-
113
- /**
114
- * Ensures that user is logged in.
115
- *
116
- * @param {Object} req
117
- * @param {Object} res
118
- * @param {Function} next
119
- */
120
- exports.requireLoggedInUser = function(req, res, next) {
121
- if (!req.session || !req.session.user) {
122
- res.json({success: false, reason: 'Forbidden'}, 403);
123
- } else {
124
- next();
125
- }
126
- };
127
-
128
- /**
129
- * Looks up comment by ID.
130
- *
131
- * Stores it into `req.comment`.
132
- *
133
- * @param {Object} req
134
- * @param {Object} res
135
- * @param {Function} next
136
- */
137
- exports.findComment = function(req, res, next) {
138
- if (req.params.commentId) {
139
- Comment.findById(req.params.commentId, function(err, comment) {
140
- req.comment = comment;
141
- next();
142
- });
143
- } else {
144
- res.json({success: false, reason: 'No such comment'});
145
- }
146
- };
147
-
148
- /**
149
- * Looks up comment meta by comment ID.
150
- *
151
- * Stores it into `req.commentMeta`.
152
- *
153
- * @param {Object} req
154
- * @param {Object} res
155
- * @param {Function} next
156
- */
157
- exports.findCommentMeta = function(req, res, next) {
158
- if (req.params.commentId) {
159
-
160
- var userCommentMeta = {
161
- userId: req.session.user.userid,
162
- commentId: req.params.commentId
163
- };
164
-
165
- Meta.findOne(userCommentMeta, function(err, commentMeta) {
166
- req.commentMeta = commentMeta || new Meta(userCommentMeta);
167
- next();
168
- });
169
- } else {
170
- res.json({success: false, reason: 'No such comment'});
171
- }
172
- };
173
-
174
- // True if the user is moderator
175
- function isModerator(user) {
176
- return _.include(user.membergroupids, 7);
177
- }
178
-
179
- // True if the user is author of the comment
180
- function isAuthor(user, comment) {
181
- return user.username === comment.author;
182
- }
183
-
184
- /**
185
- * Ensures that user is allowed to modify/delete the comment,
186
- * that is, he is the owner of the comment or a moderator.
187
- *
188
- * @param {Object} req
189
- * @param {Object} res
190
- * @param {Function} next
191
- */
192
- exports.requireOwner = function(req, res, next) {
193
- if (isModerator(req.session.user) || isAuthor(req.session.user, req.comment)) {
194
- next();
195
- }
196
- else {
197
- res.json({ success: false, reason: 'Forbidden' }, 403);
198
- }
199
- };
200
-
201
- /**
202
- * Sends e-mail updates when comment is posted to a thread that has
203
- * subscribers.
204
- *
205
- * @param {Comment} comment
206
- */
207
- exports.sendEmailUpdates = function(comment) {
208
- var mailTransport = nodemailer.createTransport("SMTP",{
209
- host: 'localhost',
210
- port: 25
211
- });
212
-
213
- var sendSubscriptionEmail = function(emails) {
214
- var email = emails.shift();
215
-
216
- if (email) {
217
- nodemailer.sendMail(email, function(err){
218
- if (err){
219
- console.log(err);
220
- } else{
221
- console.log("Sent email to " + email.to);
222
- sendSubscriptionEmail(emails);
223
- }
224
- });
225
- } else {
226
- console.log("Finished sending emails");
227
- mailTransport.close();
228
- }
229
- };
230
-
231
- var subscriptionBody = {
232
- sdk: comment.sdk,
233
- version: comment.version,
234
- target: comment.target
235
- };
236
-
237
- var emails = [];
238
-
239
- Subscription.find(subscriptionBody, function(err, subscriptions) {
240
- _.each(subscriptions, function(subscription) {
241
- var mailOptions = {
242
- transport: mailTransport,
243
- from: "Sencha Documentation <no-reply@sencha.com>",
244
- to: subscription.email,
245
- subject: "Comment on '" + comment.title + "'",
246
- text: [
247
- "A comment by " + comment.author + " on '" + comment.title + "' was posted on the Sencha Documentation:\n",
248
- comment.content + "\n",
249
- "--",
250
- "Original thread: " + comment.url,
251
- "Unsubscribe from this thread: http://projects.sencha.com/auth/unsubscribe/" + subscription._id,
252
- "Unsubscribe from all threads: http://projects.sencha.com/auth/unsubscribe/" + subscription._id + '?all=true'
253
- ].join("\n")
254
- };
255
-
256
- if (Number(comment.userId) != Number(subscription.userId)) {
257
- emails.push(mailOptions);
258
- }
259
- });
260
-
261
- if (emails.length) {
262
- sendSubscriptionEmail(emails);
263
- } else {
264
- console.log("No emails to send");
265
- }
266
- });
267
- };
268
-
269
- /**
270
- * Retrieves comment counts for each target.
271
- *
272
- * Stores into `req.commentCounts` field an array like this:
273
- *
274
- * [
275
- * {"_id": "class__Ext__", "value": 3},
276
- * {"_id": "class__Ext__method-define", "value": 1},
277
- * {"_id": "class__Ext.Panel__cfg-title", "value": 8}
278
- * ]
279
- *
280
- * @param {Object} req
281
- * @param {Object} res
282
- * @param {Function} next
283
- */
284
- exports.getCommentCounts = function(req, res, next) {
285
- // Map each comment into: ("type__Class__member", 1)
286
- var map = function() {
287
- if (this.target) {
288
- emit(this.target.slice(0,3).join('__'), 1);
289
- } else {
290
- return;
291
- }
292
- };
293
-
294
- // Sum comment counts for each target
295
- var reduce = function(key, values) {
296
- var total = 0;
297
-
298
- for (var i = 0; i < values.length; i++) {
299
- total += values[i];
300
- }
301
-
302
- return total;
303
- };
304
-
305
- mongoose.connection.db.executeDbCommand({
306
- mapreduce: 'comments',
307
- map: map.toString(),
308
- reduce: reduce.toString(),
309
- out: 'commentCounts',
310
- query: {
311
- deleted: { '$ne': true },
312
- sdk: req.params.sdk,
313
- version: req.params.version
314
- }
315
- }, function(err, dbres) {
316
- mongoose.connection.db.collection('commentCounts', function(err, collection) {
317
- collection.find({}).toArray(function(err, comments) {
318
- req.commentCounts = comments;
319
- next();
320
- });
321
- });
322
- });
323
- };
324
-
325
- /**
326
- * Retrieves list of commenting targets into which the current user
327
- * has subscribed for e-mail updates.
328
- *
329
- * Stores them into `req.commentMeta.subscriptions` field as array:
330
- *
331
- * [
332
- * ["class", "Ext", ""],
333
- * ["class", "Ext", "method-define"],
334
- * ["class", "Ext.Panel", "cfg-title"]
335
- * ]
336
- *
337
- * @param {Object} req
338
- * @param {Object} res
339
- * @param {Function} next
340
- */
341
- exports.getCommentSubscriptions = function(req, res, next) {
342
-
343
- req.commentMeta = req.commentMeta || {};
344
- req.commentMeta.subscriptions = req.commentMeta.subscriptions || [];
345
-
346
- if (req.session.user) {
347
- Subscription.find({
348
- sdk: req.params.sdk,
349
- version: req.params.version,
350
- userId: req.session.user.userid
351
- }, function(err, subscriptions) {
352
- req.commentMeta.subscriptions = _.map(subscriptions, function(subscription) {
353
- return subscription.target;
354
- });
355
- next();
356
- });
357
- } else {
358
- next();
359
- }
360
- };
361
-
362
- /**
363
- * Retrieves list of comments marked 'read' by the current user.
364
- *
365
- * Stores them into `req.commentMeta.reads` field as array:
366
- *
367
- * [
368
- * 'abc123',
369
- * 'abc456',
370
- * 'abc789'
371
- * ]
372
- *
373
- * @param {Object} req
374
- * @param {Object} res
375
- * @param {Function} next
376
- */
377
- exports.getCommentReads = function(req, res, next) {
378
-
379
- req.commentMeta = req.commentMeta || {};
380
- req.commentMeta.reads = req.commentMeta.reads || [];
381
-
382
- if (req.session.user && isModerator(req.session.user)) {
383
- Meta.find({
384
- userId: req.session.user.userid
385
- }, function(err, commentMeta) {
386
- req.commentMeta.reads = _.map(commentMeta, function(commentMeta) {
387
- return commentMeta.commentId;
388
- });
389
- next();
390
- });
391
- } else {
392
- next();
393
- }
394
- };
395
-
396
-