mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 19:15:58 +01:00 
			
		
		
		
	closes #450
backup database before upgrade! upgrade script will take the first post of each topic and set the `mainPid` property on the topic. then it will remove that pid from the sorted sets for that topic, this was done to make alternative sorting work. added a new sorted set called `tid:<id>:posts:votes` that is used to sort topic posts by vote count, the original sorted set `tid:<id>:posts` is used to sort by oldest first or newest first. the main post is added to the returned posts array on topic load and is always at the top. theme changes are minimal just a few new data properties on the posts and the sorting dropdown. hopefully didn't miss anything too critical.
This commit is contained in:
		| @@ -111,5 +111,10 @@ | |||||||
|  |  | ||||||
| 	"more_users_and_guests": "%1 more user(s) and %2 guest(s)", | 	"more_users_and_guests": "%1 more user(s) and %2 guest(s)", | ||||||
| 	"more_users": "%1 more user(s)", | 	"more_users": "%1 more user(s)", | ||||||
| 	"more_guests": "%1 more guest(s)" | 	"more_guests": "%1 more guest(s)", | ||||||
|  |  | ||||||
|  | 	"sort_by": "Sort by", | ||||||
|  | 	"oldest_to_newest": "Oldest to Newest", | ||||||
|  | 	"newest_to_oldest": "Newest to Oldest", | ||||||
|  | 	"most_votes": "Most votes" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,14 +8,16 @@ define('forum/infinitescroll', function() { | |||||||
| 	var callback; | 	var callback; | ||||||
| 	var previousScrollTop = 0; | 	var previousScrollTop = 0; | ||||||
| 	var loadingMore	= false; | 	var loadingMore	= false; | ||||||
|  | 	var topOffset = 0; | ||||||
|  |  | ||||||
| 	scroll.init = function(cb) { | 	scroll.init = function(cb, _topOffest) { | ||||||
| 		callback = cb; | 		callback = cb; | ||||||
|  | 		topOffset = _topOffest || 0; | ||||||
| 		$(window).off('scroll', onScroll).on('scroll', onScroll); | 		$(window).off('scroll', onScroll).on('scroll', onScroll); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	function onScroll() { | 	function onScroll() { | ||||||
| 		var top = $(window).height() * 0.1; | 		var top = $(window).height() * 0.1 + topOffset; | ||||||
| 		var bottom = ($(document).height() - $(window).height()) * 0.9; | 		var bottom = ($(document).height() - $(window).height()) * 0.9; | ||||||
| 		var currentScrollTop = $(window).scrollTop(); | 		var currentScrollTop = $(window).scrollTop(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,6 +40,8 @@ define('forum/topic', ['forum/pagination', 'forum/infinitescroll', 'forum/topic/ | |||||||
| 		threadTools.init(tid, thread_state); | 		threadTools.init(tid, thread_state); | ||||||
| 		events.init(); | 		events.init(); | ||||||
|  |  | ||||||
|  | 		handleSorting(); | ||||||
|  |  | ||||||
| 		hidePostToolsForDeletedPosts(); | 		hidePostToolsForDeletedPosts(); | ||||||
|  |  | ||||||
| 		enableInfiniteLoadingOrPagination(); | 		enableInfiniteLoadingOrPagination(); | ||||||
| @@ -77,6 +79,21 @@ define('forum/topic', ['forum/pagination', 'forum/infinitescroll', 'forum/topic/ | |||||||
| 		socket.emit('topics.increaseViewCount', tid); | 		socket.emit('topics.increaseViewCount', tid); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	function handleSorting() { | ||||||
|  | 		var threadSort = $('.thread-sort'); | ||||||
|  | 		threadSort.find('i').removeClass('fa-check'); | ||||||
|  | 		var currentSetting = threadSort.find('a[data-sort="' + config.topicPostSort + '"]'); | ||||||
|  | 		currentSetting.find('i').addClass('fa-check'); | ||||||
|  |  | ||||||
|  | 		$('.thread-sort').on('click', 'a', function() { | ||||||
|  | 			var newSetting = $(this).attr('data-sort'); | ||||||
|  | 			socket.emit('user.setTopicSort', newSetting, function(err) { | ||||||
|  | 				config.topicPostSort = newSetting; | ||||||
|  | 				ajaxify.go('topic/' + ajaxify.variables.get('topic_slug')); | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	function getPostIndex() { | 	function getPostIndex() { | ||||||
| 		var parts = window.location.pathname.split('/'); | 		var parts = window.location.pathname.split('/'); | ||||||
| 		return parts[4] ? (parseInt(parts[4], 10) - 1) : ''; | 		return parts[4] ? (parseInt(parts[4], 10) - 1) : ''; | ||||||
| @@ -122,7 +139,7 @@ define('forum/topic', ['forum/pagination', 'forum/infinitescroll', 'forum/topic/ | |||||||
|  |  | ||||||
| 	function enableInfiniteLoadingOrPagination() { | 	function enableInfiniteLoadingOrPagination() { | ||||||
| 		if(!config.usePagination) { | 		if(!config.usePagination) { | ||||||
| 			infinitescroll.init(loadMorePosts); | 			infinitescroll.init(loadMorePosts, $('#post-container .post-row[data-index="0"]').height()); | ||||||
| 		} else { | 		} else { | ||||||
| 			navigator.hide(); | 			navigator.hide(); | ||||||
|  |  | ||||||
| @@ -283,25 +300,36 @@ define('forum/topic', ['forum/pagination', 'forum/infinitescroll', 'forum/topic/ | |||||||
| 			before = null; | 			before = null; | ||||||
|  |  | ||||||
| 		function findInsertionPoint() { | 		function findInsertionPoint() { | ||||||
| 			var firstPid = parseInt(data.posts[0].pid, 10); | 			var firstPostTimestamp = parseInt(data.posts[0].timestamp, 10); | ||||||
|  | 			var firstPostVotes = parseInt(data.posts[0].votes, 10); | ||||||
|  | 			var firstPostPid = data.posts[0].pid; | ||||||
|  |  | ||||||
| 			$('#post-container li[data-pid]').each(function() { | 			var firstReply = $('#post-container li.post-row[data-index!="0"]').first(); | ||||||
| 				var $this = $(this); | 			var lastReply = $('#post-container li.post-row[data-index!="0"]').last(); | ||||||
|  |  | ||||||
| 				if(firstPid > parseInt($this.attr('data-pid'), 10)) { | 			if (config.topicPostSort === 'oldest_to_newest') { | ||||||
| 					after = $this; | 				if (firstPostTimestamp < parseInt(firstReply.attr('data-timestamp'), 10)) { | ||||||
| 					if(after.next().length && after.next().hasClass('post-bar')) { | 					before = firstReply; | ||||||
| 						after = after.next(); | 				} else if(firstPostTimestamp >= parseInt(lastReply.attr('data-timestamp'), 10)) { | ||||||
| 					} | 					after = lastReply; | ||||||
| 				} else { |  | ||||||
| 					return false; |  | ||||||
| 				} | 				} | ||||||
| 			}); | 			} else if(config.topicPostSort === 'newest_to_oldest') { | ||||||
|  | 				if (firstPostTimestamp > parseInt(firstReply.attr('data-timestamp'), 10)) { | ||||||
| 			if (!after) { | 					before = firstReply; | ||||||
| 				var firstPost = $('#post-container .post-row').first(); | 				} else if(firstPostTimestamp <= parseInt(lastReply.attr('data-timestamp'), 10)) { | ||||||
| 				if(firstPid < parseInt(firstPost.attr('data-pid'), 10)) { | 					after = lastReply; | ||||||
| 					before = firstPost; | 				} | ||||||
|  | 			} else if(config.topicPostSort === 'most_votes') { | ||||||
|  | 				if (firstPostVotes > parseInt(firstReply.attr('data-votes'), 10)) { | ||||||
|  | 					before = firstReply; | ||||||
|  | 				} else if(firstPostVotes < parseInt(firstReply.attr('data-votes'), 10)) { | ||||||
|  | 					after = lastReply; | ||||||
|  | 				} else { | ||||||
|  | 					if (firstPostPid > firstReply.attr('data-pid')) { | ||||||
|  | 						before = firstReply; | ||||||
|  | 					} else if(firstPostPid <= firstReply.attr('data-pid')) { | ||||||
|  | 						after = lastReply; | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -373,7 +401,7 @@ define('forum/topic', ['forum/pagination', 'forum/infinitescroll', 'forum/topic/ | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		infinitescroll.calculateAfter(direction, '#post-container .post-row', config.postsPerPage, function(after, offset, el) { | 		infinitescroll.calculateAfter(direction, '#post-container .post-row[data-index!="0"]', config.postsPerPage, function(after, offset, el) { | ||||||
| 			loadPostsAfter(after, function() { | 			loadPostsAfter(after, function() { | ||||||
| 				if (direction < 0 && el) { | 				if (direction < 0 && el) { | ||||||
| 					Topic.scrollToPost(el.attr('data-index'), false, 0, offset); | 					Topic.scrollToPost(el.attr('data-index'), false, 0, offset); | ||||||
| @@ -384,7 +412,7 @@ define('forum/topic', ['forum/pagination', 'forum/infinitescroll', 'forum/topic/ | |||||||
|  |  | ||||||
| 	function loadPostsAfter(after, callback) { | 	function loadPostsAfter(after, callback) { | ||||||
| 		var tid = ajaxify.variables.get('topic_id'); | 		var tid = ajaxify.variables.get('topic_id'); | ||||||
| 		if (!utils.isNumber(tid) || !utils.isNumber(after) || (after === 0 && $('#post-container li.post-row[data-index="0"]').length)) { | 		if (!utils.isNumber(tid) || !utils.isNumber(after) || (after === 0 && $('#post-container li.post-row[data-index="1"]').length)) { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ apiController.getConfig = function(req, res, next) { | |||||||
| 	config.isLoggedIn = !!req.user; | 	config.isLoggedIn = !!req.user; | ||||||
| 	config['cache-buster'] = meta.config['cache-buster'] || ''; | 	config['cache-buster'] = meta.config['cache-buster'] || ''; | ||||||
| 	config.requireEmailConfirmation = parseInt(meta.config.requireEmailConfirmation, 10) === 1; | 	config.requireEmailConfirmation = parseInt(meta.config.requireEmailConfirmation, 10) === 1; | ||||||
|  | 	config.topicPostSort = meta.config.topicPostSort || 'oldest_to_newest'; | ||||||
| 	config.version = pkg.version; | 	config.version = pkg.version; | ||||||
|  |  | ||||||
| 	if (!req.user) { | 	if (!req.user) { | ||||||
| @@ -64,6 +65,7 @@ apiController.getConfig = function(req, res, next) { | |||||||
| 		config.notificationSounds = settings.notificationSounds; | 		config.notificationSounds = settings.notificationSounds; | ||||||
| 		config.defaultLang = settings.language || config.defaultLang; | 		config.defaultLang = settings.language || config.defaultLang; | ||||||
| 		config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab; | 		config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab; | ||||||
|  | 		config.topicPostSort = settings.topicPostSort || config.topicPostSort; | ||||||
|  |  | ||||||
| 		if (res.locals.isAPI) { | 		if (res.locals.isAPI) { | ||||||
| 			res.json(200, config); | 			res.json(200, config); | ||||||
|   | |||||||
| @@ -44,7 +44,17 @@ topicsController.get = function(req, res, next) { | |||||||
| 			var start = (page - 1) * settings.postsPerPage + postIndex, | 			var start = (page - 1) * settings.postsPerPage + postIndex, | ||||||
| 				end = start + settings.postsPerPage - 1; | 				end = start + settings.postsPerPage - 1; | ||||||
|  |  | ||||||
| 			topics.getTopicWithPosts(tid, uid, start, end, function (err, topicData) { | 			var set = 'tid:' + tid + ':posts', | ||||||
|  | 				reverse = false; | ||||||
|  |  | ||||||
|  | 			if (settings.topicPostSort === 'newest_to_oldest') { | ||||||
|  | 				reverse = true; | ||||||
|  | 			} else if (settings.topicPostSort === 'most_votes') { | ||||||
|  | 				reverse = true; | ||||||
|  | 				set = 'tid:' + tid + ':posts:votes'; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			topics.getTopicWithPosts(tid, set, uid, start, end, reverse, function (err, topicData) { | ||||||
| 				if (topicData) { | 				if (topicData) { | ||||||
| 					if (parseInt(topicData.deleted, 10) === 1 && !userPrivileges.view_deleted) { | 					if (parseInt(topicData.deleted, 10) === 1 && !userPrivileges.view_deleted) { | ||||||
| 						return next(new Error('[[error:no-topic]]')); | 						return next(new Error('[[error:no-topic]]')); | ||||||
|   | |||||||
| @@ -88,7 +88,8 @@ var async = require('async'), | |||||||
| 					return callback(err); | 					return callback(err); | ||||||
| 				} | 				} | ||||||
| 				var voteCount = parseInt(results.upvotes, 10) - parseInt(results.downvotes, 10); | 				var voteCount = parseInt(results.upvotes, 10) - parseInt(results.downvotes, 10); | ||||||
| 				posts.setPostField(pid, 'votes', voteCount, function(err) { |  | ||||||
|  | 				posts.updatePostVoteCount(pid, voteCount, function(err) { | ||||||
| 					callback(err, voteCount); | 					callback(err, voteCount); | ||||||
| 				}); | 				}); | ||||||
| 			}); | 			}); | ||||||
|   | |||||||
| @@ -85,9 +85,10 @@ middleware.checkPostIndex = function(req, res, next) { | |||||||
| 			return next(err); | 			return next(err); | ||||||
| 		} | 		} | ||||||
| 		var postIndex = parseInt(req.params.post_index, 10); | 		var postIndex = parseInt(req.params.post_index, 10); | ||||||
|  | 		postCount = parseInt(postCount, 10) + 1; | ||||||
| 		if (postIndex > postCount) { | 		if (postIndex > postCount) { | ||||||
| 			return res.locals.isAPI ? res.json(302, '/topic/' + req.params.topic_id + '/' + req.params.slug + '/' + postCount) : res.redirect('/topic/' + req.params.topic_id + '/' + req.params.slug + '/' + postCount); | 			return res.locals.isAPI ? res.json(302, '/topic/' + req.params.topic_id + '/' + req.params.slug + '/' + postCount) : res.redirect('/topic/' + req.params.topic_id + '/' + req.params.slug + '/' + postCount); | ||||||
| 		} else if (postIndex < 1) { | 		} else if (postIndex <= 1) { | ||||||
| 			return res.locals.isAPI ? res.json(302, '/topic/' + req.params.topic_id + '/' + req.params.slug) : res.redirect('/topic/' + req.params.topic_id + '/' + req.params.slug); | 			return res.locals.isAPI ? res.json(302, '/topic/' + req.params.topic_id + '/' + req.params.slug) : res.redirect('/topic/' + req.params.topic_id + '/' + req.params.slug); | ||||||
| 		} | 		} | ||||||
| 		next(); | 		next(); | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								src/posts.js
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								src/posts.js
									
									
									
									
									
								
							| @@ -90,8 +90,8 @@ var db = require('./database'), | |||||||
| 		], callback); | 		], callback); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	Posts.getPostsByTid = function(tid, start, end, reverse, callback) { | 	Posts.getPostsByTid = function(tid, set, start, end, reverse, callback) { | ||||||
| 		db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange']('tid:' + tid + ':posts', start, end, function(err, pids) { | 		db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, end, function(err, pids) { | ||||||
| 			if(err) { | 			if(err) { | ||||||
| 				return callback(err); | 				return callback(err); | ||||||
| 			} | 			} | ||||||
| @@ -157,8 +157,6 @@ var db = require('./database'), | |||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	Posts.getRecentPosts = function(uid, start, stop, term, callback) { | 	Posts.getRecentPosts = function(uid, start, stop, term, callback) { | ||||||
| 		var terms = { | 		var terms = { | ||||||
| 			day: 86400000, | 			day: 86400000, | ||||||
| @@ -469,7 +467,9 @@ var db = require('./database'), | |||||||
| 				return callback(err); | 				return callback(err); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			db.sortedSetRank('tid:' + tid + ':posts', pid, callback); | 			db.sortedSetRank('tid:' + tid + ':posts', pid, function(err, index) { | ||||||
|  | 				callback(err, parseInt(index, 10) + 1); | ||||||
|  | 			}); | ||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -482,5 +482,28 @@ var db = require('./database'), | |||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	Posts.updatePostVoteCount = function(pid, voteCount, callback) { | ||||||
|  | 		async.parallel([ | ||||||
|  | 			function(next) { | ||||||
|  | 				Posts.getPostField(pid, 'tid', function(err, tid) { | ||||||
|  | 					if (err) { | ||||||
|  | 						return next(err); | ||||||
|  | 					} | ||||||
|  | 					topics.getTopicField(tid, 'mainPid', function(err, mainPid) { | ||||||
|  | 						if (err) { | ||||||
|  | 							return next(err); | ||||||
|  | 						} | ||||||
|  | 						if (parseInt(mainPid, 10) === parseInt(pid, 10)) { | ||||||
|  | 							return next(); | ||||||
|  | 						} | ||||||
|  | 						db.sortedSetAdd('tid:' + tid + ':posts:votes', voteCount, pid, next); | ||||||
|  | 					}); | ||||||
|  | 				}); | ||||||
|  | 			}, | ||||||
|  | 			function(next) { | ||||||
|  | 				Posts.setPostField(pid, 'votes', voteCount, next); | ||||||
|  | 			} | ||||||
|  | 		], callback); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| }(exports)); | }(exports)); | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ function hasPrivileges(method, id, req, res, next) { | |||||||
| function generateForTopic(req, res, next) { | function generateForTopic(req, res, next) { | ||||||
| 	var tid = req.params.topic_id; | 	var tid = req.params.topic_id; | ||||||
| 	var uid = req.user ? req.user.uid : 0; | 	var uid = req.user ? req.user.uid : 0; | ||||||
| 	topics.getTopicWithPosts(tid, uid, 0, 25, function (err, topicData) { | 	topics.getTopicWithPosts(tid, 'tid:' + tid + ':posts', uid, 0, 25, false, function (err, topicData) { | ||||||
| 		if (err) { | 		if (err) { | ||||||
| 			return next(err); | 			return next(err); | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -314,12 +314,22 @@ SocketTopics.loadMore = function(socket, data, callback) { | |||||||
| 			return callback(err); | 			return callback(err); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		var start = parseInt(data.after, 10), | 		var start = Math.max(parseInt(data.after, 10) - 1, 0), | ||||||
| 			end = start + settings.postsPerPage - 1; | 			end = start + settings.postsPerPage - 1; | ||||||
|  |  | ||||||
|  | 		var set = 'tid:' + data.tid + ':posts', | ||||||
|  | 			reverse = false; | ||||||
|  |  | ||||||
|  | 		if (settings.topicPostSort === 'newest_to_oldest') { | ||||||
|  | 			reverse = true; | ||||||
|  | 		} else if (settings.topicPostSort === 'most_votes') { | ||||||
|  | 			reverse = true; | ||||||
|  | 			set = 'tid:' + data.tid + ':posts:votes'; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		async.parallel({ | 		async.parallel({ | ||||||
| 			posts: function(next) { | 			posts: function(next) { | ||||||
| 				topics.getTopicPosts(data.tid, start, end, socket.uid, false, next); | 				topics.getTopicPosts(data.tid, set, start, end, socket.uid, reverse, next); | ||||||
| 			}, | 			}, | ||||||
| 			privileges: function(next) { | 			privileges: function(next) { | ||||||
| 				privileges.topics.get(data.tid, socket.uid, next); | 				privileges.topics.get(data.tid, socket.uid, next); | ||||||
|   | |||||||
| @@ -178,6 +178,12 @@ SocketUser.saveSettings = function(socket, data, callback) { | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | SocketUser.setTopicSort = function(socket, sort, callback) { | ||||||
|  | 	if(socket.uid) { | ||||||
|  | 		user.setSetting(socket.uid, 'topicPostSort', sort, callback); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
| SocketUser.getOnlineUsers = function(socket, data, callback) { | SocketUser.getOnlineUsers = function(socket, data, callback) { | ||||||
| 	var returnData = {}; | 	var returnData = {}; | ||||||
| 	if(!data) { | 	if(!data) { | ||||||
|   | |||||||
| @@ -262,7 +262,7 @@ var async = require('async'), | |||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	Topics.getTopicWithPosts = function(tid, uid, start, end, callback) { | 	Topics.getTopicWithPosts = function(tid, set, uid, start, end, reverse, callback) { | ||||||
| 		Topics.getTopicData(tid, function(err, topicData) { | 		Topics.getTopicData(tid, function(err, topicData) { | ||||||
| 			if (err || !topicData) { | 			if (err || !topicData) { | ||||||
| 				return callback(err || new Error('[[error:no-topic]]')); | 				return callback(err || new Error('[[error:no-topic]]')); | ||||||
| @@ -270,7 +270,7 @@ var async = require('async'), | |||||||
|  |  | ||||||
| 			async.parallel({ | 			async.parallel({ | ||||||
| 				posts: function(next) { | 				posts: function(next) { | ||||||
| 					Topics.getTopicPosts(tid, start, end, uid, false, next); | 					Topics.getTopicPosts(tid, set, start, end, uid, reverse, next); | ||||||
| 				}, | 				}, | ||||||
| 				category: function(next) { | 				category: function(next) { | ||||||
| 					Topics.getCategoryData(tid, next); | 					Topics.getCategoryData(tid, next); | ||||||
| @@ -283,6 +283,26 @@ var async = require('async'), | |||||||
| 				}, | 				}, | ||||||
| 				tags: function(next) { | 				tags: function(next) { | ||||||
| 					Topics.getTopicTagsObjects(tid, next); | 					Topics.getTopicTagsObjects(tid, next); | ||||||
|  | 				}, | ||||||
|  | 				mainPost: function(next) { | ||||||
|  | 					Topics.getTopicField(tid, 'mainPid', function(err, mainPid) { | ||||||
|  | 						if (err) { | ||||||
|  | 							return next(err); | ||||||
|  | 						} | ||||||
|  | 						if (!parseInt(mainPid, 10)) { | ||||||
|  | 							return next(null, []); | ||||||
|  | 						} | ||||||
|  | 						posts.getPostsByPids([mainPid], function(err, postData) { | ||||||
|  | 							if (err) { | ||||||
|  | 								return next(err); | ||||||
|  | 							} | ||||||
|  | 							if (!Array.isArray(postData) || !postData.length) { | ||||||
|  | 								return next(null, []); | ||||||
|  | 							} | ||||||
|  | 							postData[0].index = 0; | ||||||
|  | 							Topics.addPostData(postData, uid, next); | ||||||
|  | 						}); | ||||||
|  | 					}); | ||||||
| 				} | 				} | ||||||
| 			}, function(err, results) { | 			}, function(err, results) { | ||||||
| 				if (err) { | 				if (err) { | ||||||
| @@ -290,7 +310,7 @@ var async = require('async'), | |||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				topicData.category = results.category; | 				topicData.category = results.category; | ||||||
| 				topicData.posts = results.posts; | 				topicData.posts = results.mainPost.concat(results.posts); | ||||||
| 				topicData.tags = results.tags; | 				topicData.tags = results.tags; | ||||||
| 				topicData.thread_tools = results.threadTools; | 				topicData.thread_tools = results.threadTools; | ||||||
| 				topicData.pageCount = results.pageCount; | 				topicData.pageCount = results.pageCount; | ||||||
|   | |||||||
| @@ -37,6 +37,7 @@ module.exports = function(Topics) { | |||||||
| 				'tid': tid, | 				'tid': tid, | ||||||
| 				'uid': uid, | 				'uid': uid, | ||||||
| 				'cid': cid, | 				'cid': cid, | ||||||
|  | 				'mainPid': 0, | ||||||
| 				'title': title, | 				'title': title, | ||||||
| 				'slug': slug, | 				'slug': slug, | ||||||
| 				'timestamp': timestamp, | 				'timestamp': timestamp, | ||||||
|   | |||||||
| @@ -71,7 +71,7 @@ module.exports = function(Topics) { | |||||||
| 				return callback(err || new Error('[[error:no-topic]]')); | 				return callback(err || new Error('[[error:no-topic]]')); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			posts.getPostFields(pid, ['deleted', 'tid', 'timestamp'], function(err, postData) { | 			posts.getPostFields(pid, ['deleted', 'tid', 'timestamp', 'votes'], function(err, postData) { | ||||||
| 				if(err) { | 				if(err) { | ||||||
| 					return callback(err); | 					return callback(err); | ||||||
| 				} | 				} | ||||||
| @@ -91,7 +91,7 @@ module.exports = function(Topics) { | |||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					posts.setPostField(pid, 'tid', tid); | 					posts.setPostField(pid, 'tid', tid); | ||||||
| 					Topics.addPostToTopic(tid, pid, postData.timestamp, callback); | 					Topics.addPostToTopic(tid, pid, postData.timestamp, postData.votes, callback); | ||||||
| 				}); | 				}); | ||||||
| 			}); | 			}); | ||||||
| 		}); | 		}); | ||||||
|   | |||||||
| @@ -15,13 +15,13 @@ module.exports = function(Topics) { | |||||||
| 	Topics.onNewPostMade = function(postData) { | 	Topics.onNewPostMade = function(postData) { | ||||||
| 		Topics.increasePostCount(postData.tid); | 		Topics.increasePostCount(postData.tid); | ||||||
| 		Topics.updateTimestamp(postData.tid, postData.timestamp); | 		Topics.updateTimestamp(postData.tid, postData.timestamp); | ||||||
| 		Topics.addPostToTopic(postData.tid, postData.pid, postData.timestamp); | 		Topics.addPostToTopic(postData.tid, postData.pid, postData.timestamp, 0); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	emitter.on('event:newpost', Topics.onNewPostMade); | 	emitter.on('event:newpost', Topics.onNewPostMade); | ||||||
|  |  | ||||||
| 	Topics.getTopicPosts = function(tid, start, end, uid, reverse, callback) { | 	Topics.getTopicPosts = function(tid, set, start, end, uid, reverse, callback) { | ||||||
| 		posts.getPostsByTid(tid, start, end, reverse, function(err, postData) { | 		posts.getPostsByTid(tid, set, start, end, reverse, function(err, postData) { | ||||||
| 			if(err) { | 			if(err) { | ||||||
| 				return callback(err); | 				return callback(err); | ||||||
| 			} | 			} | ||||||
| @@ -29,52 +29,57 @@ module.exports = function(Topics) { | |||||||
| 			if (Array.isArray(postData) && !postData.length) { | 			if (Array.isArray(postData) && !postData.length) { | ||||||
| 				return callback(null, []); | 				return callback(null, []); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			start = parseInt(start, 10); | 			start = parseInt(start, 10); | ||||||
| 			for(var i=0; i<postData.length; ++i) { | 			for(var i=0; i<postData.length; ++i) { | ||||||
| 				postData[i].index = start + i; | 				postData[i].index = start + i + 1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			var pids = postData.map(function(post) { | 			Topics.addPostData(postData, uid, callback); | ||||||
| 				return post.pid; | 		}); | ||||||
| 			}); | 	}; | ||||||
|  |  | ||||||
| 			async.parallel({ | 	Topics.addPostData = function(postData, uid, callback) { | ||||||
| 				favourites : function(next) { | 		var pids = postData.map(function(post) { | ||||||
| 					favourites.getFavouritesByPostIDs(pids, uid, next); | 			return post.pid; | ||||||
| 				}, | 		}); | ||||||
| 				voteData : function(next) { |  | ||||||
| 					favourites.getVoteStatusByPostIDs(pids, uid, next); | 		async.parallel({ | ||||||
| 				}, | 			favourites : function(next) { | ||||||
| 				userData : function(next) { | 				favourites.getFavouritesByPostIDs(pids, uid, next); | ||||||
| 					async.each(postData, posts.addUserInfoToPost, next); | 			}, | ||||||
| 				}, | 			voteData : function(next) { | ||||||
| 				privileges : function(next) { | 				favourites.getVoteStatusByPostIDs(pids, uid, next); | ||||||
| 					async.map(pids, function (pid, next) { | 			}, | ||||||
| 						privileges.posts.get(pid, uid, next); | 			userData : function(next) { | ||||||
| 					}, next); | 				async.each(postData, posts.addUserInfoToPost, next); | ||||||
| 				} | 			}, | ||||||
| 			}, function(err, results) { | 			privileges : function(next) { | ||||||
| 				if(err) { | 				async.map(pids, function (pid, next) { | ||||||
| 					return callback(err); | 					privileges.posts.get(pid, uid, next); | ||||||
|  | 				}, next); | ||||||
|  | 			} | ||||||
|  | 		}, function(err, results) { | ||||||
|  | 			if(err) { | ||||||
|  | 				return callback(err); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			for (var i = 0; i < postData.length; ++i) { | ||||||
|  | 				postData[i].deleted = parseInt(postData[i].deleted, 10) === 1; | ||||||
|  | 				postData[i].favourited = results.favourites[i]; | ||||||
|  | 				postData[i].upvoted = results.voteData[i].upvoted; | ||||||
|  | 				postData[i].downvoted = results.voteData[i].downvoted; | ||||||
|  | 				postData[i].votes = postData[i].votes || 0; | ||||||
|  | 				postData[i].display_moderator_tools = results.privileges[i].editable; | ||||||
|  | 				postData[i].display_move_tools = results.privileges[i].move; | ||||||
|  | 				postData[i].selfPost = parseInt(uid, 10) === parseInt(postData[i].uid, 10); | ||||||
|  |  | ||||||
|  | 				if(postData[i].deleted && !results.privileges[i].view_deleted) { | ||||||
|  | 					postData[i].content = '[[topic:post_is_deleted]]'; | ||||||
| 				} | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 				for (var i = 0; i < postData.length; ++i) { | 			callback(null, postData); | ||||||
| 					postData[i].deleted = parseInt(postData[i].deleted, 10) === 1; |  | ||||||
| 					postData[i].favourited = results.favourites[i]; |  | ||||||
| 					postData[i].upvoted = results.voteData[i].upvoted; |  | ||||||
| 					postData[i].downvoted = results.voteData[i].downvoted; |  | ||||||
| 					postData[i].votes = postData[i].votes || 0; |  | ||||||
| 					postData[i].display_moderator_tools = results.privileges[i].editable; |  | ||||||
| 					postData[i].display_move_tools = results.privileges[i].move; |  | ||||||
| 					postData[i].selfPost = parseInt(uid, 10) === parseInt(postData[i].uid, 10); |  | ||||||
|  |  | ||||||
| 					if(postData[i].deleted && !results.privileges[i].view_deleted) { |  | ||||||
| 						postData[i].content = '[[topic:post_is_deleted]]'; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				callback(null, postData); |  | ||||||
| 			}); |  | ||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -108,8 +113,21 @@ module.exports = function(Topics) { | |||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	Topics.addPostToTopic = function(tid, pid, timestamp, callback) { | 	Topics.addPostToTopic = function(tid, pid, timestamp, votes, callback) { | ||||||
| 		db.sortedSetAdd('tid:' + tid + ':posts', timestamp, pid, callback); | 		Topics.getTopicField(tid, 'mainPid', function(err, mainPid) { | ||||||
|  | 			if (!parseInt(mainPid, 10)) { | ||||||
|  | 				Topics.setTopicField(tid, 'mainPid', pid, callback); | ||||||
|  | 			} else { | ||||||
|  | 				async.parallel([ | ||||||
|  | 					function(next) { | ||||||
|  | 						db.sortedSetAdd('tid:' + tid + ':posts', timestamp, pid, next); | ||||||
|  | 					}, | ||||||
|  | 					function(next) { | ||||||
|  | 						db.sortedSetAdd('tid:' + tid + ':posts:votes', votes, pid, next); | ||||||
|  | 					} | ||||||
|  | 				], callback); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	Topics.removePostFromTopic = function(tid, pid, callback) { | 	Topics.removePostFromTopic = function(tid, pid, callback) { | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ var db = require('./database'), | |||||||
| 	schemaDate, thisSchemaDate, | 	schemaDate, thisSchemaDate, | ||||||
|  |  | ||||||
| 	// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema | 	// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema | ||||||
| 	latestSchema = Date.UTC(2014, 4, 22); | 	latestSchema = Date.UTC(2014, 5, 6); | ||||||
|  |  | ||||||
| Upgrade.check = function(callback) { | Upgrade.check = function(callback) { | ||||||
| 	db.get('schemaDate', function(err, value) { | 	db.get('schemaDate', function(err, value) { | ||||||
| @@ -733,6 +733,74 @@ Upgrade.upgrade = function(callback) { | |||||||
| 				winston.info('[2014/5/16] Tags upgrade - skipped'); | 				winston.info('[2014/5/16] Tags upgrade - skipped'); | ||||||
| 				next(); | 				next(); | ||||||
| 			} | 			} | ||||||
|  | 		}, | ||||||
|  | 		function(next) { | ||||||
|  | 			thisSchemaDate = Date.UTC(2014, 5, 6); | ||||||
|  |  | ||||||
|  | 			if (schemaDate < thisSchemaDate) { | ||||||
|  | 				db.getSortedSetRange('topics:tid', 0, -1, function(err, tids) { | ||||||
|  | 					function upgradeTopic(tid, callback) { | ||||||
|  |  | ||||||
|  | 						Topics.getTopicField(tid, 'mainPid', function(err, mainPid) { | ||||||
|  | 							if (err) { | ||||||
|  | 								return callback(err); | ||||||
|  | 							} | ||||||
|  |  | ||||||
|  | 							db.getSortedSetRange('tid:' + tid + ':posts', 0, -1, function(err, pids) { | ||||||
|  | 								if (err) { | ||||||
|  | 									return callback(err); | ||||||
|  | 								} | ||||||
|  |  | ||||||
|  | 								if (!Array.isArray(pids) || !pids.length) { | ||||||
|  | 									return callback(); | ||||||
|  | 								} | ||||||
|  |  | ||||||
|  | 								if (!parseInt(mainPid, 10)) { | ||||||
|  | 									mainPid = pids[0]; | ||||||
|  | 									pids.splice(0, 1); | ||||||
|  | 									Topics.setTopicField(tid, 'mainPid', mainPid); | ||||||
|  | 									db.sortedSetRemove('tid:' + tid + ':posts', mainPid); | ||||||
|  | 									db.sortedSetRemove('tid:' + tid + ':posts:votes', mainPid); | ||||||
|  | 								} | ||||||
|  |  | ||||||
|  | 								if (!pids.length) { | ||||||
|  | 									return callback(); | ||||||
|  | 								} | ||||||
|  |  | ||||||
|  | 								async.each(pids, function(pid, next) { | ||||||
|  | 									Posts.getPostField(pid, 'votes', function(err, votes) { | ||||||
|  | 										if (err) { | ||||||
|  | 											return next(err); | ||||||
|  | 										} | ||||||
|  | 										db.sortedSetAdd('tid:' + tid + ':posts:votes', votes ? votes : 0, pid, next); | ||||||
|  | 									}); | ||||||
|  | 								}, callback); | ||||||
|  | 							}); | ||||||
|  | 						}); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					if (err) { | ||||||
|  | 						return next(err); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					if (!Array.isArray(tids) || !tids.length)  { | ||||||
|  | 						winston.info('[2014/6/6] Skipping topic upgrade'); | ||||||
|  | 						return Upgrade.update(thisSchemaDate, next); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					async.each(tids, upgradeTopic, function(err) { | ||||||
|  | 						if (err) { | ||||||
|  | 							winston.error('[2014/6/6] Error encountered while upgrading topics'); | ||||||
|  | 							return next(err); | ||||||
|  | 						} | ||||||
|  | 						winston.info('[2014/6/6] Topics upgraded.'); | ||||||
|  | 						Upgrade.update(thisSchemaDate, next); | ||||||
|  | 					}); | ||||||
|  | 				}); | ||||||
|  | 			} else { | ||||||
|  | 				winston.info('[2014/6/6] Topic upgrade - skipped'); | ||||||
|  | 				next(); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		// Add new schema updates here | 		// Add new schema updates here | ||||||
| 		// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!! | 		// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!! | ||||||
|   | |||||||
| @@ -66,7 +66,14 @@ module.exports = function(User) { | |||||||
| 				return callback(err); | 				return callback(err); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			db.sortedSetRemove('tid:' + postData.tid + ':posts', pid, function(err) { | 			async.parallel([ | ||||||
|  | 				function(next) { | ||||||
|  | 					db.sortedSetRemove('tid:' + postData.tid + ':posts', pid, next); | ||||||
|  | 				}, | ||||||
|  | 				function(next) { | ||||||
|  | 					db.sortedSetRemove('tid:' + postData.tid + ':posts:votes', pid, next); | ||||||
|  | 				} | ||||||
|  | 			], function(err) { | ||||||
| 				if (err) { | 				if (err) { | ||||||
| 					return callback(err); | 					return callback(err); | ||||||
| 				} | 				} | ||||||
|   | |||||||
| @@ -32,6 +32,7 @@ module.exports = function(User) { | |||||||
| 				settings.postsPerPage = settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : parseInt(meta.config.postsPerPage, 10) || 10; | 				settings.postsPerPage = settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : parseInt(meta.config.postsPerPage, 10) || 10; | ||||||
| 				settings.notificationSounds = settings.notificationSounds ? parseInt(settings.notificationSounds, 10) === 1 : true; | 				settings.notificationSounds = settings.notificationSounds ? parseInt(settings.notificationSounds, 10) === 1 : true; | ||||||
| 				settings.language = settings.language || meta.config.defaultLang || 'en_GB'; | 				settings.language = settings.language || meta.config.defaultLang || 'en_GB'; | ||||||
|  | 				settings.topicPostSort = settings.topicPostSort || meta.config.topicPostSort || 'oldest_to_newest'; | ||||||
| 				callback(null, settings); | 				callback(null, settings); | ||||||
| 			}); | 			}); | ||||||
| 		}); | 		}); | ||||||
| @@ -82,4 +83,8 @@ module.exports = function(User) { | |||||||
| 			language: data.language || meta.config.defaultLang | 			language: data.language || meta.config.defaultLang | ||||||
| 		}, callback); | 		}, callback); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	User.setSetting = function(uid, key, value, callback) { | ||||||
|  | 		db.setObjectField('user:' + uid + ':settings', key, value, callback); | ||||||
|  | 	}; | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user