diff --git a/services/assets.js b/services/assets.js index 8f93de009..4aac2addd 100644 --- a/services/assets.js +++ b/services/assets.js @@ -116,7 +116,7 @@ module.exports = class AssetsService { static search({value, limit, open, sortOrder, cursor} = {}) { let assets = AssetModel.find({}); - if (value) { + if (value && value.length > 0) { assets.merge({ $text: { $search: value diff --git a/services/regex.js b/services/regex.js new file mode 100644 index 000000000..9092df18a --- /dev/null +++ b/services/regex.js @@ -0,0 +1,10 @@ +/** + * Escape string for special regular expression characters. + */ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +module.exports = { + escapeRegExp, +}; diff --git a/services/users.js b/services/users.js index 1dc9bceb6..78708b40a 100644 --- a/services/users.js +++ b/services/users.js @@ -24,6 +24,7 @@ const ActionsService = require('./actions'); const MailerService = require('./mailer'); const Wordlist = require('./wordlist'); const Domainlist = require('./domainlist'); +const {escapeRegExp} = require('./regex'); const EMAIL_CONFIRM_JWT_SUBJECT = 'email_confirm'; const PASSWORD_RESET_JWT_SUBJECT = 'password_reset'; @@ -630,14 +631,19 @@ module.exports = class UsersService { * @return {Promise} */ static search(value) { + if (!value || typeof value !== 'string' || value.length === 0) { + return UserModel.find({}); + } + + value = escapeRegExp(value); + return UserModel.find({ $or: [ // Search by a prefix match on the username. { - 'username': { - $regex: new RegExp(`^${value}`), - $options: 'i' + 'lowercaseUsername': { + $regex: new RegExp(value.toLowerCase()) } }, @@ -646,7 +652,7 @@ module.exports = class UsersService { 'profiles': { $elemMatch: { id: { - $regex: new RegExp(`^${value}`), + $regex: new RegExp(value), $options: 'i' }, provider: 'local' diff --git a/services/wordlist.js b/services/wordlist.js index 8d9ee95bb..601f4bc79 100644 --- a/services/wordlist.js +++ b/services/wordlist.js @@ -3,13 +3,7 @@ const _ = require('lodash'); const SettingsService = require('./settings'); const Errors = require('../errors'); const memoize = require('lodash/memoize'); - -/** - * Escape string for special regular expression characters. - */ -function escapeRegExp(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string -} +const {escapeRegExp} = require('./regex'); /** * Generate a regulare expression that catches the `phrases`. diff --git a/test/server/services/users.js b/test/server/services/users.js index 57d0f3815..251618187 100644 --- a/test/server/services/users.js +++ b/test/server/services/users.js @@ -208,6 +208,50 @@ describe('services.UsersService', () => { }); }); + describe('#search', () => { + it('should return all the results without a value', async () => { + expect(await UsersService.search()).to.have.length(3); + }); + + it('should match the search terms', async () => { + const tests = [ + { + search: 'monster', + results: 1, + id: mockUsers[1].id, + }, + { + search: 'Stamp', + results: 1, + id: mockUsers[0].id, + }, + { + search: 'sockmonster@gmail.com', + results: 1, + id: mockUsers[1].id, + }, + { + search: 'marvel', + results: 1, + id: mockUsers[2].id, + }, + { + search: 'gmail.com', + results: 3 + } + ]; + + for (const test of tests) { + const users = await UsersService.search(test.search); + + expect(users).to.have.length(test.results); + if (test.results === 1) { + expect(users[0]).to.have.property('id', test.id); + } + } + }); + }); + describe('#editName', () => { it('should let the user edit their username if the proper toggle is set', () => { return UsersService