'use strict'; var async = require('async'); var meta = require('../meta'); var plugins = require('../plugins'); var db = require('../database'); module.exports = function (User) { User.search = function (data, callback) { var query = data.query || ''; var searchBy = data.searchBy || 'username'; var page = data.page || 1; var uid = data.uid || 0; var paginate = data.hasOwnProperty('paginate') ? data.paginate : true; if (searchBy === 'ip') { return searchByIP(query, uid, callback); } var startTime = process.hrtime(); var searchResult = {}; async.waterfall([ function (next) { if (data.findUids) { data.findUids(query, searchBy, next); } else { findUids(query, searchBy, next); } }, function (uids, next) { filterAndSortUids(uids, data, next); }, function (uids, next) { plugins.fireHook('filter:users.search', { uids: uids, uid: uid }, next); }, function (data, next) { var uids = data.uids; searchResult.matchCount = uids.length; if (paginate) { var resultsPerPage = parseInt(meta.config.userSearchResultsPerPage, 10) || 20; var start = Math.max(0, page - 1) * resultsPerPage; var stop = start + resultsPerPage; searchResult.pageCount = Math.ceil(uids.length / resultsPerPage); uids = uids.slice(start, stop); } User.getUsers(uids, uid, next); }, function (userData, next) { searchResult.timing = (process.elapsedTimeSince(startTime) / 1000).toFixed(2); searchResult.users = userData; next(null, searchResult); }, ], callback); }; function findUids(query, searchBy, callback) { if (!query) { return callback(null, []); } query = query.toLowerCase(); var min = query; var max = query.substr(0, query.length - 1) + String.fromCharCode(query.charCodeAt(query.length - 1) + 1); var resultsPerPage = parseInt(meta.config.userSearchResultsPerPage, 10) || 20; var hardCap = resultsPerPage * 10; db.getSortedSetRangeByLex(searchBy + ':sorted', min, max, 0, hardCap, function (err, data) { if (err) { return callback(err); } var uids = data.map(function (data) { return data.split(':')[1]; }); callback(null, uids); }); } function filterAndSortUids(uids, data, callback) { var sortBy = data.sortBy || 'joindate'; var fields = ['uid', sortBy]; if (data.onlineOnly) { fields = fields.concat(['status', 'lastonline']); } if (data.bannedOnly) { fields.push('banned'); } if (data.flaggedOnly) { fields.push('flags'); } User.getUsersFields(uids, fields, function (err, userData) { if (err) { return callback(err); } if (data.onlineOnly) { userData = userData.filter(function (user) { return user && user.status !== 'offline' && (Date.now() - parseInt(user.lastonline, 10) < 300000); }); } if (data.bannedOnly) { userData = userData.filter(function (user) { return user && user.banned; }); } if (data.flaggedOnly) { userData = userData.filter(function (user) { return user && parseInt(user.flags, 10) > 0; }); } sortUsers(userData, sortBy); uids = userData.map(function (user) { return user && user.uid; }); callback(null, uids); }); } function sortUsers(userData, sortBy) { if (sortBy === 'joindate' || sortBy === 'postcount' || sortBy === 'reputation') { userData.sort(function (u1, u2) { return u2[sortBy] - u1[sortBy]; }); } else { userData.sort(function (u1, u2) { if (u1[sortBy] < u2[sortBy]) { return -1; } else if (u1[sortBy] > u2[sortBy]) { return 1; } return 0; }); } } function searchByIP(ip, uid, callback) { var start = process.hrtime(); async.waterfall([ function (next) { db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1, next); }, function (uids, next) { User.getUsers(uids, uid, next); }, function (users, next) { var diff = process.hrtime(start); var timing = ((diff[0] * 1e3) + (diff[1] / 1e6)).toFixed(1); next(null, { timing: timing, users: users }); }, ], callback); } };