mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 11:35:55 +01:00
@@ -5,7 +5,7 @@ define('forum/category', [
|
|||||||
'forum/infinitescroll',
|
'forum/infinitescroll',
|
||||||
'share',
|
'share',
|
||||||
'navigator',
|
'navigator',
|
||||||
'forum/categoryTools',
|
'forum/category/tools',
|
||||||
'sort',
|
'sort',
|
||||||
'components',
|
'components',
|
||||||
'translator',
|
'translator',
|
||||||
|
|||||||
@@ -4,7 +4,12 @@
|
|||||||
/* globals define, app, socket, bootbox, ajaxify */
|
/* 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 = {};
|
var CategoryTools = {};
|
||||||
|
|
||||||
@@ -13,6 +18,8 @@ define('forum/categoryTools', ['forum/topic/move', 'topicSelect', 'components',
|
|||||||
|
|
||||||
topicSelect.init(updateDropdownOptions);
|
topicSelect.init(updateDropdownOptions);
|
||||||
|
|
||||||
|
handlePinnedTopicSort();
|
||||||
|
|
||||||
components.get('topic/delete').on('click', function () {
|
components.get('topic/delete').on('click', function () {
|
||||||
categoryCommand('delete', topicSelect.getSelectedTids());
|
categoryCommand('delete', topicSelect.getSelectedTids());
|
||||||
return false;
|
return false;
|
||||||
@@ -235,5 +242,30 @@ define('forum/categoryTools', ['forum/topic/move', 'topicSelect', 'components',
|
|||||||
getTopicEl(data.tid).remove();
|
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;
|
return CategoryTools;
|
||||||
});
|
});
|
||||||
@@ -58,7 +58,7 @@ module.exports = function (Meta) {
|
|||||||
'public/src/client/topic/threadTools.js',
|
'public/src/client/topic/threadTools.js',
|
||||||
'public/src/client/categories.js',
|
'public/src/client/categories.js',
|
||||||
'public/src/client/category.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/translator.js',
|
||||||
'public/src/modules/notifications.js',
|
'public/src/modules/notifications.js',
|
||||||
|
|||||||
@@ -121,4 +121,12 @@ module.exports = function (SocketTopics) {
|
|||||||
], callback);
|
], 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';
|
'use strict';
|
||||||
|
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
var db = require('../database');
|
var db = require('../database');
|
||||||
var categories = require('../categories');
|
var categories = require('../categories');
|
||||||
@@ -211,6 +212,49 @@ module.exports = function (Topics) {
|
|||||||
], callback);
|
], 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) {
|
topicTools.move = function (tid, cid, uid, callback) {
|
||||||
var topic;
|
var topic;
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
--reporter dot
|
--reporter dot
|
||||||
--timeout 10000
|
--timeout 15000
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ describe('Plugins', function () {
|
|||||||
var latest;
|
var latest;
|
||||||
var pluginName = 'nodebb-plugin-imgur';
|
var pluginName = 'nodebb-plugin-imgur';
|
||||||
it('should install a plugin', function (done) {
|
it('should install a plugin', function (done) {
|
||||||
|
this.timeout(20000);
|
||||||
plugins.toggleInstall(pluginName, '1.0.16', function (err, pluginData) {
|
plugins.toggleInstall(pluginName, '1.0.16', function (err, pluginData) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ describe('Topic\'s', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.post', function () {
|
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 () {
|
describe('.ignore', function () {
|
||||||
var newTid;
|
var newTid;
|
||||||
var uid;
|
var uid;
|
||||||
|
|||||||
Reference in New Issue
Block a user