From edd07befe21b4ac941423eae5fe593098e69fdc5 Mon Sep 17 00:00:00 2001 From: "John R. Supplee" Date: Thu, 1 Apr 2021 23:41:32 +0200 Subject: [PATCH] Add a new search operator `creator` --- client/components/main/globalSearch.js | 2 + config/query-classes.js | 4 +- config/search-const.js | 5 +- i18n/en.i18n.json | 2 + server/publications/cards.js | 67 ++++++++++++-------------- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/client/components/main/globalSearch.js b/client/components/main/globalSearch.js index 50bc9ae7e..294ac378f 100644 --- a/client/components/main/globalSearch.js +++ b/client/components/main/globalSearch.js @@ -123,6 +123,7 @@ class GlobalSearchComponent extends CardSearchPagedComponent { operator_member_abbrev: TAPi18n.__('operator-member-abbrev'), operator_assignee: TAPi18n.__('operator-assignee'), operator_assignee_abbrev: TAPi18n.__('operator-assignee-abbrev'), + operator_creator: TAPi18n.__('operator-creator'), operator_due: TAPi18n.__('operator-due'), operator_created: TAPi18n.__('operator-created'), operator_modified: TAPi18n.__('operator-modified'), @@ -167,6 +168,7 @@ class GlobalSearchComponent extends CardSearchPagedComponent { ['\n* ', 'globalSearch-instructions-operator-at'], ['\n* ', 'globalSearch-instructions-operator-member'], ['\n* ', 'globalSearch-instructions-operator-assignee'], + ['\n* ', 'globalSearch-instructions-operator-creator'], ['\n* ', 'globalSearch-instructions-operator-due'], ['\n* ', 'globalSearch-instructions-operator-created'], ['\n* ', 'globalSearch-instructions-operator-modified'], diff --git a/config/query-classes.js b/config/query-classes.js index 2c8a49ee0..3955bcd75 100644 --- a/config/query-classes.js +++ b/config/query-classes.js @@ -2,7 +2,7 @@ import { OPERATOR_ASSIGNEE, OPERATOR_BOARD, OPERATOR_COMMENT, - OPERATOR_CREATED_AT, + OPERATOR_CREATED_AT, OPERATOR_CREATOR, OPERATOR_DUE, OPERATOR_HAS, OPERATOR_LABEL, @@ -107,6 +107,7 @@ export class QueryErrors { [OPERATOR_USER, 'user-username-not-found'], [OPERATOR_ASSIGNEE, 'user-username-not-found'], [OPERATOR_MEMBER, 'user-username-not-found'], + [OPERATOR_CREATOR, 'user-username-not-found'], ]; constructor() { @@ -238,6 +239,7 @@ export class Query { 'operator-member': OPERATOR_MEMBER, 'operator-member-abbrev': OPERATOR_MEMBER, 'operator-assignee': OPERATOR_ASSIGNEE, + 'operator-creator': OPERATOR_CREATOR, 'operator-assignee-abbrev': OPERATOR_ASSIGNEE, 'operator-status': OPERATOR_STATUS, 'operator-due': OPERATOR_DUE, diff --git a/config/search-const.js b/config/search-const.js index 26f8ad00b..5a7f54b6b 100644 --- a/config/search-const.js +++ b/config/search-const.js @@ -1,14 +1,15 @@ export const DEFAULT_LIMIT = 25; -export const OPERATOR_ASSIGNEE = 'assignee'; +export const OPERATOR_ASSIGNEE = 'assignees'; export const OPERATOR_COMMENT = 'comment'; export const OPERATOR_CREATED_AT = 'createdAt'; +export const OPERATOR_CREATOR = 'userId'; export const OPERATOR_DUE = 'dueAt'; export const OPERATOR_BOARD = 'board'; export const OPERATOR_HAS = 'has'; export const OPERATOR_LABEL = 'label'; export const OPERATOR_LIMIT = 'limit'; export const OPERATOR_LIST = 'list'; -export const OPERATOR_MEMBER = 'member'; +export const OPERATOR_MEMBER = 'members'; export const OPERATOR_MODIFIED_AT = 'modifiedAt'; export const OPERATOR_SORT = 'sort'; export const OPERATOR_STATUS = 'status'; diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 916351156..73141e8b1 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -901,6 +901,7 @@ "operator-member-abbrev": "m", "operator-assignee": "assignee", "operator-assignee-abbrev": "a", + "operator-creator": "creator", "operator-status": "status", "operator-due": "due", "operator-created": "created", @@ -952,6 +953,7 @@ "globalSearch-instructions-operator-at": "`__operator_user_abbrev__username` - shorthand for `user:`", "globalSearch-instructions-operator-member": "`__operator_member__:` - cards where ** is a *member*", "globalSearch-instructions-operator-assignee": "`__operator_assignee__:` - cards where ** is an *assignee*", + "globalSearch-instructions-operator-creator": "`__operator_creator__:` - cards where ** is the card's creator", "globalSearch-instructions-operator-due": "`__operator_due__:` - cards which are due up to ** days from now. `__operator_due__:__predicate_overdue__ lists all cards past their due date.", "globalSearch-instructions-operator-created": "`__operator_created__:` - cards which were created ** days ago or less", "globalSearch-instructions-operator-modified": "`__operator_modified__:` - cards which were modified ** days ago or less", diff --git a/server/publications/cards.js b/server/publications/cards.js index 871af13e6..1af29bdb0 100644 --- a/server/publications/cards.js +++ b/server/publications/cards.js @@ -15,12 +15,15 @@ import { OPERATOR_ASSIGNEE, OPERATOR_BOARD, OPERATOR_COMMENT, + OPERATOR_CREATED_AT, + OPERATOR_CREATOR, OPERATOR_DUE, OPERATOR_HAS, OPERATOR_LABEL, OPERATOR_LIMIT, OPERATOR_LIST, OPERATOR_MEMBER, + OPERATOR_MODIFIED_AT, OPERATOR_SORT, OPERATOR_STATUS, OPERATOR_SWIMLANE, @@ -163,7 +166,7 @@ function buildSelector(queryParams) { if (queryParams.hasOperator(OPERATOR_BOARD)) { const queryBoards = []; - queryParams.hasOperator(OPERATOR_BOARD).forEach(query => { + queryParams.getPredicates(OPERATOR_BOARD).forEach(query => { const boards = Boards.userSearch(userId, { title: new RegExp(escapeForRegex(query), 'i'), }); @@ -240,7 +243,7 @@ function buildSelector(queryParams) { } } - [OPERATOR_DUE, 'createdAt', 'modifiedAt'].forEach(field => { + [OPERATOR_DUE, OPERATOR_CREATED_AT, OPERATOR_MODIFIED_AT].forEach(field => { if (queryParams.hasOperator(field)) { selector[field] = {}; const predicate = queryParams.getPredicate(field); @@ -251,52 +254,42 @@ function buildSelector(queryParams) { const queryUsers = {}; queryUsers[OPERATOR_ASSIGNEE] = []; queryUsers[OPERATOR_MEMBER] = []; + queryUsers[OPERATOR_CREATOR] = []; if (queryParams.hasOperator(OPERATOR_USER)) { + const users = []; queryParams.getPredicates(OPERATOR_USER).forEach(username => { const user = Users.findOne({ username }); if (user) { - queryUsers[OPERATOR_MEMBER].push(user._id); - queryUsers[OPERATOR_ASSIGNEE].push(user._id); + users.push(user._id); } else { errors.addNotFound(OPERATOR_USER, username); } }); - } - - [OPERATOR_MEMBER, OPERATOR_ASSIGNEE].forEach(key => { - if (queryParams.hasOperator(key)) { - queryParams.getPredicates(key).forEach(query => { - const users = Users.find({ - username: query, - }); - if (users.count()) { - users.forEach(user => { - queryUsers[key].push(user._id); - }); - } else { - errors.addNotFound(key, query); - } + if (users.length) { + selector.$and.push({ + $or: [{ members: { $in: users } }, { assignees: { $in: users } }], }); } - }); - - if ( - queryUsers[OPERATOR_MEMBER].length && - queryUsers[OPERATOR_ASSIGNEE].length - ) { - selector.$and.push({ - $or: [ - { members: { $in: queryUsers[OPERATOR_MEMBER] } }, - { assignees: { $in: queryUsers[OPERATOR_ASSIGNEE] } }, - ], - }); - } else if (queryUsers[OPERATOR_MEMBER].length) { - selector.members = { $in: queryUsers[OPERATOR_MEMBER] }; - } else if (queryUsers[OPERATOR_ASSIGNEE].length) { - selector.assignees = { $in: queryUsers[OPERATOR_ASSIGNEE] }; } + [OPERATOR_MEMBER, OPERATOR_ASSIGNEE, OPERATOR_CREATOR].forEach(key => { + if (queryParams.hasOperator(key)) { + const users = []; + queryParams.getPredicates(key).forEach(username => { + const user = Users.findOne({ username }); + if (user) { + users.push(user._id); + } else { + errors.addNotFound(key, username); + } + }); + if (users.length) { + selector[key] = { $in: users }; + } + } + }); + if (queryParams.hasOperator(OPERATOR_LABEL)) { queryParams.getPredicates(OPERATOR_LABEL).forEach(label => { const queryLabels = []; @@ -443,9 +436,9 @@ function buildSelector(queryParams) { } // eslint-disable-next-line no-console - // console.log('selector:', selector); + console.log('selector:', selector); // eslint-disable-next-line no-console - // console.log('selector.$and:', selector.$and); + console.log('selector.$and:', selector.$and); const query = new Query(); query.selector = selector;