From 2c140c2107deab5912e481188da70df372b6da56 Mon Sep 17 00:00:00 2001 From: barisusakli <barisusakli@gmail.com> Date: Fri, 16 Sep 2016 14:20:07 +0300 Subject: [PATCH] ability to filter flags by category --- public/src/admin/manage/flags.js | 2 -- src/categories.js | 33 ++++++++++++++++++ src/controllers/admin/flags.js | 59 +++++++++++++++++++++++++------- src/controllers/search.js | 50 +++++---------------------- src/plugins.js | 1 + src/posts/flags.js | 53 +++++++++------------------- src/routes/debug.js | 9 ++--- src/views/admin/manage/flags.tpl | 18 ++++++++-- 8 files changed, 126 insertions(+), 99 deletions(-) diff --git a/public/src/admin/manage/flags.js b/public/src/admin/manage/flags.js index ccf13b789a..15417faa30 100644 --- a/public/src/admin/manage/flags.js +++ b/public/src/admin/manage/flags.js @@ -12,8 +12,6 @@ define('admin/manage/flags', [ Flags.init = function() { $('.post-container .content img:not(.not-responsive)').addClass('img-responsive'); - var params = utils.params(); - $('#flag-sort-by').val(params.sortBy); autocomplete.user($('#byUsername')); handleDismiss(); diff --git a/src/categories.js b/src/categories.js index 3233f2dbcd..b5291b2f8b 100644 --- a/src/categories.js +++ b/src/categories.js @@ -305,6 +305,39 @@ var privileges = require('./privileges'); return tree; }; + Categories.buildForSelect = function(uid, callback) { + function recursive(category, categoriesData, level) { + if (category.link) { + return; + } + + var bullet = level ? '• ' : ''; + category.value = category.cid; + category.text = level + bullet + category.name + categoriesData.push(category); + + category.children.forEach(function(child) { + recursive(child, categoriesData, ' ' + level); + }); + } + Categories.getCategoriesByPrivilege('cid:0:children', uid, 'read', function(err, categories) { + if (err) { + return callback(err); + } + + var categoriesData = []; + + categories = categories.filter(function(category) { + return category && !category.link && !parseInt(category.parentCid, 10); + }); + + categories.forEach(function(category) { + recursive(category, categoriesData, ''); + }); + callback(null, categoriesData); + }); + }; + Categories.getIgnorers = function(cid, start, stop, callback) { db.getSortedSetRevRange('cid:' + cid + ':ignorers', start, stop, callback); }; diff --git a/src/controllers/admin/flags.js b/src/controllers/admin/flags.js index 54a52aa319..4b44b1d951 100644 --- a/src/controllers/admin/flags.js +++ b/src/controllers/admin/flags.js @@ -3,28 +3,26 @@ var async = require('async'); var posts = require('../../posts'); var user = require('../../user'); +var categories = require('../../categories'); var analytics = require('../../analytics'); var pagination = require('../../pagination'); var flagsController = {}; +var itemsPerPage = 20; + flagsController.get = function(req, res, next) { - var sortBy = req.query.sortBy || 'count'; var byUsername = req.query.byUsername || ''; - + var cid = req.query.cid || 0; + var sortBy = req.query.sortBy || 'count'; var page = parseInt(req.query.page, 10) || 1; - var itemsPerPage = 20; - var start = (page - 1) * itemsPerPage; - var stop = start + itemsPerPage - 1; async.parallel({ + categories: function(next) { + categories.buildForSelect(req.uid, next); + }, flagData: function(next) { - if (byUsername) { - posts.getUserFlags(byUsername, sortBy, req.uid, start, stop, next); - } else { - var set = sortBy === 'count' ? 'posts:flags:count' : 'posts:flagged'; - posts.getFlags(set, req.uid, start, stop, next); - } + getFlagData(req, next); }, analytics: function(next) { analytics.getDailyStatsForSet('analytics:flags', Date.now(), 30, next); @@ -47,12 +45,18 @@ flagsController.get = function(req, res, next) { var pageCount = Math.max(1, Math.ceil(results.flagData.count / itemsPerPage)); + results.categories.forEach(function(category) { + category.selected = parseInt(category.cid, 10) === parseInt(cid, 10); + }); + var data = { posts: results.flagData.posts, assignees: results.assignees, analytics: results.analytics, - next: stop + 1, + categories: results.categories, byUsername: byUsername, + sortByCount: sortBy === 'count', + sortByTime: sortBy === 'time', pagination: pagination.create(page, pageCount, req.query), title: '[[pages:flagged-posts]]' }; @@ -60,5 +64,36 @@ flagsController.get = function(req, res, next) { }); }; +function getFlagData(req, callback) { + var sortBy = req.query.sortBy || 'count'; + var byUsername = req.query.byUsername || ''; + var cid = req.query.cid || 0; + var page = parseInt(req.query.page, 10) || 1; + var start = (page - 1) * itemsPerPage; + var stop = start + itemsPerPage - 1; + + var sets = [sortBy === 'count' ? 'posts:flags:count' : 'posts:flagged']; + if (cid) { + sets.push('cid:' + cid + ':pids'); + } + + async.waterfall([ + function(next) { + if (byUsername) { + user.getUidByUsername(byUsername, next); + } else { + process.nextTick(next, null, 0); + } + }, + function(uid, next) { + if (uid) { + sets.push('uid:' + uid + ':flag:pids'); + } + + posts.getFlags(sets, req.uid, start, stop, next); + } + ], callback); +} + module.exports = flagsController; diff --git a/src/controllers/search.js b/src/controllers/search.js index 2466f17670..8c016c759c 100644 --- a/src/controllers/search.js +++ b/src/controllers/search.js @@ -45,14 +45,20 @@ searchController.search = function(req, res, next) { }; async.parallel({ - categories: async.apply(buildCategories, req.uid), + categories: async.apply(categories.buildForSelect, req.uid), search: async.apply(search.search, data) }, function(err, results) { if (err) { return next(err); } + + var categoriesData = [ + {value: 'all', text: '[[unread:all_categories]]'}, + {value: 'watched', text: '[[category:watched-categories]]'} + ].concat(results.categories); + var searchData = results.search; - searchData.categories = results.categories; + searchData.categories = categoriesData; searchData.categoriesCount = results.categories.length; searchData.pagination = pagination.create(page, searchData.pageCount, req.query); searchData.showAsPosts = !req.query.showAs || req.query.showAs === 'posts'; @@ -65,44 +71,4 @@ searchController.search = function(req, res, next) { }); }; -function buildCategories(uid, callback) { - categories.getCategoriesByPrivilege('cid:0:children', uid, 'read', function(err, categories) { - if (err) { - return callback(err); - } - - var categoriesData = [ - {value: 'all', text: '[[unread:all_categories]]'}, - {value: 'watched', text: '[[category:watched-categories]]'} - ]; - - categories = categories.filter(function(category) { - return category && !category.link && !parseInt(category.parentCid, 10); - }); - - categories.forEach(function(category) { - recursive(category, categoriesData, ''); - }); - callback(null, categoriesData); - }); -} - - -function recursive(category, categoriesData, level) { - if (category.link) { - return; - } - - var bullet = level ? '• ' : ''; - - categoriesData.push({ - value: category.cid, - text: level + bullet + category.name - }); - - category.children.forEach(function(child) { - recursive(child, categoriesData, ' ' + level); - }); -} - module.exports = searchController; diff --git a/src/plugins.js b/src/plugins.js index 0d6bb02fb5..af3bc887c9 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -260,6 +260,7 @@ var middleware; }, function(err, res, body) { if (err) { winston.error('Error parsing plugins : ' + err.message); + return callback(err); } Plugins.normalise(body, callback); diff --git a/src/posts/flags.js b/src/posts/flags.js index 566a03ae21..0d4a782ee8 100644 --- a/src/posts/flags.js +++ b/src/posts/flags.js @@ -154,14 +154,23 @@ module.exports = function(Posts) { }; Posts.getFlags = function(set, uid, start, stop, callback) { + set = set.length > 1 ? set : set[0]; async.parallel({ count: function(next) { - db.sortedSetCard(set, next); + if (Array.isArray(set)) { + db.sortedSetIntersectCard(set, next); + } else { + db.sortedSetCard(set, next); + } }, posts: function(next) { async.waterfall([ function (next) { - db.getSortedSetRevRange(set, start, stop, next); + if (Array.isArray(set)) { + db.getSortedSetRevIntersect({sets: set, start: start, stop: stop, aggregate: 'MAX'}, next); + } else { + db.getSortedSetRevRange(set, start, stop, next); + } }, function (pids, next) { getFlaggedPostsWithReasons(pids, uid, next); @@ -171,35 +180,6 @@ module.exports = function(Posts) { }, callback); }; - Posts.getUserFlags = function(byUsername, sortBy, callerUID, start, stop, callback) { - var count = 0; - async.waterfall([ - function(next) { - user.getUidByUsername(byUsername, next); - }, - function(uid, next) { - if (!uid) { - return next(null, []); - } - - db.getSortedSetRevRange('uid:' + uid + ':flag:pids', 0, -1, next); - }, - function(pids, next) { - count = pids.length; - getFlaggedPostsWithReasons(pids, callerUID, next); - }, - function(posts, next) { - if (sortBy === 'count') { - posts.sort(function(a, b) { - return b.flags - a.flags; - }); - } - - next(null, {posts: posts.slice(start, stop === -1 ? undefined : stop + 1), count: count}); - } - ], callback); - }; - function getFlaggedPostsWithReasons(pids, uid, callback) { async.waterfall([ function (next) { @@ -229,8 +209,6 @@ module.exports = function(Posts) { } results.posts.forEach(function(post, index) { - var history; - if (post) { post.flagReasons = reasons[index]; } @@ -352,11 +330,12 @@ module.exports = function(Posts) { Posts.expandFlagHistory = function(posts, callback) { // Expand flag history async.map(posts, function(post, next) { + var history; try { - var history = JSON.parse(post['flag:history'] || '[]'); + history = JSON.parse(post['flag:history'] || '[]'); } catch (e) { winston.warn('[posts/getFlags] Unable to deserialise post flag history, likely malformed data'); - callback(e); + return callback(e); } async.map(history, function(event, next) { @@ -392,7 +371,7 @@ module.exports = function(Posts) { } ], function(err) { next(err, event); - }) + }); }, function(err, history) { if (err) { return next(err); @@ -402,5 +381,5 @@ module.exports = function(Posts) { next(null, post); }); }, callback); - } + }; }; diff --git a/src/routes/debug.js b/src/routes/debug.js index a2191d8ffa..87c536c4c6 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -3,10 +3,11 @@ var express = require('express'); var nconf = require('nconf'); var winston = require('winston'); -var user = require('./../user'); -var categories = require('./../categories'); -var topics = require('./../topics'); -var posts = require('./../posts'); +var user = require('../user'); +var categories = require('../categories'); +var topics = require('../topics'); +var posts = require('../posts'); +var db = require('../database'); module.exports = function(app, middleware, controllers) { var router = express.Router(); diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 4a87588467..54209a279e 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -24,13 +24,27 @@ </div> </div> + <div class="form-group"> + <div> + <div> + <label>Category</label> + <select class="form-control" id="category-selector" name="cid"> + <option value="">[[unread:all_categories]]</option> + <!-- BEGIN categories --> + <option value="{categories.cid}" <!-- IF categories.selected -->selected<!-- ENDIF categories.selected -->>{categories.text}</option> + <!-- END categories --> + </select> + </div> + </div> + </div> + <div class="form-group"> <label>Sort By</label> <div> <div> <select id="flag-sort-by" class="form-control" name="sortBy"> - <option value="count">Most Flags</option> - <option value="time">Most Recent</option> + <option value="count" <!-- IF sortByCount -->selected<!-- ENDIF sortByCount -->>Most Flags</option> + <option value="time" <!-- IF sortByTime -->selected<!-- ENDIF sortByTime -->>Most Recent</option> </select> </div> </div>