diff --git a/public/src/client/groups/list.js b/public/src/client/groups/list.js index 06ce88ade9..45c5ce5a97 100644 --- a/public/src/client/groups/list.js +++ b/public/src/client/groups/list.js @@ -39,12 +39,14 @@ define('forum/groups/list', function() { Groups.search = function() { var groupsEl = $('#groups-list'), - queryEl = $('#search-text'); + queryEl = $('#search-text'), + sortEl = $('#search-sort'); socket.emit('groups.search', { query: queryEl.val(), options: { - expand: true + expand: true, + sort: sortEl.val() } }, function(err, groups) { templates.parse('partials/groups/list', { diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 74da932a18..565189dd8f 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -400,6 +400,50 @@ module.exports = function(db, module) { }); }; + module.isMemberOfSortedSets = function(keys, value, callback) { + if (!Array.isArray(keys)) { + return callback(); + } + value = helpers.valueToString(value); + db.collection('objects').find({_key: {$in: keys}, value: value}, {fields: {_id: 0, _key: 1, value: 1}}).toArray(function(err, results) { + if (err) { + return callback(err); + } + + results = results.map(function(item) { + return item._key; + }); + + results = keys.map(function(key) { + return results.indexOf(key) !== -1; + }); + callback(null, results); + }); + }; + + module.getSortedSetsMembers = function(keys, callback) { + if (!Array.isArray(keys) || !keys.length) { + return callback(null, []); + } + db.collection('objects').find({_key: {$in: keys}}, {_id: 0, _key: 1, value: 1}).toArray(function(err, data) { + if (err) { + return callback(err); + } + + var sets = {}; + data.forEach(function(set) { + sets[set._key] = sets[set._key] || []; + sets[set._key].push(set.value); + }); + + var returnData = new Array(keys.length); + for(var i=0; i b.slug; + }).sort(function(a, b) { + return a.memberCount < b.memberCount; + }); + break; + + case 'alpha': // intentional fall-through + default: + groups = groups.sort(function(a, b) { + return a.slug > b.slug; + }); + } + + next(null, groups); + }; + }(module.exports)); diff --git a/src/upgrade.js b/src/upgrade.js index b957adbe7d..506639c463 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -21,7 +21,7 @@ var db = require('./database'), schemaDate, thisSchemaDate, // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema - latestSchema = Date.UTC(2015, 0, 19); + latestSchema = Date.UTC(2015, 0, 21); Upgrade.check = function(callback) { db.get('schemaDate', function(err, value) { @@ -713,6 +713,55 @@ Upgrade.upgrade = function(callback) { winston.info('[2015/01/19] Generating group slugs skipped'); next(); } + }, + function(next) { + thisSchemaDate = Date.UTC(2015, 0, 21); + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.info('[2015/01/21] Upgrading groups to sorted set'); + + db.getSetMembers('groups', function(err, groupNames) { + if (err) { + return next(err); + } + + var now = Date.now(); + async.each(groupNames, function(groupName, next) { + db.getSetMembers('group:' + groupName + ':members', function(err, members) { + if (err) { + return next(err); + } + + async.series([ + function(next) { + if (members && members.length) { + db.delete('group:' + groupName + ':members', function(err) { + if (err) { + return next(err); + } + var scores = members.map(function() { + return now; + }); + db.sortedSetAdd('group:' + groupName + ':members', scores, members, next); + }); + } else { + next(); + } + }, + async.apply(db.sortedSetAdd, 'groups:createtime', now, groupName), + async.apply(db.setObjectField, 'group:' + groupName, 'createtime', now) + ], next); + }); + + }, function(err) { + winston.info('[2015/01/21] Upgrading groups to sorted set done'); + Upgrade.update(thisSchemaDate, next); + }); + }); + } else { + winston.info('[2015/01/21] Upgrading groups to sorted set skipped'); + next(); + } } // Add new schema updates here diff --git a/tests/database/sorted.js b/tests/database/sorted.js index 1739989689..ed0bea521f 100644 --- a/tests/database/sorted.js +++ b/tests/database/sorted.js @@ -377,6 +377,32 @@ describe('Sorted Set methods', function() { }); }); + describe('isMemberOfSortedSets', function() { + it('should return true for members false for non members', function(done) { + db.isMemberOfSortedSets(['doesnotexist', 'sortedSetTest1', 'sortedSetTest2'], 'value2', function(err, isMembers) { + assert.equal(err, null); + assert.equal(arguments.length, 2); + assert.deepEqual(isMembers, [false, true, false]); + done(); + }); + }); + }); + + describe('getSortedSetsMembers', function() { + it('should return members of multiple sorted sets', function(done) { + db.getSortedSetMembers(['doesnotexist', 'sortedSetTest1'], function(err, sortedSets) { + assert.equal(err, null); + assert.equal(arguments.length, 2); + assert.deepEqual(sortedSets[0], []); + sortedSets[0].forEach(function(element) { + assert.notEqual(['value1', 'value2', 'value3'].indexOf(element), -1); + }); + + done(); + }); + }); + }); + describe('getSortedSetUnion()', function() { it('should return an array of values from both sorted sets sorted by scores lowest to highest', function(done) { db.getSortedSetUnion(['sortedSetTest2', 'sortedSetTest3'], 0, -1, function(err, values) {