2021-01-25 15:39:36 +02:00
|
|
|
const escapeForRegex = require('escape-string-regexp');
|
|
|
|
|
2019-12-22 09:44:58 +02:00
|
|
|
Meteor.publish('card', cardId => {
|
|
|
|
check(cardId, String);
|
|
|
|
return Cards.find({ _id: cardId });
|
|
|
|
});
|
2020-12-31 19:14:55 +02:00
|
|
|
|
|
|
|
Meteor.publish('myCards', function() {
|
2021-01-10 18:08:03 +02:00
|
|
|
const userId = Meteor.userId();
|
2020-12-31 19:14:55 +02:00
|
|
|
|
2021-01-10 18:08:03 +02:00
|
|
|
const archivedBoards = [];
|
|
|
|
Boards.find({ archived: true }).forEach(board => {
|
|
|
|
archivedBoards.push(board._id);
|
|
|
|
});
|
|
|
|
|
|
|
|
const archivedSwimlanes = [];
|
|
|
|
Swimlanes.find({ archived: true }).forEach(swimlane => {
|
|
|
|
archivedSwimlanes.push(swimlane._id);
|
|
|
|
});
|
|
|
|
|
|
|
|
const archivedLists = [];
|
|
|
|
Lists.find({ archived: true }).forEach(list => {
|
|
|
|
archivedLists.push(list._id);
|
|
|
|
});
|
|
|
|
|
|
|
|
selector = {
|
|
|
|
archived: false,
|
|
|
|
boardId: { $nin: archivedBoards },
|
|
|
|
swimlaneId: { $nin: archivedSwimlanes },
|
|
|
|
listId: { $nin: archivedLists },
|
|
|
|
$or: [{ members: userId }, { assignees: userId }],
|
|
|
|
};
|
|
|
|
|
|
|
|
const cards = Cards.find(selector, {
|
|
|
|
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,
|
2020-12-31 19:14:55 +02:00
|
|
|
},
|
2021-01-10 18:08:03 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
const boards = [];
|
|
|
|
const swimlanes = [];
|
|
|
|
const lists = [];
|
|
|
|
const users = [];
|
|
|
|
|
|
|
|
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.members) {
|
|
|
|
card.members.forEach(userId => {
|
|
|
|
users.push(userId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (card.assignees) {
|
|
|
|
card.assignees.forEach(userId => {
|
|
|
|
users.push(userId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return [
|
|
|
|
cards,
|
|
|
|
Boards.find({ _id: { $in: boards } }),
|
|
|
|
Swimlanes.find({ _id: { $in: swimlanes } }),
|
|
|
|
Lists.find({ _id: { $in: lists } }),
|
2021-01-16 19:20:31 +02:00
|
|
|
Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
|
2021-01-10 18:08:03 +02:00
|
|
|
];
|
2020-12-31 19:14:55 +02:00
|
|
|
});
|
2021-01-07 22:36:10 +02:00
|
|
|
|
|
|
|
Meteor.publish('dueCards', function(allUsers = false) {
|
|
|
|
check(allUsers, Boolean);
|
|
|
|
|
2021-01-09 18:36:27 +02:00
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
// console.log('all users:', allUsers);
|
|
|
|
|
2021-01-16 19:20:31 +02:00
|
|
|
const user = Users.findOne({ _id: this.userId });
|
2021-01-07 22:36:10 +02:00
|
|
|
|
|
|
|
const archivedBoards = [];
|
|
|
|
Boards.find({ archived: true }).forEach(board => {
|
|
|
|
archivedBoards.push(board._id);
|
|
|
|
});
|
|
|
|
|
|
|
|
const permiitedBoards = [];
|
|
|
|
let selector = {
|
|
|
|
archived: false,
|
|
|
|
};
|
2021-01-16 19:20:31 +02:00
|
|
|
|
2021-01-11 05:23:11 +02:00
|
|
|
selector.$or = [
|
|
|
|
{ permission: 'public' },
|
|
|
|
{ members: { $elemMatch: { userId: user._id, isActive: true } } },
|
|
|
|
];
|
2021-01-16 19:20:31 +02:00
|
|
|
|
2021-01-07 22:36:10 +02:00
|
|
|
Boards.find(selector).forEach(board => {
|
|
|
|
permiitedBoards.push(board._id);
|
|
|
|
});
|
|
|
|
|
|
|
|
const archivedSwimlanes = [];
|
|
|
|
Swimlanes.find({ archived: true }).forEach(swimlane => {
|
|
|
|
archivedSwimlanes.push(swimlane._id);
|
|
|
|
});
|
|
|
|
|
|
|
|
const archivedLists = [];
|
|
|
|
Lists.find({ archived: true }).forEach(list => {
|
|
|
|
archivedLists.push(list._id);
|
|
|
|
});
|
|
|
|
|
|
|
|
selector = {
|
|
|
|
archived: false,
|
|
|
|
boardId: { $nin: archivedBoards, $in: permiitedBoards },
|
|
|
|
swimlaneId: { $nin: archivedSwimlanes },
|
|
|
|
listId: { $nin: archivedLists },
|
|
|
|
dueAt: { $ne: null },
|
|
|
|
endAt: null,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!allUsers) {
|
|
|
|
selector.$or = [{ members: user._id }, { assignees: user._id }];
|
|
|
|
}
|
|
|
|
|
|
|
|
const cards = Cards.find(selector, {
|
|
|
|
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,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const boards = [];
|
|
|
|
const swimlanes = [];
|
|
|
|
const lists = [];
|
2021-01-10 18:08:03 +02:00
|
|
|
const users = [];
|
2021-01-07 22:36:10 +02:00
|
|
|
|
|
|
|
cards.forEach(card => {
|
2021-01-08 21:51:28 +02:00
|
|
|
if (card.boardId) boards.push(card.boardId);
|
|
|
|
if (card.swimlaneId) swimlanes.push(card.swimlaneId);
|
|
|
|
if (card.listId) lists.push(card.listId);
|
2021-01-10 18:08:03 +02:00
|
|
|
if (card.members) {
|
|
|
|
card.members.forEach(userId => {
|
|
|
|
users.push(userId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (card.assignees) {
|
|
|
|
card.assignees.forEach(userId => {
|
|
|
|
users.push(userId);
|
|
|
|
});
|
|
|
|
}
|
2021-01-07 22:36:10 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
return [
|
|
|
|
cards,
|
|
|
|
Boards.find({ _id: { $in: boards } }),
|
|
|
|
Swimlanes.find({ _id: { $in: swimlanes } }),
|
|
|
|
Lists.find({ _id: { $in: lists } }),
|
2021-01-16 19:20:31 +02:00
|
|
|
Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
|
2021-01-07 22:36:10 +02:00
|
|
|
];
|
|
|
|
});
|
2021-01-10 22:58:29 +02:00
|
|
|
|
2021-01-24 12:28:36 +02:00
|
|
|
Meteor.publish('globalSearch', function(sessionId, queryParams) {
|
|
|
|
check(sessionId, String);
|
2021-01-10 22:58:29 +02:00
|
|
|
check(queryParams, Object);
|
|
|
|
|
2021-01-27 16:15:54 +02:00
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
// console.log('queryParams:', queryParams);
|
|
|
|
|
2021-01-25 15:39:36 +02:00
|
|
|
const userId = Meteor.userId();
|
2021-01-10 22:58:29 +02:00
|
|
|
// eslint-disable-next-line no-console
|
2021-01-25 15:39:36 +02:00
|
|
|
// console.log('userId:', userId);
|
|
|
|
|
|
|
|
const errors = new (class {
|
|
|
|
constructor() {
|
|
|
|
this.notFound = {
|
|
|
|
boards: [],
|
|
|
|
swimlanes: [],
|
|
|
|
lists: [],
|
|
|
|
labels: [],
|
|
|
|
users: [],
|
|
|
|
members: [],
|
|
|
|
assignees: [],
|
2021-01-26 18:39:09 +02:00
|
|
|
status: [],
|
2021-01-25 15:39:36 +02:00
|
|
|
comments: [],
|
|
|
|
};
|
|
|
|
|
2021-02-02 17:56:18 +02:00
|
|
|
this.colorMap = Boards.colorMap();
|
2021-01-25 15:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
hasErrors() {
|
2021-01-27 02:21:12 +02:00
|
|
|
for (const value of Object.values(this.notFound)) {
|
|
|
|
if (value.length) {
|
2021-01-25 15:39:36 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2021-01-10 22:58:29 +02:00
|
|
|
|
2021-01-25 15:39:36 +02:00
|
|
|
errorMessages() {
|
|
|
|
const messages = [];
|
|
|
|
|
|
|
|
this.notFound.boards.forEach(board => {
|
|
|
|
messages.push({ tag: 'board-title-not-found', value: board });
|
|
|
|
});
|
|
|
|
this.notFound.swimlanes.forEach(swim => {
|
|
|
|
messages.push({ tag: 'swimlane-title-not-found', value: swim });
|
|
|
|
});
|
|
|
|
this.notFound.lists.forEach(list => {
|
|
|
|
messages.push({ tag: 'list-title-not-found', value: list });
|
|
|
|
});
|
|
|
|
this.notFound.comments.forEach(comments => {
|
|
|
|
comments.forEach(text => {
|
|
|
|
messages.push({ tag: 'comment-not-found', value: text });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
this.notFound.labels.forEach(label => {
|
2021-02-02 17:56:18 +02:00
|
|
|
messages.push({
|
|
|
|
tag: 'label-not-found',
|
|
|
|
value: label,
|
|
|
|
color: Boards.labelColors().includes(label),
|
|
|
|
});
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
|
|
|
this.notFound.users.forEach(user => {
|
|
|
|
messages.push({ tag: 'user-username-not-found', value: user });
|
|
|
|
});
|
|
|
|
this.notFound.members.forEach(user => {
|
|
|
|
messages.push({ tag: 'user-username-not-found', value: user });
|
|
|
|
});
|
|
|
|
this.notFound.assignees.forEach(user => {
|
|
|
|
messages.push({ tag: 'user-username-not-found', value: user });
|
|
|
|
});
|
|
|
|
|
|
|
|
return messages;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
let selector = {};
|
|
|
|
let skip = 0;
|
|
|
|
if (queryParams.skip) {
|
|
|
|
skip = queryParams.skip;
|
|
|
|
}
|
|
|
|
let limit = 25;
|
|
|
|
if (queryParams.limit) {
|
|
|
|
limit = queryParams.limit;
|
2021-01-26 18:39:09 +02:00
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (queryParams.selector) {
|
|
|
|
selector = queryParams.selector;
|
|
|
|
} else {
|
2021-02-23 17:56:28 +02:00
|
|
|
const boardsSelector = {};
|
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
let archived = false;
|
|
|
|
let endAt = null;
|
|
|
|
if (queryParams.status.length) {
|
|
|
|
queryParams.status.forEach(status => {
|
|
|
|
if (status === 'archived') {
|
|
|
|
archived = true;
|
|
|
|
} else if (status === 'all') {
|
|
|
|
archived = null;
|
|
|
|
} else if (status === 'ended') {
|
|
|
|
endAt = { $nin: [null, ''] };
|
2021-02-23 17:56:28 +02:00
|
|
|
} else if (['private', 'public'].includes(status)) {
|
|
|
|
boardsSelector.permission = status;
|
2021-01-27 02:21:12 +02:00
|
|
|
}
|
2021-01-26 18:39:09 +02:00
|
|
|
});
|
|
|
|
}
|
2021-01-27 02:21:12 +02:00
|
|
|
selector = {
|
|
|
|
type: 'cardType-card',
|
|
|
|
// boardId: { $in: Boards.userBoardIds(userId) },
|
|
|
|
$and: [],
|
|
|
|
};
|
2021-01-26 18:39:09 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (archived !== null) {
|
|
|
|
if (archived) {
|
2021-02-23 17:56:28 +02:00
|
|
|
selector.boardId = {
|
|
|
|
$in: Boards.userBoardIds(userId, null, boardsSelector),
|
|
|
|
};
|
2021-01-27 02:21:12 +02:00
|
|
|
selector.$and.push({
|
|
|
|
$or: [
|
2021-02-23 17:56:28 +02:00
|
|
|
{
|
|
|
|
boardId: {
|
|
|
|
$in: Boards.userBoardIds(userId, archived, boardsSelector),
|
|
|
|
},
|
|
|
|
},
|
2021-01-27 02:21:12 +02:00
|
|
|
{ swimlaneId: { $in: Swimlanes.archivedSwimlaneIds() } },
|
|
|
|
{ listId: { $in: Lists.archivedListIds() } },
|
|
|
|
{ archived: true },
|
|
|
|
],
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
|
|
|
} else {
|
2021-02-23 17:56:28 +02:00
|
|
|
selector.boardId = {
|
|
|
|
$in: Boards.userBoardIds(userId, false, boardsSelector),
|
|
|
|
};
|
2021-01-27 02:21:12 +02:00
|
|
|
selector.swimlaneId = { $nin: Swimlanes.archivedSwimlaneIds() };
|
|
|
|
selector.listId = { $nin: Lists.archivedListIds() };
|
|
|
|
selector.archived = false;
|
2021-01-25 15:39:36 +02:00
|
|
|
}
|
2021-01-27 02:21:12 +02:00
|
|
|
} else {
|
2021-02-23 17:56:28 +02:00
|
|
|
selector.boardId = {
|
|
|
|
$in: Boards.userBoardIds(userId, null, boardsSelector),
|
|
|
|
};
|
2021-01-27 02:21:12 +02:00
|
|
|
}
|
|
|
|
if (endAt !== null) {
|
|
|
|
selector.endAt = endAt;
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (queryParams.boards.length) {
|
|
|
|
const queryBoards = [];
|
|
|
|
queryParams.boards.forEach(query => {
|
|
|
|
const boards = Boards.userSearch(userId, {
|
|
|
|
title: new RegExp(escapeForRegex(query), 'i'),
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
2021-01-27 02:21:12 +02:00
|
|
|
if (boards.count()) {
|
|
|
|
boards.forEach(board => {
|
|
|
|
queryBoards.push(board._id);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
errors.notFound.boards.push(query);
|
|
|
|
}
|
|
|
|
});
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
selector.boardId.$in = queryBoards;
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (queryParams.swimlanes.length) {
|
|
|
|
const querySwimlanes = [];
|
|
|
|
queryParams.swimlanes.forEach(query => {
|
|
|
|
const swimlanes = Swimlanes.find({
|
|
|
|
title: new RegExp(escapeForRegex(query), 'i'),
|
|
|
|
});
|
|
|
|
if (swimlanes.count()) {
|
|
|
|
swimlanes.forEach(swim => {
|
|
|
|
querySwimlanes.push(swim._id);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
errors.notFound.swimlanes.push(query);
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
2021-01-27 02:21:12 +02:00
|
|
|
|
2021-02-21 01:39:34 +02:00
|
|
|
// eslint-disable-next-line no-prototype-builtins
|
2021-01-27 16:15:54 +02:00
|
|
|
if (!selector.swimlaneId.hasOwnProperty('swimlaneId')) {
|
|
|
|
selector.swimlaneId = { $in: [] };
|
|
|
|
}
|
2021-01-27 02:21:12 +02:00
|
|
|
selector.swimlaneId.$in = querySwimlanes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queryParams.lists.length) {
|
|
|
|
const queryLists = [];
|
|
|
|
queryParams.lists.forEach(query => {
|
|
|
|
const lists = Lists.find({
|
|
|
|
title: new RegExp(escapeForRegex(query), 'i'),
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
2021-01-27 02:21:12 +02:00
|
|
|
if (lists.count()) {
|
|
|
|
lists.forEach(list => {
|
|
|
|
queryLists.push(list._id);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
errors.notFound.lists.push(query);
|
|
|
|
}
|
|
|
|
});
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-02-21 01:39:34 +02:00
|
|
|
// eslint-disable-next-line no-prototype-builtins
|
2021-01-27 16:15:54 +02:00
|
|
|
if (!selector.hasOwnProperty('listId')) {
|
|
|
|
selector.listId = { $in: [] };
|
|
|
|
}
|
2021-01-27 02:21:12 +02:00
|
|
|
selector.listId.$in = queryLists;
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (queryParams.comments.length) {
|
|
|
|
const cardIds = CardComments.textSearch(userId, queryParams.comments).map(
|
|
|
|
com => {
|
|
|
|
return com.cardId;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
if (cardIds.length) {
|
|
|
|
selector._id = { $in: cardIds };
|
|
|
|
} else {
|
|
|
|
errors.notFound.comments.push(queryParams.comments);
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
}
|
|
|
|
|
2021-02-26 01:13:45 +02:00
|
|
|
['dueAt', 'createdAt', 'modifiedAt'].forEach(field => {
|
|
|
|
if (queryParams[field]) {
|
|
|
|
selector[field] = {};
|
|
|
|
selector[field][queryParams[field]['operator']] = new Date(
|
|
|
|
queryParams[field]['value'],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
const queryMembers = [];
|
|
|
|
const queryAssignees = [];
|
|
|
|
if (queryParams.users.length) {
|
|
|
|
queryParams.users.forEach(query => {
|
|
|
|
const users = Users.find({
|
|
|
|
username: query,
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
2021-01-27 02:21:12 +02:00
|
|
|
if (users.count()) {
|
|
|
|
users.forEach(user => {
|
|
|
|
queryMembers.push(user._id);
|
|
|
|
queryAssignees.push(user._id);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
errors.notFound.users.push(query);
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
2021-01-27 02:21:12 +02:00
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (queryParams.members.length) {
|
|
|
|
queryParams.members.forEach(query => {
|
|
|
|
const users = Users.find({
|
|
|
|
username: query,
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
2021-01-27 02:21:12 +02:00
|
|
|
if (users.count()) {
|
|
|
|
users.forEach(user => {
|
|
|
|
queryMembers.push(user._id);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
errors.notFound.members.push(query);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (queryParams.assignees.length) {
|
|
|
|
queryParams.assignees.forEach(query => {
|
|
|
|
const users = Users.find({
|
|
|
|
username: query,
|
|
|
|
});
|
|
|
|
if (users.count()) {
|
|
|
|
users.forEach(user => {
|
|
|
|
queryAssignees.push(user._id);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
errors.notFound.assignees.push(query);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (queryMembers.length && queryAssignees.length) {
|
|
|
|
selector.$and.push({
|
|
|
|
$or: [
|
|
|
|
{ members: { $in: queryMembers } },
|
|
|
|
{ assignees: { $in: queryAssignees } },
|
|
|
|
],
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
2021-01-27 02:21:12 +02:00
|
|
|
} else if (queryMembers.length) {
|
|
|
|
selector.members = { $in: queryMembers };
|
|
|
|
} else if (queryAssignees.length) {
|
|
|
|
selector.assignees = { $in: queryAssignees };
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (queryParams.labels.length) {
|
|
|
|
queryParams.labels.forEach(label => {
|
|
|
|
const queryLabels = [];
|
|
|
|
|
|
|
|
let boards = Boards.userSearch(userId, {
|
|
|
|
labels: { $elemMatch: { color: label.toLowerCase() } },
|
2021-01-25 15:39:36 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
if (boards.count()) {
|
|
|
|
boards.forEach(board => {
|
2021-01-27 02:21:12 +02:00
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
// console.log('board:', board);
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
// console.log('board.labels:', board.labels);
|
2021-01-25 15:39:36 +02:00
|
|
|
board.labels
|
|
|
|
.filter(boardLabel => {
|
2021-01-27 02:21:12 +02:00
|
|
|
return boardLabel.color === label.toLowerCase();
|
2021-01-25 15:39:36 +02:00
|
|
|
})
|
|
|
|
.forEach(boardLabel => {
|
|
|
|
queryLabels.push(boardLabel._id);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
2021-01-27 02:21:12 +02:00
|
|
|
// 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.userSearch(userId, {
|
|
|
|
labels: { $elemMatch: { name: reLabel } },
|
|
|
|
});
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
if (boards.count()) {
|
|
|
|
boards.forEach(board => {
|
|
|
|
board.labels
|
|
|
|
.filter(boardLabel => {
|
|
|
|
return boardLabel.name.match(reLabel);
|
|
|
|
})
|
|
|
|
.forEach(boardLabel => {
|
|
|
|
queryLabels.push(boardLabel._id);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
errors.notFound.labels.push(label);
|
|
|
|
}
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
selector.labelIds = { $in: queryLabels };
|
|
|
|
});
|
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-02-21 01:41:58 +02:00
|
|
|
if (queryParams.has.length) {
|
|
|
|
queryParams.has.forEach(has => {
|
|
|
|
if (has === 'description') {
|
|
|
|
selector.description = { $exists: true, $nin: [null, ''] };
|
|
|
|
} else if (has === 'attachment') {
|
|
|
|
const attachments = Attachments.find({}, { fields: { cardId: 1 } });
|
|
|
|
selector.$and.push({ _id: { $in: attachments.map(a => a.cardId) } });
|
|
|
|
} else if (has === 'checklist') {
|
|
|
|
const checklists = Checklists.find({}, { fields: { cardId: 1 } });
|
|
|
|
selector.$and.push({ _id: { $in: checklists.map(a => a.cardId) } });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-01-25 15:39:36 +02:00
|
|
|
if (queryParams.text) {
|
|
|
|
const regex = new RegExp(escapeForRegex(queryParams.text), 'i');
|
2021-02-21 01:39:34 +02:00
|
|
|
|
|
|
|
const items = ChecklistItems.find(
|
|
|
|
{ title: regex },
|
|
|
|
{ fields: { cardId: 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 });
|
|
|
|
|
2021-02-25 18:38:51 +02:00
|
|
|
// const comments = CardComments.find(
|
|
|
|
// { text: regex },
|
|
|
|
// { fields: { cardId: 1 } },
|
|
|
|
// );
|
|
|
|
|
2021-01-26 18:39:09 +02:00
|
|
|
selector.$and.push({
|
|
|
|
$or: [
|
|
|
|
{ title: regex },
|
|
|
|
{ description: regex },
|
|
|
|
{ customFields: { $elemMatch: { value: regex } } },
|
|
|
|
{
|
|
|
|
_id: {
|
|
|
|
$in: CardComments.textSearch(userId, [queryParams.text]).map(
|
|
|
|
com => com.cardId,
|
|
|
|
),
|
|
|
|
},
|
2021-01-25 15:39:36 +02:00
|
|
|
},
|
2021-02-20 18:35:44 +02:00
|
|
|
{ _id: { $in: checklists.map(list => list.cardId) } },
|
2021-02-21 01:39:34 +02:00
|
|
|
{ _id: { $in: attachments.map(attach => attach.cardId) } },
|
2021-02-25 18:38:51 +02:00
|
|
|
// { _id: { $in: comments.map(com => com.cardId) } },
|
2021-01-26 18:39:09 +02:00
|
|
|
],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selector.$and.length === 0) {
|
|
|
|
delete selector.$and;
|
2021-01-25 15:39:36 +02:00
|
|
|
}
|
2021-01-27 02:21:12 +02:00
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-01-27 02:21:12 +02:00
|
|
|
// eslint-disable-next-line no-console
|
2021-01-27 16:15:54 +02:00
|
|
|
// console.log('selector:', selector);
|
2021-01-27 02:21:12 +02:00
|
|
|
// eslint-disable-next-line no-console
|
2021-01-27 16:15:54 +02:00
|
|
|
// console.log('selector.$and:', selector.$and);
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-02-25 18:38:51 +02:00
|
|
|
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,
|
|
|
|
},
|
|
|
|
sort: {
|
|
|
|
boardId: 1,
|
|
|
|
swimlaneId: 1,
|
|
|
|
listId: 1,
|
|
|
|
sort: 1,
|
|
|
|
},
|
|
|
|
skip,
|
|
|
|
limit,
|
|
|
|
};
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-02-25 18:38:51 +02:00
|
|
|
if (queryParams.sort) {
|
|
|
|
const order = queryParams.sort.order === 'asc' ? 1 : -1;
|
|
|
|
switch (queryParams.sort.name) {
|
|
|
|
case 'dueAt':
|
|
|
|
projection.sort = {
|
|
|
|
dueAt: order,
|
|
|
|
boardId: 1,
|
|
|
|
swimlaneId: 1,
|
|
|
|
listId: 1,
|
|
|
|
sort: 1,
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
case 'modifiedAt':
|
|
|
|
projection.sort = {
|
|
|
|
modifiedAt: order,
|
|
|
|
boardId: 1,
|
|
|
|
swimlaneId: 1,
|
|
|
|
listId: 1,
|
|
|
|
sort: 1,
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
case 'createdAt':
|
|
|
|
projection.sort = {
|
|
|
|
createdAt: order,
|
|
|
|
boardId: 1,
|
|
|
|
swimlaneId: 1,
|
|
|
|
listId: 1,
|
|
|
|
sort: 1,
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
case 'system':
|
|
|
|
projection.sort = {
|
|
|
|
boardId: order,
|
|
|
|
swimlaneId: order,
|
|
|
|
listId: order,
|
|
|
|
modifiedAt: order,
|
|
|
|
sort: order,
|
|
|
|
};
|
|
|
|
break;
|
2021-01-25 15:39:36 +02:00
|
|
|
}
|
2021-02-25 18:38:51 +02:00
|
|
|
}
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-02-25 18:38:51 +02:00
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
// console.log('projection:', projection);
|
|
|
|
|
|
|
|
return findCards(sessionId, selector, projection, errors);
|
|
|
|
});
|
|
|
|
|
|
|
|
Meteor.publish('brokenCards', function() {
|
|
|
|
const user = Users.findOne({ _id: this.userId });
|
|
|
|
|
|
|
|
const permiitedBoards = [null];
|
|
|
|
let selector = {};
|
|
|
|
selector.$or = [
|
|
|
|
{ permission: 'public' },
|
|
|
|
{ members: { $elemMatch: { userId: user._id, isActive: true } } },
|
|
|
|
];
|
|
|
|
|
|
|
|
Boards.find(selector).forEach(board => {
|
|
|
|
permiitedBoards.push(board._id);
|
|
|
|
});
|
|
|
|
|
|
|
|
selector = {
|
|
|
|
boardId: { $in: permiitedBoards },
|
|
|
|
$or: [
|
|
|
|
{ boardId: { $in: [null, ''] } },
|
|
|
|
{ swimlaneId: { $in: [null, ''] } },
|
|
|
|
{ listId: { $in: [null, ''] } },
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
const cards = Cards.find(selector, {
|
|
|
|
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,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const boards = [];
|
|
|
|
const swimlanes = [];
|
|
|
|
const lists = [];
|
|
|
|
const users = [];
|
|
|
|
|
|
|
|
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.members) {
|
|
|
|
card.members.forEach(userId => {
|
|
|
|
users.push(userId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (card.assignees) {
|
|
|
|
card.assignees.forEach(userId => {
|
|
|
|
users.push(userId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return [
|
|
|
|
cards,
|
|
|
|
Boards.find({ _id: { $in: boards } }),
|
|
|
|
Swimlanes.find({ _id: { $in: swimlanes } }),
|
|
|
|
Lists.find({ _id: { $in: lists } }),
|
|
|
|
Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
|
|
|
|
];
|
|
|
|
});
|
|
|
|
|
|
|
|
Meteor.publish('nextPage', function(sessionId) {
|
|
|
|
check(sessionId, String);
|
2021-01-25 15:39:36 +02:00
|
|
|
|
2021-02-25 18:38:51 +02:00
|
|
|
const session = SessionData.findOne({ sessionId });
|
|
|
|
const projection = session.getProjection();
|
|
|
|
projection.skip = session.lastHit;
|
|
|
|
|
|
|
|
return findCards(sessionId, 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, session.getSelector(), projection);
|
|
|
|
});
|
|
|
|
|
|
|
|
function findCards(sessionId, selector, projection, errors = null) {
|
|
|
|
const userId = Meteor.userId();
|
|
|
|
|
2021-02-26 17:31:44 +02:00
|
|
|
console.log('selector:', selector);
|
|
|
|
console.log('projection:', projection);
|
2021-02-26 23:19:12 +02:00
|
|
|
// if (selector.dueAt) {
|
|
|
|
// console.log('dueAt:', typeof selector.dueAt.$lt, selector.dueAt.$lt.constructor.name, selector.dueAt.$lt);
|
|
|
|
// }
|
2021-02-25 18:38:51 +02:00
|
|
|
let cards;
|
|
|
|
if (!errors || !errors.hasErrors()) {
|
|
|
|
cards = Cards.find(selector, projection);
|
2021-01-25 15:39:36 +02:00
|
|
|
}
|
2021-02-25 18:38:51 +02:00
|
|
|
console.log('count:', cards.count());
|
2021-02-26 23:19:12 +02:00
|
|
|
|
2021-01-24 02:32:37 +02:00
|
|
|
const update = {
|
|
|
|
$set: {
|
|
|
|
totalHits: 0,
|
|
|
|
lastHit: 0,
|
2021-01-27 02:21:12 +02:00
|
|
|
resultsCount: 0,
|
2021-01-24 02:32:37 +02:00
|
|
|
cards: [],
|
2021-01-27 16:15:54 +02:00
|
|
|
selector: SessionData.pickle(selector),
|
2021-02-25 18:38:51 +02:00
|
|
|
projection: SessionData.pickle(projection),
|
2021-01-24 02:32:37 +02:00
|
|
|
},
|
|
|
|
};
|
2021-02-25 18:38:51 +02:00
|
|
|
if (errors) {
|
|
|
|
update.$set.errors = errors.errorMessages();
|
|
|
|
}
|
2021-01-10 22:58:29 +02:00
|
|
|
|
2021-01-24 02:32:37 +02:00
|
|
|
if (cards) {
|
|
|
|
update.$set.totalHits = cards.count();
|
2021-01-27 02:21:12 +02:00
|
|
|
update.$set.lastHit =
|
2021-02-25 18:38:51 +02:00
|
|
|
projection.skip + projection.limit < cards.count()
|
|
|
|
? projection.skip + projection.limit
|
|
|
|
: cards.count();
|
2021-01-24 02:32:37 +02:00
|
|
|
update.$set.cards = cards.map(card => {
|
|
|
|
return card._id;
|
|
|
|
});
|
2021-01-27 02:21:12 +02:00
|
|
|
update.$set.resultsCount = update.$set.cards.length;
|
2021-01-17 16:01:42 +02:00
|
|
|
}
|
|
|
|
|
2021-01-25 16:12:33 +02:00
|
|
|
SessionData.upsert({ userId, sessionId }, update);
|
|
|
|
|
|
|
|
// remove old session data
|
|
|
|
SessionData.remove({
|
|
|
|
userId,
|
|
|
|
modifiedAt: {
|
|
|
|
$lt: new Date(
|
|
|
|
moment()
|
|
|
|
.subtract(1, 'day')
|
|
|
|
.format(),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
});
|
2021-01-16 19:20:31 +02:00
|
|
|
|
2021-01-24 02:32:37 +02:00
|
|
|
if (cards) {
|
2021-01-25 15:39:36 +02:00
|
|
|
const boards = [];
|
|
|
|
const swimlanes = [];
|
|
|
|
const lists = [];
|
2021-01-27 17:06:57 +02:00
|
|
|
const customFieldIds = [];
|
2021-01-25 15:39:36 +02:00
|
|
|
const users = [this.userId];
|
|
|
|
|
2021-01-24 02:32:37 +02:00
|
|
|
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.members) {
|
|
|
|
card.members.forEach(userId => {
|
|
|
|
users.push(userId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (card.assignees) {
|
|
|
|
card.assignees.forEach(userId => {
|
|
|
|
users.push(userId);
|
|
|
|
});
|
|
|
|
}
|
2021-01-27 17:06:57 +02:00
|
|
|
if (card.customFields) {
|
|
|
|
card.customFields.forEach(field => {
|
|
|
|
customFieldIds.push(field._id);
|
|
|
|
});
|
|
|
|
}
|
2021-01-24 02:32:37 +02:00
|
|
|
});
|
2021-01-10 22:58:29 +02:00
|
|
|
|
2021-01-25 15:39:36 +02:00
|
|
|
const fields = {
|
|
|
|
_id: 1,
|
|
|
|
title: 1,
|
|
|
|
archived: 1,
|
2021-01-25 15:55:35 +02:00
|
|
|
sort: 1,
|
|
|
|
type: 1,
|
2021-01-25 15:39:36 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
return [
|
|
|
|
cards,
|
2021-01-25 15:55:35 +02:00
|
|
|
Boards.find(
|
|
|
|
{ _id: { $in: boards } },
|
|
|
|
{ fields: { ...fields, labels: 1, color: 1 } },
|
|
|
|
),
|
|
|
|
Swimlanes.find(
|
|
|
|
{ _id: { $in: swimlanes } },
|
|
|
|
{ fields: { ...fields, color: 1 } },
|
|
|
|
),
|
2021-01-25 15:39:36 +02:00
|
|
|
Lists.find({ _id: { $in: lists } }, { fields }),
|
2021-01-27 17:06:57 +02:00
|
|
|
CustomFields.find({ _id: { $in: customFieldIds } }),
|
2021-01-25 15:39:36 +02:00
|
|
|
Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
|
2021-02-23 17:56:28 +02:00
|
|
|
Checklists.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) } }),
|
2021-02-25 18:38:51 +02:00
|
|
|
SessionData.find({ userId, sessionId }),
|
2021-01-25 15:39:36 +02:00
|
|
|
];
|
2021-01-24 02:32:37 +02:00
|
|
|
}
|
|
|
|
|
2021-02-25 18:38:51 +02:00
|
|
|
return [SessionData.find({ userId: userId, sessionId })];
|
|
|
|
}
|