mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-07 17:37:11 +02:00
Merge remote-tracking branch 'origin/master' into develop
This commit is contained in:
4
app.js
4
app.js
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
NodeBB - A better forum platform for the modern web
|
||||
https://github.com/NodeBB/NodeBB/
|
||||
Copyright (C) 2013-2016 NodeBB Inc.
|
||||
Copyright (C) 2013-2017 NodeBB Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -389,4 +389,4 @@ function versionCheck() {
|
||||
winston.warn('Your version of Node.js is too outdated for NodeBB. Please update your version of Node.js.');
|
||||
winston.warn('Recommended ' + range.green + ', '.reset + version.yellow + ' provided\n'.reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"start": "node loader.js",
|
||||
"lint": "eslint --cache .",
|
||||
"pretest": "npm run lint",
|
||||
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R dot",
|
||||
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec",
|
||||
"coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -61,7 +61,7 @@
|
||||
"nodebb-plugin-spam-be-gone": "0.4.10",
|
||||
"nodebb-rewards-essentials": "0.0.9",
|
||||
"nodebb-theme-lavender": "3.0.15",
|
||||
"nodebb-theme-persona": "4.1.90",
|
||||
"nodebb-theme-persona": "4.1.93",
|
||||
"nodebb-theme-vanilla": "5.1.57",
|
||||
"nodebb-widget-essentials": "2.0.13",
|
||||
"nodemailer": "2.6.4",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"plugin-item.themes": "Themes",
|
||||
"plugin-item.deactivate": "Deactivate",
|
||||
"plugin-item.activate": "Activate",
|
||||
"plugin-item.install": "Install",
|
||||
"plugin-item.uninstall": "Uninstall",
|
||||
"plugin-item.settings": "Settings",
|
||||
"plugin-item.installed": "Installed",
|
||||
@@ -43,4 +44,4 @@
|
||||
"alert.package-manager-unreachable": "<p>NodeBB could not reach the package manager, an upgrade is not suggested at this time.</p>",
|
||||
"alert.incompatible": "<p>Your version of NodeBB (v%1) is only cleared to upgrade to v%2 of this plugin. Please update your NodeBB if you wish to install a newer version of this plugin.</p>",
|
||||
"alert.possibly-incompatible": "<div class=\"alert alert-warning\"><p><strong>No Compatibility Information Found</strong></p><p>This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.</p></div><p>In the event that NodeBB cannot boot properly:</p><pre><code>$ ./nodebb reset plugin=\"%1\"</code></pre><p>Continue installation of latest version of this plugin?</p>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"section-appearance": "Appearance",
|
||||
"appearance/themes": "Themes",
|
||||
"appearance/skins": "Skins",
|
||||
"appearance/customise": "Custom HTML & CSS",
|
||||
"appearance/customise": "Custom HTML & CSS",
|
||||
|
||||
"section-extend": "Extend",
|
||||
"extend/plugins": "Plugins",
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
}
|
||||
|
||||
url = [config.relative_path, url].join('/');
|
||||
var fallback;
|
||||
|
||||
$('#main-menu li').removeClass('active');
|
||||
$('#main-menu a').removeClass('active').filter('[href="' + url + '"]').each(function () {
|
||||
@@ -102,36 +103,35 @@
|
||||
menu
|
||||
.parent().addClass('active')
|
||||
.parents('.menu-item').addClass('active');
|
||||
|
||||
var match = menu.attr('href').match(/admin\/((.+?)\/.+?)$/);
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
var str = '[[admin/menu:' + match[1] + ']]';
|
||||
if (match[2] === 'settings') {
|
||||
str = translator.compile('admin/menu:settings.page-title', str);
|
||||
}
|
||||
translator.translate(str, function (text) {
|
||||
$('#main-page-title').text(text);
|
||||
});
|
||||
fallback = menu.text();
|
||||
});
|
||||
|
||||
var title = url;
|
||||
if (/admin\/general\/dashboard$/.test(title)) {
|
||||
title = '[[admin/menu:general/dashboard]]';
|
||||
var mainTitle;
|
||||
var pageTitle;
|
||||
if (/admin\/general\/dashboard$/.test(url)) {
|
||||
mainTitle = pageTitle = '[[admin/menu:general/dashboard]]';
|
||||
} else if (/admin\/plugins\//.test(url)) {
|
||||
mainTitle = fallback;
|
||||
pageTitle = '[[admin/menu:section-plugins]] > ' + mainTitle;
|
||||
} else {
|
||||
title = title.match(/admin\/(.+?)\/(.+?)$/);
|
||||
title = '[[admin/menu:section-' +
|
||||
(title[1] === 'development' ? 'advanced' : title[1]) +
|
||||
']]' + (title[2] ? (' > [[admin/menu:' +
|
||||
title[1] + '/' + title[2] + ']]') : '');
|
||||
var matches = url.match(/admin\/(.+?)\/(.+?)$/);
|
||||
mainTitle = '[[admin/menu:' + matches[1] + '/' + matches[2] + ']]';
|
||||
pageTitle = '[[admin/menu:section-' +
|
||||
(matches[1] === 'development' ? 'advanced' : matches[1]) +
|
||||
']]' + (matches[2] ? (' > ' + mainTitle) : '');
|
||||
if (matches[2] === 'settings') {
|
||||
mainTitle = translator.compile('admin/menu:settings.page-title', mainTitle);
|
||||
}
|
||||
}
|
||||
|
||||
title = '[[admin/admin:acp-title, ' + title + ']]';
|
||||
pageTitle = translator.compile('admin/admin:acp-title', pageTitle);
|
||||
|
||||
translator.translate(title, function (title) {
|
||||
translator.translate(pageTitle, function (title) {
|
||||
document.title = title.replace(/>/g, '>');
|
||||
});
|
||||
translator.translate(mainTitle, function (text) {
|
||||
$('#main-page-title').text(text);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ define('forum/category', [
|
||||
'forum/infinitescroll',
|
||||
'share',
|
||||
'navigator',
|
||||
'forum/categoryTools',
|
||||
'forum/category/tools',
|
||||
'sort',
|
||||
'components',
|
||||
'translator',
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
/* globals define, app, socket, bootbox, ajaxify */
|
||||
|
||||
|
||||
define('forum/categoryTools', ['forum/topic/move', 'topicSelect', 'components', 'translator'], function (move, topicSelect, components, translator) {
|
||||
define('forum/category/tools', [
|
||||
'forum/topic/move',
|
||||
'topicSelect',
|
||||
'components',
|
||||
'translator'
|
||||
], function (move, topicSelect, components, translator) {
|
||||
|
||||
var CategoryTools = {};
|
||||
|
||||
@@ -13,6 +18,8 @@ define('forum/categoryTools', ['forum/topic/move', 'topicSelect', 'components',
|
||||
|
||||
topicSelect.init(updateDropdownOptions);
|
||||
|
||||
handlePinnedTopicSort();
|
||||
|
||||
components.get('topic/delete').on('click', function () {
|
||||
categoryCommand('delete', topicSelect.getSelectedTids());
|
||||
return false;
|
||||
@@ -235,5 +242,30 @@ define('forum/categoryTools', ['forum/topic/move', 'topicSelect', 'components',
|
||||
getTopicEl(data.tid).remove();
|
||||
}
|
||||
|
||||
function handlePinnedTopicSort() {
|
||||
if (!ajaxify.data.privileges.isAdminOrMod) {
|
||||
return;
|
||||
}
|
||||
app.loadJQueryUI(function () {
|
||||
$('[component="category"]').sortable({
|
||||
items: '[component="category/topic"].pinned',
|
||||
update: function () {
|
||||
var data = [];
|
||||
|
||||
var pinnedTopics = $('[component="category/topic"].pinned');
|
||||
pinnedTopics.each(function (index, element) {
|
||||
data.push({tid: $(element).attr('data-tid'), order: pinnedTopics.length - index - 1});
|
||||
});
|
||||
|
||||
socket.emit('topics.orderPinnedTopics', data, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return CategoryTools;
|
||||
});
|
||||
@@ -111,7 +111,7 @@ module.exports = function (Categories) {
|
||||
|
||||
Categories.onNewPostMade = function (cid, pinned, postData, callback) {
|
||||
if (!cid || !postData) {
|
||||
return callback();
|
||||
return setImmediate(callback);
|
||||
}
|
||||
|
||||
async.parallel([
|
||||
@@ -123,17 +123,23 @@ module.exports = function (Categories) {
|
||||
},
|
||||
function (next) {
|
||||
if (parseInt(pinned, 10) === 1) {
|
||||
next();
|
||||
} else {
|
||||
db.sortedSetAdd('cid:' + cid + ':tids', postData.timestamp, postData.tid, next);
|
||||
return setImmediate(next);
|
||||
}
|
||||
|
||||
async.parallel([
|
||||
function (next) {
|
||||
db.sortedSetAdd('cid:' + cid + ':tids', postData.timestamp, postData.tid, next);
|
||||
},
|
||||
function (next) {
|
||||
db.sortedSetIncrBy('cid:' + cid + ':tids:posts', 1, postData.tid, next);
|
||||
}
|
||||
], function (err) {
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
Categories.updateRecentTid(cid, postData.tid, next);
|
||||
},
|
||||
function (next) {
|
||||
db.sortedSetIncrBy('cid:' + cid + ':tids:posts', 1, postData.tid, next);
|
||||
}
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ module.exports = function (Meta) {
|
||||
'public/src/client/topic/threadTools.js',
|
||||
'public/src/client/categories.js',
|
||||
'public/src/client/category.js',
|
||||
'public/src/client/categoryTools.js',
|
||||
'public/src/client/category/tools.js',
|
||||
|
||||
'public/src/modules/translator.js',
|
||||
'public/src/modules/notifications.js',
|
||||
|
||||
@@ -39,6 +39,11 @@ module.exports = function (Plugins) {
|
||||
};
|
||||
|
||||
Plugins.prepareForBuild = function (callback) {
|
||||
Plugins.cssFiles.length = 0;
|
||||
Plugins.lessFiles.length = 0;
|
||||
Plugins.clientScripts.length = 0;
|
||||
Plugins.acpScripts.length = 0;
|
||||
|
||||
async.waterfall([
|
||||
async.apply(Plugins.getPluginPaths),
|
||||
function (paths, next) {
|
||||
|
||||
@@ -65,8 +65,8 @@ module.exports = function (Posts) {
|
||||
}
|
||||
post.user = results.users[post.uid];
|
||||
post.topic = results.topics[post.tid];
|
||||
post.category = results.categories[post.topic.cid];
|
||||
post.isMainPost = parseInt(post.pid, 10) === parseInt(post.topic.mainPid, 10);
|
||||
post.category = post.topic && results.categories[post.topic.cid];
|
||||
post.isMainPost = post.topic && parseInt(post.pid, 10) === parseInt(post.topic.mainPid, 10);
|
||||
post.deleted = parseInt(post.deleted, 10) === 1;
|
||||
post.upvotes = parseInt(post.upvotes, 10) || 0;
|
||||
post.downvotes = parseInt(post.downvotes, 10) || 0;
|
||||
|
||||
@@ -150,7 +150,7 @@ module.exports = function (SocketPosts) {
|
||||
return callback(new Error('[[error:cant-purge-main-post]]'));
|
||||
}
|
||||
if (results.isMain && results.isLast) {
|
||||
deleteTopicOf(data.pid, socket, next);
|
||||
return deleteTopicOf(data.pid, socket, next);
|
||||
}
|
||||
setImmediate(next);
|
||||
},
|
||||
|
||||
@@ -121,4 +121,12 @@ module.exports = function (SocketTopics) {
|
||||
], callback);
|
||||
}
|
||||
|
||||
SocketTopics.orderPinnedTopics = function (socket, data, callback) {
|
||||
if (!Array.isArray(data)) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
topics.tools.orderPinnedTopics(socket.uid, data, callback);
|
||||
};
|
||||
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var _ = require('underscore');
|
||||
|
||||
var db = require('../database');
|
||||
var categories = require('../categories');
|
||||
@@ -184,13 +185,13 @@ module.exports = function (Topics) {
|
||||
async.parallel([
|
||||
async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:pinned', Date.now(), tid),
|
||||
async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids', tid),
|
||||
async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:posts', tid),
|
||||
async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:posts', tid)
|
||||
], next);
|
||||
} else {
|
||||
async.parallel([
|
||||
async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:pinned', tid),
|
||||
async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids', topicData.lastposttime, tid),
|
||||
async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:posts', topicData.postcount, tid),
|
||||
async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:posts', topicData.postcount, tid)
|
||||
], next);
|
||||
}
|
||||
}
|
||||
@@ -211,6 +212,49 @@ module.exports = function (Topics) {
|
||||
], callback);
|
||||
}
|
||||
|
||||
topicTools.orderPinnedTopics = function (uid, data, callback) {
|
||||
var cid;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
var tids = data.map(function (topic) {
|
||||
return topic && topic.tid;
|
||||
});
|
||||
Topics.getTopicsFields(tids, ['cid'], next);
|
||||
},
|
||||
function (topicData, next) {
|
||||
var uniqueCids = _.unique(topicData.map(function (topicData) {
|
||||
return topicData && parseInt(topicData.cid, 10);
|
||||
}));
|
||||
|
||||
if (uniqueCids.length > 1 || !uniqueCids.length || !uniqueCids[0]) {
|
||||
return next(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
cid = uniqueCids[0];
|
||||
|
||||
privileges.categories.isAdminOrMod(cid, uid, next);
|
||||
},
|
||||
function (isAdminOrMod, next) {
|
||||
if (!isAdminOrMod) {
|
||||
return next(new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
async.eachSeries(data, function (topicData, next) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.isSortedSetMember('cid:' + cid + ':tids:pinned', topicData.tid, next);
|
||||
},
|
||||
function (isPinned, next) {
|
||||
if (isPinned) {
|
||||
db.sortedSetAdd('cid:' + cid + ':tids:pinned', topicData.order, topicData.tid, next);
|
||||
} else {
|
||||
setImmediate(next);
|
||||
}
|
||||
}
|
||||
], next);
|
||||
}, next);
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
topicTools.move = function (tid, cid, uid, callback) {
|
||||
var topic;
|
||||
async.waterfall([
|
||||
|
||||
@@ -28,9 +28,7 @@
|
||||
<a target="_blank" href="{config.relative_path}/api/admin/users/csv" class="btn btn-primary pull-right">[[admin/manage/users:download-csv]]</a>
|
||||
|
||||
<!-- IF inviteOnly -->
|
||||
<!-- IF loggedIn -->
|
||||
<button component="user/invite" class="btn btn-success form-control"><i class="fa fa-users"></i> [[admin/manage/users:invite]]</button>
|
||||
<!-- ENDIF loggedIn -->
|
||||
<!-- ENDIF inviteOnly -->
|
||||
|
||||
<button id="createUser" class="btn btn-primary pull-right">[[admin/manage/users:new]]</button>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
--reporter dot
|
||||
--timeout 10000
|
||||
--timeout 15000
|
||||
|
||||
@@ -101,6 +101,7 @@ describe('Plugins', function () {
|
||||
var latest;
|
||||
var pluginName = 'nodebb-plugin-imgur';
|
||||
it('should install a plugin', function (done) {
|
||||
this.timeout(20000);
|
||||
plugins.toggleInstall(pluginName, '1.0.16', function (err, pluginData) {
|
||||
assert.ifError(err);
|
||||
|
||||
|
||||
@@ -185,31 +185,37 @@ describe('Post\'s', function () {
|
||||
});
|
||||
|
||||
describe('delete/restore/purge', function () {
|
||||
function createTopicWithReply(callback) {
|
||||
topics.post({
|
||||
uid: voterUid,
|
||||
cid: cid,
|
||||
title: 'topic to delete/restore/purge',
|
||||
content: 'A post to delete/restore/purge'
|
||||
}, function (err, topicPostData) {
|
||||
assert.ifError(err);
|
||||
topics.reply({
|
||||
uid: voterUid,
|
||||
tid: topicPostData.topicData.tid,
|
||||
timestamp: Date.now(),
|
||||
content: 'A post to delete/restore and purge'
|
||||
}, function (err, replyData) {
|
||||
assert.ifError(err);
|
||||
callback(topicPostData, replyData);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var tid;
|
||||
var mainPid;
|
||||
var replyPid;
|
||||
|
||||
var socketPosts = require('../src/socket.io/posts');
|
||||
before(function (done) {
|
||||
topics.post({
|
||||
uid: voterUid,
|
||||
cid: cid,
|
||||
title: 'topic to delete/restore/purge',
|
||||
content: 'A post to delete/restore/purge'
|
||||
}, function (err, data) {
|
||||
assert.ifError(err);
|
||||
tid = data.topicData.tid;
|
||||
mainPid = data.postData.pid;
|
||||
topics.reply({
|
||||
uid: voterUid,
|
||||
tid: topicData.tid,
|
||||
timestamp: Date.now(),
|
||||
content: 'A post to delete/restore and purge'
|
||||
}, function (err, data) {
|
||||
assert.ifError(err);
|
||||
replyPid = data.pid;
|
||||
privileges.categories.give(['purge'], cid, 'registered-users', done);
|
||||
});
|
||||
createTopicWithReply(function (topicPostData, replyData) {
|
||||
tid = topicPostData.topicData.tid;
|
||||
mainPid = topicPostData.postData.pid;
|
||||
replyPid = replyData.pid;
|
||||
privileges.categories.give(['purge'], cid, 'registered-users', done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -242,27 +248,48 @@ describe('Post\'s', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete posts and topic', function (done) {
|
||||
it('should delete posts', function (done) {
|
||||
socketPosts.deletePosts({uid: globalModUid}, {pids: [replyPid, mainPid], tid: tid}, function (err) {
|
||||
assert.ifError(err);
|
||||
topics.getTopicField(tid, 'deleted', function (err, deleted) {
|
||||
posts.getPostField(replyPid, 'deleted', function (err, deleted) {
|
||||
assert.ifError(err);
|
||||
assert.equal(parseInt(deleted, 10), 1);
|
||||
done();
|
||||
posts.getPostField(mainPid, 'deleted', function (err, deleted) {
|
||||
assert.ifError(err);
|
||||
assert.equal(parseInt(deleted, 10), 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should purge posts', function (done) {
|
||||
var socketTopics = require('../src/socket.io/topics');
|
||||
socketTopics.restore({uid: globalModUid}, {tids: [tid], cid: cid}, function (err) {
|
||||
it('should delete topic if last main post is deleted', function (done) {
|
||||
topics.post({uid: voterUid, cid: cid, title: 'test topic', content: 'test topic'}, function (err, data) {
|
||||
assert.ifError(err);
|
||||
socketPosts.purgePosts({uid: voterUid}, {pids: [replyPid, mainPid], tid: tid}, function (err) {
|
||||
socketPosts.deletePosts({uid: globalModUid}, {pids: [data.postData.pid], tid: data.topicData.tid}, function (err) {
|
||||
assert.ifError(err);
|
||||
posts.exists('post:' + replyPid, function (err, exists) {
|
||||
topics.getTopicField(data.topicData.tid, 'deleted', function (err, deleted) {
|
||||
assert.ifError(err);
|
||||
assert.equal(parseInt(deleted, 10), 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should purge posts and delete topic', function (done) {
|
||||
|
||||
createTopicWithReply(function (topicPostData, replyData) {
|
||||
socketPosts.purgePosts({uid: voterUid}, {pids: [replyData.pid, topicPostData.postData.pid], tid: topicPostData.topicData.tid}, function (err) {
|
||||
assert.ifError(err);
|
||||
posts.exists('post:' + replyData.pid, function (err, exists) {
|
||||
assert.ifError(err);
|
||||
assert.equal(exists, false);
|
||||
done();
|
||||
topics.getTopicField(topicPostData.topicData.tid, 'deleted', function (err, deleted) {
|
||||
assert.ifError(err);
|
||||
assert.equal(parseInt(deleted, 10), 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,8 +45,6 @@ describe('Topic\'s', function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('.post', function () {
|
||||
@@ -362,6 +360,98 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('order pinned topics', function () {
|
||||
var tid1;
|
||||
var tid2;
|
||||
var tid3;
|
||||
before(function (done) {
|
||||
function createTopic(callback) {
|
||||
topics.post({
|
||||
uid: topic.userId,
|
||||
title: 'topic for test',
|
||||
content: 'topic content',
|
||||
cid: topic.categoryId
|
||||
}, callback);
|
||||
}
|
||||
async.series({
|
||||
topic1: function (next) {
|
||||
createTopic(next);
|
||||
},
|
||||
topic2: function (next) {
|
||||
createTopic(next);
|
||||
},
|
||||
topic3: function (next) {
|
||||
createTopic(next);
|
||||
}
|
||||
}, function (err, results) {
|
||||
assert.ifError(err);
|
||||
tid1 = results.topic1.topicData.tid;
|
||||
tid2 = results.topic2.topicData.tid;
|
||||
tid3 = results.topic3.topicData.tid;
|
||||
async.series([
|
||||
function (next) {
|
||||
topics.tools.pin(tid1, adminUid, next);
|
||||
},
|
||||
function (next) {
|
||||
topics.tools.pin(tid2, adminUid, next);
|
||||
}
|
||||
], done);
|
||||
});
|
||||
});
|
||||
|
||||
var socketTopics = require('../src/socket.io/topics');
|
||||
it('should error with invalid data', function (done) {
|
||||
socketTopics.orderPinnedTopics({uid: adminUid}, null, function (err) {
|
||||
assert.equal(err.message, '[[error:invalid-data]]');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error with invalid data', function (done) {
|
||||
socketTopics.orderPinnedTopics({uid: adminUid}, [null, null], function (err) {
|
||||
assert.equal(err.message, '[[error:invalid-data]]');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error with unprivileged user', function (done) {
|
||||
socketTopics.orderPinnedTopics({uid: 0}, [{tid: tid1}, {tid: tid2}], function (err) {
|
||||
assert.equal(err.message, '[[error:no-privileges]]');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not do anything if topics are not pinned', function (done) {
|
||||
socketTopics.orderPinnedTopics({uid: adminUid}, [{tid: tid3}], function (err) {
|
||||
assert.ifError(err);
|
||||
db.isSortedSetMember('cid:' + topic.categoryId + ':tids:pinned', tid3, function (err, isMember) {
|
||||
assert.ifError(err);
|
||||
assert(!isMember);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should order pinned topics', function (done) {
|
||||
db.getSortedSetRevRange('cid:' + topic.categoryId + ':tids:pinned', 0, -1, function (err, pinnedTids) {
|
||||
assert.ifError(err);
|
||||
assert.equal(pinnedTids[0], tid2);
|
||||
assert.equal(pinnedTids[1], tid1);
|
||||
socketTopics.orderPinnedTopics({uid: adminUid}, [{tid: tid1, order: 1}, {tid: tid2, order: 0}], function (err) {
|
||||
assert.ifError(err);
|
||||
db.getSortedSetRevRange('cid:' + topic.categoryId + ':tids:pinned', 0, -1, function (err, pinnedTids) {
|
||||
assert.ifError(err);
|
||||
assert.equal(pinnedTids[0], tid1);
|
||||
assert.equal(pinnedTids[1], tid2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('.ignore', function () {
|
||||
var newTid;
|
||||
var uid;
|
||||
|
||||
Reference in New Issue
Block a user