cleanup and tests

v1.18.x
Baris Usakli 8 years ago
parent 82cab53508
commit 062bced3dd

@ -313,16 +313,13 @@ topicsController.teaser = function (req, res, next) {
}
posts.getPostSummaryByPids([pid], req.uid, { stripTags: false }, next);
},
], function (err, posts) {
if (err) {
return next(err);
}
if (!Array.isArray(posts) || !posts.length) {
return res.status(404).json('not-found');
}
res.json(posts[0]);
});
function (posts) {
if (!Array.isArray(posts) || !posts.length) {
return res.status(404).json('not-found');
}
res.json(posts[0]);
},
], next);
};
topicsController.pagination = function (req, res, callback) {

@ -108,14 +108,15 @@ function expose(exposedField, method, field, req, res, next) {
if (!req.params.hasOwnProperty(field)) {
return next();
}
method(req.params[field], function (err, id) {
if (err) {
return next(err);
}
res.locals[exposedField] = id;
next();
});
async.waterfall([
function (next) {
method(req.params[field], next);
},
function (id, next) {
res.locals[exposedField] = id;
next();
},
], next);
}
middleware.privateUploads = function (req, res, next) {

@ -1,38 +1,44 @@
'use strict';
var async = require('async');
var nconf = require('nconf');
var meta = require('../meta');
var user = require('../user');
module.exports = function (middleware) {
middleware.maintenanceMode = function (req, res, next) {
middleware.maintenanceMode = function (req, res, callback) {
if (parseInt(meta.config.maintenanceMode, 10) !== 1) {
return next();
return callback();
}
var url = req.url.replace(nconf.get('relative_path'), '');
if (url.startsWith('/login') || url.startsWith('/api/login')) {
return next();
return callback();
}
var data;
async.waterfall([
function (next) {
user.isAdministrator(req.uid, next);
},
function (isAdmin, next) {
if (isAdmin) {
return callback();
}
res.status(503);
data = {
site_title: meta.config.title || 'NodeBB',
message: meta.config.maintenanceModeMessage,
};
user.isAdministrator(req.uid, function (err, isAdmin) {
if (err || isAdmin) {
return next(err);
}
if (res.locals.isAPI) {
return res.json(data);
}
res.status(503);
var data = {
site_title: meta.config.title || 'NodeBB',
message: meta.config.maintenanceModeMessage,
};
if (res.locals.isAPI) {
return res.json(data);
}
middleware.buildHeader(req, res, function () {
middleware.buildHeader(req, res, next);
},
function () {
res.render('503', data);
});
});
},
], callback);
};
};

@ -18,69 +18,70 @@ module.exports = function (Posts) {
if (!parseInt(uid, 10)) {
return callback(new Error('[[error:not-logged-in]]'));
}
var isBookmarking = type === 'bookmark';
async.parallel({
owner: function (next) {
Posts.getPostField(pid, 'uid', next);
},
postData: function (next) {
Posts.getPostFields(pid, ['pid', 'uid'], next);
},
hasBookmarked: function (next) {
Posts.hasBookmarked(pid, uid, next);
var isBookmarking = type === 'bookmark';
var postData;
var hasBookmarked;
var owner;
async.waterfall([
function (next) {
async.parallel({
owner: function (next) {
Posts.getPostField(pid, 'uid', next);
},
postData: function (next) {
Posts.getPostFields(pid, ['pid', 'uid'], next);
},
hasBookmarked: function (next) {
Posts.hasBookmarked(pid, uid, next);
},
}, next);
},
}, function (err, results) {
if (err) {
return callback(err);
}
if (isBookmarking && results.hasBookmarked) {
return callback(new Error('[[error:already-bookmarked]]'));
}
function (results, next) {
owner = results.owner;
postData = results.postData;
hasBookmarked = results.hasBookmarked;
if (!isBookmarking && !results.hasBookmarked) {
return callback(new Error('[[error:already-unbookmarked]]'));
}
if (isBookmarking && hasBookmarked) {
return callback(new Error('[[error:already-bookmarked]]'));
}
async.waterfall([
function (next) {
if (isBookmarking) {
db.sortedSetAdd('uid:' + uid + ':bookmarks', Date.now(), pid, next);
} else {
db.sortedSetRemove('uid:' + uid + ':bookmarks', pid, next);
}
},
function (next) {
db[isBookmarking ? 'setAdd' : 'setRemove']('pid:' + pid + ':users_bookmarked', uid, next);
},
function (next) {
db.setCount('pid:' + pid + ':users_bookmarked', next);
},
function (count, next) {
results.postData.bookmarks = count;
Posts.setPostField(pid, 'bookmarks', count, next);
},
], function (err) {
if (err) {
return callback(err);
if (!isBookmarking && !hasBookmarked) {
return callback(new Error('[[error:already-unbookmarked]]'));
}
var current = results.hasBookmarked ? 'bookmarked' : 'unbookmarked';
if (isBookmarking) {
db.sortedSetAdd('uid:' + uid + ':bookmarks', Date.now(), pid, next);
} else {
db.sortedSetRemove('uid:' + uid + ':bookmarks', pid, next);
}
},
function (next) {
db[isBookmarking ? 'setAdd' : 'setRemove']('pid:' + pid + ':users_bookmarked', uid, next);
},
function (next) {
db.setCount('pid:' + pid + ':users_bookmarked', next);
},
function (count, next) {
postData.bookmarks = count;
Posts.setPostField(pid, 'bookmarks', count, next);
},
function (next) {
var current = hasBookmarked ? 'bookmarked' : 'unbookmarked';
plugins.fireHook('action:post.' + type, {
pid: pid,
uid: uid,
owner: results.owner,
owner: owner,
current: current,
});
callback(null, {
post: results.postData,
next(null, {
post: postData,
isBookmarked: isBookmarking,
});
});
});
},
], callback);
}
Posts.hasBookmarked = function (pid, uid, callback) {

@ -102,12 +102,12 @@ module.exports = function (Posts) {
db.incrObjectField('global', 'postCount', next);
},
], function (err) {
if (err) {
return next(err);
}
plugins.fireHook('filter:post.get', { post: postData, uid: data.uid }, next);
next(err);
});
},
function (next) {
plugins.fireHook('filter:post.get', { post: postData, uid: data.uid }, next);
},
function (data, next) {
data.post.isMain = isMain;
plugins.fireHook('action:post.save', { post: _.clone(data.post) });

@ -216,87 +216,89 @@ module.exports = function (Posts) {
}
function deletePostFromCategoryRecentPosts(pid, callback) {
db.getSortedSetRange('categories:cid', 0, -1, function (err, cids) {
if (err) {
return callback(err);
}
var sets = cids.map(function (cid) {
return 'cid:' + cid + ':pids';
});
async.waterfall([
function (next) {
db.getSortedSetRange('categories:cid', 0, -1, next);
},
function (cids, next) {
var sets = cids.map(function (cid) {
return 'cid:' + cid + ':pids';
});
db.sortedSetsRemove(sets, pid, callback);
});
db.sortedSetsRemove(sets, pid, next);
},
], callback);
}
function deletePostFromUsersBookmarks(pid, callback) {
db.getSetMembers('pid:' + pid + ':users_bookmarked', function (err, uids) {
if (err) {
return callback(err);
}
var sets = uids.map(function (uid) {
return 'uid:' + uid + ':bookmarks';
});
db.sortedSetsRemove(sets, pid, function (err) {
if (err) {
return callback(err);
}
async.waterfall([
function (next) {
db.getSetMembers('pid:' + pid + ':users_bookmarked', next);
},
function (uids, next) {
var sets = uids.map(function (uid) {
return 'uid:' + uid + ':bookmarks';
});
db.delete('pid:' + pid + ':users_bookmarked', callback);
});
});
db.sortedSetsRemove(sets, pid, next);
},
function (next) {
db.delete('pid:' + pid + ':users_bookmarked', next);
},
], callback);
}
function deletePostFromUsersVotes(pid, callback) {
async.parallel({
upvoters: function (next) {
db.getSetMembers('pid:' + pid + ':upvote', next);
},
downvoters: function (next) {
db.getSetMembers('pid:' + pid + ':downvote', next);
async.waterfall([
function (next) {
async.parallel({
upvoters: function (next) {
db.getSetMembers('pid:' + pid + ':upvote', next);
},
downvoters: function (next) {
db.getSetMembers('pid:' + pid + ':downvote', next);
},
}, next);
},
}, function (err, results) {
if (err) {
return callback(err);
}
var upvoterSets = results.upvoters.map(function (uid) {
return 'uid:' + uid + ':upvote';
});
function (results, next) {
var upvoterSets = results.upvoters.map(function (uid) {
return 'uid:' + uid + ':upvote';
});
var downvoterSets = results.downvoters.map(function (uid) {
return 'uid:' + uid + ':downvote';
});
var downvoterSets = results.downvoters.map(function (uid) {
return 'uid:' + uid + ':downvote';
});
async.parallel([
function (next) {
db.sortedSetsRemove(upvoterSets, pid, next);
},
function (next) {
db.sortedSetsRemove(downvoterSets, pid, next);
},
function (next) {
db.deleteAll(['pid:' + pid + ':upvote', 'pid:' + pid + ':downvote'], next);
},
], callback);
});
async.parallel([
function (next) {
db.sortedSetsRemove(upvoterSets, pid, next);
},
function (next) {
db.sortedSetsRemove(downvoterSets, pid, next);
},
function (next) {
db.deleteAll(['pid:' + pid + ':upvote', 'pid:' + pid + ':downvote'], next);
},
], next);
},
], callback);
}
function deletePostFromReplies(pid, callback) {
Posts.getPostField(pid, 'toPid', function (err, toPid) {
if (err) {
return callback(err);
}
if (!parseInt(toPid, 10)) {
return callback(null);
}
async.parallel([
async.apply(db.sortedSetRemove, 'pid:' + toPid + ':replies', pid),
async.apply(db.decrObjectField, 'post:' + toPid, 'replies'),
], callback);
});
async.waterfall([
function (next) {
Posts.getPostField(pid, 'toPid', next);
},
function (toPid, next) {
if (!parseInt(toPid, 10)) {
return callback(null);
}
async.parallel([
async.apply(db.sortedSetRemove, 'pid:' + toPid + ':replies', pid),
async.apply(db.decrObjectField, 'post:' + toPid, 'replies'),
], next);
},
], callback);
}
function deletePostFromGroups(pid, callback) {

@ -83,74 +83,74 @@ module.exports = function (Posts) {
var tid = postData.tid;
var title = data.title ? data.title.trim() : '';
async.parallel({
topic: function (next) {
topics.getTopicFields(tid, ['cid', 'title', 'timestamp'], next);
},
isMain: function (next) {
Posts.isMain(data.pid, next);
var topicData;
var results;
async.waterfall([
function (next) {
async.parallel({
topic: function (next) {
topics.getTopicFields(tid, ['cid', 'title', 'timestamp'], next);
},
isMain: function (next) {
Posts.isMain(data.pid, next);
},
}, next);
},
}, function (err, results) {
if (err) {
return callback(err);
}
function (_results, next) {
results = _results;
if (!results.isMain) {
return callback(null, {
tid: tid,
cid: results.topic.cid,
isMainPost: false,
renamed: false,
});
}
if (!results.isMain) {
return callback(null, {
topicData = {
tid: tid,
cid: results.topic.cid,
isMainPost: false,
renamed: false,
uid: postData.uid,
mainPid: data.pid,
};
if (title) {
topicData.title = title;
topicData.slug = tid + '/' + (utils.slugify(title) || 'topic');
}
topicData.thumb = data.thumb || '';
data.tags = data.tags || [];
plugins.fireHook('filter:topic.edit', { req: data.req, topic: topicData, data: data }, next);
},
function (results, next) {
db.setObject('topic:' + tid, results.topic, next);
},
function (next) {
topics.updateTags(tid, data.tags, next);
},
function (next) {
topics.getTopicTagsObjects(tid, next);
},
function (tags, next) {
topicData.tags = data.tags;
topicData.oldTitle = results.topic.title;
topicData.timestamp = results.topic.timestamp;
plugins.fireHook('action:topic.edit', { topic: topicData, uid: data.uid });
next(null, {
tid: tid,
cid: topicData.cid,
uid: postData.uid,
title: validator.escape(String(title)),
oldTitle: results.topic.title,
slug: topicData.slug,
isMainPost: true,
renamed: title !== results.topic.title,
tags: tags,
});
}
var topicData = {
tid: tid,
cid: results.topic.cid,
uid: postData.uid,
mainPid: data.pid,
};
if (title) {
topicData.title = title;
topicData.slug = tid + '/' + (utils.slugify(title) || 'topic');
}
topicData.thumb = data.thumb || '';
data.tags = data.tags || [];
async.waterfall([
function (next) {
plugins.fireHook('filter:topic.edit', { req: data.req, topic: topicData, data: data }, next);
},
function (results, next) {
db.setObject('topic:' + tid, results.topic, next);
},
function (next) {
topics.updateTags(tid, data.tags, next);
},
function (next) {
topics.getTopicTagsObjects(tid, next);
},
function (tags, next) {
topicData.tags = data.tags;
topicData.oldTitle = results.topic.title;
topicData.timestamp = results.topic.timestamp;
plugins.fireHook('action:topic.edit', { topic: topicData, uid: data.uid });
next(null, {
tid: tid,
cid: results.topic.cid,
uid: postData.uid,
title: validator.escape(String(title)),
oldTitle: results.topic.title,
slug: topicData.slug,
isMainPost: true,
renamed: title !== results.topic.title,
tags: tags,
});
},
], callback);
});
},
], callback);
}
};

@ -89,47 +89,48 @@ module.exports = function (Posts) {
function parsePosts(posts, options, callback) {
async.map(posts, function (post, next) {
if (!post.content || !options.parse) {
if (options.stripTags) {
post.content = stripTags(post.content);
}
post.content = post.content ? validator.escape(String(post.content)) : post.content;
return next(null, post);
}
Posts.parsePost(post, function (err, post) {
if (err) {
return next(err);
}
if (options.stripTags) {
post.content = stripTags(post.content);
}
next(null, post);
});
async.waterfall([
function (next) {
if (!post.content || !options.parse) {
post.content = post.content ? validator.escape(String(post.content)) : post.content;
return next(null, post);
}
Posts.parsePost(post, next);
},
function (post, next) {
if (options.stripTags) {
post.content = stripTags(post.content);
}
next(null, post);
},
], next);
}, callback);
}
function getTopicAndCategories(tids, callback) {
topics.getTopicsFields(tids, ['uid', 'tid', 'title', 'cid', 'slug', 'deleted', 'postcount', 'mainPid'], function (err, topics) {
if (err) {
return callback(err);
}
var cids = topics.map(function (topic) {
if (topic) {
topic.title = String(topic.title);
topic.deleted = parseInt(topic.deleted, 10) === 1;
}
return topic && topic.cid;
}).filter(function (topic, index, array) {
return topic && array.indexOf(topic) === index;
});
categories.getCategoriesFields(cids, ['cid', 'name', 'icon', 'slug', 'parentCid', 'bgColor', 'color'], function (err, categories) {
callback(err, { topics: topics, categories: categories });
});
});
var topicsData;
async.waterfall([
function (next) {
topics.getTopicsFields(tids, ['uid', 'tid', 'title', 'cid', 'slug', 'deleted', 'postcount', 'mainPid'], next);
},
function (_topicsData, next) {
topicsData = _topicsData;
var cids = topicsData.map(function (topic) {
if (topic) {
topic.title = String(topic.title);
topic.deleted = parseInt(topic.deleted, 10) === 1;
}
return topic && topic.cid;
}).filter(function (topic, index, array) {
return topic && array.indexOf(topic) === index;
});
categories.getCategoriesFields(cids, ['cid', 'name', 'icon', 'slug', 'parentCid', 'bgColor', 'color'], next);
},
function (categoriesData, next) {
next(null, { topics: topicsData, categories: categoriesData });
},
], callback);
}
function toObject(key, data) {

@ -25,69 +25,67 @@ module.exports = function (Posts) {
});
groups.getGroupsData(groupTitles, next);
},
], function (err, groupsData) {
if (err) {
return callback(err);
}
groupsData.forEach(function (group) {
if (group && group.userTitleEnabled) {
groupsMap[group.name] = {
name: group.name,
slug: group.slug,
labelColor: group.labelColor,
icon: group.icon,
userTitle: group.userTitle,
};
}
});
userData.forEach(function (userData) {
userData.uid = userData.uid || 0;
userData.username = userData.username || '[[global:guest]]';
userData.userslug = userData.userslug || '';
userData.reputation = userData.reputation || 0;
userData.postcount = userData.postcount || 0;
userData.banned = parseInt(userData.banned, 10) === 1;
userData.picture = userData.picture || '';
userData.status = user.getStatus(userData);
userData.signature = validator.escape(String(userData.signature || ''));
userData.fullname = validator.escape(String(userData.fullname || ''));
});
async.map(userData, function (userData, next) {
async.parallel({
isMemberOfGroup: function (next) {
if (!userData.groupTitle || !groupsMap[userData.groupTitle]) {
return next();
}
groups.isMember(userData.uid, userData.groupTitle, next);
},
signature: function (next) {
if (!userData.signature || parseInt(meta.config.disableSignatures, 10) === 1) {
userData.signature = '';
return next();
}
Posts.parseSignature(userData, uid, next);
},
customProfileInfo: function (next) {
plugins.fireHook('filter:posts.custom_profile_info', { profile: [], uid: userData.uid }, next);
},
}, function (err, results) {
if (err) {
return next(err);
function (groupsData, next) {
groupsData.forEach(function (group) {
if (group && group.userTitleEnabled) {
groupsMap[group.name] = {
name: group.name,
slug: group.slug,
labelColor: group.labelColor,
icon: group.icon,
userTitle: group.userTitle,
};
}
});
if (results.isMemberOfGroup && userData.groupTitle && groupsMap[userData.groupTitle]) {
userData.selectedGroup = groupsMap[userData.groupTitle];
}
userData.forEach(function (userData) {
userData.uid = userData.uid || 0;
userData.username = userData.username || '[[global:guest]]';
userData.userslug = userData.userslug || '';
userData.reputation = userData.reputation || 0;
userData.postcount = userData.postcount || 0;
userData.banned = parseInt(userData.banned, 10) === 1;
userData.picture = userData.picture || '';
userData.status = user.getStatus(userData);
userData.signature = validator.escape(String(userData.signature || ''));
userData.fullname = validator.escape(String(userData.fullname || ''));
});
userData.custom_profile_info = results.customProfileInfo.profile;
async.map(userData, function (userData, next) {
async.waterfall([
function (next) {
async.parallel({
isMemberOfGroup: function (next) {
if (!userData.groupTitle || !groupsMap[userData.groupTitle]) {
return next();
}
groups.isMember(userData.uid, userData.groupTitle, next);
},
signature: function (next) {
if (!userData.signature || parseInt(meta.config.disableSignatures, 10) === 1) {
userData.signature = '';
return next();
}
Posts.parseSignature(userData, uid, next);
},
customProfileInfo: function (next) {
plugins.fireHook('filter:posts.custom_profile_info', { profile: [], uid: userData.uid }, next);
},
}, next);
},
function (results, next) {
if (results.isMemberOfGroup && userData.groupTitle && groupsMap[userData.groupTitle]) {
userData.selectedGroup = groupsMap[userData.groupTitle];
}
plugins.fireHook('filter:posts.modifyUserInfo', userData, next);
});
}, callback);
});
userData.custom_profile_info = results.customProfileInfo.profile;
plugins.fireHook('filter:posts.modifyUserInfo', userData, next);
},
], next);
}, next);
},
], callback);
};
Posts.isOwner = function (pid, uid, callback) {

@ -65,14 +65,14 @@ module.exports = function (Posts) {
if (!parseInt(uid, 10)) {
return callback(null, { upvoted: false, downvoted: false });
}
db.isMemberOfSets(['pid:' + pid + ':upvote', 'pid:' + pid + ':downvote'], uid, function (err, hasVoted) {
if (err) {
return callback(err);
}
callback(null, { upvoted: hasVoted[0], downvoted: hasVoted[1] });
});
async.waterfall([
function (next) {
db.isMemberOfSets(['pid:' + pid + ':upvote', 'pid:' + pid + ':downvote'], uid, next);
},
function (hasVoted, next) {
next(null, { upvoted: hasVoted[0], downvoted: hasVoted[1] });
},
], callback);
};
Posts.getVoteStatusByPostIDs = function (pids, uid, callback) {
@ -124,151 +124,157 @@ module.exports = function (Posts) {
}
function toggleVote(type, pid, uid, callback) {
unvote(pid, uid, type, function (err) {
if (err) {
return callback(err);
}
vote(type, false, pid, uid, callback);
});
async.waterfall([
function (next) {
unvote(pid, uid, type, function (err) {
next(err);
});
},
function (next) {
vote(type, false, pid, uid, next);
},
], callback);
}
function unvote(pid, uid, command, callback) {
async.parallel({
owner: function (next) {
Posts.getPostField(pid, 'uid', next);
},
voteStatus: function (next) {
Posts.hasVoted(pid, uid, next);
},
reputation: function (next) {
user.getUserField(uid, 'reputation', next);
async.waterfall([
function (next) {
async.parallel({
owner: function (next) {
Posts.getPostField(pid, 'uid', next);
},
voteStatus: function (next) {
Posts.hasVoted(pid, uid, next);
},
reputation: function (next) {
user.getUserField(uid, 'reputation', next);
},
}, next);
},
}, function (err, results) {
if (err) {
return callback(err);
}
if (parseInt(uid, 10) === parseInt(results.owner, 10)) {
return callback(new Error('self-vote'));
}
function (results, next) {
if (parseInt(uid, 10) === parseInt(results.owner, 10)) {
return callback(new Error('self-vote'));
}
if (command === 'downvote' && parseInt(results.reputation, 10) < parseInt(meta.config['privileges:downvote'], 10)) {
return callback(new Error('[[error:not-enough-reputation-to-downvote]]'));
}
if (command === 'downvote' && parseInt(results.reputation, 10) < parseInt(meta.config['privileges:downvote'], 10)) {
return callback(new Error('[[error:not-enough-reputation-to-downvote]]'));
}
var voteStatus = results.voteStatus;
var hook;
var current = voteStatus.upvoted ? 'upvote' : 'downvote';
if ((voteStatus.upvoted && command === 'downvote') || (voteStatus.downvoted && command === 'upvote')) { // e.g. User *has* upvoted, and clicks downvote
hook = command;
} else if (voteStatus.upvoted || voteStatus.downvoted) { // e.g. User *has* upvoted, clicks upvote (so we "unvote")
hook = 'unvote';
} else { // e.g. User *has not* voted, clicks upvote
hook = command;
current = 'unvote';
}
var voteStatus = results.voteStatus;
var hook;
var current = voteStatus.upvoted ? 'upvote' : 'downvote';
if ((voteStatus.upvoted && command === 'downvote') || (voteStatus.downvoted && command === 'upvote')) { // e.g. User *has* upvoted, and clicks downvote
hook = command;
} else if (voteStatus.upvoted || voteStatus.downvoted) { // e.g. User *has* upvoted, clicks upvote (so we "unvote")
hook = 'unvote';
} else { // e.g. User *has not* voted, clicks upvote
hook = command;
current = 'unvote';
}
plugins.fireHook('action:post.' + hook, {
pid: pid,
uid: uid,
owner: results.owner,
current: current,
});
plugins.fireHook('action:post.' + hook, {
pid: pid,
uid: uid,
owner: results.owner,
current: current,
});
if (!voteStatus || (!voteStatus.upvoted && !voteStatus.downvoted)) {
return callback();
}
if (!voteStatus || (!voteStatus.upvoted && !voteStatus.downvoted)) {
return callback();
}
vote(voteStatus.upvoted ? 'downvote' : 'upvote', true, pid, uid, callback);
});
vote(voteStatus.upvoted ? 'downvote' : 'upvote', true, pid, uid, next);
},
], callback);
}
function vote(type, unvote, pid, uid, callback) {
uid = parseInt(uid, 10);
if (uid === 0) {
if (!uid) {
return callback(new Error('[[error:not-logged-in]]'));
}
var postData;
var newreputation;
async.waterfall([
function (next) {
Posts.getPostFields(pid, ['pid', 'uid', 'tid'], next);
},
function (_postData, next) {
postData = _postData;
var now = Date.now();
Posts.getPostFields(pid, ['pid', 'uid', 'tid'], function (err, postData) {
if (err) {
return callback(err);
}
var now = Date.now();
if (type === 'upvote' && !unvote) {
db.sortedSetAdd('uid:' + uid + ':upvote', now, pid);
} else {
db.sortedSetRemove('uid:' + uid + ':upvote', pid);
}
if (type === 'upvote' || unvote) {
db.sortedSetRemove('uid:' + uid + ':downvote', pid);
} else {
db.sortedSetAdd('uid:' + uid + ':downvote', now, pid);
}
if (type === 'upvote' && !unvote) {
db.sortedSetAdd('uid:' + uid + ':upvote', now, pid);
} else {
db.sortedSetRemove('uid:' + uid + ':upvote', pid);
}
user[type === 'upvote' ? 'incrementUserFieldBy' : 'decrementUserFieldBy'](postData.uid, 'reputation', 1, function (err, newreputation) {
if (err) {
return callback(err);
if (type === 'upvote' || unvote) {
db.sortedSetRemove('uid:' + uid + ':downvote', pid);
} else {
db.sortedSetAdd('uid:' + uid + ':downvote', now, pid);
}
user[type === 'upvote' ? 'incrementUserFieldBy' : 'decrementUserFieldBy'](postData.uid, 'reputation', 1, next);
},
function (_newreputation, next) {
newreputation = _newreputation;
if (parseInt(postData.uid, 10)) {
db.sortedSetAdd('users:reputation', newreputation, postData.uid);
}
adjustPostVotes(postData, uid, type, unvote, function (err) {
callback(err, {
user: {
reputation: newreputation,
},
post: postData,
upvote: type === 'upvote' && !unvote,
downvote: type === 'downvote' && !unvote,
});
adjustPostVotes(postData, uid, type, unvote, next);
},
function (next) {
next(null, {
user: {
reputation: newreputation,
},
post: postData,
upvote: type === 'upvote' && !unvote,
downvote: type === 'downvote' && !unvote,
});
});
});
},
], callback);
}
function adjustPostVotes(postData, uid, type, unvote, callback) {
var notType = (type === 'upvote' ? 'downvote' : 'upvote');
async.series([
async.waterfall([
function (next) {
if (unvote) {
db.setRemove('pid:' + postData.pid + ':' + type, uid, next);
} else {
db.setAdd('pid:' + postData.pid + ':' + type, uid, next);
}
async.series([
function (next) {
if (unvote) {
db.setRemove('pid:' + postData.pid + ':' + type, uid, next);
} else {
db.setAdd('pid:' + postData.pid + ':' + type, uid, next);
}
},
function (next) {
db.setRemove('pid:' + postData.pid + ':' + notType, uid, next);
},
], function (err) {
next(err);
});
},
function (next) {
db.setRemove('pid:' + postData.pid + ':' + notType, uid, next);
async.parallel({
upvotes: function (next) {
db.setCount('pid:' + postData.pid + ':upvote', next);
},
downvotes: function (next) {
db.setCount('pid:' + postData.pid + ':downvote', next);
},
}, next);
},
], function (err) {
if (err) {
return callback(err);
}
async.parallel({
upvotes: function (next) {
db.setCount('pid:' + postData.pid + ':upvote', next);
},
downvotes: function (next) {
db.setCount('pid:' + postData.pid + ':downvote', next);
},
}, function (err, results) {
if (err) {
return callback(err);
}
function (results, next) {
postData.upvotes = parseInt(results.upvotes, 10);
postData.downvotes = parseInt(results.downvotes, 10);
postData.votes = postData.upvotes - postData.downvotes;
Posts.updatePostVoteCount(postData, callback);
});
});
Posts.updatePostVoteCount(postData, next);
},
], callback);
}
};

@ -8,119 +8,132 @@ var plugins = require('../plugins');
var translator = require('../translator');
var db = require('../database');
var widgets = {};
var widgets = module.exports;
widgets.render = function (uid, area, req, res, callback) {
if (!area.locations || !area.template) {
return callback(new Error('[[error:invalid-data]]'));
}
widgets.getAreas(['global', area.template], area.locations, function (err, data) {
if (err) {
return callback(err);
}
var widgetsByLocation = {};
async.map(area.locations, function (location, done) {
widgetsByLocation[location] = data.global[location].concat(data[area.template][location]);
async.waterfall([
function (next) {
widgets.getAreas(['global', area.template], area.locations, next);
},
function (data, next) {
var widgetsByLocation = {};
if (!widgetsByLocation[location].length) {
return done(null, { location: location, widgets: [] });
}
async.map(area.locations, function (location, done) {
widgetsByLocation[location] = data.global[location].concat(data[area.template][location]);
async.map(widgetsByLocation[location], function (widget, next) {
if (!widget || !widget.data ||
(!!widget.data['hide-registered'] && uid !== 0) ||
(!!widget.data['hide-guests'] && uid === 0) ||
(!!widget.data['hide-mobile'] && area.isMobile)) {
return next();
if (!widgetsByLocation[location].length) {
return done(null, { location: location, widgets: [] });
}
plugins.fireHook('filter:widget.render:' + widget.widget, {
uid: uid,
area: area,
data: widget.data,
req: req,
res: res,
}, function (err, data) {
if (err || data === null) {
return next(err);
}
var html = data;
if (typeof html !== 'string') {
html = data.html;
} else {
winston.warn('[widgets.render] passing a string is deprecated!, filter:widget.render:' + widget.widget + '. Please set hookData.html in your plugin.');
async.map(widgetsByLocation[location], function (widget, next) {
if (!widget || !widget.data ||
(!!widget.data['hide-registered'] && uid !== 0) ||
(!!widget.data['hide-guests'] && uid === 0) ||
(!!widget.data['hide-mobile'] && area.isMobile)) {
return next();
}
if (widget.data.container && widget.data.container.match('{body}')) {
translator.translate(widget.data.title, function (title) {
html = templates.parse(widget.data.container, {
title: title,
body: html,
});
next(null, { html: html });
});
} else {
next(null, { html: html });
}
renderWidget(widget, uid, area, req, res, next);
}, function (err, result) {
done(err, { location: location, widgets: result.filter(Boolean) });
});
}, function (err, result) {
done(err, { location: location, widgets: result.filter(Boolean) });
});
}, callback);
});
}, next);
},
], callback);
};
function renderWidget(widget, uid, area, req, res, callback) {
async.waterfall([
function (next) {
plugins.fireHook('filter:widget.render:' + widget.widget, {
uid: uid,
area: area,
data: widget.data,
req: req,
res: res,
}, next);
},
function (data, next) {
if (!data) {
return callback();
}
var html = data;
if (typeof html !== 'string') {
html = data.html;
} else {
winston.warn('[widgets.render] passing a string is deprecated!, filter:widget.render:' + widget.widget + '. Please set hookData.html in your plugin.');
}
if (widget.data.container && widget.data.container.match('{body}')) {
translator.translate(widget.data.title, function (title) {
html = templates.parse(widget.data.container, {
title: title,
body: html,
});
next(null, { html: html });
});
} else {
next(null, { html: html });
}
},
], callback);
}
widgets.getAreas = function (templates, locations, callback) {
var keys = templates.map(function (tpl) {
return 'widgets:' + tpl;
});
db.getObjectsFields(keys, locations, function (err, data) {
if (err) {
return callback(err);
}
var returnData = {};
templates.forEach(function (template, index) {
returnData[template] = returnData[template] || {};
locations.forEach(function (location) {
if (data && data[index] && data[index][location]) {
try {
returnData[template][location] = JSON.parse(data[index][location]);
} catch (err) {
winston.error('can not parse widget data. template: ' + template + ' location: ' + location);
async.waterfall([
function (next) {
db.getObjectsFields(keys, locations, next);
},
function (data, next) {
var returnData = {};
templates.forEach(function (template, index) {
returnData[template] = returnData[template] || {};
locations.forEach(function (location) {
if (data && data[index] && data[index][location]) {
try {
returnData[template][location] = JSON.parse(data[index][location]);
} catch (err) {
winston.error('can not parse widget data. template: ' + template + ' location: ' + location);
returnData[template][location] = [];
}
} else {
returnData[template][location] = [];
}
} else {
returnData[template][location] = [];
}
});
});
});
callback(null, returnData);
});
next(null, returnData);
},
], callback);
};
widgets.getArea = function (template, location, callback) {
db.getObjectField('widgets:' + template, location, function (err, result) {
if (err) {
return callback(err);
}
if (!result) {
return callback(null, []);
}
try {
result = JSON.parse(result);
} catch (err) {
return callback(err);
}
callback(null, result);
});
async.waterfall([
function (next) {
db.getObjectField('widgets:' + template, location, next);
},
function (result, next) {
if (!result) {
return callback(null, []);
}
try {
result = JSON.parse(result);
} catch (err) {
return callback(err);
}
next(null, result);
},
], callback);
};
widgets.setArea = function (area, callback) {
@ -137,42 +150,42 @@ widgets.reset = function (callback) {
{ name: 'Draft Zone', template: 'global', location: 'footer' },
{ name: 'Draft Zone', template: 'global', location: 'sidebar' },
];
async.parallel({
areas: function (next) {
plugins.fireHook('filter:widgets.getAreas', defaultAreas, next);
var drafts;
async.waterfall([
function (next) {
async.parallel({
areas: function (next) {
plugins.fireHook('filter:widgets.getAreas', defaultAreas, next);
},
drafts: function (next) {
widgets.getArea('global', 'drafts', next);
},
}, next);
},
drafts: function (next) {
widgets.getArea('global', 'drafts', next);
function (results, next) {
drafts = results.drafts || [];
async.each(results.areas, function (area, next) {
async.waterfall([
function (next) {
widgets.getArea(area.template, area.location, next);
},
function (areaData, next) {
drafts = drafts.concat(areaData);
area.widgets = [];
widgets.setArea(area, next);
},
], next);
}, next);
},
}, function (err, results) {
if (err) {
return callback(err);
}
var drafts = results.drafts || [];
async.each(results.areas, function (area, next) {
widgets.getArea(area.template, area.location, function (err, areaData) {
if (err) {
return next(err);
}
drafts = drafts.concat(areaData);
area.widgets = [];
widgets.setArea(area, next);
});
}, function (err) {
if (err) {
return callback(err);
}
function (next) {
widgets.setArea({
template: 'global',
location: 'drafts',
widgets: drafts,
}, callback);
});
});
}, next);
},
], callback);
};
module.exports = widgets;

@ -138,6 +138,9 @@ function setupMockDefaults(callback) {
function (next) {
db.emptydb(next);
},
function (next) {
db.createIndices(next);
},
function (next) {
winston.info('test_database flushed');
setupDefaultConfigs(meta, next);

Loading…
Cancel
Save