| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var async = require('async'); | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | const _ = require('lodash'); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | var db = require('../database'); | 
					
						
							|  |  |  | var user = require('../user'); | 
					
						
							|  |  |  | var meta = require('../meta'); | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | var groups = require('../groups'); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | var topics = require('../topics'); | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | var categories = require('../categories'); | 
					
						
							| 
									
										
										
										
											2017-08-16 15:15:54 -04:00
										 |  |  | var notifications = require('../notifications'); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | var privileges = require('../privileges'); | 
					
						
							| 
									
										
										
										
											2017-10-27 17:24:43 -04:00
										 |  |  | var plugins = require('../plugins'); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | var socketHelpers = require('../socket.io/helpers'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = function (Posts) { | 
					
						
							|  |  |  | 	Posts.shouldQueue = function (uid, data, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2018-10-21 16:47:51 -04:00
										 |  |  | 				user.getUserFields(uid, ['uid', 'reputation', 'postcount'], next); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			function (userData, next) { | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | 				const shouldQueue = meta.config.postQueue && (!userData.uid || userData.reputation < 0 || userData.postcount <= 0); | 
					
						
							| 
									
										
										
										
											2017-10-27 17:24:43 -04:00
										 |  |  | 				plugins.fireHook('filter:post.shouldQueue', { | 
					
						
							|  |  |  | 					shouldQueue: shouldQueue, | 
					
						
							|  |  |  | 					uid: uid, | 
					
						
							|  |  |  | 					data: data, | 
					
						
							|  |  |  | 				}, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (result, next) { | 
					
						
							|  |  |  | 				next(null, result.shouldQueue); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | 	function removeQueueNotification(id, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				notifications.rescind('post-queue-' + id, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				getParsedObject(id, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (data, next) { | 
					
						
							|  |  |  | 				if (!data) { | 
					
						
							|  |  |  | 					return callback(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				getCid(data.type, data, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (cid, next) { | 
					
						
							|  |  |  | 				getNotificationUids(cid, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (uids, next) { | 
					
						
							|  |  |  | 				uids.forEach(uid => user.notifications.pushCount(uid)); | 
					
						
							|  |  |  | 				next(); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function getNotificationUids(cid, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				async.parallel([ | 
					
						
							|  |  |  | 					async.apply(groups.getMembersOfGroups, ['administrators', 'Global Moderators']), | 
					
						
							|  |  |  | 					async.apply(categories.getModeratorUids, [cid]), | 
					
						
							|  |  |  | 				], next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (results, next) { | 
					
						
							| 
									
										
										
										
											2019-01-14 22:38:15 -05:00
										 |  |  | 				next(null, _.uniq(_.flattenDeep(results))); | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 	Posts.addToQueue = function (data, callback) { | 
					
						
							|  |  |  | 		var type = data.title ? 'topic' : 'reply'; | 
					
						
							|  |  |  | 		var id = type + '-' + Date.now(); | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				canPost(type, data, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				db.sortedSetAdd('post:queue', Date.now(), id, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				db.setObject('post:queue:' + id, { | 
					
						
							|  |  |  | 					id: id, | 
					
						
							|  |  |  | 					uid: data.uid, | 
					
						
							|  |  |  | 					type: type, | 
					
						
							|  |  |  | 					data: JSON.stringify(data), | 
					
						
							|  |  |  | 				}, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2017-10-31 09:43:11 -04:00
										 |  |  | 				user.setUserField(data.uid, 'lastqueuetime', Date.now(), next); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-08-16 15:15:54 -04:00
										 |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2017-11-15 21:35:10 -05:00
										 |  |  | 				async.parallel({ | 
					
						
							|  |  |  | 					notification: function (next) { | 
					
						
							|  |  |  | 						notifications.create({ | 
					
						
							|  |  |  | 							type: 'post-queue', | 
					
						
							|  |  |  | 							nid: 'post-queue-' + id, | 
					
						
							|  |  |  | 							mergeId: 'post-queue', | 
					
						
							|  |  |  | 							bodyShort: '[[notifications:post_awaiting_review]]', | 
					
						
							|  |  |  | 							bodyLong: data.content, | 
					
						
							|  |  |  | 							path: '/post-queue', | 
					
						
							|  |  |  | 						}, next); | 
					
						
							|  |  |  | 					}, | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | 					uids: function (next) { | 
					
						
							|  |  |  | 						async.waterfall([ | 
					
						
							|  |  |  | 							function (next) { | 
					
						
							|  |  |  | 								getCid(type, data, next); | 
					
						
							|  |  |  | 							}, | 
					
						
							|  |  |  | 							function (cid, next) { | 
					
						
							|  |  |  | 								getNotificationUids(cid, next); | 
					
						
							|  |  |  | 							}, | 
					
						
							|  |  |  | 						], next); | 
					
						
							| 
									
										
										
										
											2017-11-15 21:35:10 -05:00
										 |  |  | 					}, | 
					
						
							| 
									
										
										
										
											2017-08-16 15:15:54 -04:00
										 |  |  | 				}, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-11-15 21:35:10 -05:00
										 |  |  | 			function (results, next) { | 
					
						
							|  |  |  | 				if (results.notification) { | 
					
						
							| 
									
										
										
										
											2019-01-04 13:41:19 -05:00
										 |  |  | 					notifications.push(results.notification, results.uids, next); | 
					
						
							| 
									
										
										
										
											2017-08-16 15:15:54 -04:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					next(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 			function (next) { | 
					
						
							|  |  |  | 				next(null, { | 
					
						
							| 
									
										
										
										
											2017-10-31 10:53:28 -04:00
										 |  |  | 					id: id, | 
					
						
							|  |  |  | 					type: type, | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 					queued: true, | 
					
						
							|  |  |  | 					message: '[[success:post-queued]]', | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-15 21:35:10 -05:00
										 |  |  | 	function getCid(type, data, callback) { | 
					
						
							|  |  |  | 		if (type === 'topic') { | 
					
						
							|  |  |  | 			return setImmediate(callback, null, data.cid); | 
					
						
							|  |  |  | 		} else if (type === 'reply') { | 
					
						
							|  |  |  | 			topics.getTopicField(data.tid, 'cid', callback); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return setImmediate(callback, null, null); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 	function canPost(type, data, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2017-11-15 21:35:10 -05:00
										 |  |  | 				getCid(type, data, next); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			function (cid, next) { | 
					
						
							|  |  |  | 				async.parallel({ | 
					
						
							|  |  |  | 					canPost: function (next) { | 
					
						
							|  |  |  | 						if (type === 'topic') { | 
					
						
							| 
									
										
										
										
											2017-11-15 21:35:10 -05:00
										 |  |  | 							privileges.categories.can('topics:create', cid, data.uid, next); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 						} else if (type === 'reply') { | 
					
						
							|  |  |  | 							privileges.categories.can('topics:reply', cid, data.uid, next); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}, | 
					
						
							| 
									
										
										
										
											2017-10-31 09:43:11 -04:00
										 |  |  | 					isReadyToQueue: function (next) { | 
					
						
							|  |  |  | 						user.isReadyToQueue(data.uid, cid, next); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				}, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (results, next) { | 
					
						
							|  |  |  | 				if (!results.canPost) { | 
					
						
							|  |  |  | 					return next(new Error('[[error:no-privileges]]')); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				next(); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Posts.removeFromQueue = function (id, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | 				removeQueueNotification(id, next); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | 				db.sortedSetRemove('post:queue', id, next); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-08-16 15:15:54 -04:00
										 |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2019-01-04 13:27:31 -05:00
										 |  |  | 				db.delete('post:queue:' + id, next); | 
					
						
							| 
									
										
										
										
											2017-08-16 15:15:54 -04:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 		], callback); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Posts.submitFromQueue = function (id, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2017-10-31 16:04:25 -04:00
										 |  |  | 				getParsedObject(id, next); | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			function (data, next) { | 
					
						
							|  |  |  | 				if (!data) { | 
					
						
							|  |  |  | 					return callback(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (data.type === 'topic') { | 
					
						
							|  |  |  | 					createTopic(data.data, next); | 
					
						
							|  |  |  | 				} else if (data.type === 'reply') { | 
					
						
							|  |  |  | 					createReply(data.data, next); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				Posts.removeFromQueue(id, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 16:04:25 -04:00
										 |  |  | 	function getParsedObject(id, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				db.getObject('post:queue:' + id, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (data, next) { | 
					
						
							|  |  |  | 				if (!data) { | 
					
						
							|  |  |  | 					return callback(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				try { | 
					
						
							|  |  |  | 					data.data = JSON.parse(data.data); | 
					
						
							|  |  |  | 				} catch (err) { | 
					
						
							|  |  |  | 					return next(err); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				next(null, data); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 	function createTopic(data, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				topics.post(data, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (result, next) { | 
					
						
							|  |  |  | 				socketHelpers.notifyNew(data.uid, 'newTopic', { posts: [result.postData], topic: result.topicData }); | 
					
						
							|  |  |  | 				next(); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function createReply(data, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				topics.reply(data, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (postData, next) { | 
					
						
							|  |  |  | 				var result = { | 
					
						
							|  |  |  | 					posts: [postData], | 
					
						
							| 
									
										
										
										
											2018-10-21 16:47:51 -04:00
										 |  |  | 					'reputation:disabled': !!meta.config['reputation:disabled'], | 
					
						
							|  |  |  | 					'downvote:disabled': !!meta.config['downvote:disabled'], | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | 				}; | 
					
						
							|  |  |  | 				socketHelpers.notifyNew(data.uid, 'newPost', result); | 
					
						
							|  |  |  | 				next(); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-31 10:53:28 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Posts.editQueuedContent = function (uid, id, content, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							| 
									
										
										
										
											2017-10-31 16:04:25 -04:00
										 |  |  | 				Posts.canEditQueue(uid, id, next); | 
					
						
							| 
									
										
										
										
											2017-10-31 10:53:28 -04:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-10-31 16:04:25 -04:00
										 |  |  | 			function (canEditQueue, next) { | 
					
						
							|  |  |  | 				if (!canEditQueue) { | 
					
						
							| 
									
										
										
										
											2017-10-31 10:53:28 -04:00
										 |  |  | 					return callback(new Error('[[error:no-privileges]]')); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-10-31 16:04:25 -04:00
										 |  |  | 				getParsedObject(id, next); | 
					
						
							| 
									
										
										
										
											2017-10-31 10:53:28 -04:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			function (data, next) { | 
					
						
							| 
									
										
										
										
											2017-10-31 16:04:25 -04:00
										 |  |  | 				if (!data) { | 
					
						
							|  |  |  | 					return callback(); | 
					
						
							| 
									
										
										
										
											2017-10-31 10:53:28 -04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				data.data.content = content; | 
					
						
							|  |  |  | 				db.setObjectField('post:queue:' + id, 'data', JSON.stringify(data.data), next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2017-10-31 16:04:25 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Posts.canEditQueue = function (uid, id, callback) { | 
					
						
							|  |  |  | 		async.waterfall([ | 
					
						
							|  |  |  | 			function (next) { | 
					
						
							|  |  |  | 				async.parallel({ | 
					
						
							|  |  |  | 					isAdminOrGlobalMod: function (next) { | 
					
						
							|  |  |  | 						user.isAdminOrGlobalMod(uid, next); | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					data: function (next) { | 
					
						
							|  |  |  | 						getParsedObject(id, next); | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (results, next) { | 
					
						
							|  |  |  | 				if (results.isAdminOrGlobalMod) { | 
					
						
							|  |  |  | 					return callback(null, true); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (!results.data) { | 
					
						
							|  |  |  | 					return callback(null, false); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (results.data.type === 'topic') { | 
					
						
							|  |  |  | 					next(null, results.data.data.cid); | 
					
						
							|  |  |  | 				} else if (results.data.type === 'reply') { | 
					
						
							|  |  |  | 					topics.getTopicField(results.data.data.tid, 'cid', next); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			function (cid, next) { | 
					
						
							|  |  |  | 				user.isModerator(uid, cid, next); | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		], callback); | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2017-08-15 12:59:40 -04:00
										 |  |  | }; |