mirror of
https://github.com/wekan/wekan.git
synced 2025-12-27 12:48:49 +01:00
- the global search only returns the card details data needed to display the search results, but for opening the popup card details a lot more information is needed. It already worked if the data was already in the minimongo, but if not, nearly nothing was displayed
733 lines
20 KiB
JavaScript
733 lines
20 KiB
JavaScript
import moment from 'moment';
|
|
import Users from '../../models/users';
|
|
import Boards from '../../models/boards';
|
|
import Lists from '../../models/lists';
|
|
import Swimlanes from '../../models/swimlanes';
|
|
import Cards from '../../models/cards';
|
|
import CardComments from '../../models/cardComments';
|
|
import Attachments from '../../models/attachments';
|
|
import Checklists from '../../models/checklists';
|
|
import ChecklistItems from '../../models/checklistItems';
|
|
import SessionData from '../../models/usersessiondata';
|
|
import CustomFields from '../../models/customFields';
|
|
import {
|
|
DEFAULT_LIMIT,
|
|
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,
|
|
OPERATOR_USER,
|
|
ORDER_ASCENDING,
|
|
PREDICATE_ALL,
|
|
PREDICATE_ARCHIVED,
|
|
PREDICATE_ASSIGNEES,
|
|
PREDICATE_ATTACHMENT,
|
|
PREDICATE_CHECKLIST,
|
|
PREDICATE_CREATED_AT,
|
|
PREDICATE_DESCRIPTION,
|
|
PREDICATE_DUE_AT,
|
|
PREDICATE_END_AT,
|
|
PREDICATE_ENDED,
|
|
PREDICATE_MEMBERS,
|
|
PREDICATE_MODIFIED_AT,
|
|
PREDICATE_PRIVATE,
|
|
PREDICATE_PUBLIC,
|
|
PREDICATE_START_AT,
|
|
PREDICATE_SYSTEM,
|
|
} from '/config/search-const';
|
|
import { QueryErrors, QueryParams, Query } from '/config/query-classes';
|
|
|
|
const escapeForRegex = require('escape-string-regexp');
|
|
|
|
Meteor.publish('card', cardId => {
|
|
check(cardId, String);
|
|
const ret = Cards.find({ _id: cardId });
|
|
return ret;
|
|
});
|
|
|
|
/** publish all data which is necessary to display card details as popup
|
|
* @returns array of cursors
|
|
*/
|
|
Meteor.publishRelations('popupCardData', function(cardId) {
|
|
check(cardId, String);
|
|
this.cursor(
|
|
Cards.find({_id: cardId}),
|
|
function(cardId, card) {
|
|
this.cursor(Boards.find({_id: card.boardId}));
|
|
},
|
|
);
|
|
return this.ready()
|
|
});
|
|
|
|
Meteor.publish('myCards', function(sessionId) {
|
|
check(sessionId, String);
|
|
|
|
const queryParams = new QueryParams();
|
|
queryParams.addPredicate(OPERATOR_USER, Meteor.user().username);
|
|
queryParams.setPredicate(OPERATOR_LIMIT, 200);
|
|
|
|
const query = buildQuery(queryParams);
|
|
query.projection.sort = {
|
|
boardId: 1,
|
|
swimlaneId: 1,
|
|
listId: 1,
|
|
};
|
|
|
|
return findCards(sessionId, query);
|
|
});
|
|
|
|
// Meteor.publish('dueCards', function(sessionId, allUsers = false) {
|
|
// check(sessionId, String);
|
|
// check(allUsers, Boolean);
|
|
//
|
|
// // eslint-disable-next-line no-console
|
|
// // console.log('all users:', allUsers);
|
|
//
|
|
// const queryParams = {
|
|
// has: [{ field: 'dueAt', exists: true }],
|
|
// limit: 25,
|
|
// skip: 0,
|
|
// sort: { name: 'dueAt', order: 'des' },
|
|
// };
|
|
//
|
|
// if (!allUsers) {
|
|
// queryParams.users = [Meteor.user().username];
|
|
// }
|
|
//
|
|
// return buildQuery(sessionId, queryParams);
|
|
// });
|
|
|
|
Meteor.publish('globalSearch', function(sessionId, params, text) {
|
|
check(sessionId, String);
|
|
check(params, Object);
|
|
check(text, String);
|
|
|
|
// eslint-disable-next-line no-console
|
|
// console.log('queryParams:', params);
|
|
|
|
return findCards(sessionId, buildQuery(new QueryParams(params, text)));
|
|
});
|
|
|
|
function buildSelector(queryParams) {
|
|
const userId = Meteor.userId();
|
|
|
|
const errors = new QueryErrors();
|
|
|
|
let selector = {};
|
|
|
|
// eslint-disable-next-line no-console
|
|
// console.log('queryParams:', queryParams);
|
|
|
|
if (queryParams.selector) {
|
|
selector = queryParams.selector;
|
|
} else {
|
|
const boardsSelector = {};
|
|
|
|
let archived = false;
|
|
let endAt = null;
|
|
if (queryParams.hasOperator(OPERATOR_STATUS)) {
|
|
queryParams.getPredicates(OPERATOR_STATUS).forEach(status => {
|
|
if (status === PREDICATE_ARCHIVED) {
|
|
archived = true;
|
|
} else if (status === PREDICATE_ALL) {
|
|
archived = null;
|
|
} else if (status === PREDICATE_ENDED) {
|
|
endAt = { $nin: [null, ''] };
|
|
} else if ([PREDICATE_PRIVATE, PREDICATE_PUBLIC].includes(status)) {
|
|
boardsSelector.permission = status;
|
|
}
|
|
});
|
|
}
|
|
selector = {
|
|
type: 'cardType-card',
|
|
// boardId: { $in: Boards.userBoardIds(userId) },
|
|
$and: [],
|
|
};
|
|
|
|
if (archived !== null) {
|
|
if (archived) {
|
|
selector.boardId = {
|
|
$in: Boards.userBoardIds(userId, null, boardsSelector),
|
|
};
|
|
selector.$and.push({
|
|
$or: [
|
|
{
|
|
boardId: {
|
|
$in: Boards.userBoardIds(userId, archived, boardsSelector),
|
|
},
|
|
},
|
|
{ swimlaneId: { $in: Swimlanes.archivedSwimlaneIds() } },
|
|
{ listId: { $in: Lists.archivedListIds() } },
|
|
{ archived: true },
|
|
],
|
|
});
|
|
} else {
|
|
selector.boardId = {
|
|
$in: Boards.userBoardIds(userId, false, boardsSelector),
|
|
};
|
|
selector.swimlaneId = { $nin: Swimlanes.archivedSwimlaneIds() };
|
|
selector.listId = { $nin: Lists.archivedListIds() };
|
|
selector.archived = false;
|
|
}
|
|
} else {
|
|
selector.boardId = {
|
|
$in: Boards.userBoardIds(userId, null, boardsSelector),
|
|
};
|
|
}
|
|
if (endAt !== null) {
|
|
selector.endAt = endAt;
|
|
}
|
|
|
|
if (queryParams.hasOperator(OPERATOR_BOARD)) {
|
|
const queryBoards = [];
|
|
queryParams.getPredicates(OPERATOR_BOARD).forEach(query => {
|
|
const boards = Boards.userSearch(userId, {
|
|
title: new RegExp(escapeForRegex(query), 'i'),
|
|
});
|
|
if (boards.count()) {
|
|
boards.forEach(board => {
|
|
queryBoards.push(board._id);
|
|
});
|
|
} else {
|
|
errors.addNotFound(OPERATOR_BOARD, query);
|
|
}
|
|
});
|
|
|
|
selector.boardId.$in = queryBoards;
|
|
}
|
|
|
|
if (queryParams.hasOperator(OPERATOR_SWIMLANE)) {
|
|
const querySwimlanes = [];
|
|
queryParams.getPredicates(OPERATOR_SWIMLANE).forEach(query => {
|
|
const swimlanes = Swimlanes.find({
|
|
title: new RegExp(escapeForRegex(query), 'i'),
|
|
});
|
|
if (swimlanes.count()) {
|
|
swimlanes.forEach(swim => {
|
|
querySwimlanes.push(swim._id);
|
|
});
|
|
} else {
|
|
errors.addNotFound(OPERATOR_SWIMLANE, query);
|
|
}
|
|
});
|
|
|
|
// eslint-disable-next-line no-prototype-builtins
|
|
if (!selector.swimlaneId.hasOwnProperty('swimlaneId')) {
|
|
selector.swimlaneId = { $in: [] };
|
|
}
|
|
selector.swimlaneId.$in = querySwimlanes;
|
|
}
|
|
|
|
if (queryParams.hasOperator(OPERATOR_LIST)) {
|
|
const queryLists = [];
|
|
queryParams.getPredicates(OPERATOR_LIST).forEach(query => {
|
|
const lists = Lists.find({
|
|
title: new RegExp(escapeForRegex(query), 'i'),
|
|
});
|
|
if (lists.count()) {
|
|
lists.forEach(list => {
|
|
queryLists.push(list._id);
|
|
});
|
|
} else {
|
|
errors.addNotFound(OPERATOR_LIST, query);
|
|
}
|
|
});
|
|
|
|
// eslint-disable-next-line no-prototype-builtins
|
|
if (!selector.hasOwnProperty('listId')) {
|
|
selector.listId = { $in: [] };
|
|
}
|
|
selector.listId.$in = queryLists;
|
|
}
|
|
|
|
if (queryParams.hasOperator(OPERATOR_COMMENT)) {
|
|
const cardIds = CardComments.textSearch(
|
|
userId,
|
|
queryParams.getPredicates(OPERATOR_COMMENT),
|
|
com => {
|
|
return com.cardId;
|
|
},
|
|
);
|
|
if (cardIds.length) {
|
|
selector._id = { $in: cardIds };
|
|
} else {
|
|
queryParams.getPredicates(OPERATOR_COMMENT).forEach(comment => {
|
|
errors.addNotFound(OPERATOR_COMMENT, comment);
|
|
});
|
|
}
|
|
}
|
|
|
|
[OPERATOR_DUE, OPERATOR_CREATED_AT, OPERATOR_MODIFIED_AT].forEach(field => {
|
|
if (queryParams.hasOperator(field)) {
|
|
selector[field] = {};
|
|
const predicate = queryParams.getPredicate(field);
|
|
selector[field][predicate.operator] = new Date(predicate.value);
|
|
}
|
|
});
|
|
|
|
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) {
|
|
users.push(user._id);
|
|
} else {
|
|
errors.addNotFound(OPERATOR_USER, username);
|
|
}
|
|
});
|
|
if (users.length) {
|
|
selector.$and.push({
|
|
$or: [{ members: { $in: users } }, { assignees: { $in: users } }],
|
|
});
|
|
}
|
|
}
|
|
|
|
[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)) {
|
|
const queryLabels = [];
|
|
queryParams.getPredicates(OPERATOR_LABEL).forEach(label => {
|
|
let boards = Boards.userBoards(userId, null, {
|
|
labels: { $elemMatch: { color: label.toLowerCase() } },
|
|
});
|
|
|
|
if (boards.count()) {
|
|
boards.forEach(board => {
|
|
// eslint-disable-next-line no-console
|
|
// console.log('board:', board);
|
|
// eslint-disable-next-line no-console
|
|
// console.log('board.labels:', board.labels);
|
|
board.labels
|
|
.filter(boardLabel => {
|
|
return boardLabel.color === label.toLowerCase();
|
|
})
|
|
.forEach(boardLabel => {
|
|
queryLabels.push(boardLabel._id);
|
|
});
|
|
});
|
|
} else {
|
|
// eslint-disable-next-line no-console
|
|
// console.log('label:', label);
|
|
const reLabel = new RegExp(escapeForRegex(label), 'i');
|
|
// eslint-disable-next-line no-console
|
|
// console.log('reLabel:', reLabel);
|
|
boards = Boards.userBoards(userId, null, {
|
|
labels: { $elemMatch: { name: reLabel } },
|
|
});
|
|
|
|
if (boards.count()) {
|
|
boards.forEach(board => {
|
|
board.labels
|
|
.filter(boardLabel => {
|
|
if (!boardLabel.name) {
|
|
return false;
|
|
}
|
|
return boardLabel.name.match(reLabel);
|
|
})
|
|
.forEach(boardLabel => {
|
|
queryLabels.push(boardLabel._id);
|
|
});
|
|
});
|
|
} else {
|
|
errors.addNotFound(OPERATOR_LABEL, label);
|
|
}
|
|
}
|
|
});
|
|
if (queryLabels.length) {
|
|
// eslint-disable-next-line no-console
|
|
// console.log('queryLabels:', queryLabels);
|
|
selector.labelIds = { $in: _.uniq(queryLabels) };
|
|
}
|
|
}
|
|
|
|
if (queryParams.hasOperator(OPERATOR_HAS)) {
|
|
queryParams.getPredicates(OPERATOR_HAS).forEach(has => {
|
|
switch (has.field) {
|
|
case PREDICATE_ATTACHMENT:
|
|
selector.$and.push({
|
|
_id: {
|
|
$in: Attachments.find({}, { fields: { cardId: 1 } }).map(
|
|
a => a.cardId,
|
|
),
|
|
},
|
|
});
|
|
break;
|
|
case PREDICATE_CHECKLIST:
|
|
selector.$and.push({
|
|
_id: {
|
|
$in: Checklists.find({}, { fields: { cardId: 1 } }).map(
|
|
a => a.cardId,
|
|
),
|
|
},
|
|
});
|
|
break;
|
|
case PREDICATE_DESCRIPTION:
|
|
case PREDICATE_START_AT:
|
|
case PREDICATE_DUE_AT:
|
|
case PREDICATE_END_AT:
|
|
if (has.exists) {
|
|
selector[has.field] = { $exists: true, $nin: [null, ''] };
|
|
} else {
|
|
selector[has.field] = { $in: [null, ''] };
|
|
}
|
|
break;
|
|
case PREDICATE_ASSIGNEES:
|
|
case PREDICATE_MEMBERS:
|
|
if (has.exists) {
|
|
selector[has.field] = { $exists: true, $nin: [null, []] };
|
|
} else {
|
|
selector[has.field] = { $in: [null, []] };
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (queryParams.text) {
|
|
const regex = new RegExp(escapeForRegex(queryParams.text), 'i');
|
|
|
|
const items = ChecklistItems.find(
|
|
{ title: regex },
|
|
{ fields: { cardId: 1, checklistId: 1 } },
|
|
);
|
|
const checklists = Checklists.find(
|
|
{
|
|
$or: [
|
|
{ title: regex },
|
|
{ _id: { $in: items.map(item => item.checklistId) } },
|
|
],
|
|
},
|
|
{ fields: { cardId: 1 } },
|
|
);
|
|
|
|
const attachments = Attachments.find({ 'original.name': regex });
|
|
|
|
const comments = CardComments.find(
|
|
{ text: regex },
|
|
{ fields: { cardId: 1 } },
|
|
);
|
|
|
|
let cardsSelector = [
|
|
{ title: regex },
|
|
{ description: regex },
|
|
{ customFields: { $elemMatch: { value: regex } } },
|
|
{ _id: { $in: checklists.map(list => list.cardId) } },
|
|
{ _id: { $in: attachments.map(attach => attach.cardId) } },
|
|
{ _id: { $in: comments.map(com => com.cardId) } },
|
|
];
|
|
if (queryParams.text == "false" || queryParams.text == "true") {
|
|
cardsSelector.push({ customFields: { $elemMatch: { value: queryParams.text == "true" ? true : false } } } );
|
|
}
|
|
selector.$and.push({ $or: cardsSelector });
|
|
}
|
|
|
|
if (selector.$and.length === 0) {
|
|
delete selector.$and;
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line no-console
|
|
//console.log('cards selector:', JSON.stringify(selector, null, 2));
|
|
|
|
const query = new Query();
|
|
query.selector = selector;
|
|
query.setQueryParams(queryParams);
|
|
query._errors = errors;
|
|
|
|
return query;
|
|
}
|
|
|
|
function buildProjection(query) {
|
|
// eslint-disable-next-line no-console
|
|
// console.log('query:', query);
|
|
let skip = 0;
|
|
if (query.getQueryParams().skip) {
|
|
skip = query.getQueryParams().skip;
|
|
}
|
|
let limit = DEFAULT_LIMIT;
|
|
const configLimit = parseInt(process.env.RESULTS_PER_PAGE, 10);
|
|
if (!isNaN(configLimit) && configLimit > 0) {
|
|
limit = configLimit;
|
|
}
|
|
|
|
if (query.getQueryParams().hasOperator(OPERATOR_LIMIT)) {
|
|
limit = query.getQueryParams().getPredicate(OPERATOR_LIMIT);
|
|
}
|
|
|
|
const projection = {
|
|
fields: {
|
|
_id: 1,
|
|
archived: 1,
|
|
boardId: 1,
|
|
swimlaneId: 1,
|
|
listId: 1,
|
|
title: 1,
|
|
type: 1,
|
|
sort: 1,
|
|
members: 1,
|
|
assignees: 1,
|
|
colors: 1,
|
|
dueAt: 1,
|
|
createdAt: 1,
|
|
modifiedAt: 1,
|
|
labelIds: 1,
|
|
customFields: 1,
|
|
userId: 1,
|
|
description: 1,
|
|
},
|
|
sort: {
|
|
boardId: 1,
|
|
swimlaneId: 1,
|
|
listId: 1,
|
|
sort: 1,
|
|
},
|
|
skip,
|
|
limit,
|
|
};
|
|
|
|
if (query.getQueryParams().hasOperator(OPERATOR_SORT)) {
|
|
const order =
|
|
query.getQueryParams().getPredicate(OPERATOR_SORT).order ===
|
|
ORDER_ASCENDING
|
|
? 1
|
|
: -1;
|
|
switch (query.getQueryParams().getPredicate(OPERATOR_SORT).name) {
|
|
case PREDICATE_DUE_AT:
|
|
projection.sort = {
|
|
dueAt: order,
|
|
boardId: 1,
|
|
swimlaneId: 1,
|
|
listId: 1,
|
|
sort: 1,
|
|
};
|
|
break;
|
|
case PREDICATE_MODIFIED_AT:
|
|
projection.sort = {
|
|
modifiedAt: order,
|
|
boardId: 1,
|
|
swimlaneId: 1,
|
|
listId: 1,
|
|
sort: 1,
|
|
};
|
|
break;
|
|
case PREDICATE_CREATED_AT:
|
|
projection.sort = {
|
|
createdAt: order,
|
|
boardId: 1,
|
|
swimlaneId: 1,
|
|
listId: 1,
|
|
sort: 1,
|
|
};
|
|
break;
|
|
case PREDICATE_SYSTEM:
|
|
projection.sort = {
|
|
boardId: order,
|
|
swimlaneId: order,
|
|
listId: order,
|
|
modifiedAt: order,
|
|
sort: order,
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line no-console
|
|
// console.log('projection:', projection);
|
|
|
|
query.projection = projection;
|
|
|
|
return query;
|
|
}
|
|
|
|
function buildQuery(queryParams) {
|
|
const query = buildSelector(queryParams);
|
|
|
|
return buildProjection(query);
|
|
}
|
|
|
|
Meteor.publish('brokenCards', function(sessionId) {
|
|
check(sessionId, String);
|
|
|
|
const params = new QueryParams();
|
|
params.addPredicate(OPERATOR_STATUS, PREDICATE_ALL);
|
|
const query = buildQuery(params);
|
|
query.selector.$or = [
|
|
{ boardId: { $in: [null, ''] } },
|
|
{ swimlaneId: { $in: [null, ''] } },
|
|
{ listId: { $in: [null, ''] } },
|
|
];
|
|
// console.log('brokenCards selector:', query.selector);
|
|
|
|
return findCards(sessionId, query);
|
|
});
|
|
|
|
Meteor.publish('nextPage', function(sessionId) {
|
|
check(sessionId, String);
|
|
|
|
const session = SessionData.findOne({ sessionId });
|
|
const projection = session.getProjection();
|
|
projection.skip = session.lastHit;
|
|
|
|
return findCards(sessionId, new Query(session.getSelector(), projection));
|
|
});
|
|
|
|
Meteor.publish('previousPage', function(sessionId) {
|
|
check(sessionId, String);
|
|
|
|
const session = SessionData.findOne({ sessionId });
|
|
const projection = session.getProjection();
|
|
projection.skip = session.lastHit - session.resultsCount - projection.limit;
|
|
|
|
return findCards(sessionId, new Query(session.getSelector(), projection));
|
|
});
|
|
|
|
function findCards(sessionId, query) {
|
|
const userId = Meteor.userId();
|
|
|
|
// eslint-disable-next-line no-console
|
|
// console.log('selector:', query.selector);
|
|
// console.log('selector.$and:', query.selector.$and);
|
|
// eslint-disable-next-line no-console
|
|
// console.log('projection:', query.projection);
|
|
|
|
const cards = Cards.find(query.selector, query.projection);
|
|
// eslint-disable-next-line no-console
|
|
// console.log('count:', cards.count());
|
|
|
|
const update = {
|
|
$set: {
|
|
totalHits: 0,
|
|
lastHit: 0,
|
|
resultsCount: 0,
|
|
cards: [],
|
|
selector: SessionData.pickle(query.selector),
|
|
projection: SessionData.pickle(query.projection),
|
|
errors: query.errors(),
|
|
},
|
|
};
|
|
|
|
if (cards) {
|
|
update.$set.totalHits = cards.count();
|
|
update.$set.lastHit =
|
|
query.projection.skip + query.projection.limit < cards.count()
|
|
? query.projection.skip + query.projection.limit
|
|
: cards.count();
|
|
update.$set.cards = cards.map(card => {
|
|
return card._id;
|
|
});
|
|
update.$set.resultsCount = update.$set.cards.length;
|
|
}
|
|
|
|
// eslint-disable-next-line no-console
|
|
// console.log('sessionId:', sessionId);
|
|
// eslint-disable-next-line no-console
|
|
// console.log('userId:', userId);
|
|
// eslint-disable-next-line no-console
|
|
// console.log('update:', update);
|
|
SessionData.upsert({ userId, sessionId }, update);
|
|
|
|
// remove old session data
|
|
SessionData.remove({
|
|
userId,
|
|
modifiedAt: {
|
|
$lt: new Date(
|
|
moment()
|
|
.subtract(1, 'day')
|
|
.format(),
|
|
),
|
|
},
|
|
});
|
|
|
|
if (cards) {
|
|
const boards = [];
|
|
const swimlanes = [];
|
|
const lists = [];
|
|
const customFieldIds = [];
|
|
const users = [this.userId];
|
|
|
|
cards.forEach(card => {
|
|
if (card.boardId) boards.push(card.boardId);
|
|
if (card.swimlaneId) swimlanes.push(card.swimlaneId);
|
|
if (card.listId) lists.push(card.listId);
|
|
if (card.userId) {
|
|
users.push(card.userId);
|
|
}
|
|
if (card.members) {
|
|
card.members.forEach(userId => {
|
|
users.push(userId);
|
|
});
|
|
}
|
|
if (card.assignees) {
|
|
card.assignees.forEach(userId => {
|
|
users.push(userId);
|
|
});
|
|
}
|
|
if (card.customFields) {
|
|
card.customFields.forEach(field => {
|
|
customFieldIds.push(field._id);
|
|
});
|
|
}
|
|
});
|
|
|
|
const fields = {
|
|
_id: 1,
|
|
title: 1,
|
|
archived: 1,
|
|
sort: 1,
|
|
type: 1,
|
|
};
|
|
|
|
return [
|
|
cards,
|
|
Boards.find(
|
|
{ _id: { $in: boards } },
|
|
{ fields: { ...fields, labels: 1, color: 1 } },
|
|
),
|
|
Swimlanes.find(
|
|
{ _id: { $in: swimlanes } },
|
|
{ fields: { ...fields, color: 1 } },
|
|
),
|
|
Lists.find({ _id: { $in: lists } }, { fields }),
|
|
CustomFields.find({ _id: { $in: customFieldIds } }),
|
|
Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
|
|
Checklists.find({ cardId: { $in: cards.map(c => c._id) } }),
|
|
ChecklistItems.find({ cardId: { $in: cards.map(c => c._id) } }),
|
|
Attachments.find({ cardId: { $in: cards.map(c => c._id) } }),
|
|
CardComments.find({ cardId: { $in: cards.map(c => c._id) } }),
|
|
SessionData.find({ userId, sessionId }),
|
|
];
|
|
}
|
|
|
|
return [SessionData.find({ userId, sessionId })];
|
|
}
|