Update ReactiveCache call sites to use async/await for Meteor 3.0

Part 3 of ReactiveCache async migration:
- Add await before all ReactiveCache.getX() calls
- Make functions containing ReactiveCache calls async
- Convert forEach/map/filter loops with async callbacks to for...of
- Update model helpers, Meteor methods, JsonRoutes handlers
- Update collection hooks (.before/.after insert/update/remove)
- Update .allow() callbacks to async

Files updated across models/ and server/ directories:
- Model files: cards, boards, lists, swimlanes, activities, users,
  checklists, checklistItems, customFields, attachments, integrations,
  cardComments, settings files, creators, exporters, and more
- Server files: publications, methods, notifications, routes, migrations
This commit is contained in:
Harry Adel 2026-02-01 00:54:38 +02:00
parent 2f6e34c5f5
commit 71eb01e233
81 changed files with 2218 additions and 2148 deletions

View file

@ -5,7 +5,7 @@ import { ReactiveCache } from '/imports/reactiveCache';
// 2. The card activity tab
// We use this publication to paginate for these two publications.
Meteor.publish('activities', function(kind, id, limit, showActivities) {
Meteor.publish('activities', async function(kind, id, limit, showActivities) {
check(
kind,
Match.Where(x => {
@ -29,27 +29,27 @@ Meteor.publish('activities', function(kind, id, limit, showActivities) {
let board;
if (kind === 'board') {
board = ReactiveCache.getBoard(id);
board = await ReactiveCache.getBoard(id);
if (!board || !board.isVisibleBy(this.userId)) {
return this.ready();
}
// Get linked boards, but only those visible to the user
ReactiveCache.getCards({
(await ReactiveCache.getCards({
"type": "cardType-linkedBoard",
"boardId": id
}).forEach(card => {
const linkedBoard = ReactiveCache.getBoard(card.linkedId);
})).forEach(async card => {
const linkedBoard = await ReactiveCache.getBoard(card.linkedId);
if (linkedBoard && linkedBoard.isVisibleBy(this.userId)) {
linkedElmtId.push(card.linkedId);
}
});
} else if (kind === 'card') {
const card = ReactiveCache.getCard(id);
const card = await ReactiveCache.getCard(id);
if (!card) {
return this.ready();
}
board = ReactiveCache.getBoard(card.boardId);
board = await ReactiveCache.getBoard(card.boardId);
if (!board || !board.isVisibleBy(this.userId)) {
return this.ready();
}
@ -58,7 +58,7 @@ Meteor.publish('activities', function(kind, id, limit, showActivities) {
const selector = showActivities
? { [`${kind}Id`]: { $in: linkedElmtId } }
: { $and: [{ activityType: 'addComment' }, { [`${kind}Id`]: { $in: linkedElmtId } }] };
const ret = ReactiveCache.getActivities(selector,
const ret = await ReactiveCache.getActivities(selector,
{
limit,
sort: { createdAt: -1 },

View file

@ -1,16 +1,16 @@
import Attachments from '/models/attachments';
import { ObjectID } from 'bson';
Meteor.publish('attachmentsList', function(limit) {
Meteor.publish('attachmentsList', async function(limit) {
const userId = this.userId;
// Get boards the user has access to
const userBoards = ReactiveCache.getBoards({
const userBoards = (await ReactiveCache.getBoards({
$or: [
{ permission: 'public' },
{ members: { $elemMatch: { userId, isActive: true } } }
]
}).map(board => board._id);
})).map(board => board._id);
if (userBoards.length === 0) {
// User has no access to any boards, return empty cursor
@ -18,10 +18,10 @@ Meteor.publish('attachmentsList', function(limit) {
}
// Get cards from those boards
const userCards = ReactiveCache.getCards({
const userCards = (await ReactiveCache.getCards({
boardId: { $in: userBoards },
archived: false
}).map(card => card._id);
})).map(card => card._id);
if (userCards.length === 0) {
// No cards found, return empty cursor
@ -29,7 +29,7 @@ Meteor.publish('attachmentsList', function(limit) {
}
// Only return attachments for cards the user has access to
const ret = ReactiveCache.getAttachments(
const ret = (await ReactiveCache.getAttachments(
{ 'meta.cardId': { $in: userCards } },
{
fields: {
@ -47,6 +47,6 @@ Meteor.publish('attachmentsList', function(limit) {
limit: limit,
},
true,
).cursor;
)).cursor;
return ret;
});

View file

@ -1,5 +1,5 @@
import Avatars from '../../models/avatars';
Meteor.publish('my-avatars', function() {
const ret = ReactiveCache.getAvatars({ userId: this.userId }, {}, true).cursor;
Meteor.publish('my-avatars', async function() {
const ret = (await ReactiveCache.getAvatars({ userId: this.userId }, {}, true)).cursor;
return ret;
});

View file

@ -18,8 +18,8 @@ publishComposite('boards', function() {
}
return {
find() {
return ReactiveCache.getBoards(
async find() {
return await ReactiveCache.getBoards(
{
archived: false,
_id: { $in: Boards.userBoardIds(userId, false) },
@ -32,10 +32,10 @@ publishComposite('boards', function() {
},
children: [
{
find(board) {
async find(board) {
// Publish lists with extended fields for proper sync
// Including swimlaneId, modifiedAt, and _updatedAt for list order changes
return ReactiveCache.getLists(
return await ReactiveCache.getLists(
{ boardId: board._id, archived: false },
{
fields: {
@ -54,8 +54,8 @@ publishComposite('boards', function() {
}
},
{
find(board) {
return ReactiveCache.getCards(
async find(board) {
return await ReactiveCache.getCards(
{ boardId: board._id, archived: false },
{
fields: {
@ -74,13 +74,13 @@ publishComposite('boards', function() {
};
});
Meteor.publish('boardsReport', function() {
Meteor.publish('boardsReport', async function() {
const userId = this.userId;
// Ensure that the user is connected. If it is not, we need to return an empty
// array to tell the client to remove the previously published docs.
if (!Match.test(userId, String) || !userId) return [];
const boards = ReactiveCache.getBoards(
const boards = await ReactiveCache.getBoards(
{
_id: { $in: Boards.userBoardIds(userId, null) },
},
@ -129,18 +129,18 @@ Meteor.publish('boardsReport', function() {
const ret = [
boards,
ReactiveCache.getUsers({ _id: { $in: userIds } }, { fields: Users.safeFields }, true),
ReactiveCache.getTeams({ _id: { $in: teamIds } }, {}, true),
ReactiveCache.getOrgs({ _id: { $in: orgIds } }, {}, true),
await ReactiveCache.getUsers({ _id: { $in: userIds } }, { fields: Users.safeFields }, true),
await ReactiveCache.getTeams({ _id: { $in: teamIds } }, {}, true),
await ReactiveCache.getOrgs({ _id: { $in: orgIds } }, {}, true),
]
return ret;
});
Meteor.publish('archivedBoards', function() {
Meteor.publish('archivedBoards', async function() {
const userId = this.userId;
if (!Match.test(userId, String)) return [];
const ret = ReactiveCache.getBoards(
const ret = await ReactiveCache.getBoards(
{
_id: { $in: Boards.userBoardIds(userId, true)},
archived: true,
@ -170,14 +170,14 @@ Meteor.publish('archivedBoards', function() {
// If isArchived = false, this will only return board elements which are not archived.
// If isArchived = true, this will only return board elements which are archived.
publishComposite('board', function(boardId, isArchived) {
publishComposite('board', async function(boardId, isArchived) {
check(boardId, String);
check(isArchived, Boolean);
const thisUserId = this.userId;
const $or = [{ permission: 'public' }];
let currUser = (!Match.test(thisUserId, String) || !thisUserId) ? 'undefined' : ReactiveCache.getUser(thisUserId);
let currUser = (!Match.test(thisUserId, String) || !thisUserId) ? 'undefined' : await ReactiveCache.getUser(thisUserId);
let orgIdsUserBelongs = currUser !== 'undefined' && currUser.teams !== 'undefined' ? currUser.orgIdsUserBelongs() : '';
let teamIdsUserBelongs = currUser !== 'undefined' && currUser.teams !== 'undefined' ? currUser.teamIdsUserBelongs() : '';
let orgsIds = [];
@ -197,8 +197,8 @@ publishComposite('board', function(boardId, isArchived) {
}
return {
find() {
return ReactiveCache.getBoards(
async find() {
return await ReactiveCache.getBoards(
{
_id: boardId,
archived: false,
@ -212,32 +212,32 @@ publishComposite('board', function(boardId, isArchived) {
children: [
// Lists
{
find(board) {
return ReactiveCache.getLists({ boardId: board._id, archived: isArchived }, {}, true);
async find(board) {
return await ReactiveCache.getLists({ boardId: board._id, archived: isArchived }, {}, true);
}
},
// Swimlanes
{
find(board) {
return ReactiveCache.getSwimlanes({ boardId: board._id, archived: isArchived }, {}, true);
async find(board) {
return await ReactiveCache.getSwimlanes({ boardId: board._id, archived: isArchived }, {}, true);
}
},
// Integrations
{
find(board) {
return ReactiveCache.getIntegrations({ boardId: board._id }, {}, true);
async find(board) {
return await ReactiveCache.getIntegrations({ boardId: board._id }, {}, true);
}
},
// CardCommentReactions at board level
{
find(board) {
return ReactiveCache.getCardCommentReactions({ boardId: board._id }, {}, true);
async find(board) {
return await ReactiveCache.getCardCommentReactions({ boardId: board._id }, {}, true);
}
},
// CustomFields
{
find(board) {
return ReactiveCache.getCustomFields(
async find(board) {
return await ReactiveCache.getCustomFields(
{ boardIds: { $in: [board._id] } },
{ sort: { name: 1 } },
true,
@ -246,7 +246,7 @@ publishComposite('board', function(boardId, isArchived) {
},
// Cards and their related data
{
find(board) {
async find(board) {
const cardSelector = {
boardId: { $in: [board._id, board.subtasksDefaultBoardId] },
archived: isArchived,
@ -261,7 +261,7 @@ publishComposite('board', function(boardId, isArchived) {
}
}
return ReactiveCache.getCards(cardSelector, {}, true);
return await ReactiveCache.getCards(cardSelector, {}, true);
},
children: [
// CardComments for each card
@ -366,7 +366,7 @@ publishComposite('board', function(boardId, isArchived) {
},
// Board members/Users
{
find(board) {
async find(board) {
if (board.members) {
// Board members. This publication also includes former board members that
// aren't members anymore but may have some activities attached to them in
@ -376,7 +376,7 @@ publishComposite('board', function(boardId, isArchived) {
// We omit the current user because the client should already have that data,
// and sending it triggers a subtle bug:
// https://github.com/wefork/wekan/issues/15
return ReactiveCache.getUsers(
return await ReactiveCache.getUsers(
{
_id: { $in: _.without(memberIds, thisUserId) },
},
@ -399,12 +399,12 @@ publishComposite('board', function(boardId, isArchived) {
});
Meteor.methods({
copyBoard(boardId, properties) {
async copyBoard(boardId, properties) {
check(boardId, String);
check(properties, Object);
let ret = null;
const board = ReactiveCache.getBoard(boardId);
const board = await ReactiveCache.getBoard(boardId);
if (board) {
for (const key in properties) {
board[key] = properties[key];

View file

@ -74,21 +74,21 @@ import { CARD_TYPES } from '../../config/const';
import Org from "../../models/org";
import Team from "../../models/team";
Meteor.publish('card', cardId => {
Meteor.publish('card', async cardId => {
check(cardId, String);
const userId = Meteor.userId();
const card = ReactiveCache.getCard({ _id: cardId });
const card = await ReactiveCache.getCard({ _id: cardId });
if (!card || !card.boardId) {
return [];
}
const board = ReactiveCache.getBoard({ _id: card.boardId });
const board = await ReactiveCache.getBoard({ _id: card.boardId });
if (!board || !board.isVisibleBy(userId)) {
return [];
}
// If user has assigned-only permissions, check if they're assigned to this card
if (userId && board.members) {
const member = _.findWhere(board.members, { userId: userId, isActive: true });
@ -99,8 +99,8 @@ Meteor.publish('card', cardId => {
}
}
}
const ret = ReactiveCache.getCards(
const ret = await ReactiveCache.getCards(
{ _id: cardId },
{},
true,
@ -111,17 +111,17 @@ Meteor.publish('card', cardId => {
/** publish all data which is necessary to display card details as popup
* @returns array of cursors
*/
publishComposite('popupCardData', function(cardId) {
publishComposite('popupCardData', async function(cardId) {
check(cardId, String);
const userId = this.userId;
const card = ReactiveCache.getCard({ _id: cardId });
const card = await ReactiveCache.getCard({ _id: cardId });
if (!card || !card.boardId) {
return [];
}
const board = ReactiveCache.getBoard({ _id: card.boardId });
const board = await ReactiveCache.getBoard({ _id: card.boardId });
if (!board || !board.isVisibleBy(userId)) {
return [];
}
@ -138,29 +138,29 @@ publishComposite('popupCardData', function(cardId) {
}
return {
find() {
return ReactiveCache.getCards({ _id: cardId }, {}, true);
async find() {
return await ReactiveCache.getCards({ _id: cardId }, {}, true);
},
children: [
{
find(card) {
return ReactiveCache.getBoards({ _id: card.boardId }, {}, true);
async find(card) {
return await ReactiveCache.getBoards({ _id: card.boardId }, {}, true);
}
},
{
find(card) {
return ReactiveCache.getLists({ boardId: card.boardId }, {}, true);
async find(card) {
return await ReactiveCache.getLists({ boardId: card.boardId }, {}, true);
}
}
]
};
});
Meteor.publish('myCards', function(sessionId) {
Meteor.publish('myCards', async function(sessionId) {
check(sessionId, String);
const queryParams = new QueryParams();
queryParams.addPredicate(OPERATOR_USER, ReactiveCache.getCurrentUser().username);
queryParams.addPredicate(OPERATOR_USER, (await ReactiveCache.getCurrentUser()).username);
queryParams.setPredicate(OPERATOR_LIMIT, 200);
const query = buildQuery(queryParams);
@ -175,9 +175,9 @@ Meteor.publish('myCards', function(sessionId) {
});
// Optimized due cards publication for better performance
Meteor.publish('dueCards', function(allUsers = false) {
Meteor.publish('dueCards', async function(allUsers = false) {
check(allUsers, Boolean);
const userId = this.userId;
if (!userId) {
return this.ready();
@ -188,12 +188,12 @@ Meteor.publish('dueCards', function(allUsers = false) {
}
// Get user's board memberships for efficient filtering
const userBoards = ReactiveCache.getBoards({
const userBoards = (await ReactiveCache.getBoards({
$or: [
{ permission: 'public' },
{ members: { $elemMatch: { userId, isActive: true } } }
]
}).map(board => board._id);
})).map(board => board._id);
if (process.env.DEBUG === 'true') {
console.log('dueCards userBoards:', userBoards);
@ -273,7 +273,7 @@ Meteor.publish('dueCards', function(allUsers = false) {
return result;
});
Meteor.publish('globalSearch', function(sessionId, params, text) {
Meteor.publish('globalSearch', async function(sessionId, params, text) {
check(sessionId, String);
check(params, Object);
check(text, String);
@ -282,7 +282,7 @@ Meteor.publish('globalSearch', function(sessionId, params, text) {
console.log('globalSearch publication called with:', { sessionId, params, text });
}
const ret = findCards(sessionId, buildQuery(new QueryParams(params, text)));
const ret = findCards(sessionId, await buildQuery(new QueryParams(params, text)));
if (process.env.DEBUG === 'true') {
console.log('globalSearch publication returning:', ret);
}
@ -303,7 +303,7 @@ Meteor.publish('sessionData', function(sessionId) {
return cursor;
});
function buildSelector(queryParams) {
async function buildSelector(queryParams) {
const userId = Meteor.userId();
const errors = new QueryErrors();
@ -336,8 +336,8 @@ function buildSelector(queryParams) {
if (queryParams.hasOperator(OPERATOR_ORG)) {
const orgs = [];
queryParams.getPredicates(OPERATOR_ORG).forEach(name => {
const org = ReactiveCache.getOrg({
for (const name of queryParams.getPredicates(OPERATOR_ORG)) {
const org = await ReactiveCache.getOrg({
$or: [
{ orgDisplayName: name },
{ orgShortName: name }
@ -348,7 +348,7 @@ function buildSelector(queryParams) {
} else {
errors.addNotFound(OPERATOR_ORG, name);
}
});
}
if (orgs.length) {
boardsSelector.orgs = {
$elemMatch: { orgId: { $in: orgs }, isActive: true }
@ -358,8 +358,8 @@ function buildSelector(queryParams) {
if (queryParams.hasOperator(OPERATOR_TEAM)) {
const teams = [];
queryParams.getPredicates(OPERATOR_TEAM).forEach(name => {
const team = ReactiveCache.getTeam({
for (const name of queryParams.getPredicates(OPERATOR_TEAM)) {
const team = await ReactiveCache.getTeam({
$or: [
{ teamDisplayName: name },
{ teamShortName: name }
@ -370,7 +370,7 @@ function buildSelector(queryParams) {
} else {
errors.addNotFound(OPERATOR_TEAM, name);
}
});
}
if (teams.length) {
boardsSelector.teams = {
$elemMatch: { teamId: { $in: teams }, isActive: true }
@ -442,8 +442,8 @@ function buildSelector(queryParams) {
if (queryParams.hasOperator(OPERATOR_SWIMLANE)) {
const querySwimlanes = [];
queryParams.getPredicates(OPERATOR_SWIMLANE).forEach(query => {
const swimlanes = ReactiveCache.getSwimlanes({
for (const query of queryParams.getPredicates(OPERATOR_SWIMLANE)) {
const swimlanes = await ReactiveCache.getSwimlanes({
title: new RegExp(escapeForRegex(query), 'i'),
});
if (swimlanes.length) {
@ -453,7 +453,7 @@ function buildSelector(queryParams) {
} else {
errors.addNotFound(OPERATOR_SWIMLANE, query);
}
});
}
// eslint-disable-next-line no-prototype-builtins
if (!selector.swimlaneId.hasOwnProperty('swimlaneId')) {
@ -464,8 +464,8 @@ function buildSelector(queryParams) {
if (queryParams.hasOperator(OPERATOR_LIST)) {
const queryLists = [];
queryParams.getPredicates(OPERATOR_LIST).forEach(query => {
const lists = ReactiveCache.getLists({
for (const query of queryParams.getPredicates(OPERATOR_LIST)) {
const lists = await ReactiveCache.getLists({
title: new RegExp(escapeForRegex(query), 'i'),
});
if (lists.length) {
@ -475,7 +475,7 @@ function buildSelector(queryParams) {
} else {
errors.addNotFound(OPERATOR_LIST, query);
}
});
}
// eslint-disable-next-line no-prototype-builtins
if (!selector.hasOwnProperty('listId')) {
@ -516,14 +516,14 @@ function buildSelector(queryParams) {
if (queryParams.hasOperator(OPERATOR_USER)) {
const users = [];
queryParams.getPredicates(OPERATOR_USER).forEach(username => {
const user = ReactiveCache.getUser({ username });
for (const username of queryParams.getPredicates(OPERATOR_USER)) {
const user = await ReactiveCache.getUser({ 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 } }],
@ -531,22 +531,22 @@ function buildSelector(queryParams) {
}
}
[OPERATOR_MEMBER, OPERATOR_ASSIGNEE, OPERATOR_CREATOR].forEach(key => {
for (const key of [OPERATOR_MEMBER, OPERATOR_ASSIGNEE, OPERATOR_CREATOR]) {
if (queryParams.hasOperator(key)) {
const users = [];
queryParams.getPredicates(key).forEach(username => {
const user = ReactiveCache.getUser({ username });
for (const username of queryParams.getPredicates(key)) {
const user = await ReactiveCache.getUser({ 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 = [];
@ -605,12 +605,12 @@ function buildSelector(queryParams) {
}
if (queryParams.hasOperator(OPERATOR_HAS)) {
queryParams.getPredicates(OPERATOR_HAS).forEach(has => {
for (const has of queryParams.getPredicates(OPERATOR_HAS)) {
switch (has.field) {
case PREDICATE_ATTACHMENT:
selector.$and.push({
_id: {
$in: ReactiveCache.getAttachments({}, { fields: { cardId: 1 } }).map(
$in: (await ReactiveCache.getAttachments({}, { fields: { cardId: 1 } })).map(
a => a.cardId,
),
},
@ -619,7 +619,7 @@ function buildSelector(queryParams) {
case PREDICATE_CHECKLIST:
selector.$and.push({
_id: {
$in: ReactiveCache.getChecklists({}, { fields: { cardId: 1 } }).map(
$in: (await ReactiveCache.getChecklists({}, { fields: { cardId: 1 } })).map(
a => a.cardId,
),
},
@ -644,17 +644,17 @@ function buildSelector(queryParams) {
}
break;
}
});
}
}
if (queryParams.text) {
const regex = new RegExp(escapeForRegex(queryParams.text), 'i');
const items = ReactiveCache.getChecklistItems(
const items = await ReactiveCache.getChecklistItems(
{ title: regex },
{ fields: { cardId: 1, checklistId: 1 } },
);
const checklists = ReactiveCache.getChecklists(
const checklists = await ReactiveCache.getChecklists(
{
$or: [
{ title: regex },
@ -664,9 +664,9 @@ function buildSelector(queryParams) {
{ fields: { cardId: 1 } },
);
const attachments = ReactiveCache.getAttachments({ 'original.name': regex });
const attachments = await ReactiveCache.getAttachments({ 'original.name': regex });
const comments = ReactiveCache.getCardComments(
const comments = await ReactiveCache.getCardComments(
{ text: regex },
{ fields: { cardId: 1 } },
);
@ -806,18 +806,18 @@ function buildProjection(query) {
return query;
}
function buildQuery(queryParams) {
const query = buildSelector(queryParams);
async function buildQuery(queryParams) {
const query = await buildSelector(queryParams);
return buildProjection(query);
}
Meteor.publish('brokenCards', function(sessionId) {
Meteor.publish('brokenCards', async function(sessionId) {
check(sessionId, String);
const params = new QueryParams();
params.addPredicate(OPERATOR_STATUS, PREDICATE_ALL);
const query = buildQuery(params);
const query = await buildQuery(params);
query.selector.$or = [
{ boardId: { $in: [null, ''] } },
{ swimlaneId: { $in: [null, ''] } },
@ -830,10 +830,10 @@ Meteor.publish('brokenCards', function(sessionId) {
return ret;
});
Meteor.publish('nextPage', function(sessionId) {
Meteor.publish('nextPage', async function(sessionId) {
check(sessionId, String);
const session = ReactiveCache.getSessionData({ sessionId });
const session = await ReactiveCache.getSessionData({ sessionId });
const projection = session.getProjection();
projection.skip = session.lastHit;
@ -841,10 +841,10 @@ Meteor.publish('nextPage', function(sessionId) {
return ret;
});
Meteor.publish('previousPage', function(sessionId) {
Meteor.publish('previousPage', async function(sessionId) {
check(sessionId, String);
const session = ReactiveCache.getSessionData({ sessionId });
const session = await ReactiveCache.getSessionData({ sessionId });
const projection = session.getProjection();
projection.skip = session.lastHit - session.resultsCount - projection.limit;
@ -852,7 +852,7 @@ Meteor.publish('previousPage', function(sessionId) {
return ret;
});
function findCards(sessionId, query) {
async function findCards(sessionId, query) {
const userId = Meteor.userId();
// eslint-disable-next-line no-console
@ -863,7 +863,7 @@ function findCards(sessionId, query) {
console.log('findCards - projection:', query.projection);
}
const cards = ReactiveCache.getCards(query.selector, query.projection, true);
const cards = await ReactiveCache.getCards(query.selector, query.projection, true);
if (process.env.DEBUG === 'true') {
console.log('findCards - cards count:', cards ? cards.count() : 0);
}
@ -977,23 +977,23 @@ function findCards(sessionId, query) {
return [
cards,
ReactiveCache.getBoards(
await ReactiveCache.getBoards(
{ _id: { $in: boards } },
{ fields: { ...fields, labels: 1, color: 1 } },
true,
),
ReactiveCache.getSwimlanes(
await ReactiveCache.getSwimlanes(
{ _id: { $in: swimlanes } },
{ fields: { ...fields, color: 1 } },
true,
),
ReactiveCache.getLists({ _id: { $in: lists } }, { fields }, true),
ReactiveCache.getCustomFields({ _id: { $in: customFieldIds } }, {}, true),
ReactiveCache.getUsers({ _id: { $in: users } }, { fields: Users.safeFields }, true),
ReactiveCache.getChecklists({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
ReactiveCache.getChecklistItems({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
ReactiveCache.getAttachments({ 'meta.cardId': { $in: cards.map(c => c._id) } }, {}, true).cursor,
ReactiveCache.getCardComments({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
await ReactiveCache.getLists({ _id: { $in: lists } }, { fields }, true),
await ReactiveCache.getCustomFields({ _id: { $in: customFieldIds } }, {}, true),
await ReactiveCache.getUsers({ _id: { $in: users } }, { fields: Users.safeFields }, true),
await ReactiveCache.getChecklists({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
await ReactiveCache.getChecklistItems({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
(await ReactiveCache.getAttachments({ 'meta.cardId': { $in: cards.map(c => c._id) } }, {}, true)).cursor,
await ReactiveCache.getCardComments({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
sessionDataCursor,
];
}

View file

@ -3,33 +3,33 @@ import { ReactiveCache } from '/imports/reactiveCache';
// We use these when displaying notifications in the notificationsDrawer
// gets all activities associated with the current user
Meteor.publish('notificationActivities', () => {
const ret = activities();
Meteor.publish('notificationActivities', async () => {
const ret = await activities();
return ret;
});
// gets all attachments associated with activities associated with the current user
Meteor.publish('notificationAttachments', function() {
const ret = ReactiveCache.getAttachments(
Meteor.publish('notificationAttachments', async function() {
const ret = (await ReactiveCache.getAttachments(
{
_id: {
$in: activities()
$in: (await activities())
.map(v => v.attachmentId)
.filter(v => !!v),
},
},
{},
true,
).cursor;
)).cursor;
return ret;
});
// gets all cards associated with activities associated with the current user
Meteor.publish('notificationCards', function() {
const ret = ReactiveCache.getCards(
Meteor.publish('notificationCards', async function() {
const ret = await ReactiveCache.getCards(
{
_id: {
$in: activities()
$in: (await activities())
.map(v => v.cardId)
.filter(v => !!v),
},
@ -41,11 +41,11 @@ Meteor.publish('notificationCards', function() {
});
// gets all checklistItems associated with activities associated with the current user
Meteor.publish('notificationChecklistItems', function() {
const ret = ReactiveCache.getChecklistItems(
Meteor.publish('notificationChecklistItems', async function() {
const ret = await ReactiveCache.getChecklistItems(
{
_id: {
$in: activities()
$in: (await activities())
.map(v => v.checklistItemId)
.filter(v => !!v),
},
@ -57,11 +57,11 @@ Meteor.publish('notificationChecklistItems', function() {
});
// gets all checklists associated with activities associated with the current user
Meteor.publish('notificationChecklists', function() {
const ret = ReactiveCache.getChecklists(
Meteor.publish('notificationChecklists', async function() {
const ret = await ReactiveCache.getChecklists(
{
_id: {
$in: activities()
$in: (await activities())
.map(v => v.checklistId)
.filter(v => !!v),
},
@ -73,11 +73,11 @@ Meteor.publish('notificationChecklists', function() {
});
// gets all comments associated with activities associated with the current user
Meteor.publish('notificationComments', function() {
const ret = ReactiveCache.getCardComments(
Meteor.publish('notificationComments', async function() {
const ret = await ReactiveCache.getCardComments(
{
_id: {
$in: activities()
$in: (await activities())
.map(v => v.commentId)
.filter(v => !!v),
},
@ -89,11 +89,11 @@ Meteor.publish('notificationComments', function() {
});
// gets all lists associated with activities associated with the current user
Meteor.publish('notificationLists', function() {
const ret = ReactiveCache.getLists(
Meteor.publish('notificationLists', async function() {
const ret = await ReactiveCache.getLists(
{
_id: {
$in: activities()
$in: (await activities())
.map(v => v.listId)
.filter(v => !!v),
},
@ -105,11 +105,11 @@ Meteor.publish('notificationLists', function() {
});
// gets all swimlanes associated with activities associated with the current user
Meteor.publish('notificationSwimlanes', function() {
const ret = ReactiveCache.getSwimlanes(
Meteor.publish('notificationSwimlanes', async function() {
const ret = await ReactiveCache.getSwimlanes(
{
_id: {
$in: activities()
$in: (await activities())
.map(v => v.swimlaneId)
.filter(v => !!v),
},
@ -121,11 +121,11 @@ Meteor.publish('notificationSwimlanes', function() {
});
// gets all users associated with activities associated with the current user
Meteor.publish('notificationUsers', function() {
const ret = ReactiveCache.getUsers(
Meteor.publish('notificationUsers', async function() {
const ret = await ReactiveCache.getUsers(
{
_id: {
$in: activities()
$in: (await activities())
.map(v => v.userId)
.filter(v => !!v),
},
@ -136,11 +136,11 @@ Meteor.publish('notificationUsers', function() {
return ret;
});
function activities() {
const activityIds = ReactiveCache.getCurrentUser()?.profile?.notifications?.map(v => v.activity) || [];
async function activities() {
const activityIds = (await ReactiveCache.getCurrentUser())?.profile?.notifications?.map(v => v.activity) || [];
let ret = [];
if (activityIds.length > 0) {
ret = ReactiveCache.getActivities(
ret = await ReactiveCache.getActivities(
{
_id: { $in: activityIds },
},

View file

@ -1,14 +1,14 @@
import { ReactiveCache } from '/imports/reactiveCache';
Meteor.publish('org', function(query, limit) {
Meteor.publish('org', async function(query, limit) {
check(query, Match.OneOf(Object, null));
check(limit, Number);
let ret = [];
const user = ReactiveCache.getCurrentUser();
const user = await ReactiveCache.getCurrentUser();
if (user && user.isAdmin) {
ret = ReactiveCache.getOrgs(query,
ret = await ReactiveCache.getOrgs(query,
{
limit,
sort: { createdAt: -1 },

View file

@ -1,14 +1,14 @@
import { ReactiveCache } from '/imports/reactiveCache';
Meteor.publish('people', function(query, limit) {
Meteor.publish('people', async function(query, limit) {
check(query, Match.OneOf(Object, null));
check(limit, Number);
let ret = [];
const user = ReactiveCache.getCurrentUser();
const user = await ReactiveCache.getCurrentUser();
if (user && user.isAdmin) {
ret = ReactiveCache.getUsers(query, {
ret = await ReactiveCache.getUsers(query, {
limit,
sort: { createdAt: -1 },
fields: {

View file

@ -4,24 +4,24 @@ import Triggers from '/models/triggers';
import Rules from '/models/rules';
import { ReactiveCache } from '/imports/reactiveCache';
Meteor.publish('rules', function(ruleId) {
Meteor.publish('rules', async function(ruleId) {
check(ruleId, String);
if (!this.userId) {
return this.ready();
}
const rule = ReactiveCache.getRule(ruleId);
const rule = await ReactiveCache.getRule(ruleId);
if (!rule) {
return this.ready();
}
const board = ReactiveCache.getBoard(rule.boardId);
const board = await ReactiveCache.getBoard(rule.boardId);
if (!board || !board.isVisibleBy(this.userId)) {
return this.ready();
}
const ret = ReactiveCache.getRules(
const ret = await ReactiveCache.getRules(
{
_id: ruleId,
},
@ -31,39 +31,39 @@ Meteor.publish('rules', function(ruleId) {
return ret;
});
Meteor.publish('allRules', function() {
if (!this.userId || !ReactiveCache.getUser(this.userId).isAdmin) {
Meteor.publish('allRules', async function() {
if (!this.userId || !(await ReactiveCache.getUser(this.userId)).isAdmin) {
return this.ready();
}
const ret = ReactiveCache.getRules({}, {}, true);
const ret = await ReactiveCache.getRules({}, {}, true);
return ret;
});
Meteor.publish('allTriggers', function() {
if (!this.userId || !ReactiveCache.getUser(this.userId).isAdmin) {
Meteor.publish('allTriggers', async function() {
if (!this.userId || !(await ReactiveCache.getUser(this.userId)).isAdmin) {
return this.ready();
}
const ret = ReactiveCache.getTriggers({}, {}, true);
const ret = await ReactiveCache.getTriggers({}, {}, true);
return ret;
});
Meteor.publish('allActions', function() {
if (!this.userId || !ReactiveCache.getUser(this.userId).isAdmin) {
Meteor.publish('allActions', async function() {
if (!this.userId || !(await ReactiveCache.getUser(this.userId)).isAdmin) {
return this.ready();
}
const ret = ReactiveCache.getActions({}, {}, true);
const ret = await ReactiveCache.getActions({}, {}, true);
return ret;
});
Meteor.publish('rulesReport', function() {
if (!this.userId || !ReactiveCache.getUser(this.userId).isAdmin) {
Meteor.publish('rulesReport', async function() {
if (!this.userId || !(await ReactiveCache.getUser(this.userId)).isAdmin) {
return this.ready();
}
const rules = ReactiveCache.getRules({}, {}, true);
const rules = await ReactiveCache.getRules({}, {}, true);
const actionIds = [];
const triggerIds = [];
const boardIds = [];
@ -76,9 +76,9 @@ Meteor.publish('rulesReport', function() {
const ret = [
rules,
ReactiveCache.getActions({ _id: { $in: actionIds } }, {}, true),
ReactiveCache.getTriggers({ _id: { $in: triggerIds } }, {}, true),
ReactiveCache.getBoards({ _id: { $in: boardIds } }, { fields: { title: 1 } }, true),
await ReactiveCache.getActions({ _id: { $in: actionIds } }, {}, true),
await ReactiveCache.getTriggers({ _id: { $in: triggerIds } }, {}, true),
await ReactiveCache.getBoards({ _id: { $in: boardIds } }, { fields: { title: 1 } }, true),
];
return ret;
});

View file

@ -1,8 +1,8 @@
import { ReactiveCache } from '/imports/reactiveCache';
Meteor.publish('globalwebhooks', () => {
Meteor.publish('globalwebhooks', async () => {
const boardId = Integrations.Const.GLOBAL_WEBHOOK_ID;
const ret = ReactiveCache.getIntegrations(
const ret = await ReactiveCache.getIntegrations(
{
boardId,
},
@ -47,8 +47,8 @@ Meteor.publish('setting', () => {
return ret;
});
Meteor.publish('mailServer', function() {
const user = ReactiveCache.getCurrentUser();
Meteor.publish('mailServer', async function() {
const user = await ReactiveCache.getCurrentUser();
let ret = []
if (user && user.isAdmin) {

View file

@ -1,12 +1,12 @@
import { ReactiveCache } from '/imports/reactiveCache';
Meteor.methods({
copySwimlane(swimlaneId, toBoardId) {
async copySwimlane(swimlaneId, toBoardId) {
check(swimlaneId, String);
check(toBoardId, String);
const swimlane = ReactiveCache.getSwimlane(swimlaneId);
const toBoard = ReactiveCache.getBoard(toBoardId);
const swimlane = await ReactiveCache.getSwimlane(swimlaneId);
const toBoard = await ReactiveCache.getBoard(toBoardId);
let ret = false;
if (swimlane && toBoard) {
@ -21,8 +21,8 @@ Meteor.methods({
check(swimlaneId, String);
check(toBoardId, String);
const swimlane = ReactiveCache.getSwimlane(swimlaneId);
const toBoard = ReactiveCache.getBoard(toBoardId);
const swimlane = await ReactiveCache.getSwimlane(swimlaneId);
const toBoard = await ReactiveCache.getBoard(toBoardId);
let ret = false;
if (swimlane && toBoard) {

View file

@ -1,14 +1,14 @@
import { ReactiveCache } from '/imports/reactiveCache';
Meteor.publish('team', function(query, limit) {
Meteor.publish('team', async function(query, limit) {
check(query, Match.OneOf(Object, null));
check(limit, Number);
const user = ReactiveCache.getCurrentUser();
const user = await ReactiveCache.getCurrentUser();
let ret = [];
if (user && user.isAdmin) {
ret = ReactiveCache.getTeams(query,
ret = await ReactiveCache.getTeams(query,
{
limit,
sort: { createdAt: -1 },

View file

@ -1,14 +1,14 @@
import { ReactiveCache } from '/imports/reactiveCache';
Meteor.publish('translation', function(query, limit) {
Meteor.publish('translation', async function(query, limit) {
check(query, Match.OneOf(Object, null));
check(limit, Number);
let ret = [];
const user = ReactiveCache.getCurrentUser();
const user = await ReactiveCache.getCurrentUser();
if (user && user.isAdmin) {
ret = ReactiveCache.getTranslations(query,
ret = await ReactiveCache.getTranslations(query,
{
limit,
sort: { modifiedAt: -1 },

View file

@ -1,9 +1,9 @@
Meteor.publish('user-miniprofile', function (usernames) {
Meteor.publish('user-miniprofile', async function (usernames) {
check(usernames, Array);
// eslint-disable-next-line no-console
// console.log('usernames:', usernames);
const ret = ReactiveCache.getUsers(
const ret = await ReactiveCache.getUsers(
{
$or: [
{ username: { $in: usernames } },
@ -33,9 +33,9 @@ Meteor.publish('user-admin', function () {
return ret;
});
Meteor.publish('user-authenticationMethod', function (match) {
Meteor.publish('user-authenticationMethod', async function (match) {
check(match, String);
const ret = ReactiveCache.getUsers(
const ret = await ReactiveCache.getUsers(
{ $or: [{ _id: match }, { email: match }, { username: match }] },
{
fields: {
@ -50,7 +50,7 @@ Meteor.publish('user-authenticationMethod', function (match) {
});
// Secure user search publication for board sharing
Meteor.publish('user-search', function (searchTerm) {
Meteor.publish('user-search', async function (searchTerm) {
check(searchTerm, String);
// Only allow logged-in users to search for other users
@ -62,7 +62,7 @@ Meteor.publish('user-search', function (searchTerm) {
const searchRegex = new RegExp(searchTerm, 'i');
// Search for users by username, fullname, or email
const ret = ReactiveCache.getUsers(
const ret = await ReactiveCache.getUsers(
{
$or: [
{ username: searchRegex },