From aa0dee1fba42dbe6e5f04b4211b0a1550014feef Mon Sep 17 00:00:00 2001 From: John Supplee Date: Wed, 22 Dec 2021 00:33:13 +0200 Subject: [PATCH] Bug fix for #3864 searching archived cards and add new operators for organizations and teams --- config/query-classes.js | 6 ++++ config/search-const.js | 2 ++ i18n/en.i18n.json | 4 +++ models/boards.js | 4 +-- models/lists.js | 11 ++++++++ models/swimlanes.js | 11 ++++++++ models/users.js | 2 ++ server/publications/cards.js | 55 +++++++++++++++++++++++++++++++++--- 8 files changed, 89 insertions(+), 6 deletions(-) diff --git a/config/query-classes.js b/config/query-classes.js index 8649d19f8..a1abec3a1 100644 --- a/config/query-classes.js +++ b/config/query-classes.js @@ -12,9 +12,11 @@ import { OPERATOR_LIST, OPERATOR_MEMBER, OPERATOR_MODIFIED_AT, + OPERATOR_ORG, OPERATOR_SORT, OPERATOR_STATUS, OPERATOR_SWIMLANE, + OPERATOR_TEAM, OPERATOR_UNKNOWN, OPERATOR_USER, ORDER_ASCENDING, @@ -161,6 +163,8 @@ export class QueryErrors { [OPERATOR_ASSIGNEE, 'user-username-not-found'], [OPERATOR_MEMBER, 'user-username-not-found'], [OPERATOR_CREATOR, 'user-username-not-found'], + [OPERATOR_ORG, 'org-name-not-found'], + [OPERATOR_TEAM, 'team-name-not-found'], ]; constructor() { @@ -313,6 +317,8 @@ export class Query { 'operator-sort': OPERATOR_SORT, 'operator-limit': OPERATOR_LIMIT, 'operator-debug': OPERATOR_DEBUG, + 'operator-org': OPERATOR_ORG, + 'operator-team': OPERATOR_TEAM, }; const predicates = { diff --git a/config/search-const.js b/config/search-const.js index 1b8b5b27c..19ff1ac9e 100644 --- a/config/search-const.js +++ b/config/search-const.js @@ -12,9 +12,11 @@ export const OPERATOR_LIMIT = 'limit'; export const OPERATOR_LIST = 'list'; export const OPERATOR_MEMBER = 'members'; export const OPERATOR_MODIFIED_AT = 'modifiedAt'; +export const OPERATOR_ORG = 'org'; export const OPERATOR_SORT = 'sort'; export const OPERATOR_STATUS = 'status'; export const OPERATOR_SWIMLANE = 'swimlane'; +export const OPERATOR_TEAM = 'team'; export const OPERATOR_UNKNOWN = 'unknown'; export const OPERATOR_USER = 'user'; export const ORDER_ASCENDING = 'asc'; diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 02d70f42d..700947c7b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -943,6 +943,8 @@ "label-color-not-found": "Label color %s not found.", "user-username-not-found": "Username '%s' not found.", "comment-not-found": "Card with comment containing text '%s' not found.", + "org-name-not-found": "Organization '%s' not found.", + "team-name-not-found": "Team '%s' not found.", "globalSearch-title": "Search All Boards", "no-cards-found": "No Cards Found", "one-card-found": "One Card Found", @@ -972,6 +974,8 @@ "operator-has": "has", "operator-limit": "limit", "operator-debug": "debug", + "operator-org": "org", + "operator-team": "team", "predicate-archived": "archived", "predicate-open": "open", "predicate-ended": "ended", diff --git a/models/boards.js b/models/boards.js index 6244e5aca..75d6d20d2 100644 --- a/models/boards.js +++ b/models/boards.js @@ -1501,8 +1501,8 @@ Boards.userBoards = ( selector.$or = [ { permission: 'public' }, { members: { $elemMatch: { userId, isActive: true } } }, - { 'orgs.orgId': { $in: user.orgIds() } }, - { 'teams.teamId': { $in : user.teamIds() } }, + { orgs: { $elemMatch: { orgId: { $in: user.orgIds() }, isActive: true } } }, + { teams: { $elemMatch: { teamId: { $in: user.teamIds() }, isActive: true } } }, ]; return Boards.find(selector, projection); diff --git a/models/lists.js b/models/lists.js index 1e9868d5d..8fe336e79 100644 --- a/models/lists.js +++ b/models/lists.js @@ -345,6 +345,17 @@ Lists.mutations({ }, }); +Lists.userArchivedLists = userId => { + return Lists.find({ + boardId: { $in: Boards.userBoardIds(userId, null) }, + archived: true, + }) +}; + +Lists.userArchivedListIds = () => { + return Lists.userArchivedLists().map(list => { return list._id; }); +}; + Lists.archivedLists = () => { return Lists.find({ archived: true }); }; diff --git a/models/swimlanes.js b/models/swimlanes.js index c83d8139e..1378876c8 100644 --- a/models/swimlanes.js +++ b/models/swimlanes.js @@ -306,6 +306,17 @@ Swimlanes.mutations({ }, }); +Swimlanes.userArchivedSwimlanes = userId => { + return Swimlanes.find({ + boardId: { $in: Boards.userBoardIds(userId, null) }, + archived: true, + }) +}; + +Swimlanes.userArchivedSwimlaneIds = () => { + return Swimlanes.userArchivedSwimlanes().map(swim => { return swim._id; }); +}; + Swimlanes.archivedSwimlanes = () => { return Swimlanes.find({ archived: true }); }; diff --git a/models/users.js b/models/users.js index 05354e045..0592b61fc 100644 --- a/models/users.js +++ b/models/users.js @@ -521,12 +521,14 @@ Users.helpers({ }, teamIds() { if (this.teams) { + // TODO: Should the Team collection be queried to determine if the team isActive? return this.teams.map(team => { return team.teamId }); } return []; }, orgIds() { if (this.orgs) { + // TODO: Should the Org collection be queried to determine if the organization isActive? return this.orgs.map(org => { return org.orgId }); } return []; diff --git a/server/publications/cards.js b/server/publications/cards.js index 7f7348a08..456da3b67 100644 --- a/server/publications/cards.js +++ b/server/publications/cards.js @@ -24,10 +24,10 @@ import { OPERATOR_LIMIT, OPERATOR_LIST, OPERATOR_MEMBER, - OPERATOR_MODIFIED_AT, + OPERATOR_MODIFIED_AT, OPERATOR_ORG, OPERATOR_SORT, OPERATOR_STATUS, - OPERATOR_SWIMLANE, + OPERATOR_SWIMLANE, OPERATOR_TEAM, OPERATOR_USER, ORDER_ASCENDING, PREDICATE_ALL, @@ -49,6 +49,8 @@ import { } from '/config/search-const'; import { QueryErrors, QueryParams, Query } from '/config/query-classes'; import { CARD_TYPES } from '../../config/const'; +import Org from "../../models/org"; +import Team from "../../models/team"; const escapeForRegex = require('escape-string-regexp'); @@ -151,6 +153,51 @@ function buildSelector(queryParams) { } }); } + + if (queryParams.hasOperator(OPERATOR_ORG)) { + const orgs = []; + queryParams.getPredicates(OPERATOR_ORG).forEach(name => { + const org = Org.findOne({ + $or: [ + { orgDisplayName: name }, + { orgShortName: name } + ] + }); + if (org) { + orgs.push(org._id); + } else { + errors.addNotFound(OPERATOR_ORG, name); + } + }); + if (orgs.length) { + boardsSelector.orgs = { + $elemMatch: { orgId: { $in: orgs }, isActive: true } + }; + } + } + + if (queryParams.hasOperator(OPERATOR_TEAM)) { + const teams = []; + queryParams.getPredicates(OPERATOR_TEAM).forEach(name => { + const team = Team.findOne({ + $or: [ + { teamDisplayName: name }, + { teamShortName: name } + ] + }); + if (team) { + teams.push(team._id); + } else { + errors.addNotFound(OPERATOR_TEAM, name); + } + }); + if (teams.length) { + boardsSelector.teams = { + $elemMatch: { teamId: { $in: teams }, isActive: true } + }; + } + } + selector = { type: 'cardType-card', // boardId: { $in: Boards.userBoardIds(userId) }, @@ -169,8 +216,8 @@ function buildSelector(queryParams) { $in: Boards.userBoardIds(userId, archived, boardsSelector), }, }, - { swimlaneId: { $in: Swimlanes.archivedSwimlaneIds() } }, - { listId: { $in: Lists.archivedListIds() } }, + { swimlaneId: { $in: Swimlanes.userArchivedSwimlaneIds(userId) } }, + { listId: { $in: Lists.userArchivedListIds(userId) } }, { archived: true }, ], });