diff --git a/models/accessibilitySettings.js b/models/accessibilitySettings.js
index b9785bb5a..12be6e2ad 100644
--- a/models/accessibilitySettings.js
+++ b/models/accessibilitySettings.js
@@ -46,8 +46,8 @@ AccessibilitySettings.attachSchema(
);
AccessibilitySettings.allow({
- update(userId) {
- const user = ReactiveCache.getUser(userId);
+ async update(userId) {
+ const user = await ReactiveCache.getUser(userId);
return user && user.isAdmin;
},
});
diff --git a/models/accountSettings.js b/models/accountSettings.js
index 6b5a6b246..38fed5c82 100644
--- a/models/accountSettings.js
+++ b/models/accountSettings.js
@@ -45,8 +45,8 @@ AccountSettings.attachSchema(
);
AccountSettings.allow({
- update(userId) {
- const user = ReactiveCache.getUser(userId);
+ async update(userId) {
+ const user = await ReactiveCache.getUser(userId);
return user && user.isAdmin;
},
});
diff --git a/models/actions.js b/models/actions.js
index b7c946318..e8209febd 100644
--- a/models/actions.js
+++ b/models/actions.js
@@ -4,14 +4,14 @@ import { Meteor } from 'meteor/meteor';
Actions = new Mongo.Collection('actions');
Actions.allow({
- insert(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async insert(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
- update(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async update(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
- remove(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async remove(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
});
diff --git a/models/activities.js b/models/activities.js
index e3080c1da..03d3df499 100644
--- a/models/activities.js
+++ b/models/activities.js
@@ -13,54 +13,54 @@ import { ReactiveCache } from '/imports/reactiveCache';
Activities = new Mongo.Collection('activities');
Activities.helpers({
- board() {
- return ReactiveCache.getBoard(this.boardId);
+ async board() {
+ return await ReactiveCache.getBoard(this.boardId);
},
- oldBoard() {
- return ReactiveCache.getBoard(this.oldBoardId);
+ async oldBoard() {
+ return await ReactiveCache.getBoard(this.oldBoardId);
},
- user() {
- return ReactiveCache.getUser(this.userId);
+ async user() {
+ return await ReactiveCache.getUser(this.userId);
},
- member() {
- return ReactiveCache.getUser(this.memberId);
+ async member() {
+ return await ReactiveCache.getUser(this.memberId);
},
- list() {
- return ReactiveCache.getList(this.listId);
+ async list() {
+ return await ReactiveCache.getList(this.listId);
},
- swimlane() {
- return ReactiveCache.getSwimlane(this.swimlaneId);
+ async swimlane() {
+ return await ReactiveCache.getSwimlane(this.swimlaneId);
},
- oldSwimlane() {
- return ReactiveCache.getSwimlane(this.oldSwimlaneId);
+ async oldSwimlane() {
+ return await ReactiveCache.getSwimlane(this.oldSwimlaneId);
},
- oldList() {
- return ReactiveCache.getList(this.oldListId);
+ async oldList() {
+ return await ReactiveCache.getList(this.oldListId);
},
- card() {
- return ReactiveCache.getCard(this.cardId);
+ async card() {
+ return await ReactiveCache.getCard(this.cardId);
},
- comment() {
- return ReactiveCache.getCardComment(this.commentId);
+ async comment() {
+ return await ReactiveCache.getCardComment(this.commentId);
},
- attachment() {
- return ReactiveCache.getAttachment(this.attachmentId);
+ async attachment() {
+ return await ReactiveCache.getAttachment(this.attachmentId);
},
- checklist() {
- return ReactiveCache.getChecklist(this.checklistId);
+ async checklist() {
+ return await ReactiveCache.getChecklist(this.checklistId);
},
- checklistItem() {
- return ReactiveCache.getChecklistItem(this.checklistItemId);
+ async checklistItem() {
+ return await ReactiveCache.getChecklistItem(this.checklistItemId);
},
- subtasks() {
- return ReactiveCache.getCard(this.subtaskId);
+ async subtasks() {
+ return await ReactiveCache.getCard(this.subtaskId);
},
- customField() {
- return ReactiveCache.getCustomField(this.customFieldId);
+ async customField() {
+ return await ReactiveCache.getCustomField(this.customFieldId);
},
- label() {
+ async label() {
// Label activity did not work yet, unable to edit labels when tried this.
- return ReactiveCache.getCard(this.labelId);
+ return await ReactiveCache.getCard(this.labelId);
},
});
@@ -105,12 +105,12 @@ if (Meteor.isServer) {
//Activities._collection.dropIndex({ labelId: 1 }, { partialFilterExpression: { labelId: { $exists: true } } });
});
- Activities.after.insert((userId, doc) => {
+ Activities.after.insert(async (userId, doc) => {
const activity = Activities._transform(doc);
let participants = [];
let watchers = [];
let title = 'act-activity-notify';
- const board = ReactiveCache.getBoard(activity.boardId);
+ const board = await ReactiveCache.getBoard(activity.boardId);
const description = `act-${activity.activityType}`;
const params = {
activityId: activity._id,
@@ -203,14 +203,16 @@ if (Meteor.isServer) {
let hasMentions = false; // Track if comment has @mentions
if (board) {
const comment = params.comment;
- const knownUsers = board.members.map((member) => {
- const u = ReactiveCache.getUser(member.userId);
+ // Build knownUsers with async user lookups
+ const knownUsers = [];
+ for (const member of board.members) {
+ const u = await ReactiveCache.getUser(member.userId);
if (u) {
member.username = u.username;
member.emails = u.emails;
}
- return member;
- });
+ knownUsers.push(member);
+ }
// Match @mentions including usernames with @ symbols (like email addresses)
// Pattern matches: @username, @user@example.com, @"quoted username"
const mentionRegex = /\B@(?:(?:"([\w.\s-]*)")|([\w.@-]+))/gi;
@@ -225,30 +227,31 @@ if (Meteor.isServer) {
if (activity.boardId && username === 'board_members') {
// mentions all board members
- const validUserIds = knownUsers
- .map((u) => u.userId)
- .filter((userId) => {
- const user = ReactiveCache.getUser(userId);
- return user && user._id;
- });
+ const validUserIds = [];
+ for (const u of knownUsers) {
+ const user = await ReactiveCache.getUser(u.userId);
+ if (user && user._id) {
+ validUserIds.push(u.userId);
+ }
+ }
watchers = _.union(watchers, validUserIds);
title = 'act-atUserComment';
hasMentions = true;
} else if (activity.boardId && username === 'board_assignees') {
// mentions all assignees of all cards on the board
- const allCards = ReactiveCache.getCards({ boardId: activity.boardId });
+ const allCards = await ReactiveCache.getCards({ boardId: activity.boardId });
const assigneeIds = [];
- allCards.forEach((card) => {
+ for (const card of allCards) {
if (card.assignees && card.assignees.length > 0) {
- card.assignees.forEach((assigneeId) => {
+ for (const assigneeId of card.assignees) {
// Only add if the user exists and is a board member
- const user = ReactiveCache.getUser(assigneeId);
+ const user = await ReactiveCache.getUser(assigneeId);
if (user && _.findWhere(knownUsers, { userId: assigneeId })) {
assigneeIds.push(assigneeId);
}
- });
+ }
}
- });
+ }
watchers = _.union(watchers, assigneeIds);
title = 'act-atUserComment';
hasMentions = true;
@@ -257,10 +260,13 @@ if (Meteor.isServer) {
const card = activity.card();
if (card && card.members && card.members.length > 0) {
// Filter to only valid users who are board members
- const validMembers = card.members.filter((memberId) => {
- const user = ReactiveCache.getUser(memberId);
- return user && user._id && _.findWhere(knownUsers, { userId: memberId });
- });
+ const validMembers = [];
+ for (const memberId of card.members) {
+ const user = await ReactiveCache.getUser(memberId);
+ if (user && user._id && _.findWhere(knownUsers, { userId: memberId })) {
+ validMembers.push(memberId);
+ }
+ }
watchers = _.union(watchers, validMembers);
}
title = 'act-atUserComment';
@@ -270,10 +276,13 @@ if (Meteor.isServer) {
const card = activity.card();
if (card && card.assignees && card.assignees.length > 0) {
// Filter to only valid users who are board members
- const validAssignees = card.assignees.filter((assigneeId) => {
- const user = ReactiveCache.getUser(assigneeId);
- return user && user._id && _.findWhere(knownUsers, { userId: assigneeId });
- });
+ const validAssignees = [];
+ for (const assigneeId of card.assignees) {
+ const user = await ReactiveCache.getUser(assigneeId);
+ if (user && user._id && _.findWhere(knownUsers, { userId: assigneeId })) {
+ validAssignees.push(assigneeId);
+ }
+ }
watchers = _.union(watchers, validAssignees);
}
title = 'act-atUserComment';
@@ -390,7 +399,7 @@ if (Meteor.isServer) {
Notifications.getUsers(watchers).forEach((user) => {
// Skip if user is undefined or doesn't have an _id (e.g., deleted user or invalid ID)
if (!user || !user._id) return;
-
+
// Don't notify a user of their own behavior, EXCEPT for self-mentions
const isSelfMention = (user._id === userId && title === 'act-atUserComment');
if (user._id !== userId || isSelfMention) {
@@ -398,7 +407,7 @@ if (Meteor.isServer) {
}
});
- const integrations = ReactiveCache.getIntegrations({
+ const integrations = await ReactiveCache.getIntegrations({
boardId: { $in: [board._id, Integrations.Const.GLOBAL_WEBHOOK_ID] },
// type: 'outgoing-webhooks', // all types
enabled: true,
diff --git a/models/announcements.js b/models/announcements.js
index b44f7a229..1c3f60e7a 100644
--- a/models/announcements.js
+++ b/models/announcements.js
@@ -50,8 +50,8 @@ Announcements.attachSchema(
);
Announcements.allow({
- update(userId) {
- const user = ReactiveCache.getUser(userId);
+ async update(userId) {
+ const user = await ReactiveCache.getUser(userId);
return user && user.isAdmin;
},
});
diff --git a/models/attachmentStorageSettings.js b/models/attachmentStorageSettings.js
index f0a67271c..df7721cba 100644
--- a/models/attachmentStorageSettings.js
+++ b/models/attachmentStorageSettings.js
@@ -257,18 +257,18 @@ AttachmentStorageSettings.helpers({
if (Meteor.isServer) {
// Get or create default settings
Meteor.methods({
- 'getAttachmentStorageSettings'() {
+ async 'getAttachmentStorageSettings'() {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
let settings = AttachmentStorageSettings.findOne({});
-
+
if (!settings) {
// Create default settings
settings = {
@@ -299,20 +299,20 @@ if (Meteor.isServer) {
createdBy: this.userId,
updatedBy: this.userId
};
-
+
AttachmentStorageSettings.insert(settings);
settings = AttachmentStorageSettings.findOne({});
}
-
+
return settings;
},
- 'updateAttachmentStorageSettings'(settings) {
+ async 'updateAttachmentStorageSettings'(settings) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
@@ -320,7 +320,7 @@ if (Meteor.isServer) {
// Validate settings
const schema = AttachmentStorageSettings.simpleSchema();
schema.validate(settings);
-
+
// Update settings
const result = AttachmentStorageSettings.upsert(
{},
@@ -332,7 +332,7 @@ if (Meteor.isServer) {
}
}
);
-
+
return result;
},
@@ -345,12 +345,12 @@ if (Meteor.isServer) {
return settings ? settings.getDefaultStorage() : STORAGE_NAME_FILESYSTEM;
},
- 'setDefaultAttachmentStorage'(storageName) {
+ async 'setDefaultAttachmentStorage'(storageName) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
@@ -369,18 +369,18 @@ if (Meteor.isServer) {
}
}
);
-
+
return result;
}
});
// Publication for settings
- Meteor.publish('attachmentStorageSettings', function() {
+ Meteor.publish('attachmentStorageSettings', async function() {
if (!this.userId) {
return this.ready();
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user || !user.isAdmin) {
return this.ready();
}
diff --git a/models/attachments.js b/models/attachments.js
index 3ac87da3b..a2e52e1fc 100644
--- a/models/attachments.js
+++ b/models/attachments.js
@@ -179,13 +179,13 @@ Attachments = new FilesCollection({
// We authorize the attachment download either:
// - if the board is public, everyone (even unconnected) can download it
// - if the board is private, only board members can download it
- protected(fileObj) {
+ async protected(fileObj) {
// file may have been deleted already again after upload validation failed
if (!fileObj) {
return false;
}
- const board = ReactiveCache.getBoard(fileObj.meta.boardId);
+ const board = await ReactiveCache.getBoard(fileObj.meta.boardId);
if (board.isPublic()) {
return true;
}
@@ -196,11 +196,11 @@ Attachments = new FilesCollection({
if (Meteor.isServer) {
Attachments.allow({
- insert(userId, fileObj) {
+ async insert(userId, fileObj) {
// ReadOnly users cannot upload attachments
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(fileObj.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(fileObj.boardId));
},
- update(userId, fileObj, fields) {
+ async update(userId, fileObj, fields) {
// SECURITY: The 'name' field is sanitized in onBeforeUpload and server-side methods,
// but we block direct client-side $set operations on 'versions.*.path' to prevent
// path traversal attacks via storage migration exploits.
@@ -230,9 +230,9 @@ if (Meteor.isServer) {
}
// ReadOnly users cannot update attachments
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(fileObj.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(fileObj.boardId));
},
- remove(userId, fileObj) {
+ async remove(userId, fileObj) {
// Additional security check: ensure the file belongs to the board the user has access to
if (!fileObj || !fileObj.boardId) {
if (process.env.DEBUG === 'true') {
@@ -241,7 +241,7 @@ if (Meteor.isServer) {
return false;
}
- const board = ReactiveCache.getBoard(fileObj.boardId);
+ const board = await ReactiveCache.getBoard(fileObj.boardId);
if (!board) {
if (process.env.DEBUG === 'true') {
console.warn('Blocked attachment removal: board not found');
@@ -293,7 +293,7 @@ if (Meteor.isServer) {
return { valid: true };
},
- moveAttachmentToStorage(fileObjId, storageDestination) {
+ async moveAttachmentToStorage(fileObjId, storageDestination) {
check(fileObjId, String);
check(storageDestination, String);
@@ -301,12 +301,12 @@ if (Meteor.isServer) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
- const fileObj = ReactiveCache.getAttachment(fileObjId);
+ const fileObj = await ReactiveCache.getAttachment(fileObjId);
if (!fileObj) {
throw new Meteor.Error('attachment-not-found', 'Attachment not found');
}
- const board = ReactiveCache.getBoard(fileObj.boardId);
+ const board = await ReactiveCache.getBoard(fileObj.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
@@ -319,7 +319,7 @@ if (Meteor.isServer) {
moveToStorage(fileObj, storageDestination, fileStoreStrategyFactory);
},
- renameAttachment(fileObjId, newName) {
+ async renameAttachment(fileObjId, newName) {
check(fileObjId, String);
check(newName, String);
@@ -328,13 +328,13 @@ if (Meteor.isServer) {
throw new Meteor.Error('not-authorized', 'User must be logged in');
}
- const fileObj = ReactiveCache.getAttachment(fileObjId);
+ const fileObj = await ReactiveCache.getAttachment(fileObjId);
if (!fileObj) {
throw new Meteor.Error('file-not-found', 'Attachment not found');
}
// Verify the user has permission to modify this attachment
- const board = ReactiveCache.getBoard(fileObj.boardId);
+ const board = await ReactiveCache.getBoard(fileObj.boardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found');
}
@@ -348,30 +348,30 @@ if (Meteor.isServer) {
rename(fileObj, newName, fileStoreStrategyFactory);
},
- validateAttachment(fileObjId) {
+ async validateAttachment(fileObjId) {
check(fileObjId, String);
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
- const fileObj = ReactiveCache.getAttachment(fileObjId);
+ const fileObj = await ReactiveCache.getAttachment(fileObjId);
if (!fileObj) {
throw new Meteor.Error('attachment-not-found', 'Attachment not found');
}
- const board = ReactiveCache.getBoard(fileObj.boardId);
+ const board = await ReactiveCache.getBoard(fileObj.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
- const isValid = Promise.await(isFileValid(fileObj, attachmentUploadMimeTypes, attachmentUploadSize, attachmentUploadExternalProgram));
+ const isValid = await isFileValid(fileObj, attachmentUploadMimeTypes, attachmentUploadSize, attachmentUploadExternalProgram);
if (!isValid) {
Attachments.remove(fileObjId);
}
},
- validateAttachmentAndMoveToStorage(fileObjId, storageDestination) {
+ async validateAttachmentAndMoveToStorage(fileObjId, storageDestination) {
check(fileObjId, String);
check(storageDestination, String);
@@ -379,12 +379,12 @@ if (Meteor.isServer) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
- const fileObj = ReactiveCache.getAttachment(fileObjId);
+ const fileObj = await ReactiveCache.getAttachment(fileObjId);
if (!fileObj) {
throw new Meteor.Error('attachment-not-found', 'Attachment not found');
}
- const board = ReactiveCache.getBoard(fileObj.boardId);
+ const board = await ReactiveCache.getBoard(fileObj.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
@@ -395,9 +395,9 @@ if (Meteor.isServer) {
throw new Meteor.Error('invalid-storage-destination', 'Invalid storage destination');
}
- Meteor.call('validateAttachment', fileObjId);
+ await Meteor.callAsync('validateAttachment', fileObjId);
- const fileObjAfter = ReactiveCache.getAttachment(fileObjId);
+ const fileObjAfter = await ReactiveCache.getAttachment(fileObjId);
if (fileObjAfter) {
Meteor.defer(() => Meteor.call('moveAttachmentToStorage', fileObjId, storageDestination));
diff --git a/models/avatars.js b/models/avatars.js
index da3033bc8..369eb473b 100644
--- a/models/avatars.js
+++ b/models/avatars.js
@@ -106,7 +106,7 @@ Avatars = new FilesCollection({
}
return TAPi18n.__('avatar-too-big', {size: filesize(avatarsUploadSize)});
},
- onAfterUpload(fileObj) {
+ async onAfterUpload(fileObj) {
// current storage is the filesystem, update object and database
Object.keys(fileObj.versions).forEach(versionName => {
fileObj.versions[versionName].storage = STORAGE_NAME_FILESYSTEM;
@@ -114,12 +114,13 @@ Avatars = new FilesCollection({
Avatars.update({ _id: fileObj._id }, { $set: { "versions": fileObj.versions } });
- const isValid = Promise.await(isFileValid(fileObj, avatarsUploadMimeTypes, avatarsUploadSize, avatarsUploadExternalProgram));
+ const isValid = await isFileValid(fileObj, avatarsUploadMimeTypes, avatarsUploadSize, avatarsUploadExternalProgram);
if (isValid) {
// Set avatar URL using universal URL generator (URL-agnostic)
const universalUrl = generateUniversalAvatarUrl(fileObj._id);
- ReactiveCache.getUser(fileObj.userId).setAvatarUrl(universalUrl);
+ const user = await ReactiveCache.getUser(fileObj.userId);
+ user.setAvatarUrl(universalUrl);
} else {
Avatars.remove(fileObj._id);
}
@@ -128,12 +129,13 @@ Avatars = new FilesCollection({
const ret = fileStoreStrategyFactory.getFileStrategy(fileObj, versionName).interceptDownload(http, this.cacheControl);
return ret;
},
- onBeforeRemove(files) {
- files.forEach(fileObj => {
+ async onBeforeRemove(files) {
+ for (const fileObj of files) {
if (fileObj.userId) {
- ReactiveCache.getUser(fileObj.userId).setAvatarUrl('');
+ const user = await ReactiveCache.getUser(fileObj.userId);
+ user.setAvatarUrl('');
}
- });
+ }
return true;
},
diff --git a/models/boards.js b/models/boards.js
index 479b2530e..45bf1f6dd 100644
--- a/models/boards.js
+++ b/models/boards.js
@@ -703,12 +703,12 @@ Boards.attachSchema(
);
Boards.helpers({
- copy() {
+ async copy() {
const oldId = this._id;
const oldWatchers = this.watchers ? this.watchers.slice() : [];
delete this._id;
delete this.slug;
- this.title = this.copyTitle();
+ this.title = await this.copyTitle();
const _id = Boards.insert(this);
// Temporary remove watchers to disable notifications
@@ -719,23 +719,26 @@ Boards.helpers({
});
// Copy all swimlanes in board
- ReactiveCache.getSwimlanes({
+ const swimlanes = await ReactiveCache.getSwimlanes({
boardId: oldId,
archived: false,
- }).forEach(swimlane => {
+ });
+ for (const swimlane of swimlanes) {
swimlane.type = 'swimlane';
swimlane.copy(_id);
- });
+ }
// copy custom field definitions
const cfMap = {};
- ReactiveCache.getCustomFields({ boardIds: oldId }).forEach(cf => {
+ const customFields = await ReactiveCache.getCustomFields({ boardIds: oldId });
+ for (const cf of customFields) {
const id = cf._id;
delete cf._id;
cf.boardIds = [_id];
cfMap[id] = CustomFields.insert(cf);
- });
- ReactiveCache.getCards({ boardId: _id }).forEach(card => {
+ }
+ const cards = await ReactiveCache.getCards({ boardId: _id });
+ for (const card of cards) {
Cards.update(card._id, {
$set: {
customFields: card.customFields.map(cf => {
@@ -744,30 +747,33 @@ Boards.helpers({
}),
},
});
- });
+ }
// copy rules, actions, and triggers
const actionsMap = {};
- ReactiveCache.getActions({ boardId: oldId }).forEach(action => {
+ const actions = await ReactiveCache.getActions({ boardId: oldId });
+ for (const action of actions) {
const id = action._id;
delete action._id;
action.boardId = _id;
actionsMap[id] = Actions.insert(action);
- });
+ }
const triggersMap = {};
- ReactiveCache.getTriggers({ boardId: oldId }).forEach(trigger => {
+ const triggers = await ReactiveCache.getTriggers({ boardId: oldId });
+ for (const trigger of triggers) {
const id = trigger._id;
delete trigger._id;
trigger.boardId = _id;
triggersMap[id] = Triggers.insert(trigger);
- });
- ReactiveCache.getRules({ boardId: oldId }).forEach(rule => {
+ }
+ const rules = await ReactiveCache.getRules({ boardId: oldId });
+ for (const rule of rules) {
delete rule._id;
rule.boardId = _id;
rule.actionId = actionsMap[rule.actionId];
rule.triggerId = triggersMap[rule.triggerId];
Rules.insert(rule);
- });
+ }
// Re-set Watchers to reenable notification
Boards.update(_id, {
@@ -781,8 +787,8 @@ Boards.helpers({
*
* @returns {string|null}
*/
- copyTitle() {
- return Boards.uniqueTitle(this.title);
+ async copyTitle() {
+ return await Boards.uniqueTitle(this.title);
},
/**
@@ -823,8 +829,8 @@ Boards.helpers({
},
- cards() {
- const ret = ReactiveCache.getCards(
+ async cards() {
+ const ret = await ReactiveCache.getCards(
{ boardId: this._id, archived: false },
{ sort: { title: 1 } },
);
@@ -835,11 +841,12 @@ Boards.helpers({
return this.draggableLists();
},
- newestLists() {
+ async newestLists() {
// sorted lists from newest to the oldest, by its creation date or its cards' last modification date
- const value = ReactiveCache.getCurrentUser()._getListSortBy();
+ const user = await ReactiveCache.getCurrentUser();
+ const value = user._getListSortBy();
const sortKey = { starred: -1, [value[0]]: value[1] }; // [["starred",-1],value];
- return ReactiveCache.getLists(
+ return await ReactiveCache.getLists(
{
boardId: this._id,
archived: false,
@@ -848,8 +855,8 @@ Boards.helpers({
);
},
- draggableLists() {
- return ReactiveCache.getLists(
+ async draggableLists() {
+ return await ReactiveCache.getLists(
{
boardId: this._id,
},
@@ -860,28 +867,28 @@ Boards.helpers({
/** returns the last list
* @returns Document the last list
*/
- getLastList() {
- const ret = ReactiveCache.getList({ boardId: this._id }, { sort: { sort: 'desc' } });
+ async getLastList() {
+ const ret = await ReactiveCache.getList({ boardId: this._id }, { sort: { sort: 'desc' } });
return ret;
},
- nullSortLists() {
- return ReactiveCache.getLists({
+ async nullSortLists() {
+ return await ReactiveCache.getLists({
boardId: this._id,
archived: false,
sort: { $eq: null },
});
},
- swimlanes() {
- return ReactiveCache.getSwimlanes(
+ async swimlanes() {
+ return await ReactiveCache.getSwimlanes(
{ boardId: this._id, archived: false },
{ sort: { sort: 1 } },
);
},
- nextSwimlane(swimlane) {
- return ReactiveCache.getSwimlane(
+ async nextSwimlane(swimlane) {
+ return await ReactiveCache.getSwimlane(
{
boardId: this._id,
archived: false,
@@ -894,16 +901,16 @@ Boards.helpers({
);
},
- nullSortSwimlanes() {
- return ReactiveCache.getSwimlanes({
+ async nullSortSwimlanes() {
+ return await ReactiveCache.getSwimlanes({
boardId: this._id,
archived: false,
sort: { $eq: null },
});
},
- hasOvertimeCards() {
- const card = ReactiveCache.getCard({
+ async hasOvertimeCards() {
+ const card = await ReactiveCache.getCard({
isOvertime: true,
boardId: this._id,
archived: false,
@@ -911,8 +918,8 @@ Boards.helpers({
return card !== undefined;
},
- hasSpentTimeCards() {
- const card = ReactiveCache.getCard({
+ async hasSpentTimeCards() {
+ const card = await ReactiveCache.getCard({
spentTime: { $gt: 0 },
boardId: this._id,
archived: false,
@@ -920,19 +927,20 @@ Boards.helpers({
return card !== undefined;
},
- activities() {
+ async activities() {
let linkedBoardId = [this._id];
- ReactiveCache.getCards({
+ const cards = await ReactiveCache.getCards({
"type": "cardType-linkedBoard",
- "boardId": this._id}
- ).forEach(card => {
- linkedBoardId.push(card.linkedId);
+ "boardId": this._id
});
- const ret = ReactiveCache.getActivities({ boardId: { $in: linkedBoardId } }, { sort: { createdAt: -1 } });
+ for (const card of cards) {
+ linkedBoardId.push(card.linkedId);
+ }
+ const ret = await ReactiveCache.getActivities({ boardId: { $in: linkedBoardId } }, { sort: { createdAt: -1 } });
return ret;
},
- activeMembers(){
+ async activeMembers(){
// Depend on the users collection for reactivity when users are loaded
const memberUserIds = _.pluck(this.members, 'userId');
const dummy = Meteor.users.find({ _id: { $in: memberUserIds } }).count();
@@ -945,16 +953,21 @@ Boards.helpers({
return selected;
});
// Filter out members where user is not loaded
- const filteredMembers = uniqueMembers.filter(member => {
- const user = ReactiveCache.getUser(member.userId);
- return user !== undefined;
- });
-
+ const filteredMembers = [];
+ for (const member of uniqueMembers) {
+ const user = await ReactiveCache.getUser(member.userId);
+ if (user !== undefined) {
+ filteredMembers.push(member);
+ }
+ }
+
// Sort by role priority first (admin, normal, normal-assigned, no-comments, comment-only, comment-assigned, worker, read-only, read-assigned), then by fullname
- return _.sortBy(filteredMembers, member => {
- const user = ReactiveCache.getUser(member.userId);
+ // Build sort keys with async user lookup
+ const membersWithSortKey = [];
+ for (const member of filteredMembers) {
+ const user = await ReactiveCache.getUser(member.userId);
let rolePriority = 8; // Default for normal
-
+
if (member.isAdmin) rolePriority = 0;
else if (member.isReadAssignedOnly) rolePriority = 8;
else if (member.isReadOnly) rolePriority = 7;
@@ -964,10 +977,11 @@ Boards.helpers({
else if (member.isNoComments) rolePriority = 3;
else if (member.isNormalAssignedOnly) rolePriority = 2;
else rolePriority = 1; // Normal
-
+
const fullname = user ? user.profile.fullname : '';
- return rolePriority + '-' + fullname;
- });
+ membersWithSortKey.push({ member, sortKey: rolePriority + '-' + fullname });
+ }
+ return _.sortBy(membersWithSortKey, 'sortKey').map(item => item.member);
},
activeOrgs() {
@@ -990,8 +1004,8 @@ Boards.helpers({
return _.where(this.members, { isActive: true, isAdmin: true });
},
- memberUsers() {
- return ReactiveCache.getUsers({ _id: { $in: _.pluck(this.members, 'userId') } });
+ async memberUsers() {
+ return await ReactiveCache.getUsers({ _id: { $in: _.pluck(this.members, 'userId') } });
},
getLabel(name, color) {
@@ -1111,8 +1125,8 @@ Boards.helpers({
return `board-color-${this.color}`;
},
- customFields() {
- const ret = ReactiveCache.getCustomFields(
+ async customFields() {
+ const ret = await ReactiveCache.getCustomFields(
{ boardIds: { $in: [this._id] } },
{ sort: { name: 1 } },
);
@@ -1141,7 +1155,7 @@ Boards.helpers({
}
},
- searchBoards(term) {
+ async searchBoards(term) {
check(term, Match.OneOf(String, null, undefined));
const query = { boardId: this._id };
@@ -1156,11 +1170,11 @@ Boards.helpers({
query.$or = [{ title: regex }, { description: regex }];
}
- const ret = ReactiveCache.getCards(query, projection);
+ const ret = await ReactiveCache.getCards(query, projection);
return ret;
},
- searchSwimlanes(term) {
+ async searchSwimlanes(term) {
check(term, Match.OneOf(String, null, undefined));
const query = { boardId: this._id };
@@ -1178,10 +1192,10 @@ Boards.helpers({
query.$or = [{ title: regex }, { description: regex }];
}
- return ReactiveCache.getSwimlanes(query, projection);
+ return await ReactiveCache.getSwimlanes(query, projection);
},
- searchLists(term) {
+ async searchLists(term) {
let ret = null;
if (term) {
check(term, Match.OneOf(String));
@@ -1203,12 +1217,12 @@ Boards.helpers({
query.$or = [{ title: regex }, { description: regex }];
}
- ret = ReactiveCache.getLists(query, projection);
+ ret = await ReactiveCache.getLists(query, projection);
}
return ret;
},
- searchCards(term, excludeLinked) {
+ async searchCards(term, excludeLinked) {
let ret = null;
if (term) {
check(term, Match.OneOf(String));
@@ -1234,7 +1248,7 @@ Boards.helpers({
{ description: regex },
{ customFields: { $elemMatch: { value: regex } } },
];
- ret = ReactiveCache.getCards(query, projection);
+ ret = await ReactiveCache.getCards(query, projection);
}
return ret;
},
@@ -1268,8 +1282,8 @@ Boards.helpers({
return this.subtasksDefaultBoardId;
},
- getDefaultSubtasksBoard() {
- return ReactiveCache.getBoard(this.getDefaultSubtasksBoardId());
+ async getDefaultSubtasksBoard() {
+ return await ReactiveCache.getBoard(this.getDefaultSubtasksBoardId());
},
//Date Settings option such as received date, start date and so on.
@@ -1301,8 +1315,8 @@ Boards.helpers({
return this.dateSettingsDefaultBoardId;
},
- getDefaultDateSettingsBoard() {
- return ReactiveCache.getBoard(this.getDefaultDateSettingsBoardId());
+ async getDefaultDateSettingsBoard() {
+ return await ReactiveCache.getBoard(this.getDefaultDateSettingsBoardId());
},
getDefaultSubtasksListId() {
@@ -1320,8 +1334,8 @@ Boards.helpers({
return this.subtasksDefaultListId;
},
- getDefaultSubtasksList() {
- return ReactiveCache.getList(this.getDefaultSubtasksListId());
+ async getDefaultSubtasksList() {
+ return await ReactiveCache.getList(this.getDefaultSubtasksListId());
},
getDefaultDateSettingsListId() {
@@ -1339,15 +1353,15 @@ Boards.helpers({
return this.dateSettingsDefaultListId;
},
- getDefaultDateSettingsList() {
- return ReactiveCache.getList(this.getDefaultDateSettingsListId());
+ async getDefaultDateSettingsList() {
+ return await ReactiveCache.getList(this.getDefaultDateSettingsListId());
},
- getDefaultSwimline() {
- let result = ReactiveCache.getSwimlane({ boardId: this._id });
+ async getDefaultSwimline() {
+ let result = await ReactiveCache.getSwimlane({ boardId: this._id });
if (result === undefined) {
// Check if any swimlane exists for this board to avoid duplicates
- const existingSwimlanes = ReactiveCache.getSwimlanes({ boardId: this._id });
+ const existingSwimlanes = await ReactiveCache.getSwimlanes({ boardId: this._id });
if (existingSwimlanes.length > 0) {
// Use the first existing swimlane
result = existingSwimlanes[0];
@@ -1358,14 +1372,14 @@ Boards.helpers({
title: title,
boardId: this._id,
});
- result = ReactiveCache.getSwimlane({ boardId: this._id });
+ result = await ReactiveCache.getSwimlane({ boardId: this._id });
}
}
return result;
},
- getNextCardNumber() {
- const boardCards = ReactiveCache.getCard(
+ async getNextCardNumber() {
+ const boardCards = await ReactiveCache.getCard(
{
boardId: this._id
},
@@ -1384,16 +1398,16 @@ Boards.helpers({
return maxCardNr + 1;
},
- cardsDueInBetween(start, end) {
- const ret = ReactiveCache.getCards({
+ async cardsDueInBetween(start, end) {
+ const ret = await ReactiveCache.getCards({
boardId: this._id,
dueAt: { $gte: start, $lte: end },
});
return ret;
},
- cardsInInterval(start, end) {
- const ret = ReactiveCache.getCards({
+ async cardsInInterval(start, end) {
+ const ret = await ReactiveCache.getCards({
boardId: this._id,
$or: [
{
@@ -1454,7 +1468,7 @@ Boards.helpers({
},
async setBackgroundImageURL(backgroundImageURL) {
- const currentUser = ReactiveCache.getCurrentUser();
+ const currentUser = await ReactiveCache.getCurrentUser();
if (currentUser.isBoardAdmin() || currentUser.isAdmin()) {
return await Boards.updateAsync(this._id, { $set: { backgroundImageURL } });
}
@@ -1717,32 +1731,31 @@ function boardRemover(userId, doc) {
);
}
-Boards.uniqueTitle = title => {
+Boards.uniqueTitle = async title => {
const m = title.match(
new RegExp('^(?
.*?)\\s*(\\[(?\\d+)]\\s*$|\\s*$)'),
);
const base = escapeForRegex(m.groups.title);
const baseTitle = m.groups.title;
- boards = ReactiveCache.getBoards({ title: new RegExp(`^${base}\\s*(\\[(?\\d+)]\\s*$|\\s*$)`) });
+ const boards = await ReactiveCache.getBoards({ title: new RegExp(`^${base}\\s*(\\[(?\\d+)]\\s*$|\\s*$)`) });
if (boards.length > 0) {
let num = 0;
- ReactiveCache.getBoards({ title: new RegExp(`^${base}\\s*\\[\\d+]\\s*$`) }).forEach(
- board => {
- const m = board.title.match(
- new RegExp('^(?.*?)\\s*\\[(?\\d+)]\\s*$'),
- );
- if (m) {
- const n = parseInt(m.groups.num, 10);
- num = num < n ? n : num;
- }
- },
- );
+ const numberedBoards = await ReactiveCache.getBoards({ title: new RegExp(`^${base}\\s*\\[\\d+]\\s*$`) });
+ for (const board of numberedBoards) {
+ const m = board.title.match(
+ new RegExp('^(?.*?)\\s*\\[(?\\d+)]\\s*$'),
+ );
+ if (m) {
+ const n = parseInt(m.groups.num, 10);
+ num = num < n ? n : num;
+ }
+ }
return `${baseTitle} [${num + 1}]`;
}
return title;
};
-Boards.userSearch = (
+Boards.userSearch = async (
userId,
selector = {},
projection = {},
@@ -1756,17 +1769,17 @@ Boards.userSearch = (
if (userId) {
selector.$or.push({ members: { $elemMatch: { userId, isActive: true } } });
}
- const ret = ReactiveCache.getBoards(selector, projection);
+ const ret = await ReactiveCache.getBoards(selector, projection);
return ret;
};
-Boards.userBoards = (
+Boards.userBoards = async (
userId,
archived = false,
selector = {},
projection = {},
) => {
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user) {
return [];
}
@@ -1785,13 +1798,14 @@ Boards.userBoards = (
{ teams: { $elemMatch: { teamId: { $in: user.teamIds() }, isActive: true } } },
];
- return ReactiveCache.getBoards(selector, projection);
+ return await ReactiveCache.getBoards(selector, projection);
};
-Boards.userBoardIds = (userId, archived = false, selector = {}) => {
- return Boards.userBoards(userId, archived, selector, {
+Boards.userBoardIds = async (userId, archived = false, selector = {}) => {
+ const boards = await Boards.userBoards(userId, archived, selector, {
fields: { _id: 1 },
- }).map(board => {
+ });
+ return boards.map(board => {
return board._id;
});
};
@@ -1810,7 +1824,7 @@ Boards.labelColors = () => {
if (Meteor.isServer) {
Boards.allow({
- insert(userId, doc) {
+ async insert(userId, doc) {
// Check if user is logged in
if (!userId) return false;
@@ -1829,7 +1843,7 @@ if (Meteor.isServer) {
// All logged in users are allowed to reorder boards by dragging at All Boards page and Public Boards page.
Boards.allow({
- update(userId, board, fieldNames) {
+ async update(userId, board, fieldNames) {
return canUpdateBoardSort(userId, board, fieldNames);
},
// Need members to verify membership in policy
@@ -1839,7 +1853,7 @@ if (Meteor.isServer) {
// The number of users that have starred this board is managed by trusted code
// and the user is not allowed to update it
Boards.deny({
- update(userId, board, fieldNames) {
+ async update(userId, board, fieldNames) {
return _.contains(fieldNames, 'stars');
},
fetch: [],
@@ -1847,7 +1861,7 @@ if (Meteor.isServer) {
// We can't remove a member if it is the last administrator
Boards.deny({
- update(userId, doc, fieldNames, modifier) {
+ async update(userId, doc, fieldNames, modifier) {
if (!_.contains(fieldNames, 'members')) return false;
// We only care in case of a $pull operation, ie remove a member
@@ -1873,7 +1887,7 @@ if (Meteor.isServer) {
// Deny changing permission to public if allowPrivateOnly is enabled
Boards.deny({
- update(userId, doc, fieldNames, modifier) {
+ async update(userId, doc, fieldNames, modifier) {
if (!_.contains(fieldNames, 'permission')) return false;
const allowPrivateOnly = TableVisibilityModeSettings.findOne('tableVisibilityMode-allowPrivateOnly')?.booleanValue;
@@ -1887,13 +1901,13 @@ if (Meteor.isServer) {
});
Meteor.methods({
- getBackgroundImageURL(boardId) {
+ async getBackgroundImageURL(boardId) {
check(boardId, String);
- return ReactiveCache.getBoard(boardId, {}, { backgroundImageUrl: 1 });
+ return await ReactiveCache.getBoard(boardId, {}, { backgroundImageUrl: 1 });
},
async quitBoard(boardId) {
check(boardId, String);
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (board) {
const userId = Meteor.userId();
const index = board.memberIndex(userId);
@@ -1903,9 +1917,9 @@ if (Meteor.isServer) {
} else throw new Meteor.Error('error-board-notAMember');
} else throw new Meteor.Error('error-board-doesNotExist');
},
- acceptInvite(boardId) {
+ async acceptInvite(boardId) {
check(boardId, String);
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('error-board-doesNotExist');
}
@@ -1927,9 +1941,10 @@ if (Meteor.isServer) {
}
});
},
- myLabelNames() {
+ async myLabelNames() {
let names = [];
- Boards.userBoards(Meteor.userId()).forEach(board => {
+ const boards = await Boards.userBoards(Meteor.userId());
+ for (const board of boards) {
// Only return labels when they exist.
if (board.labels !== undefined) {
names = names.concat(
@@ -1939,21 +1954,21 @@ if (Meteor.isServer) {
return label.name;
}),
);
- } else {
- return [];
}
- });
+ }
return _.uniq(names).sort();
},
- myBoardNames() {
+ async myBoardNames() {
+ const boards = await Boards.userBoards(Meteor.userId());
return _.uniq(
- Boards.userBoards(Meteor.userId()).map(board => {
+ boards.map(board => {
return board.title;
}),
).sort();
},
- setAllBoardsHideActivities() {
- if ((ReactiveCache.getCurrentUser() || {}).isAdmin) {
+ async setAllBoardsHideActivities() {
+ const currentUser = await ReactiveCache.getCurrentUser();
+ if ((currentUser || {}).isAdmin) {
Boards.update(
{
showActivities: true
@@ -1977,7 +1992,7 @@ if (Meteor.isServer) {
Meteor.methods({
async archiveBoard(boardId) {
check(boardId, String);
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (board) {
const userId = Meteor.userId();
const index = board.memberIndex(userId);
@@ -1987,14 +2002,14 @@ if (Meteor.isServer) {
} else throw new Meteor.Error('error-board-notAMember');
} else throw new Meteor.Error('error-board-doesNotExist');
},
- setBoardOrgs(boardOrgsArray, currBoardId){
+ async setBoardOrgs(boardOrgsArray, currBoardId){
check(boardOrgsArray, Array);
check(currBoardId, String);
const userId = Meteor.userId();
if (!userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in to perform this action.');
}
- const board = ReactiveCache.getBoard(currBoardId);
+ const board = await ReactiveCache.getBoard(currBoardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found.');
}
@@ -2013,7 +2028,7 @@ if (Meteor.isServer) {
},
});
},
- setBoardTeams(boardTeamsArray, membersArray, currBoardId){
+ async setBoardTeams(boardTeamsArray, membersArray, currBoardId){
check(boardTeamsArray, Array);
check(membersArray, Array);
check(currBoardId, String);
@@ -2021,7 +2036,7 @@ if (Meteor.isServer) {
if (!userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in to perform this action.');
}
- const board = ReactiveCache.getBoard(currBoardId);
+ const board = await ReactiveCache.getBoard(currBoardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found.');
}
@@ -2058,8 +2073,8 @@ if (Meteor.isServer) {
}
// Insert new board at last position in sort order.
-Boards.before.insert((userId, doc) => {
- const lastBoard = ReactiveCache.getBoard(
+Boards.before.insert(async (userId, doc) => {
+ const lastBoard = await ReactiveCache.getBoard(
{ sort: { $exists: true } },
{ sort: { sort: -1 } },
);
@@ -2243,7 +2258,7 @@ if (Meteor.isServer) {
* @return_type [{_id: string,
* title: string}]
*/
- JsonRoutes.add('GET', '/api/users/:userId/boards', function(req, res) {
+ JsonRoutes.add('GET', '/api/users/:userId/boards', async function(req, res) {
try {
Authentication.checkLoggedIn(req.userId);
const paramUserId = req.params.userId;
@@ -2254,7 +2269,7 @@ if (Meteor.isServer) {
req.userId === paramUserId,
);
- const data = ReactiveCache.getBoards(
+ const boards = await ReactiveCache.getBoards(
{
archived: false,
'members.userId': paramUserId,
@@ -2262,7 +2277,8 @@ if (Meteor.isServer) {
{
sort: { sort: 1 /* boards default sorting */ },
},
- ).map(function(board) {
+ );
+ const data = boards.map(function(board) {
return {
_id: board._id,
title: board.title,
@@ -2285,17 +2301,18 @@ if (Meteor.isServer) {
* @return_type [{_id: string,
title: string}]
*/
- JsonRoutes.add('GET', '/api/boards', function(req, res) {
+ JsonRoutes.add('GET', '/api/boards', async function(req, res) {
try {
Authentication.checkUserId(req.userId);
+ const boards = await ReactiveCache.getBoards(
+ { permission: 'public' },
+ {
+ sort: { sort: 1 /* boards default sorting */ },
+ },
+ );
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getBoards(
- { permission: 'public' },
- {
- sort: { sort: 1 /* boards default sorting */ },
- },
- ).map(function(doc) {
+ data: boards.map(function(doc) {
return {
_id: doc._id,
title: doc.title,
@@ -2316,14 +2333,16 @@ if (Meteor.isServer) {
*
* @return_type {private: integer, public: integer}
*/
- JsonRoutes.add('GET', '/api/boards_count', function(req, res) {
+ JsonRoutes.add('GET', '/api/boards_count', async function(req, res) {
try {
Authentication.checkUserId(req.userId);
+ const privateBoards = await ReactiveCache.getBoards({ permission: 'private' });
+ const publicBoards = await ReactiveCache.getBoards({ permission: 'public' });
JsonRoutes.sendResult(res, {
code: 200,
data: {
- private: ReactiveCache.getBoards({ permission: 'private' }).length,
- public: ReactiveCache.getBoards({ permission: 'public' }).length,
+ private: privateBoards.length,
+ public: publicBoards.length,
},
});
} catch (error) {
@@ -2341,14 +2360,15 @@ if (Meteor.isServer) {
* @param {string} boardId the ID of the board to retrieve the data
* @return_type Boards
*/
- JsonRoutes.add('GET', '/api/boards/:boardId', function(req, res) {
+ JsonRoutes.add('GET', '/api/boards/:boardId', async function(req, res) {
try {
const paramBoardId = req.params.boardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
+ const board = await ReactiveCache.getBoard(paramBoardId);
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getBoard(paramBoardId),
+ data: board,
});
} catch (error) {
JsonRoutes.sendResult(res, {
@@ -2493,12 +2513,12 @@ if (Meteor.isServer) {
*
* @return_type string
*/
- JsonRoutes.add('PUT', '/api/boards/:boardId/labels', function(req, res) {
+ JsonRoutes.add('PUT', '/api/boards/:boardId/labels', async function(req, res) {
const id = req.params.boardId;
Authentication.checkBoardWriteAccess(req.userId, id);
try {
if (req.body.hasOwnProperty('label')) {
- const board = ReactiveCache.getBoard(id);
+ const board = await ReactiveCache.getBoard(id);
const color = req.body.label.color;
const name = req.body.label.name;
const labelId = Random.id(6);
@@ -2536,14 +2556,14 @@ if (Meteor.isServer) {
*
* @return_type string
*/
-JsonRoutes.add('POST', '/api/boards/:boardId/copy', function(req, res) {
+JsonRoutes.add('POST', '/api/boards/:boardId/copy', async function(req, res) {
const id = req.params.boardId;
- const board = ReactiveCache.getBoard(id);
+ const board = await ReactiveCache.getBoard(id);
const adminAccess = board.members.some(e => e.userId === req.userId && e.isAdmin);
Authentication.checkAdminOrCondition(req.userId, adminAccess);
try {
- board['title'] = req.body.title || Boards.uniqueTitle(board.title);
- ret = board.copy();
+ board['title'] = req.body.title || await Boards.uniqueTitle(board.title);
+ ret = await board.copy();
JsonRoutes.sendResult(res, {
code: 200,
data: ret,
@@ -2580,7 +2600,7 @@ JsonRoutes.add('POST', '/api/boards/:boardId/copy', function(req, res) {
const boardId = req.params.boardId;
const memberId = req.params.memberId;
const { isAdmin, isNoComments, isCommentOnly, isWorker, isNormalAssignedOnly, isCommentAssignedOnly, isReadOnly, isReadAssignedOnly } = req.body;
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
function isTrue(data) {
try {
return data.toLowerCase() === 'true';
@@ -2630,13 +2650,14 @@ JsonRoutes.add('POST', '/api/boards/:boardId/copy', function(req, res) {
* cardId: string
* }]
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/attachments', function(req, res) {
+ JsonRoutes.add('GET', '/api/boards/:boardId/attachments', async function(req, res) {
const paramBoardId = req.params.boardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
+ const attachments = await ReactiveCache
+ .getAttachments({'meta.boardId': paramBoardId }, {}, true);
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache
- .getAttachments({'meta.boardId': paramBoardId }, {}, true)
+ data: attachments
.each()
.map(function(attachment) {
return {
diff --git a/models/cardCommentReactions.js b/models/cardCommentReactions.js
index 6ddd930fa..3a9a21608 100644
--- a/models/cardCommentReactions.js
+++ b/models/cardCommentReactions.js
@@ -50,14 +50,14 @@ CardCommentReactions.attachSchema(
);
CardCommentReactions.allow({
- insert(userId, doc) {
- return allowIsBoardMember(userId, ReactiveCache.getBoard(doc.boardId));
+ async insert(userId, doc) {
+ return allowIsBoardMember(userId, await ReactiveCache.getBoard(doc.boardId));
},
- update(userId, doc) {
- return allowIsBoardMember(userId, ReactiveCache.getBoard(doc.boardId));
+ async update(userId, doc) {
+ return allowIsBoardMember(userId, await ReactiveCache.getBoard(doc.boardId));
},
- remove(userId, doc) {
- return allowIsBoardMember(userId, ReactiveCache.getBoard(doc.boardId));
+ async remove(userId, doc) {
+ return allowIsBoardMember(userId, await ReactiveCache.getBoard(doc.boardId));
},
fetch: ['boardId'],
});
diff --git a/models/cardComments.js b/models/cardComments.js
index fd2e8502d..694d2187a 100644
--- a/models/cardComments.js
+++ b/models/cardComments.js
@@ -81,15 +81,15 @@ CardComments.attachSchema(
);
CardComments.allow({
- insert(userId, doc) {
+ async insert(userId, doc) {
// ReadOnly users cannot add comments. Only members who can comment are allowed.
- return allowIsBoardMemberCommentOnly(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberCommentOnly(userId, await ReactiveCache.getBoard(doc.boardId));
},
- update(userId, doc) {
- return userId === doc.userId || allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async update(userId, doc) {
+ return userId === doc.userId || allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
- remove(userId, doc) {
- return userId === doc.userId || allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async remove(userId, doc) {
+ return userId === doc.userId || allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
fetch: ['userId', 'boardId'],
});
@@ -101,21 +101,21 @@ CardComments.helpers({
CardComments.insert(this);
},
- user() {
- return ReactiveCache.getUser(this.userId);
+ async user() {
+ return await ReactiveCache.getUser(this.userId);
},
- reactions() {
- const cardCommentReactions = ReactiveCache.getCardCommentReaction({cardCommentId: this._id});
+ async reactions() {
+ const cardCommentReactions = await ReactiveCache.getCardCommentReaction({cardCommentId: this._id});
return !!cardCommentReactions ? cardCommentReactions.reactions : [];
},
- toggleReaction(reactionCodepoint) {
+ async toggleReaction(reactionCodepoint) {
if (reactionCodepoint !== sanitizeText(reactionCodepoint)) {
return false;
} else {
- const cardCommentReactions = ReactiveCache.getCardCommentReaction({cardCommentId: this._id});
+ const cardCommentReactions = await ReactiveCache.getCardCommentReaction({cardCommentId: this._id});
const reactions = !!cardCommentReactions ? cardCommentReactions.reactions : [];
const userId = Meteor.userId();
const reaction = reactions.find(r => r.reactionCodepoint === reactionCodepoint);
@@ -154,8 +154,8 @@ CardComments.helpers({
CardComments.hookOptions.after.update = { fetchPrevious: false };
-function commentCreation(userId, doc) {
- const card = ReactiveCache.getCard(doc.cardId);
+async function commentCreation(userId, doc) {
+ const card = await ReactiveCache.getCard(doc.cardId);
Activities.insert({
userId,
activityType: 'addComment',
@@ -167,9 +167,9 @@ function commentCreation(userId, doc) {
});
}
-CardComments.textSearch = (userId, textArray) => {
+CardComments.textSearch = async (userId, textArray) => {
const selector = {
- boardId: { $in: Boards.userBoardIds(userId) },
+ boardId: { $in: await Boards.userBoardIds(userId) },
$and: [],
};
@@ -180,7 +180,7 @@ CardComments.textSearch = (userId, textArray) => {
// eslint-disable-next-line no-console
// console.log('cardComments selector:', selector);
- const comments = ReactiveCache.getCardComments(selector);
+ const comments = await ReactiveCache.getCardComments(selector);
// eslint-disable-next-line no-console
// console.log('count:', comments.count());
// eslint-disable-next-line no-console
@@ -197,12 +197,12 @@ if (Meteor.isServer) {
await CardComments._collection.createIndexAsync({ cardId: 1, createdAt: -1 });
});
- CardComments.after.insert((userId, doc) => {
- commentCreation(userId, doc);
+ CardComments.after.insert(async (userId, doc) => {
+ await commentCreation(userId, doc);
});
- CardComments.after.update((userId, doc) => {
- const card = ReactiveCache.getCard(doc.cardId);
+ CardComments.after.update(async (userId, doc) => {
+ const card = await ReactiveCache.getCard(doc.cardId);
Activities.insert({
userId,
activityType: 'editComment',
@@ -214,8 +214,8 @@ if (Meteor.isServer) {
});
});
- CardComments.before.remove((userId, doc) => {
- const card = ReactiveCache.getCard(doc.cardId);
+ CardComments.before.remove(async (userId, doc) => {
+ const card = await ReactiveCache.getCard(doc.cardId);
Activities.insert({
userId,
activityType: 'deleteComment',
@@ -225,7 +225,7 @@ if (Meteor.isServer) {
listId: card.listId,
swimlaneId: card.swimlaneId,
});
- const activity = ReactiveCache.getActivity({ commentId: doc._id });
+ const activity = await ReactiveCache.getActivity({ commentId: doc._id });
if (activity) {
Activities.remove(activity._id);
}
@@ -244,7 +244,7 @@ if (Meteor.isServer) {
* comment: string,
* authorId: string}]
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/comments', function (
+ JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/comments', async function (
req,
res,
) {
@@ -254,10 +254,10 @@ if (Meteor.isServer) {
Authentication.checkBoardAccess(req.userId, paramBoardId);
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getCardComments({
+ data: (await ReactiveCache.getCardComments({
boardId: paramBoardId,
cardId: paramCardId,
- }).map(function (doc) {
+ })).map(function (doc) {
return {
_id: doc._id,
comment: doc.text,
@@ -285,7 +285,7 @@ if (Meteor.isServer) {
JsonRoutes.add(
'GET',
'/api/boards/:boardId/cards/:cardId/comments/:commentId',
- function (req, res) {
+ async function (req, res) {
try {
const paramBoardId = req.params.boardId;
const paramCommentId = req.params.commentId;
@@ -293,7 +293,7 @@ if (Meteor.isServer) {
Authentication.checkBoardAccess(req.userId, paramBoardId);
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getCardComment({
+ data: await ReactiveCache.getCardComment({
_id: paramCommentId,
cardId: paramCardId,
boardId: paramBoardId,
@@ -320,7 +320,7 @@ if (Meteor.isServer) {
JsonRoutes.add(
'POST',
'/api/boards/:boardId/cards/:cardId/comments',
- function (req, res) {
+ async function (req, res) {
try {
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
@@ -339,12 +339,12 @@ if (Meteor.isServer) {
},
});
- const cardComment = ReactiveCache.getCardComment({
+ const cardComment = await ReactiveCache.getCardComment({
_id: id,
cardId: paramCardId,
boardId: paramBoardId,
});
- commentCreation(req.userId, cardComment);
+ await commentCreation(req.userId, cardComment);
} catch (error) {
JsonRoutes.sendResult(res, {
code: 200,
diff --git a/models/cards.js b/models/cards.js
index dbd2f39cb..db715d1d5 100644
--- a/models/cards.js
+++ b/models/cards.js
@@ -519,7 +519,7 @@ Cards.attachSchema(
// Centralized update policy for Cards
// Security: deny any direct client updates to 'vote' fields; require write access otherwise
-canUpdateCard = function(userId, doc, fields) {
+canUpdateCard = async function(userId, doc, fields) {
if (!userId) return false;
const fieldNames = fields || [];
// Block direct updates to voting fields; voting must go through Meteor method 'cards.vote'
@@ -531,21 +531,21 @@ canUpdateCard = function(userId, doc, fields) {
return false;
}
// ReadOnly users cannot edit cards
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
};
Cards.allow({
- insert(userId, doc) {
+ async insert(userId, doc) {
// ReadOnly users cannot create cards
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
},
- update(userId, doc, fields) {
- return canUpdateCard(userId, doc, fields);
+ async update(userId, doc, fields) {
+ return await canUpdateCard(userId, doc, fields);
},
- remove(userId, doc) {
+ async remove(userId, doc) {
// ReadOnly users cannot delete cards
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
},
fetch: ['boardId'],
});
@@ -576,7 +576,7 @@ Cards.helpers({
// Map custom fields to new board
const result = [];
for (const cf of this.customFields) {
- const oldCf = ReactiveCache.getCustomField(cf._id);
+ const oldCf = await ReactiveCache.getCustomField(cf._id);
// Check if oldCf is undefined or null
if (!oldCf) {
@@ -585,7 +585,7 @@ Cards.helpers({
continue;
}
- const newCf = ReactiveCache.getCustomField({
+ const newCf = await ReactiveCache.getCustomField({
boardIds: boardId,
name: oldCf.name,
type: oldCf.type,
@@ -603,14 +603,14 @@ Cards.helpers({
},
- copy(boardId, swimlaneId, listId) {
+ async copy(boardId, swimlaneId, listId) {
const oldId = this._id;
- const oldCard = ReactiveCache.getCard(oldId);
+ const oldCard = await ReactiveCache.getCard(oldId);
// we must only copy the labels and custom fields if the target board
// differs from the source board
if (this.boardId !== boardId) {
- const oldBoard = ReactiveCache.getBoard(this.boardId);
+ const oldBoard = await ReactiveCache.getBoard(this.boardId);
const oldBoardLabels = oldBoard.labels;
// Get old label names
@@ -621,7 +621,7 @@ Cards.helpers({
'name',
);
- const newBoard = ReactiveCache.getBoard(boardId);
+ const newBoard = await ReactiveCache.getBoard(boardId);
const newBoardLabels = newBoard.labels;
const newCardLabels = _.pluck(
_.filter(newBoardLabels, label => {
@@ -633,15 +633,16 @@ Cards.helpers({
delete this.labelIds;
this.labelIds = newCardLabels;
- this.customFields = this.mapCustomFieldsToBoard(newBoard._id);
+ this.customFields = await this.mapCustomFieldsToBoard(newBoard._id);
}
delete this._id;
this.boardId = boardId;
- this.cardNumber = ReactiveCache.getBoard(boardId).getNextCardNumber();
+ const board = await ReactiveCache.getBoard(boardId);
+ this.cardNumber = board.getNextCardNumber();
this.swimlaneId = swimlaneId;
this.listId = listId;
- const _id = Cards.insert(this);
+ const _id = await Cards.insertAsync(this);
// Copy attachments
oldCard.attachments()
@@ -650,21 +651,24 @@ Cards.helpers({
});
// copy checklists
- ReactiveCache.getChecklists({ cardId: oldId }).forEach(ch => {
- ch.copy(_id);
- });
+ const checklists = await ReactiveCache.getChecklists({ cardId: oldId });
+ for (const ch of checklists) {
+ await ch.copy(_id);
+ }
// copy subtasks
- ReactiveCache.getCards({ parentId: oldId }).forEach(subtask => {
+ const subtasks = await ReactiveCache.getCards({ parentId: oldId });
+ for (const subtask of subtasks) {
subtask.parentId = _id;
subtask._id = null;
- Cards.insert(subtask);
- });
+ await Cards.insertAsync(subtask);
+ }
// copy card comments
- ReactiveCache.getCardComments({ cardId: oldId }).forEach(cmt => {
- cmt.copy(_id);
- });
+ const comments = await ReactiveCache.getCardComments({ cardId: oldId });
+ for (const cmt of comments) {
+ await cmt.copy(_id);
+ }
// restore the id, otherwise new copies will fail
this._id = oldId;
@@ -686,16 +690,16 @@ Cards.helpers({
return Cards.insert(linkCard);
},
- list() {
- return ReactiveCache.getList(this.listId);
+ async list() {
+ return await ReactiveCache.getList(this.listId);
},
- swimlane() {
- return ReactiveCache.getSwimlane(this.swimlaneId);
+ async swimlane() {
+ return await ReactiveCache.getSwimlane(this.swimlaneId);
},
- board() {
- const ret = ReactiveCache.getBoard(this.boardId);
+ async board() {
+ const ret = await ReactiveCache.getBoard(this.boardId);
return ret;
},
@@ -710,8 +714,8 @@ Cards.helpers({
return this.__id;
},
- getList() {
- const list = this.list();
+ async getList() {
+ const list = await this.list();
if (!list) {
return {
_id: this.listId,
@@ -723,8 +727,8 @@ Cards.helpers({
return list;
},
- getSwimlane() {
- const swimlane = this.swimlane();
+ async getSwimlane() {
+ const swimlane = await this.swimlane();
if (!swimlane) {
return {
_id: this.swimlaneId,
@@ -736,8 +740,8 @@ Cards.helpers({
return swimlane;
},
- getBoard() {
- const board = this.board();
+ async getBoard() {
+ const board = await this.board();
if (!board) {
return {
_id: this.boardId,
@@ -749,8 +753,9 @@ Cards.helpers({
return board;
},
- labels() {
- const boardLabels = this.board().labels;
+ async labels() {
+ const board = await this.board();
+ const boardLabels = board.labels;
const cardLabels = _.filter(boardLabels, label => {
return _.contains(this.labelIds, label._id);
});
@@ -766,7 +771,7 @@ Cards.helpers({
* @param swimlaneId a swimlane id
* top sorting of the card at the top if true, or from the bottom if false
*/
- getSort(listId, swimlaneId, top) {
+ async getSort(listId, swimlaneId, top) {
if (!_.isBoolean(top)) {
top = true;
}
@@ -782,7 +787,7 @@ Cards.helpers({
archived: false,
};
const sorting = top ? 1 : -1;
- const card = ReactiveCache.getCard(selector, { sort: { sort: sorting } }, true);
+ const card = await ReactiveCache.getCard(selector, { sort: { sort: sorting } }, true);
let ret = null
if (card) {
ret = card.sort;
@@ -794,8 +799,8 @@ Cards.helpers({
* @param listId a list id
* @param swimlaneId a swimlane id
*/
- getMinSort(listId, swimlaneId) {
- const ret = this.getSort(listId, swimlaneId, true);
+ async getMinSort(listId, swimlaneId) {
+ const ret = await this.getSort(listId, swimlaneId, true);
return ret;
},
@@ -803,40 +808,40 @@ Cards.helpers({
* @param listId a list id
* @param swimlaneId a swimlane id
*/
- getMaxSort(listId, swimlaneId) {
- const ret = this.getSort(listId, swimlaneId, false);
+ async getMaxSort(listId, swimlaneId) {
+ const ret = await this.getSort(listId, swimlaneId, false);
return ret;
},
- user() {
- return ReactiveCache.getUser(this.userId);
+ async user() {
+ return await ReactiveCache.getUser(this.userId);
},
- isAssigned(memberId) {
- return _.contains(this.getMembers(), memberId);
+ async isAssigned(memberId) {
+ return _.contains(await this.getMembers(), memberId);
},
- isAssignee(assigneeId) {
- return _.contains(this.getAssignees(), assigneeId);
+ async isAssignee(assigneeId) {
+ return _.contains(await this.getAssignees(), assigneeId);
},
- activities() {
+ async activities() {
let ret;
if (this.isLinkedBoard()) {
- ret = ReactiveCache.getActivities(
+ ret = await ReactiveCache.getActivities(
{ boardId: this.linkedId },
{ sort: { createdAt: -1 } },
);
} else {
- ret = ReactiveCache.getActivities({ cardId: this.getRealId() }, { sort: { createdAt: -1 } });
+ ret = await ReactiveCache.getActivities({ cardId: this.getRealId() }, { sort: { createdAt: -1 } });
}
return ret;
},
- comments() {
+ async comments() {
let ret
if (this.isLinkedBoard()) {
- ret = ReactiveCache.getCardComments(
+ ret = await ReactiveCache.getCardComments(
{ boardId: this.linkedId },
{ sort: { createdAt: -1 } },
);
@@ -850,18 +855,18 @@ Cards.helpers({
return ret;
},
- attachments() {
- const ret = ReactiveCache.getAttachments(
+ async attachments() {
+ const ret = (await ReactiveCache.getAttachments(
{ 'meta.cardId': this.getRealId() },
{ sort: { uploadedAt: -1 } },
true,
- ).each();
+ )).each();
return ret;
},
- cover() {
+ async cover() {
if (!this.coverId) return false;
- const cover = ReactiveCache.getAttachment(this.coverId);
+ const cover = await ReactiveCache.getAttachment(this.coverId);
// if we return a cover before it is fully stored, we will get errors when we try to display it
// todo XXX we could return a default "upload pending" image in the meantime?
return cover && cover.link() && cover;
@@ -967,9 +972,9 @@ Cards.helpers({
},
// customFields with definitions
- customFieldsWD() {
+ async customFieldsWD() {
// get all definitions
- const definitions = ReactiveCache.getCustomFields({
+ const definitions = await ReactiveCache.getCustomFields({
boardIds: { $in: [this.boardId] },
});
if (!definitions) {
@@ -1020,8 +1025,8 @@ Cards.helpers({
return '';
},
- absoluteUrl() {
- const board = this.board();
+ async absoluteUrl() {
+ const board = await this.board();
if (!board) return undefined;
return FlowRouter.url('card', {
boardId: board._id,
@@ -1029,8 +1034,8 @@ Cards.helpers({
cardId: this._id,
});
},
- originRelativeUrl() {
- const board = this.board();
+ async originRelativeUrl() {
+ const board = await this.board();
if (!board) return undefined;
return FlowRouter.path('card', {
boardId: board._id,
@@ -1039,8 +1044,8 @@ Cards.helpers({
});
},
- canBeRestored() {
- const list = ReactiveCache.getList(this.listId);
+ async canBeRestored() {
+ const list = await ReactiveCache.getList(this.listId);
if (
!list.getWipLimit('soft') &&
list.getWipLimit('enabled') &&
@@ -1051,18 +1056,18 @@ Cards.helpers({
return true;
},
- parentCard() {
+ async parentCard() {
let ret = null;
if (this.parentId) {
- ret = ReactiveCache.getCard(this.parentId);
+ ret = await ReactiveCache.getCard(this.parentId);
}
return ret;
},
- parentCardName() {
+ async parentCardName() {
let result = '';
if (this.parentId) {
- const card = ReactiveCache.getCard(this.parentId);
+ const card = await ReactiveCache.getCard(this.parentId);
if (card) {
result = card.title;
}
@@ -1070,11 +1075,11 @@ Cards.helpers({
return result;
},
- parentListId() {
+ async parentListId() {
const result = [];
let crtParentId = this.parentId;
while (crtParentId) {
- const crt = ReactiveCache.getCard(crtParentId);
+ const crt = await ReactiveCache.getCard(crtParentId);
if (crt === null || crt === undefined) {
// maybe it has been deleted
break;
@@ -1089,12 +1094,12 @@ Cards.helpers({
return result;
},
- parentList() {
+ async parentList() {
const resultId = [];
const result = [];
let crtParentId = this.parentId;
while (crtParentId) {
- const crt = ReactiveCache.getCard(crtParentId);
+ const crt = await ReactiveCache.getCard(crtParentId);
if (crt === null || crt === undefined) {
// maybe it has been deleted
break;
@@ -1110,8 +1115,8 @@ Cards.helpers({
return result;
},
- parentString(sep) {
- return this.parentList()
+ async parentString(sep) {
+ return (await this.parentList())
.map(function(elem) {
return elem.title;
})
@@ -1146,13 +1151,13 @@ Cards.helpers({
}
},
- getDescription() {
+ async getDescription() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card && card.description) return card.description;
else return null;
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board && board.description) return board.description;
else return null;
} else if (this.description) {
@@ -1162,16 +1167,16 @@ Cards.helpers({
}
},
- getMembers() {
+ async getMembers() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.members;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1184,16 +1189,16 @@ Cards.helpers({
}
},
- getAssignees() {
+ async getAssignees() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.assignees;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1209,10 +1214,10 @@ Cards.helpers({
async assignMember(memberId) {
let ret;
if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
ret = await board.addMember(memberId);
} else {
- ret = Cards.update(
+ ret = await Cards.updateAsync(
{ _id: this.getRealId() },
{ $addToSet: { members: memberId } },
);
@@ -1220,17 +1225,17 @@ Cards.helpers({
return ret;
},
- assignAssignee(assigneeId) {
+ async assignAssignee(assigneeId) {
if (this.isLinkedCard()) {
- return Cards.update(
+ return await Cards.updateAsync(
{ _id: this.linkedId },
{ $addToSet: { assignees: assigneeId } },
);
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
return board.addAssignee(assigneeId);
} else {
- return Cards.update(
+ return await Cards.updateAsync(
{ _id: this._id },
{ $addToSet: { assignees: assigneeId } },
);
@@ -1239,61 +1244,63 @@ Cards.helpers({
async unassignMember(memberId) {
if (this.isLinkedCard()) {
- return Cards.update(
+ return await Cards.updateAsync(
{ _id: this.linkedId },
{ $pull: { members: memberId } },
);
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
return await board.removeMember(memberId);
} else {
- return Cards.update({ _id: this._id }, { $pull: { members: memberId } });
+ return await Cards.updateAsync({ _id: this._id }, { $pull: { members: memberId } });
}
},
- unassignAssignee(assigneeId) {
+ async unassignAssignee(assigneeId) {
if (this.isLinkedCard()) {
- return Cards.update(
+ return await Cards.updateAsync(
{ _id: this.linkedId },
{ $pull: { assignees: assigneeId } },
);
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
return board.removeAssignee(assigneeId);
} else {
- return Cards.update(
+ return await Cards.updateAsync(
{ _id: this._id },
{ $pull: { assignees: assigneeId } },
);
}
},
- toggleMember(memberId) {
- if (this.getMembers() && this.getMembers().indexOf(memberId) > -1) {
- return this.unassignMember(memberId);
+ async toggleMember(memberId) {
+ const members = await this.getMembers();
+ if (members && members.indexOf(memberId) > -1) {
+ return await this.unassignMember(memberId);
} else {
- return this.assignMember(memberId);
+ return await this.assignMember(memberId);
}
},
- toggleAssignee(assigneeId) {
- if (this.getAssignees() && this.getAssignees().indexOf(assigneeId) > -1) {
- return this.unassignAssignee(assigneeId);
+ async toggleAssignee(assigneeId) {
+ const assignees = await this.getAssignees();
+ if (assignees && assignees.indexOf(assigneeId) > -1) {
+ return await this.unassignAssignee(assigneeId);
} else {
- return this.assignAssignee(assigneeId);
+ return await this.assignAssignee(assigneeId);
}
},
- getReceived() {
+ async getReceived() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.receivedAt;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1312,16 +1319,16 @@ Cards.helpers({
}
},
- getStart() {
+ async getStart() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.startAt;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1340,16 +1347,16 @@ Cards.helpers({
}
},
- getDue() {
+ async getDue() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.dueAt;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1368,16 +1375,16 @@ Cards.helpers({
}
},
- getEnd() {
+ async getEnd() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.endAt;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1396,16 +1403,16 @@ Cards.helpers({
}
},
- getIsOvertime() {
+ async getIsOvertime() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.isOvertime;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1424,16 +1431,16 @@ Cards.helpers({
}
},
- getSpentTime() {
+ async getSpentTime() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.spentTime;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1452,9 +1459,9 @@ Cards.helpers({
}
},
- getVoteQuestion() {
+ async getVoteQuestion() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else if (card && card.vote) {
@@ -1463,7 +1470,7 @@ Cards.helpers({
return null;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else if (board && board.vote) {
@@ -1478,9 +1485,9 @@ Cards.helpers({
}
},
- getVotePublic() {
+ async getVotePublic() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else if (card && card.vote) {
@@ -1489,7 +1496,7 @@ Cards.helpers({
return null;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else if (board && board.vote) {
@@ -1504,9 +1511,9 @@ Cards.helpers({
}
},
- getVoteEnd() {
+ async getVoteEnd() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else if (card && card.vote) {
@@ -1515,7 +1522,7 @@ Cards.helpers({
return null;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else if (board && board.vote) {
@@ -1529,23 +1536,23 @@ Cards.helpers({
return null;
}
},
- expiredVote() {
- let end = this.getVoteEnd();
+ async expiredVote() {
+ let end = await this.getVoteEnd();
if (end) {
end = new Date(end);
return isBefore(end, new Date());
}
return false;
},
- voteMemberPositive() {
+ async voteMemberPositive() {
if (this.vote && this.vote.positive)
- return ReactiveCache.getUsers({ _id: { $in: this.vote.positive } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.vote.positive } });
return [];
},
- voteMemberNegative() {
+ async voteMemberNegative() {
if (this.vote && this.vote.negative)
- return ReactiveCache.getUsers({ _id: { $in: this.vote.negative } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.vote.negative } });
return [];
},
voteState() {
@@ -1564,9 +1571,9 @@ Cards.helpers({
return null;
},
- getPokerQuestion() {
+ async getPokerQuestion() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else if (card && card.poker) {
@@ -1575,7 +1582,7 @@ Cards.helpers({
return null;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else if (board && board.poker) {
@@ -1598,9 +1605,9 @@ Cards.helpers({
}
},
- getPokerEnd() {
+ async getPokerEnd() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else if (card && card.poker) {
@@ -1609,7 +1616,7 @@ Cards.helpers({
return null;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else if (board && board.poker) {
@@ -1623,62 +1630,62 @@ Cards.helpers({
return null;
}
},
- expiredPoker() {
- let end = this.getPokerEnd();
+ async expiredPoker() {
+ let end = await this.getPokerEnd();
if (end) {
end = new Date(end);
return isBefore(end, new Date());
}
return false;
},
- pokerMemberOne() {
+ async pokerMemberOne() {
if (this.poker && this.poker.one)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.one } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.one } });
return [];
},
- pokerMemberTwo() {
+ async pokerMemberTwo() {
if (this.poker && this.poker.two)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.two } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.two } });
return [];
},
- pokerMemberThree() {
+ async pokerMemberThree() {
if (this.poker && this.poker.three)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.three } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.three } });
return [];
},
- pokerMemberFive() {
+ async pokerMemberFive() {
if (this.poker && this.poker.five)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.five } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.five } });
return [];
},
- pokerMemberEight() {
+ async pokerMemberEight() {
if (this.poker && this.poker.eight)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.eight } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.eight } });
return [];
},
- pokerMemberThirteen() {
+ async pokerMemberThirteen() {
if (this.poker && this.poker.thirteen)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.thirteen } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.thirteen } });
return [];
},
- pokerMemberTwenty() {
+ async pokerMemberTwenty() {
if (this.poker && this.poker.twenty)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.twenty } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.twenty } });
return [];
},
- pokerMemberForty() {
+ async pokerMemberForty() {
if (this.poker && this.poker.forty)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.forty } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.forty } });
return [];
},
- pokerMemberOneHundred() {
+ async pokerMemberOneHundred() {
if (this.poker && this.poker.oneHundred)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.oneHundred } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.oneHundred } });
return [];
},
- pokerMemberUnsure() {
+ async pokerMemberUnsure() {
if (this.poker && this.poker.unsure)
- return ReactiveCache.getUsers({ _id: { $in: this.poker.unsure } });
+ return await ReactiveCache.getUsers({ _id: { $in: this.poker.unsure } });
return [];
},
pokerState() {
@@ -1749,16 +1756,16 @@ Cards.helpers({
return null;
},
- getTitle() {
+ async getTitle() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.title;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1775,27 +1782,27 @@ Cards.helpers({
return this.cardNumber;
},
- getBoardTitle() {
+ async getBoardTitle() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
}
- const board = ReactiveCache.getBoard(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId);
if (board === undefined) {
return null;
} else {
return board.title;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
return board.title;
}
} else {
- const board = ReactiveCache.getBoard(this.boardId);
+ const board = await ReactiveCache.getBoard(this.boardId);
if (board === undefined) {
return null;
} else {
@@ -1822,16 +1829,16 @@ Cards.helpers({
}
},
- getArchived() {
+ async getArchived() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
return card.archived;
}
} else if (this.isLinkedBoard()) {
- const board = ReactiveCache.getBoard(this.linkedId);
+ const board = await ReactiveCache.getBoard(this.linkedId);
if (board === undefined) {
return null;
} else {
@@ -1846,9 +1853,9 @@ Cards.helpers({
return Cards.update({ _id: this.getRealId() }, { $set: { requestedBy } });
},
- getRequestedBy() {
+ async getRequestedBy() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
@@ -1863,9 +1870,9 @@ Cards.helpers({
return Cards.update({ _id: this.getRealId() }, { $set: { assignedBy } });
},
- getAssignedBy() {
+ async getAssignedBy() {
if (this.isLinkedCard()) {
- const card = ReactiveCache.getCard(this.linkedId);
+ const card = await ReactiveCache.getCard(this.linkedId);
if (card === undefined) {
return null;
} else {
@@ -1958,10 +1965,10 @@ Cards.helpers({
this.pokerCountUnsure()
);
},
- pokerWinner() {
+ async pokerWinner() {
const pokerListMaps = [];
let pokerWinnersListMap = [];
- if (this.expiredPoker()) {
+ if (await this.expiredPoker()) {
const one = { count: this.pokerCountOne(), pokerCard: 1 };
const two = { count: this.pokerCountTwo(), pokerCard: 2 };
const three = { count: this.pokerCountThree(), pokerCard: 3 };
@@ -1996,7 +2003,7 @@ Cards.helpers({
},
async applyToChildren(funct) {
- const cards = ReactiveCache.getCards({ parentId: this._id });
+ const cards = await ReactiveCache.getCards({ parentId: this._id });
for (const card of cards) {
await funct(card);
}
@@ -2026,7 +2033,7 @@ Cards.helpers({
let sortIndex = 0;
if (!swimlaneId) {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
swimlaneId = board.getDefaultSwimline()._id;
}
let parentElementDom = $(`#swimlane-${swimlaneId}`).get(0);
@@ -2049,7 +2056,7 @@ Cards.helpers({
boardId = boardId || this.boardId;
swimlaneId = swimlaneId || this.swimlaneId;
if (!swimlaneId) {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
swimlaneId = board.getDefaultSwimline()._id;
}
listId = listId || this.listId;
@@ -2072,7 +2079,7 @@ Cards.helpers({
}
if (this.boardId !== boardId) {
- const oldBoard = ReactiveCache.getBoard(this.boardId);
+ const oldBoard = await ReactiveCache.getBoard(this.boardId);
const oldBoardLabels = oldBoard.labels;
const oldCardLabels = _.pluck(
_.filter(oldBoardLabels, label => {
@@ -2081,7 +2088,7 @@ Cards.helpers({
'name',
);
- const newBoard = ReactiveCache.getBoard(boardId);
+ const newBoard = await ReactiveCache.getBoard(boardId);
const newBoardLabels = newBoard.labels;
const newCardLabelIds = _.pluck(
_.filter(newBoardLabels, label => {
@@ -2097,7 +2104,7 @@ Cards.helpers({
cardNumber: newCardNumber
});
- mutatedFields.customFields = this.mapCustomFieldsToBoard(newBoard._id);
+ mutatedFields.customFields = await this.mapCustomFieldsToBoard(newBoard._id);
}
await Cards.updateAsync(this._id, { $set: mutatedFields });
@@ -2404,33 +2411,34 @@ Cards.helpers({
//FUNCTIONS FOR creation of Activities
-function updateActivities(doc, fieldNames, modifier) {
+async function updateActivities(doc, fieldNames, modifier) {
if (_.contains(fieldNames, 'labelIds') && _.contains(fieldNames, 'boardId')) {
- ReactiveCache.getActivities({
+ const activities = await ReactiveCache.getActivities({
activityType: 'addedLabel',
cardId: doc._id,
- }).forEach(a => {
+ });
+ for (const a of activities) {
const lidx = doc.labelIds.indexOf(a.labelId);
if (lidx !== -1 && modifier.$set.labelIds.length > lidx) {
- Activities.update(a._id, {
+ await Activities.updateAsync(a._id, {
$set: {
labelId: modifier.$set.labelIds[doc.labelIds.indexOf(a.labelId)],
boardId: modifier.$set.boardId,
},
});
} else {
- Activities.remove(a._id);
+ await Activities.removeAsync(a._id);
}
- });
+ }
} else if (_.contains(fieldNames, 'boardId')) {
- Activities.remove({
+ await Activities.removeAsync({
activityType: 'addedLabel',
cardId: doc._id,
});
}
}
-function cardMove(
+async function cardMove(
userId,
doc,
fieldNames,
@@ -2439,15 +2447,18 @@ function cardMove(
oldBoardId,
) {
if (_.contains(fieldNames, 'boardId') && doc.boardId !== oldBoardId) {
- Activities.insert({
+ const newBoard = await ReactiveCache.getBoard(doc.boardId);
+ const oldBoard = await ReactiveCache.getBoard(oldBoardId);
+ const swimlane = await ReactiveCache.getSwimlane(doc.swimlaneId);
+ await Activities.insertAsync({
userId,
activityType: 'moveCardBoard',
- boardName: ReactiveCache.getBoard(doc.boardId).title,
+ boardName: newBoard.title,
boardId: doc.boardId,
oldBoardId,
- oldBoardName: ReactiveCache.getBoard(oldBoardId).title,
+ oldBoardName: oldBoard.title,
cardId: doc._id,
- swimlaneName: ReactiveCache.getSwimlane(doc.swimlaneId).title,
+ swimlaneName: swimlane.title,
swimlaneId: doc.swimlaneId,
oldSwimlaneId,
});
@@ -2455,40 +2466,43 @@ function cardMove(
(_.contains(fieldNames, 'listId') && doc.listId !== oldListId) ||
(_.contains(fieldNames, 'swimlaneId') && doc.swimlaneId !== oldSwimlaneId)
) {
- Activities.insert({
+ const list = await ReactiveCache.getList(doc.listId);
+ const swimlane = await ReactiveCache.getSwimlane(doc.swimlaneId);
+ await Activities.insertAsync({
userId,
oldListId,
activityType: 'moveCard',
- listName: ReactiveCache.getList(doc.listId).title,
+ listName: list.title,
listId: doc.listId,
boardId: doc.boardId,
cardId: doc._id,
cardTitle: doc.title,
- swimlaneName: ReactiveCache.getSwimlane(doc.swimlaneId).title,
+ swimlaneName: swimlane.title,
swimlaneId: doc.swimlaneId,
oldSwimlaneId,
});
}
}
-function cardState(userId, doc, fieldNames) {
+async function cardState(userId, doc, fieldNames) {
if (_.contains(fieldNames, 'archived')) {
+ const list = await ReactiveCache.getList(doc.listId);
if (doc.archived) {
- Activities.insert({
+ await Activities.insertAsync({
userId,
activityType: 'archivedCard',
- listName: ReactiveCache.getList(doc.listId).title,
+ listName: list.title,
boardId: doc.boardId,
listId: doc.listId,
cardId: doc._id,
swimlaneId: doc.swimlaneId,
});
} else {
- Activities.insert({
+ await Activities.insertAsync({
userId,
activityType: 'restoredCard',
boardId: doc.boardId,
- listName: ReactiveCache.getList(doc.listId).title,
+ listName: list.title,
listId: doc.listId,
cardId: doc._id,
swimlaneId: doc.swimlaneId,
@@ -2497,15 +2511,16 @@ function cardState(userId, doc, fieldNames) {
}
}
-function cardMembers(userId, doc, fieldNames, modifier) {
+async function cardMembers(userId, doc, fieldNames, modifier) {
if (!_.contains(fieldNames, 'members')) return;
let memberId;
// Say hello to the new member
if (modifier.$addToSet && modifier.$addToSet.members) {
memberId = modifier.$addToSet.members;
- const username = ReactiveCache.getUser(memberId).username;
+ const user = await ReactiveCache.getUser(memberId);
+ const username = user.username;
if (!_.contains(doc.members, memberId)) {
- Activities.insert({
+ await Activities.insertAsync({
userId,
username,
activityType: 'joinMember',
@@ -2521,10 +2536,11 @@ function cardMembers(userId, doc, fieldNames, modifier) {
// Say goodbye to the former member
if (modifier.$pull && modifier.$pull.members) {
memberId = modifier.$pull.members;
- const username = ReactiveCache.getUser(memberId).username;
+ const user = await ReactiveCache.getUser(memberId);
+ const username = user.username;
// Check that the former member is member of the card
if (_.contains(doc.members, memberId)) {
- Activities.insert({
+ await Activities.insertAsync({
userId,
username,
activityType: 'unjoinMember',
@@ -2538,15 +2554,16 @@ function cardMembers(userId, doc, fieldNames, modifier) {
}
}
-function cardAssignees(userId, doc, fieldNames, modifier) {
+async function cardAssignees(userId, doc, fieldNames, modifier) {
if (!_.contains(fieldNames, 'assignees')) return;
let assigneeId;
// Say hello to the new assignee
if (modifier.$addToSet && modifier.$addToSet.assignees) {
assigneeId = modifier.$addToSet.assignees;
- const username = ReactiveCache.getUser(assigneeId).username;
+ const user = await ReactiveCache.getUser(assigneeId);
+ const username = user.username;
if (!_.contains(doc.assignees, assigneeId)) {
- Activities.insert({
+ await Activities.insertAsync({
userId,
username,
activityType: 'joinAssignee',
@@ -2561,10 +2578,11 @@ function cardAssignees(userId, doc, fieldNames, modifier) {
// Say goodbye to the former assignee
if (modifier.$pull && modifier.$pull.assignees) {
assigneeId = modifier.$pull.assignees;
- const username = ReactiveCache.getUser(assigneeId).username;
+ const user = await ReactiveCache.getUser(assigneeId);
+ const username = user.username;
// Check that the former assignee is assignee of the card
if (_.contains(doc.assignees, assigneeId)) {
- Activities.insert({
+ await Activities.insertAsync({
userId,
username,
activityType: 'unjoinAssignee',
@@ -2668,16 +2686,18 @@ function cardCustomFields(userId, doc, fieldNames, modifier) {
}
}
-function cardCreation(userId, doc) {
- Activities.insert({
+async function cardCreation(userId, doc) {
+ const list = await ReactiveCache.getList(doc.listId);
+ const swimlane = await ReactiveCache.getSwimlane(doc.swimlaneId);
+ await Activities.insertAsync({
userId,
activityType: 'createCard',
boardId: doc.boardId,
- listName: ReactiveCache.getList(doc.listId).title,
+ listName: list.title,
listId: doc.listId,
cardId: doc._id,
cardTitle: doc.title,
- swimlaneName: ReactiveCache.getSwimlane(doc.swimlaneId).title,
+ swimlaneName: swimlane.title,
swimlaneId: doc.swimlaneId,
});
}
@@ -2722,13 +2742,15 @@ function cardRemover(userId, doc) {
});
}
-const findDueCards = days => {
- const seekDue = ($from, $to, activityType) => {
- ReactiveCache.getCards({
+const findDueCards = async days => {
+ const seekDue = async ($from, $to, activityType) => {
+ const cards = await ReactiveCache.getCards({
archived: false,
dueAt: { $gte: $from, $lt: $to },
- }).forEach(card => {
- const username = ReactiveCache.getUser(card.userId).username;
+ });
+ for (const card of cards) {
+ const user = await ReactiveCache.getUser(card.userId);
+ const username = user.username;
const activity = {
userId: card.userId,
username,
@@ -2740,15 +2762,15 @@ const findDueCards = days => {
timeValue: card.dueAt,
swimlaneId: card.swimlaneId,
};
- Activities.insert(activity);
- });
+ await Activities.insertAsync(activity);
+ }
};
const now = new Date(),
aday = 3600 * 24 * 1e3,
then = day => new Date(now.setHours(0, 0, 0, 0) + day * aday);
if (!days) return;
if (!days.map) days = [days];
- days.map(day => {
+ for (const day of days) {
let args = [];
if (day === 0) {
args = [then(0), then(1), 'duenow'];
@@ -2757,8 +2779,8 @@ const findDueCards = days => {
} else {
args = [then(day), now, 'pastdue'];
}
- seekDue(...args);
- });
+ await seekDue(...args);
+ }
};
const addCronJob = _.debounce(
Meteor.bindEnvironment(function findDueCardsDebounced() {
@@ -2801,14 +2823,14 @@ const addCronJob = _.debounce(
if (Meteor.isServer) {
Meteor.methods({
// Secure poker voting: only the caller's userId is modified
- 'cards.pokerVote'(cardId, state) {
+ async 'cards.pokerVote'(cardId, state) {
check(cardId, String);
if (state !== undefined && state !== null) check(state, String);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!board) throw new Meteor.Error('not-found');
const isMember = allowIsBoardMember(this.userId, board);
@@ -2820,19 +2842,19 @@ if (Meteor.isServer) {
let mod = card.setPoker(this.userId, state);
if (!mod || typeof mod !== 'object') mod = {};
mod.$set = Object.assign({}, mod.$set, { modifiedAt: new Date(), dateLastActivity: new Date() });
- return Cards.update({ _id: cardId }, mod);
+ return await Cards.updateAsync({ _id: cardId }, mod);
},
// Configure planning poker on a card (members only)
- 'cards.setPokerQuestion'(cardId, question, allowNonBoardMembers) {
+ async 'cards.setPokerQuestion'(cardId, question, allowNonBoardMembers) {
check(cardId, String);
check(question, Boolean);
check(allowNonBoardMembers, Boolean);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
@@ -2846,96 +2868,96 @@ if (Meteor.isServer) {
dateLastActivity: new Date(),
},
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.setPokerEnd'(cardId, end) {
+ async 'cards.setPokerEnd'(cardId, end) {
check(cardId, String);
check(end, Date);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
$set: { 'poker.end': end, modifiedAt: new Date(), dateLastActivity: new Date() },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.unsetPokerEnd'(cardId) {
+ async 'cards.unsetPokerEnd'(cardId) {
check(cardId, String);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
$unset: { 'poker.end': '' },
$set: { modifiedAt: new Date(), dateLastActivity: new Date() },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.unsetPoker'(cardId) {
+ async 'cards.unsetPoker'(cardId) {
check(cardId, String);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
$unset: { poker: '' },
$set: { modifiedAt: new Date(), dateLastActivity: new Date() },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.setPokerEstimation'(cardId, estimation) {
+ async 'cards.setPokerEstimation'(cardId, estimation) {
check(cardId, String);
check(estimation, Number);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
$set: { 'poker.estimation': estimation, modifiedAt: new Date(), dateLastActivity: new Date() },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.unsetPokerEstimation'(cardId) {
+ async 'cards.unsetPokerEstimation'(cardId) {
check(cardId, String);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
$unset: { 'poker.estimation': '' },
$set: { modifiedAt: new Date(), dateLastActivity: new Date() },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.replayPoker'(cardId) {
+ async 'cards.replayPoker'(cardId) {
check(cardId, String);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
// Reset all poker votes arrays
@@ -2947,19 +2969,19 @@ if (Meteor.isServer) {
},
$unset: { 'poker.end': '' },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
// Configure voting on a card (members only)
- 'cards.setVoteQuestion'(cardId, question, publicVote, allowNonBoardMembers) {
+ async 'cards.setVoteQuestion'(cardId, question, publicVote, allowNonBoardMembers) {
check(cardId, String);
check(question, String);
check(publicVote, Boolean);
check(allowNonBoardMembers, Boolean);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
@@ -2975,66 +2997,66 @@ if (Meteor.isServer) {
dateLastActivity: new Date(),
},
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.setVoteEnd'(cardId, end) {
+ async 'cards.setVoteEnd'(cardId, end) {
check(cardId, String);
check(end, Date);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
$set: { 'vote.end': end, modifiedAt: new Date(), dateLastActivity: new Date() },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.unsetVoteEnd'(cardId) {
+ async 'cards.unsetVoteEnd'(cardId) {
check(cardId, String);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
$unset: { 'vote.end': '' },
$set: { modifiedAt: new Date(), dateLastActivity: new Date() },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
- 'cards.unsetVote'(cardId) {
+ async 'cards.unsetVote'(cardId) {
check(cardId, String);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!allowIsBoardMember(this.userId, board)) throw new Meteor.Error('not-authorized');
const modifier = {
$unset: { vote: '' },
$set: { modifiedAt: new Date(), dateLastActivity: new Date() },
};
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
// Secure voting: only the caller can set/unset their vote; non-members can vote only when allowed
- 'cards.vote'(cardId, forIt) {
+ async 'cards.vote'(cardId, forIt) {
check(cardId, String);
// forIt may be true (upvote), false (downvote), or null/undefined (clear)
if (forIt !== undefined && forIt !== null) check(forIt, Boolean);
if (!this.userId) throw new Meteor.Error('not-authorized');
- const card = ReactiveCache.getCard(cardId) || Cards.findOne(cardId);
+ const card = await ReactiveCache.getCard(cardId) || await Cards.findOneAsync(cardId);
if (!card) throw new Meteor.Error('not-found');
- const board = ReactiveCache.getBoard(card.boardId) || Boards.findOne(card.boardId);
+ const board = await ReactiveCache.getBoard(card.boardId) || await Boards.findOneAsync(card.boardId);
if (!board) throw new Meteor.Error('not-found');
const isMember = allowIsBoardMember(this.userId, board);
@@ -3065,7 +3087,7 @@ if (Meteor.isServer) {
};
}
- return Cards.update({ _id: cardId }, modifier);
+ return await Cards.updateAsync({ _id: cardId }, modifier);
},
/** copies a card
* this method is needed on the server because attachments can only be copied on the server (access to file system)
@@ -3077,7 +3099,7 @@ if (Meteor.isServer) {
* @param mergeCardValues this values into the copied card
* @return the new card id
*/
- copyCard(cardId, boardId, swimlaneId, listId, insertAtTop, mergeCardValues) {
+ async copyCard(cardId, boardId, swimlaneId, listId, insertAtTop, mergeCardValues) {
check(cardId, String);
check(boardId, String);
check(swimlaneId, String);
@@ -3085,10 +3107,10 @@ if (Meteor.isServer) {
check(insertAtTop, Boolean);
check(mergeCardValues, Object);
- const card = ReactiveCache.getCard(cardId);
+ const card = await ReactiveCache.getCard(cardId);
Object.assign(card, mergeCardValues);
- const sort = card.getSort(listId, swimlaneId, insertAtTop);
+ const sort = await card.getSort(listId, swimlaneId, insertAtTop);
if (insertAtTop) {
card.sort = sort - 1;
} else
@@ -3096,7 +3118,7 @@ if (Meteor.isServer) {
card.sort = sort + 1;
}
- const ret = card.copy(boardId, swimlaneId, listId);
+ const ret = await card.copy(boardId, swimlaneId, listId);
return ret;
},
});
@@ -3119,40 +3141,40 @@ if (Meteor.isServer) {
});
});
- Cards.after.insert((userId, doc) => {
- cardCreation(userId, doc);
+ Cards.after.insert(async (userId, doc) => {
+ await cardCreation(userId, doc);
// Track original position for new cards
- Meteor.setTimeout(() => {
- const card = Cards.findOne(doc._id);
+ Meteor.setTimeout(async () => {
+ const card = await Cards.findOneAsync(doc._id);
if (card) {
card.trackOriginalPosition();
}
}, 100);
});
// New activity for card (un)archivage
- Cards.after.update((userId, doc, fieldNames) => {
- cardState(userId, doc, fieldNames);
+ Cards.after.update(async (userId, doc, fieldNames) => {
+ await cardState(userId, doc, fieldNames);
});
//New activity for card moves
- Cards.after.update(function(userId, doc, fieldNames) {
+ Cards.after.update(async function(userId, doc, fieldNames) {
const oldListId = this.previous.listId;
const oldSwimlaneId = this.previous.swimlaneId;
const oldBoardId = this.previous.boardId;
- cardMove(userId, doc, fieldNames, oldListId, oldSwimlaneId, oldBoardId);
+ await cardMove(userId, doc, fieldNames, oldListId, oldSwimlaneId, oldBoardId);
});
// Add a new activity if we add or remove a member to the card
- Cards.before.update((userId, doc, fieldNames, modifier) => {
- cardMembers(userId, doc, fieldNames, modifier);
- updateActivities(doc, fieldNames, modifier);
+ Cards.before.update(async (userId, doc, fieldNames, modifier) => {
+ await cardMembers(userId, doc, fieldNames, modifier);
+ await updateActivities(doc, fieldNames, modifier);
});
// Add a new activity if we add or remove a assignee to the card
- Cards.before.update((userId, doc, fieldNames, modifier) => {
- cardAssignees(userId, doc, fieldNames, modifier);
- updateActivities(doc, fieldNames, modifier);
+ Cards.before.update(async (userId, doc, fieldNames, modifier) => {
+ await cardAssignees(userId, doc, fieldNames, modifier);
+ await updateActivities(doc, fieldNames, modifier);
});
// Add a new activity if we add or remove a label to the card
@@ -3166,7 +3188,7 @@ if (Meteor.isServer) {
});
// Add a new activity if modify time related field like dueAt startAt etc
- Cards.before.update((userId, doc, fieldNames, modifier) => {
+ Cards.before.update(async (userId, doc, fieldNames, modifier) => {
const dla = 'dateLastActivity';
const fields = fieldNames.filter(name => name !== dla);
const timingaction = ['receivedAt', 'dueAt', 'startAt', 'endAt'];
@@ -3176,15 +3198,15 @@ if (Meteor.isServer) {
const value = modifier.$set[action];
const oldvalue = doc[action] || '';
const activityType = `a-${action}`;
- const card = ReactiveCache.getCard(doc._id);
- const list = card.list();
+ const card = await ReactiveCache.getCard(doc._id);
+ const list = await card.list();
if (list) {
// change list modifiedAt, when user modified the key values in
// timingaction array, if it's endAt, put the modifiedAt of list
// back to one year ago for sorting purpose
const modifiedAt = add(now(), -1, 'year').toISOString();
const boardId = list.boardId;
- Lists.direct.update(
+ await Lists.direct.updateAsync(
{
_id: list._id,
},
@@ -3196,7 +3218,8 @@ if (Meteor.isServer) {
},
);
}
- const username = ReactiveCache.getUser(userId).username;
+ const user = await ReactiveCache.getUser(userId);
+ const username = user.username;
const activity = {
userId,
username,
@@ -3210,7 +3233,7 @@ if (Meteor.isServer) {
listId: card.listId,
swimlaneId: card.swimlaneId,
};
- Activities.insert(activity);
+ await Activities.insertAsync(activity);
}
});
// Remove all activities associated with a card if we remove the card
@@ -3235,18 +3258,19 @@ if (Meteor.isServer) {
JsonRoutes.add(
'GET',
'/api/boards/:boardId/swimlanes/:swimlaneId/cards',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramSwimlaneId = req.params.swimlaneId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
+ const cards = await ReactiveCache.getCards({
+ boardId: paramBoardId,
+ swimlaneId: paramSwimlaneId,
+ archived: false,
+ },
+ { sort: ['sort'] });
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getCards({
- boardId: paramBoardId,
- swimlaneId: paramSwimlaneId,
- archived: false,
- },
- { sort: ['sort'] }).map(function(doc) {
+ data: cards.map(function(doc) {
return {
_id: doc._id,
title: doc.title,
@@ -3276,21 +3300,22 @@ if (Meteor.isServer) {
* title: string,
* description: string}]
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards', function(
+ JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards', async function(
req,
res,
) {
const paramBoardId = req.params.boardId;
const paramListId = req.params.listId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
+ const cards = await ReactiveCache.getCards({
+ boardId: paramBoardId,
+ listId: paramListId,
+ archived: false,
+ },
+ { sort: ['sort'] });
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getCards({
- boardId: paramBoardId,
- listId: paramListId,
- archived: false,
- },
- { sort: ['sort'] }).map(function(doc) {
+ data: cards.map(function(doc) {
return {
_id: doc._id,
title: doc.title,
@@ -3317,9 +3342,9 @@ if (Meteor.isServer) {
JsonRoutes.add(
'GET',
'/api/cards/:cardId',
- function(req, res) {
+ async function(req, res) {
const paramCardId = req.params.cardId;
- card = ReactiveCache.getCard(paramCardId)
+ const card = await ReactiveCache.getCard(paramCardId);
Authentication.checkBoardAccess(req.userId, card.boardId);
JsonRoutes.sendResult(res, {
code: 200,
@@ -3340,14 +3365,14 @@ if (Meteor.isServer) {
JsonRoutes.add(
'GET',
'/api/boards/:boardId/lists/:listId/cards/:cardId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramListId = req.params.listId;
const paramCardId = req.params.cardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getCard({
+ data: await ReactiveCache.getCard({
_id: paramCardId,
listId: paramListId,
boardId: paramBoardId,
@@ -3372,7 +3397,7 @@ if (Meteor.isServer) {
* @param {string} [assignees] the assignee IDs list of the new card
* @return_type {_id: string}
*/
- JsonRoutes.add('POST', '/api/boards/:boardId/lists/:listId/cards', function(
+ JsonRoutes.add('POST', '/api/boards/:boardId/lists/:listId/cards', async function(
req,
res,
) {
@@ -3380,7 +3405,7 @@ if (Meteor.isServer) {
Authentication.checkLoggedIn(req.userId);
const paramBoardId = req.params.boardId;
// Check user has permission to add card to the board
- const board = ReactiveCache.getBoard(paramBoardId);
+ const board = await ReactiveCache.getBoard(paramBoardId);
const addPermission = allowIsBoardMemberCommentOnly(req.userId, board);
Authentication.checkAdminOrCondition(req.userId, addPermission);
const paramListId = req.params.listId;
@@ -3388,26 +3413,27 @@ if (Meteor.isServer) {
const nextCardNumber = board.getNextCardNumber();
let customFieldsArr = [];
+ const customFields = await ReactiveCache.getCustomFields({'boardIds': paramBoardId});
_.forEach(
- ReactiveCache.getCustomFields({'boardIds': paramBoardId}),
+ customFields,
function (field) {
if (field.automaticallyOnCard || field.alwaysOnCard)
customFieldsArr.push({ _id: field._id, value: null });
},
);
- const currentCards = ReactiveCache.getCards(
+ const currentCards = await ReactiveCache.getCards(
{
listId: paramListId,
archived: false,
},
{ sort: ['sort'] },
);
- const check = ReactiveCache.getUser(req.body.authorId);
+ const checkUser = await ReactiveCache.getUser(req.body.authorId);
const members = req.body.members;
const assignees = req.body.assignees;
- if (typeof check !== 'undefined') {
- const id = Cards.direct.insert({
+ if (typeof checkUser !== 'undefined') {
+ const id = await Cards.direct.insertAsync({
title: req.body.title,
boardId: paramBoardId,
listId: paramListId,
@@ -3428,8 +3454,8 @@ if (Meteor.isServer) {
},
});
- const card = ReactiveCache.getCard(id);
- cardCreation(req.body.authorId, card);
+ const card = await ReactiveCache.getCard(id);
+ await cardCreation(req.body.authorId, card);
} else {
JsonRoutes.sendResult(res, {
code: 401,
@@ -3444,20 +3470,21 @@ if (Meteor.isServer) {
* @param {string} boardId the board ID
* @return_type {board_cards_count: integer}
*/
-JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
+JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', async function(
req,
res,
) {
try {
const paramBoardId = req.params.boardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
+ const cards = await ReactiveCache.getCards({
+ boardId: paramBoardId,
+ archived: false,
+ });
JsonRoutes.sendResult(res, {
code: 200,
data: {
- board_cards_count: ReactiveCache.getCards({
- boardId: paramBoardId,
- archived: false,
- }).length,
+ board_cards_count: cards.length,
}
});
} catch (error) {
@@ -3476,7 +3503,7 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
* @param {string} listId the List ID
* @return_type {list_cards_count: integer}
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards_count', function(
+ JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards_count', async function(
req,
res,
) {
@@ -3484,14 +3511,15 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
const paramBoardId = req.params.boardId;
const paramListId = req.params.listId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
+ const cards = await ReactiveCache.getCards({
+ boardId: paramBoardId,
+ listId: paramListId,
+ archived: false,
+ });
JsonRoutes.sendResult(res, {
code: 200,
data: {
- list_cards_count: ReactiveCache.getCards({
- boardId: paramBoardId,
- listId: paramListId,
- archived: false,
- }).length,
+ list_cards_count: cards.length,
}
});
} catch (error) {
@@ -3560,7 +3588,7 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
JsonRoutes.add(
'PUT',
'/api/boards/:boardId/lists/:listId/cards/:cardId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
const paramListId = req.params.listId;
@@ -3913,8 +3941,8 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
);
updated = true;
- const card = ReactiveCache.getCard(paramCardId);
- cardMove(
+ const card = await ReactiveCache.getCard(paramCardId);
+ await cardMove(
req.body.authorId,
card,
{
@@ -3928,7 +3956,7 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
Authentication.checkBoardWriteAccess(req.userId, newBoardId);
// Validate that the destination list exists and belongs to the destination board
- const destList = ReactiveCache.getList({
+ const destList = await ReactiveCache.getList({
_id: newListId,
boardId: newBoardId,
archived: false,
@@ -3942,7 +3970,7 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
}
// Validate that the destination swimlane exists and belongs to the destination board
- const destSwimlane = ReactiveCache.getSwimlane({
+ const destSwimlane = await ReactiveCache.getSwimlane({
_id: newSwimlaneId,
boardId: newBoardId,
archived: false,
@@ -3956,7 +3984,7 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
}
// Move the card to the new board, swimlane, and list
- Cards.direct.update(
+ await Cards.direct.updateAsync(
{
_id: paramCardId,
listId: paramListId,
@@ -3973,8 +4001,8 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
);
updated = true;
- const card = ReactiveCache.getCard(paramCardId);
- cardMove(
+ const card = await ReactiveCache.getCard(paramCardId);
+ await cardMove(
req.userId,
card,
['boardId', 'swimlaneId', 'listId'],
@@ -4037,13 +4065,13 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
JsonRoutes.add(
'DELETE',
'/api/boards/:boardId/lists/:listId/cards/:cardId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramListId = req.params.listId;
const paramCardId = req.params.cardId;
Authentication.checkBoardWriteAccess(req.userId, paramBoardId);
- const card = ReactiveCache.getCard(paramCardId);
+ const card = await ReactiveCache.getCard(paramCardId);
Cards.direct.remove({
_id: paramCardId,
listId: paramListId,
@@ -4075,14 +4103,14 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
JsonRoutes.add(
'GET',
'/api/boards/:boardId/cardsByCustomField/:customFieldId/:customFieldValue',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCustomFieldId = req.params.customFieldId;
const paramCustomFieldValue = req.params.customFieldValue;
Authentication.checkBoardAccess(req.userId, paramBoardId);
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getCards({
+ data: await ReactiveCache.getCards({
boardId: paramBoardId,
customFields: {
$elemMatch: {
@@ -4111,14 +4139,14 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
JsonRoutes.add(
'POST',
'/api/boards/:boardId/lists/:listId/cards/:cardId/customFields/:customFieldId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
const paramListId = req.params.listId;
const paramCustomFieldId = req.params.customFieldId;
const paramCustomFieldValue = req.body.value;
Authentication.checkBoardWriteAccess(req.userId, paramBoardId);
- const card = ReactiveCache.getCard({
+ const card = await ReactiveCache.getCard({
_id: paramCardId,
listId: paramListId,
boardId: paramBoardId,
@@ -4174,7 +4202,7 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
const paramCardId = req.params.cardId;
const paramListId = req.params.listId;
Authentication.checkBoardWriteAccess(req.userId, paramBoardId);
- const card = ReactiveCache.getCard({
+ const card = await ReactiveCache.getCard({
_id: paramCardId,
listId: paramListId,
boardId: paramBoardId,
@@ -4213,7 +4241,7 @@ JsonRoutes.add('GET', '/api/boards/:boardId/cards_count', function(
const paramCardId = req.params.cardId;
const paramListId = req.params.listId;
Authentication.checkBoardWriteAccess(req.userId, paramBoardId);
- const card = ReactiveCache.getCard({
+ const card = await ReactiveCache.getCard({
_id: paramCardId,
listId: paramListId,
boardId: paramBoardId,
diff --git a/models/checklistItems.js b/models/checklistItems.js
index 7b55ac9a7..a1d1f24b7 100644
--- a/models/checklistItems.js
+++ b/models/checklistItems.js
@@ -69,17 +69,17 @@ ChecklistItems.attachSchema(
);
ChecklistItems.allow({
- insert(userId, doc) {
+ async insert(userId, doc) {
// ReadOnly users cannot create checklist items
- return allowIsBoardMemberWithWriteAccessByCard(userId, ReactiveCache.getCard(doc.cardId));
+ return allowIsBoardMemberWithWriteAccessByCard(userId, await ReactiveCache.getCard(doc.cardId));
},
- update(userId, doc) {
+ async update(userId, doc) {
// ReadOnly users cannot edit checklist items
- return allowIsBoardMemberWithWriteAccessByCard(userId, ReactiveCache.getCard(doc.cardId));
+ return allowIsBoardMemberWithWriteAccessByCard(userId, await ReactiveCache.getCard(doc.cardId));
},
- remove(userId, doc) {
+ async remove(userId, doc) {
// ReadOnly users cannot delete checklist items
- return allowIsBoardMemberWithWriteAccessByCard(userId, ReactiveCache.getCard(doc.cardId));
+ return allowIsBoardMemberWithWriteAccessByCard(userId, await ReactiveCache.getCard(doc.cardId));
},
fetch: ['userId', 'cardId'],
});
@@ -104,7 +104,8 @@ ChecklistItems.helpers({
return await ChecklistItems.updateAsync(this._id, { $set: { isFinished: !this.isFinished } });
},
async move(checklistId, sortIndex) {
- const cardId = ReactiveCache.getChecklist(checklistId).cardId;
+ const checklist = await ReactiveCache.getChecklist(checklistId);
+ const cardId = checklist.cardId;
return await ChecklistItems.updateAsync(this._id, {
$set: { cardId, checklistId, sort: sortIndex },
});
@@ -112,8 +113,8 @@ ChecklistItems.helpers({
});
// Activities helper
-function itemCreation(userId, doc) {
- const card = ReactiveCache.getCard(doc.cardId);
+async function itemCreation(userId, doc) {
+ const card = await ReactiveCache.getCard(doc.cardId);
const boardId = card.boardId;
Activities.insert({
userId,
@@ -134,8 +135,8 @@ function itemRemover(userId, doc) {
});
}
-function publishCheckActivity(userId, doc) {
- const card = ReactiveCache.getCard(doc.cardId);
+async function publishCheckActivity(userId, doc) {
+ const card = await ReactiveCache.getCard(doc.cardId);
const boardId = card.boardId;
let activityType;
if (doc.isFinished) {
@@ -157,11 +158,11 @@ function publishCheckActivity(userId, doc) {
Activities.insert(act);
}
-function publishChekListCompleted(userId, doc) {
- const card = ReactiveCache.getCard(doc.cardId);
+async function publishChekListCompleted(userId, doc) {
+ const card = await ReactiveCache.getCard(doc.cardId);
const boardId = card.boardId;
const checklistId = doc.checklistId;
- const checkList = ReactiveCache.getChecklist(checklistId);
+ const checkList = await ReactiveCache.getChecklist(checklistId);
if (checkList.isFinished()) {
const act = {
userId,
@@ -177,11 +178,11 @@ function publishChekListCompleted(userId, doc) {
}
}
-function publishChekListUncompleted(userId, doc) {
- const card = ReactiveCache.getCard(doc.cardId);
+async function publishChekListUncompleted(userId, doc) {
+ const card = await ReactiveCache.getCard(doc.cardId);
const boardId = card.boardId;
const checklistId = doc.checklistId;
- const checkList = ReactiveCache.getChecklist(checklistId);
+ const checkList = await ReactiveCache.getChecklist(checklistId);
// BUGS in IFTTT Rules: https://github.com/wekan/wekan/issues/1972
// Currently in checklist all are set as uncompleted/not checked,
// IFTTT Rule does not move card to other list.
@@ -218,22 +219,22 @@ if (Meteor.isServer) {
await ChecklistItems._collection.createIndexAsync({ cardId: 1 });
});
- ChecklistItems.after.update((userId, doc, fieldNames) => {
- publishCheckActivity(userId, doc);
- publishChekListCompleted(userId, doc, fieldNames);
+ ChecklistItems.after.update(async (userId, doc, fieldNames) => {
+ await publishCheckActivity(userId, doc);
+ await publishChekListCompleted(userId, doc, fieldNames);
});
- ChecklistItems.before.update((userId, doc, fieldNames) => {
- publishChekListUncompleted(userId, doc, fieldNames);
+ ChecklistItems.before.update(async (userId, doc, fieldNames) => {
+ await publishChekListUncompleted(userId, doc, fieldNames);
});
- ChecklistItems.after.insert((userId, doc) => {
- itemCreation(userId, doc);
+ ChecklistItems.after.insert(async (userId, doc) => {
+ await itemCreation(userId, doc);
});
- ChecklistItems.before.remove((userId, doc) => {
+ ChecklistItems.before.remove(async (userId, doc) => {
itemRemover(userId, doc);
- const card = ReactiveCache.getCard(doc.cardId);
+ const card = await ReactiveCache.getCard(doc.cardId);
const boardId = card.boardId;
Activities.insert({
userId,
@@ -264,15 +265,15 @@ if (Meteor.isServer) {
JsonRoutes.add(
'GET',
'/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
const paramChecklistId = req.params.checklistId;
const paramItemId = req.params.itemId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
- const checklistItem = ReactiveCache.getChecklistItem(paramItemId);
+ const checklistItem = await ReactiveCache.getChecklistItem(paramItemId);
if (checklistItem && checklistItem.cardId === paramCardId && checklistItem.checklistId === paramChecklistId) {
- const card = ReactiveCache.getCard(checklistItem.cardId);
+ const card = await ReactiveCache.getCard(checklistItem.cardId);
if (card && card.boardId === paramBoardId) {
JsonRoutes.sendResult(res, {
code: 200,
@@ -305,17 +306,17 @@ if (Meteor.isServer) {
JsonRoutes.add(
'POST',
'/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramChecklistId = req.params.checklistId;
const paramCardId = req.params.cardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
- const checklist = ReactiveCache.getChecklist({
+ const checklist = await ReactiveCache.getChecklist({
_id: paramChecklistId,
cardId: paramCardId,
});
if (checklist) {
- const card = ReactiveCache.getCard(paramCardId);
+ const card = await ReactiveCache.getCard(paramCardId);
if (card && card.boardId === paramBoardId) {
const id = ChecklistItems.insert({
cardId: paramCardId,
@@ -359,21 +360,21 @@ if (Meteor.isServer) {
JsonRoutes.add(
'PUT',
'/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
const paramChecklistId = req.params.checklistId;
const paramItemId = req.params.itemId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
- const checklistItem = ReactiveCache.getChecklistItem(paramItemId);
+ const checklistItem = await ReactiveCache.getChecklistItem(paramItemId);
if (!checklistItem || checklistItem.cardId !== paramCardId || checklistItem.checklistId !== paramChecklistId) {
JsonRoutes.sendResult(res, {
code: 404,
});
return;
}
- const card = ReactiveCache.getCard(checklistItem.cardId);
+ const card = await ReactiveCache.getCard(checklistItem.cardId);
if (!card || card.boardId !== paramBoardId) {
JsonRoutes.sendResult(res, {
code: 404,
@@ -427,21 +428,21 @@ if (Meteor.isServer) {
JsonRoutes.add(
'DELETE',
'/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
const paramChecklistId = req.params.checklistId;
const paramItemId = req.params.itemId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
- const checklistItem = ReactiveCache.getChecklistItem(paramItemId);
+ const checklistItem = await ReactiveCache.getChecklistItem(paramItemId);
if (!checklistItem || checklistItem.cardId !== paramCardId || checklistItem.checklistId !== paramChecklistId) {
JsonRoutes.sendResult(res, {
code: 404,
});
return;
}
- const card = ReactiveCache.getCard(checklistItem.cardId);
+ const card = await ReactiveCache.getCard(checklistItem.cardId);
if (!card || card.boardId !== paramBoardId) {
JsonRoutes.sendResult(res, {
code: 404,
diff --git a/models/checklists.js b/models/checklists.js
index 216524f2e..aa0da7b05 100644
--- a/models/checklists.js
+++ b/models/checklists.js
@@ -88,19 +88,18 @@ Checklists.attachSchema(
);
Checklists.helpers({
- copy(newCardId) {
+ async copy(newCardId) {
let copyObj = Object.assign({}, this);
delete copyObj._id;
copyObj.cardId = newCardId;
const newChecklistId = Checklists.insert(copyObj);
- ReactiveCache.getChecklistItems({ checklistId: this._id }).forEach(function(
- item,
- ) {
+ const items = await ReactiveCache.getChecklistItems({ checklistId: this._id });
+ for (const item of items) {
item._id = null;
item.checklistId = newChecklistId;
item.cardId = newCardId;
ChecklistItems.insert(item);
- });
+ }
},
itemCount() {
@@ -151,19 +150,20 @@ Checklists.helpers({
return ret;
},
async checkAllItems() {
- const checkItems = ReactiveCache.getChecklistItems({ checklistId: this._id });
+ const checkItems = await ReactiveCache.getChecklistItems({ checklistId: this._id });
for (const item of checkItems) {
await item.check();
}
},
async uncheckAllItems() {
- const checkItems = ReactiveCache.getChecklistItems({ checklistId: this._id });
+ const checkItems = await ReactiveCache.getChecklistItems({ checklistId: this._id });
for (const item of checkItems) {
await item.uncheck();
}
},
- itemIndex(itemId) {
- const items = ReactiveCache.getChecklist({ _id: this._id }).items;
+ async itemIndex(itemId) {
+ const checklist = await ReactiveCache.getChecklist({ _id: this._id });
+ const items = checklist.items;
return _.pluck(items, '_id').indexOf(itemId);
},
@@ -196,17 +196,17 @@ Checklists.helpers({
});
Checklists.allow({
- insert(userId, doc) {
+ async insert(userId, doc) {
// ReadOnly users cannot create checklists
- return allowIsBoardMemberWithWriteAccessByCard(userId, ReactiveCache.getCard(doc.cardId));
+ return allowIsBoardMemberWithWriteAccessByCard(userId, await ReactiveCache.getCard(doc.cardId));
},
- update(userId, doc) {
+ async update(userId, doc) {
// ReadOnly users cannot edit checklists
- return allowIsBoardMemberWithWriteAccessByCard(userId, ReactiveCache.getCard(doc.cardId));
+ return allowIsBoardMemberWithWriteAccessByCard(userId, await ReactiveCache.getCard(doc.cardId));
},
- remove(userId, doc) {
+ async remove(userId, doc) {
// ReadOnly users cannot delete checklists
- return allowIsBoardMemberWithWriteAccessByCard(userId, ReactiveCache.getCard(doc.cardId));
+ return allowIsBoardMemberWithWriteAccessByCard(userId, await ReactiveCache.getCard(doc.cardId));
},
fetch: ['userId', 'cardId'],
});
@@ -221,22 +221,22 @@ Checklists.before.insert((userId, doc) => {
if (Meteor.isServer) {
Meteor.methods({
- moveChecklist(checklistId, newCardId) {
+ async moveChecklist(checklistId, newCardId) {
check(checklistId, String);
check(newCardId, String);
- const checklist = ReactiveCache.getChecklist(checklistId);
+ const checklist = await ReactiveCache.getChecklist(checklistId);
if (!checklist) {
throw new Meteor.Error('checklist-not-found', 'Checklist not found');
}
- const newCard = ReactiveCache.getCard(newCardId);
+ const newCard = await ReactiveCache.getCard(newCardId);
if (!newCard) {
throw new Meteor.Error('card-not-found', 'Target card not found');
}
// Check permissions on both source and target cards
- const sourceCard = ReactiveCache.getCard(checklist.cardId);
+ const sourceCard = await ReactiveCache.getCard(checklist.cardId);
if (!allowIsBoardMemberByCard(this.userId, sourceCard)) {
throw new Meteor.Error('not-authorized', 'Not authorized to move checklist from source card');
}
@@ -245,22 +245,24 @@ if (Meteor.isServer) {
}
// Update activities
- ReactiveCache.getActivities({ checklistId }).forEach(activity => {
+ const activities = await ReactiveCache.getActivities({ checklistId });
+ for (const activity of activities) {
Activities.update(activity._id, {
$set: {
cardId: newCardId,
},
});
- });
+ }
// Update checklist items
- ReactiveCache.getChecklistItems({ checklistId }).forEach(checklistItem => {
+ const checklistItems = await ReactiveCache.getChecklistItems({ checklistId });
+ for (const checklistItem of checklistItems) {
ChecklistItems.update(checklistItem._id, {
$set: {
cardId: newCardId,
},
});
- });
+ }
// Update the checklist itself
Checklists.update(checklistId, {
@@ -278,8 +280,8 @@ if (Meteor.isServer) {
await Checklists._collection.createIndexAsync({ cardId: 1, createdAt: 1 });
});
- Checklists.after.insert((userId, doc) => {
- const card = ReactiveCache.getCard(doc.cardId);
+ Checklists.after.insert(async (userId, doc) => {
+ const card = await ReactiveCache.getCard(doc.cardId);
Activities.insert({
userId,
activityType: 'addChecklist',
@@ -292,19 +294,19 @@ if (Meteor.isServer) {
});
});
- Checklists.before.remove((userId, doc) => {
- const activities = ReactiveCache.getActivities({ checklistId: doc._id });
- const card = ReactiveCache.getCard(doc.cardId);
+ Checklists.before.remove(async (userId, doc) => {
+ const activities = await ReactiveCache.getActivities({ checklistId: doc._id });
+ const card = await ReactiveCache.getCard(doc.cardId);
if (activities) {
- activities.forEach(activity => {
+ for (const activity of activities) {
Activities.remove(activity._id);
- });
+ }
}
Activities.insert({
userId,
activityType: 'removeChecklist',
cardId: doc.cardId,
- boardId: ReactiveCache.getCard(doc.cardId).boardId,
+ boardId: (await ReactiveCache.getCard(doc.cardId)).boardId,
checklistId: doc._id,
checklistName: doc.title,
listId: card.listId,
@@ -326,13 +328,13 @@ if (Meteor.isServer) {
JsonRoutes.add(
'GET',
'/api/boards/:boardId/cards/:cardId/checklists',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
// Verify the card belongs to the board
- const card = ReactiveCache.getCard({
+ const card = await ReactiveCache.getCard({
_id: paramCardId,
boardId: paramBoardId,
});
@@ -344,7 +346,7 @@ if (Meteor.isServer) {
return;
}
- const checklists = ReactiveCache.getChecklists({ cardId: paramCardId }).map(function(
+ const checklists = (await ReactiveCache.getChecklists({ cardId: paramCardId })).map(function(
doc,
) {
return {
@@ -384,14 +386,14 @@ if (Meteor.isServer) {
JsonRoutes.add(
'GET',
'/api/boards/:boardId/cards/:cardId/checklists/:checklistId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramChecklistId = req.params.checklistId;
const paramCardId = req.params.cardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
// Verify the card belongs to the board
- const card = ReactiveCache.getCard({
+ const card = await ReactiveCache.getCard({
_id: paramCardId,
boardId: paramBoardId,
});
@@ -403,14 +405,14 @@ if (Meteor.isServer) {
return;
}
- const checklist = ReactiveCache.getChecklist({
+ const checklist = await ReactiveCache.getChecklist({
_id: paramChecklistId,
cardId: paramCardId,
});
if (checklist) {
- checklist.items = ReactiveCache.getChecklistItems({
+ checklist.items = (await ReactiveCache.getChecklistItems({
checklistId: checklist._id,
- }).map(function(doc) {
+ })).map(function(doc) {
return {
_id: doc._id,
title: doc.title,
@@ -442,19 +444,19 @@ if (Meteor.isServer) {
JsonRoutes.add(
'POST',
'/api/boards/:boardId/cards/:cardId/checklists',
- function(req, res) {
+ async function(req, res) {
// Check user is logged in
//Authentication.checkLoggedIn(req.userId);
const paramBoardId = req.params.boardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
// Check user has permission to add checklist to the card
- const board = ReactiveCache.getBoard(paramBoardId);
+ const board = await ReactiveCache.getBoard(paramBoardId);
const addPermission = allowIsBoardMemberCommentOnly(req.userId, board);
Authentication.checkAdminOrCondition(req.userId, addPermission);
const paramCardId = req.params.cardId;
// Verify the card belongs to the board
- const card = ReactiveCache.getCard({
+ const card = await ReactiveCache.getCard({
_id: paramCardId,
boardId: paramBoardId,
});
@@ -516,14 +518,14 @@ if (Meteor.isServer) {
JsonRoutes.add(
'DELETE',
'/api/boards/:boardId/cards/:cardId/checklists/:checklistId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
const paramChecklistId = req.params.checklistId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
// Verify the card belongs to the board
- const card = ReactiveCache.getCard({
+ const card = await ReactiveCache.getCard({
_id: paramCardId,
boardId: paramBoardId,
});
@@ -536,7 +538,7 @@ if (Meteor.isServer) {
}
// Verify the checklist exists and belongs to the card
- const checklist = ReactiveCache.getChecklist({
+ const checklist = await ReactiveCache.getChecklist({
_id: paramChecklistId,
cardId: paramCardId,
});
diff --git a/models/csvCreator.js b/models/csvCreator.js
index fd3ee399a..85428ab9e 100644
--- a/models/csvCreator.js
+++ b/models/csvCreator.js
@@ -247,7 +247,7 @@ export class CsvCreator {
this.swimlane = swimlaneId;
}
- createLists(csvData, boardId) {
+ async createLists(csvData, boardId) {
let numOfCreatedLists = 0;
for (let i = 1; i < csvData.length; i++) {
const listToCreate = {
@@ -256,7 +256,7 @@ export class CsvCreator {
createdAt: this._now(),
};
if (csvData[i][this.fieldIndex.stage]) {
- const existingList = ReactiveCache.getLists({
+ const existingList = await ReactiveCache.getLists({
title: csvData[i][this.fieldIndex.stage],
boardId,
});
@@ -279,7 +279,7 @@ export class CsvCreator {
}
}
- createCards(csvData, boardId) {
+ async createCards(csvData, boardId) {
for (let i = 1; i < csvData.length; i++) {
const cardToCreate = {
archived: false,
@@ -321,7 +321,7 @@ export class CsvCreator {
}
// add the labels
if (csvData[i][this.fieldIndex.labels]) {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
for (const importedLabel of csvData[i][this.fieldIndex.labels].split(
' ',
)) {
@@ -388,15 +388,15 @@ export class CsvCreator {
Meteor.settings.public &&
Meteor.settings.public.sandstorm;
if (isSandstorm && currentBoardId) {
- const currentBoard = ReactiveCache.getBoard(currentBoardId);
+ const currentBoard = await ReactiveCache.getBoard(currentBoardId);
await currentBoard.archive();
}
this.mapHeadertoCardFieldIndex(board[0]);
const boardId = this.createBoard(board);
- this.createLists(board, boardId);
+ await this.createLists(board, boardId);
this.createSwimlanes(boardId);
this.createCustomFields(boardId);
- this.createCards(board, boardId);
+ await this.createCards(board, boardId);
return boardId;
}
}
diff --git a/models/customFields.js b/models/customFields.js
index 5d1499e5f..7fa31d9ae 100644
--- a/models/customFields.js
+++ b/models/customFields.js
@@ -164,26 +164,26 @@ CustomFields.helpers({
});
CustomFields.allow({
- insert(userId, doc) {
+ async insert(userId, doc) {
return allowIsAnyBoardMember(
userId,
- ReactiveCache.getBoards({
+ await ReactiveCache.getBoards({
_id: { $in: doc.boardIds },
}),
);
},
- update(userId, doc) {
+ async update(userId, doc) {
return allowIsAnyBoardMember(
userId,
- ReactiveCache.getBoards({
+ await ReactiveCache.getBoards({
_id: { $in: doc.boardIds },
}),
);
},
- remove(userId, doc) {
+ async remove(userId, doc) {
return allowIsAnyBoardMember(
userId,
- ReactiveCache.getBoards({
+ await ReactiveCache.getBoards({
_id: { $in: doc.boardIds },
}),
);
@@ -214,9 +214,9 @@ function customFieldDeletion(userId, doc) {
// This has some bug, it does not show edited customField value at Outgoing Webhook,
// instead it shows undefined, and no listId and swimlaneId.
-function customFieldEdit(userId, doc) {
- const card = ReactiveCache.getCard(doc.cardId);
- const customFieldValue = ReactiveCache.getActivity({ customFieldId: doc._id }).value;
+async function customFieldEdit(userId, doc) {
+ const card = await ReactiveCache.getCard(doc.cardId);
+ const customFieldValue = (await ReactiveCache.getActivity({ customFieldId: doc._id })).value;
Activities.insert({
userId,
activityType: 'setCustomField',
@@ -242,14 +242,14 @@ if (Meteor.isServer) {
}
});
- CustomFields.before.update((userId, doc, fieldNames, modifier) => {
+ CustomFields.before.update(async (userId, doc, fieldNames, modifier) => {
if (_.contains(fieldNames, 'boardIds') && modifier.$pull) {
Cards.update(
{ boardId: modifier.$pull.boardIds, 'customFields._id': doc._id },
{ $pull: { customFields: { _id: doc._id } } },
{ multi: true },
);
- customFieldEdit(userId, doc);
+ await customFieldEdit(userId, doc);
Activities.remove({
customFieldId: doc._id,
boardId: modifier.$pull.boardIds,
@@ -296,7 +296,7 @@ if (Meteor.isServer) {
* name: string,
* type: string}]
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/custom-fields', function(
+ JsonRoutes.add('GET', '/api/boards/:boardId/custom-fields', async function(
req,
res,
) {
@@ -304,7 +304,7 @@ if (Meteor.isServer) {
Authentication.checkBoardAccess(req.userId, paramBoardId);
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getCustomFields({ boardIds: { $in: [paramBoardId] } }).map(
+ data: (await ReactiveCache.getCustomFields({ boardIds: { $in: [paramBoardId] } })).map(
function(cf) {
return {
_id: cf._id,
@@ -328,13 +328,13 @@ if (Meteor.isServer) {
JsonRoutes.add(
'GET',
'/api/boards/:boardId/custom-fields/:customFieldId',
- function(req, res) {
+ async function(req, res) {
const paramBoardId = req.params.boardId;
const paramCustomFieldId = req.params.customFieldId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getCustomField({
+ data: await ReactiveCache.getCustomField({
_id: paramCustomFieldId,
boardIds: { $in: [paramBoardId] },
}),
@@ -356,13 +356,13 @@ if (Meteor.isServer) {
* @param {boolean} showSumAtTopOfList should the sum of the custom fields be shown at top of list?
* @return_type {_id: string}
*/
- JsonRoutes.add('POST', '/api/boards/:boardId/custom-fields', function(
+ JsonRoutes.add('POST', '/api/boards/:boardId/custom-fields', async function(
req,
res,
) {
const paramBoardId = req.params.boardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
- const board = ReactiveCache.getBoard(paramBoardId);
+ const board = await ReactiveCache.getBoard(paramBoardId);
const id = CustomFields.direct.insert({
name: req.body.name,
type: req.body.type,
@@ -374,7 +374,7 @@ if (Meteor.isServer) {
boardIds: [board._id],
});
- const customField = ReactiveCache.getCustomField({
+ const customField = await ReactiveCache.getCustomField({
_id: id,
boardIds: { $in: [paramBoardId] },
});
diff --git a/models/export.js b/models/export.js
index a45f8dc77..c72d2ff42 100644
--- a/models/export.js
+++ b/models/export.js
@@ -27,14 +27,14 @@ if (Meteor.isServer) {
* @param {string} boardId the ID of the board we are exporting
* @param {string} authToken the loginToken
*/
- JsonRoutes.add('get', '/api/boards/:boardId/export', function (req, res) {
+ JsonRoutes.add('get', '/api/boards/:boardId/export', async function (req, res) {
const boardId = req.params.boardId;
let user = null;
let impersonateDone = false;
let adminId = null;
// First check if board exists and is public to avoid unnecessary authentication
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
JsonRoutes.sendResult(res, 404);
return;
@@ -46,7 +46,7 @@ if (Meteor.isServer) {
const exporter = new Exporter(boardId);
JsonRoutes.sendResult(res, {
code: 200,
- data: exporter.build(),
+ data: await exporter.build(),
});
return;
}
@@ -64,18 +64,18 @@ if (Meteor.isServer) {
}
const hashToken = Accounts._hashLoginToken(loginToken);
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
'services.resume.loginTokens.hashedToken': hashToken,
});
adminId = user._id.toString();
- impersonateDone = ReactiveCache.getImpersonatedUser({ adminId: adminId });
+ impersonateDone = await ReactiveCache.getImpersonatedUser({ adminId: adminId });
} else if (!Meteor.settings.public.sandstorm) {
Authentication.checkUserId(req.userId);
- user = ReactiveCache.getUser({ _id: req.userId, isAdmin: true });
+ user = await ReactiveCache.getUser({ _id: req.userId, isAdmin: true });
}
const exporter = new Exporter(boardId);
- if (exporter.canExport(user) || impersonateDone) {
+ if (await exporter.canExport(user) || impersonateDone) {
if (impersonateDone) {
ImpersonatedUsers.insert({
adminId: adminId,
@@ -86,7 +86,7 @@ if (Meteor.isServer) {
JsonRoutes.sendResult(res, {
code: 200,
- data: exporter.build(),
+ data: await exporter.build(),
});
} else {
// we could send an explicit error message, but on the other hand the only
@@ -118,7 +118,7 @@ if (Meteor.isServer) {
JsonRoutes.add(
'get',
'/api/boards/:boardId/attachments/:attachmentId/export',
- function (req, res) {
+ async function (req, res) {
const boardId = req.params.boardId;
const attachmentId = req.params.attachmentId;
let user = null;
@@ -126,7 +126,7 @@ if (Meteor.isServer) {
let adminId = null;
// First check if board exists and is public to avoid unnecessary authentication
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
JsonRoutes.sendResult(res, 404);
return;
@@ -138,7 +138,7 @@ if (Meteor.isServer) {
const exporter = new Exporter(boardId, attachmentId);
JsonRoutes.sendResult(res, {
code: 200,
- data: exporter.build(),
+ data: await exporter.build(),
});
return;
}
@@ -156,18 +156,18 @@ if (Meteor.isServer) {
}
const hashToken = Accounts._hashLoginToken(loginToken);
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
'services.resume.loginTokens.hashedToken': hashToken,
});
adminId = user._id.toString();
- impersonateDone = ReactiveCache.getImpersonatedUser({ adminId: adminId });
+ impersonateDone = await ReactiveCache.getImpersonatedUser({ adminId: adminId });
} else if (!Meteor.settings.public.sandstorm) {
Authentication.checkUserId(req.userId);
- user = ReactiveCache.getUser({ _id: req.userId, isAdmin: true });
+ user = await ReactiveCache.getUser({ _id: req.userId, isAdmin: true });
}
const exporter = new Exporter(boardId, attachmentId);
- if (exporter.canExport(user) || impersonateDone) {
+ if (await exporter.canExport(user) || impersonateDone) {
if (impersonateDone) {
ImpersonatedUsers.insert({
adminId: adminId,
@@ -178,7 +178,7 @@ if (Meteor.isServer) {
}
JsonRoutes.sendResult(res, {
code: 200,
- data: exporter.build(),
+ data: await exporter.build(),
});
} else {
// we could send an explicit error message, but on the other hand the only
@@ -203,14 +203,14 @@ if (Meteor.isServer) {
* @param {string} authToken the loginToken
* @param {string} delimiter delimiter to use while building export. Default is comma ','
*/
- Picker.route('/api/boards/:boardId/export/csv', function (params, req, res) {
+ Picker.route('/api/boards/:boardId/export/csv', async function (params, req, res) {
const boardId = params.boardId;
let user = null;
let impersonateDone = false;
let adminId = null;
// First check if board exists and is public to avoid unnecessary authentication
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
res.writeHead(404);
res.end('Board not found');
@@ -237,7 +237,7 @@ if (Meteor.isServer) {
// use Uint8Array to prevent from converting bytes to string
res.write(new Uint8Array([0xEF, 0xBB, 0xBF]));
}
- res.write(exporter.buildCsv(params.query.delimiter, 'en'));
+ res.write(await exporter.buildCsv(params.query.delimiter, 'en'));
res.end();
return;
}
@@ -256,21 +256,21 @@ if (Meteor.isServer) {
}
const hashToken = Accounts._hashLoginToken(loginToken);
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
'services.resume.loginTokens.hashedToken': hashToken,
});
adminId = user._id.toString();
- impersonateDone = ReactiveCache.getImpersonatedUser({ adminId: adminId });
+ impersonateDone = await ReactiveCache.getImpersonatedUser({ adminId: adminId });
} else if (!Meteor.settings.public.sandstorm) {
Authentication.checkUserId(req.userId);
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
_id: req.userId,
isAdmin: true,
});
}
const exporter = new Exporter(boardId);
- if (exporter.canExport(user) || impersonateDone) {
+ if (await exporter.canExport(user) || impersonateDone) {
if (impersonateDone) {
let exportType = 'exportCSV';
if( params.query.delimiter == "\t" ) {
@@ -303,7 +303,7 @@ if (Meteor.isServer) {
// use Uint8Array to prevent from converting bytes to string
res.write(new Uint8Array([0xEF, 0xBB, 0xBF]));
}
- res.write(exporter.buildCsv(params.query.delimiter, userLanguage));
+ res.write(await exporter.buildCsv(params.query.delimiter, userLanguage));
res.end();
} else {
res.writeHead(403);
diff --git a/models/exportExcel.js b/models/exportExcel.js
index 598fb92d6..aac56cd40 100644
--- a/models/exportExcel.js
+++ b/models/exportExcel.js
@@ -30,14 +30,14 @@ runOnServer(function() {
* @param {string} boardId the ID of the board we are exporting
* @param {string} authToken the loginToken
*/
- Picker.route('/api/boards/:boardId/exportExcel', function (params, req, res) {
+ Picker.route('/api/boards/:boardId/exportExcel', async function (params, req, res) {
const boardId = params.boardId;
let user = null;
let impersonateDone = false;
let adminId = null;
// First check if board exists and is public to avoid unnecessary authentication
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
res.end('Board not found');
return;
@@ -64,14 +64,14 @@ runOnServer(function() {
}
const hashToken = Accounts._hashLoginToken(loginToken);
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
'services.resume.loginTokens.hashedToken': hashToken,
});
adminId = user._id.toString();
- impersonateDone = ReactiveCache.getImpersonatedUser({ adminId: adminId });
+ impersonateDone = await ReactiveCache.getImpersonatedUser({ adminId: adminId });
} else if (!Meteor.settings.public.sandstorm) {
Authentication.checkUserId(req.userId);
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
_id: req.userId,
isAdmin: true,
});
diff --git a/models/exportPDF.js b/models/exportPDF.js
index 272651f98..14173c711 100644
--- a/models/exportPDF.js
+++ b/models/exportPDF.js
@@ -30,7 +30,7 @@ runOnServer(function() {
* @param {string} boardId the ID of the board we are exporting
* @param {string} authToken the loginToken
*/
- Picker.route('/api/boards/:boardId/lists/:listId/cards/:cardId/exportPDF', function (params, req, res) {
+ Picker.route('/api/boards/:boardId/lists/:listId/cards/:cardId/exportPDF', async function (params, req, res) {
const boardId = params.boardId;
const paramListId = req.params.listId;
const paramCardId = req.params.cardId;
@@ -39,7 +39,7 @@ runOnServer(function() {
let adminId = null;
// First check if board exists and is public to avoid unnecessary authentication
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
res.end('Board not found');
return;
@@ -66,14 +66,14 @@ runOnServer(function() {
}
const hashToken = Accounts._hashLoginToken(loginToken);
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
'services.resume.loginTokens.hashedToken': hashToken,
});
adminId = user._id.toString();
- impersonateDone = ReactiveCache.getImpersonatedUser({ adminId: adminId });
+ impersonateDone = await ReactiveCache.getImpersonatedUser({ adminId: adminId });
} else if (!Meteor.settings.public.sandstorm) {
Authentication.checkUserId(req.userId);
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
_id: req.userId,
isAdmin: true,
});
diff --git a/models/exporter.js b/models/exporter.js
index f1f601540..4cef38d1a 100644
--- a/models/exporter.js
+++ b/models/exporter.js
@@ -34,7 +34,7 @@ export class Exporter {
this._attachmentId = attachmentId;
}
- build() {
+ async build() {
const fs = Npm.require('fs');
const os = Npm.require('os');
const path = Npm.require('path');
@@ -55,7 +55,7 @@ export class Exporter {
};
_.extend(
result,
- ReactiveCache.getBoard(this._boardId, {
+ await ReactiveCache.getBoard(this._boardId, {
fields: {
stars: 0,
},
@@ -97,7 +97,7 @@ export class Exporter {
const byBoardAndAttachment = this._attachmentId
? { boardId: this._boardId, _id: this._attachmentId }
: byBoard;
- result.attachments = ReactiveCache.getAttachments(byBoardAndAttachment)
+ result.attachments = (await ReactiveCache.getAttachments(byBoardAndAttachment))
.map((attachment) => {
let filebase64 = null;
filebase64 = getBase64DataSync(attachment);
@@ -116,41 +116,41 @@ export class Exporter {
return result.attachments.length > 0 ? result.attachments[0] : {};
}
- result.lists = ReactiveCache.getLists(byBoard, noBoardId);
- result.cards = ReactiveCache.getCards(byBoardNoLinked, noBoardId);
- result.swimlanes = ReactiveCache.getSwimlanes(byBoard, noBoardId);
- result.customFields = ReactiveCache.getCustomFields(
+ result.lists = await ReactiveCache.getLists(byBoard, noBoardId);
+ result.cards = await ReactiveCache.getCards(byBoardNoLinked, noBoardId);
+ result.swimlanes = await ReactiveCache.getSwimlanes(byBoard, noBoardId);
+ result.customFields = await ReactiveCache.getCustomFields(
{ boardIds: this._boardId },
{ fields: { boardIds: 0 } },
);
- result.comments = ReactiveCache.getCardComments(byBoard, noBoardId);
- result.activities = ReactiveCache.getActivities(byBoard, noBoardId);
- result.rules = ReactiveCache.getRules(byBoard, noBoardId);
+ result.comments = await ReactiveCache.getCardComments(byBoard, noBoardId);
+ result.activities = await ReactiveCache.getActivities(byBoard, noBoardId);
+ result.rules = await ReactiveCache.getRules(byBoard, noBoardId);
result.checklists = [];
result.checklistItems = [];
result.subtaskItems = [];
result.triggers = [];
result.actions = [];
- result.cards.forEach((card) => {
+ for (const card of result.cards) {
result.checklists.push(
- ...ReactiveCache.getChecklists({
+ ...await ReactiveCache.getChecklists({
cardId: card._id,
}),
);
result.checklistItems.push(
- ...ReactiveCache.getChecklistItems({
+ ...await ReactiveCache.getChecklistItems({
cardId: card._id,
}),
);
result.subtaskItems.push(
- ...ReactiveCache.getCards({
+ ...await ReactiveCache.getCards({
parentId: card._id,
}),
);
- });
- result.rules.forEach((rule) => {
+ }
+ for (const rule of result.rules) {
result.triggers.push(
- ...ReactiveCache.getTriggers(
+ ...await ReactiveCache.getTriggers(
{
_id: rule.triggerId,
},
@@ -158,14 +158,14 @@ export class Exporter {
),
);
result.actions.push(
- ...ReactiveCache.getActions(
+ ...await ReactiveCache.getActions(
{
_id: rule.actionId,
},
noBoardId,
),
);
- });
+ }
// we also have to export some user data - as the other elements only
// include id but we have to be careful:
@@ -211,7 +211,7 @@ export class Exporter {
'profile.avatarUrl': 1,
},
};
- result.users = ReactiveCache.getUsers(byUserIds, userFields)
+ result.users = (await ReactiveCache.getUsers(byUserIds, userFields))
.map((user) => {
// user avatar is stored as a relative url, we export absolute
if ((user.profile || {}).avatarUrl) {
@@ -222,8 +222,8 @@ export class Exporter {
return result;
}
- buildCsv(userDelimiter = ',', userLanguage='en') {
- const result = this.build();
+ async buildCsv(userDelimiter = ',', userLanguage='en') {
+ const result = await this.build();
const columnHeaders = [];
const cardRows = [];
@@ -398,8 +398,8 @@ export class Exporter {
return Papa.unparse(cardRows, papaconfig);
}
- canExport(user) {
- const board = ReactiveCache.getBoard(this._boardId);
+ async canExport(user) {
+ const board = await ReactiveCache.getBoard(this._boardId);
return board && board.isVisibleBy(user);
}
}
diff --git a/models/integrations.js b/models/integrations.js
index 3daa3cb8d..fed283f95 100644
--- a/models/integrations.js
+++ b/models/integrations.js
@@ -101,21 +101,21 @@ Integrations.Const = {
},
};
const permissionHelper = {
- allow(userId, doc) {
- const user = ReactiveCache.getUser(userId);
- const isAdmin = user && ReactiveCache.getCurrentUser().isAdmin;
- return isAdmin || allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async allow(userId, doc) {
+ const user = await ReactiveCache.getUser(userId);
+ const isAdmin = user && (await ReactiveCache.getCurrentUser()).isAdmin;
+ return isAdmin || allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
};
Integrations.allow({
- insert(userId, doc) {
- return permissionHelper.allow(userId, doc);
+ async insert(userId, doc) {
+ return await permissionHelper.allow(userId, doc);
},
- update(userId, doc) {
- return permissionHelper.allow(userId, doc);
+ async update(userId, doc) {
+ return await permissionHelper.allow(userId, doc);
},
- remove(userId, doc) {
- return permissionHelper.allow(userId, doc);
+ async remove(userId, doc) {
+ return await permissionHelper.allow(userId, doc);
},
fetch: ['boardId'],
});
@@ -134,7 +134,7 @@ if (Meteor.isServer) {
* @param {string} boardId the board ID
* @return_type [Integrations]
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/integrations', function(
+ JsonRoutes.add('GET', '/api/boards/:boardId/integrations', async function(
req,
res,
) {
@@ -142,10 +142,10 @@ if (Meteor.isServer) {
const paramBoardId = req.params.boardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
- const data = ReactiveCache.getIntegrations(
+ const data = (await ReactiveCache.getIntegrations(
{ boardId: paramBoardId },
{ fields: { token: 0 } },
- ).map(function(doc) {
+ )).map(function(doc) {
return doc;
});
@@ -166,7 +166,7 @@ if (Meteor.isServer) {
* @param {string} intId the integration ID
* @return_type Integrations
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/integrations/:intId', function(
+ JsonRoutes.add('GET', '/api/boards/:boardId/integrations/:intId', async function(
req,
res,
) {
@@ -177,7 +177,7 @@ if (Meteor.isServer) {
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getIntegration(
+ data: await ReactiveCache.getIntegration(
{ _id: paramIntId, boardId: paramBoardId },
{ fields: { token: 0 } },
),
@@ -310,7 +310,7 @@ if (Meteor.isServer) {
JsonRoutes.add(
'DELETE',
'/api/boards/:boardId/integrations/:intId/activities',
- function(req, res) {
+ async function(req, res) {
try {
const paramBoardId = req.params.boardId;
const paramIntId = req.params.intId;
@@ -324,7 +324,7 @@ if (Meteor.isServer) {
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getIntegration(
+ data: await ReactiveCache.getIntegration(
{ _id: paramIntId, boardId: paramBoardId },
{ fields: { _id: 1, activities: 1 } },
),
@@ -350,7 +350,7 @@ if (Meteor.isServer) {
JsonRoutes.add(
'POST',
'/api/boards/:boardId/integrations/:intId/activities',
- function(req, res) {
+ async function(req, res) {
try {
const paramBoardId = req.params.boardId;
const paramIntId = req.params.intId;
@@ -364,7 +364,7 @@ if (Meteor.isServer) {
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getIntegration(
+ data: await ReactiveCache.getIntegration(
{ _id: paramIntId, boardId: paramBoardId },
{ fields: { _id: 1, activities: 1 } },
),
diff --git a/models/invitationCodes.js b/models/invitationCodes.js
index 31e4b4016..1fe84de7a 100644
--- a/models/invitationCodes.js
+++ b/models/invitationCodes.js
@@ -55,8 +55,8 @@ InvitationCodes.attachSchema(
);
InvitationCodes.helpers({
- author() {
- return ReactiveCache.getUser(this.authorId);
+ async author() {
+ return await ReactiveCache.getUser(this.authorId);
},
});
diff --git a/models/lib/fileStoreStrategy.js b/models/lib/fileStoreStrategy.js
index 911011526..426e956b5 100644
--- a/models/lib/fileStoreStrategy.js
+++ b/models/lib/fileStoreStrategy.js
@@ -580,8 +580,8 @@ export const moveToStorage = function(fileObj, storageDestination, fileStoreStra
});
};
-export const copyFile = function(fileObj, newCardId, fileStoreStrategyFactory) {
- const newCard = ReactiveCache.getCard(newCardId);
+export const copyFile = async function(fileObj, newCardId, fileStoreStrategyFactory) {
+ const newCard = await ReactiveCache.getCard(newCardId);
Object.keys(fileObj.versions).forEach(versionName => {
const strategyRead = fileStoreStrategyFactory.getFileStrategy(fileObj, versionName);
const readStream = strategyRead.getReadStream();
diff --git a/models/lists.js b/models/lists.js
index bc5b102a3..415e90fff 100644
--- a/models/lists.js
+++ b/models/lists.js
@@ -180,30 +180,30 @@ Lists.attachSchema(
);
Lists.allow({
- insert(userId, doc) {
+ async insert(userId, doc) {
// ReadOnly and CommentOnly users cannot create lists
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
},
- update(userId, doc) {
+ async update(userId, doc) {
// ReadOnly and CommentOnly users cannot edit lists
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
},
- remove(userId, doc) {
+ async remove(userId, doc) {
// ReadOnly and CommentOnly users cannot delete lists
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
},
fetch: ['boardId'],
});
Lists.helpers({
- copy(boardId, swimlaneId) {
+ async copy(boardId, swimlaneId) {
const oldId = this._id;
const oldSwimlaneId = this.swimlaneId || null;
this.boardId = boardId;
this.swimlaneId = swimlaneId;
let _id = null;
- const existingListWithSameName = ReactiveCache.getList({
+ const existingListWithSameName = await ReactiveCache.getList({
boardId,
title: this.title,
archived: false,
@@ -213,21 +213,22 @@ Lists.helpers({
} else {
delete this._id;
this.swimlaneId = swimlaneId; // Set the target swimlane for the copied list
- _id = Lists.insert(this);
+ _id = await Lists.insertAsync(this);
}
// Copy all cards in list
- ReactiveCache.getCards({
+ const cards = await ReactiveCache.getCards({
swimlaneId: oldSwimlaneId,
listId: oldId,
archived: false,
- }).forEach(card => {
- card.copy(boardId, swimlaneId, _id);
});
+ for (const card of cards) {
+ await card.copy(boardId, swimlaneId, _id);
+ }
},
async move(boardId, swimlaneId) {
- const boardList = ReactiveCache.getList({
+ const boardList = await ReactiveCache.getList({
boardId,
title: this.title,
archived: false,
@@ -235,13 +236,13 @@ Lists.helpers({
let listId;
if (boardList) {
listId = boardList._id;
- for (const card of this.cards()) {
+ for (const card of await this.cards()) {
await card.move(boardId, this._id, boardList._id);
}
} else {
console.log('list.title:', this.title);
console.log('boardList:', boardList);
- listId = Lists.insert({
+ listId = await Lists.insertAsync({
title: this.title,
boardId,
type: this.type,
@@ -251,42 +252,42 @@ Lists.helpers({
});
}
- for (const card of this.cards(swimlaneId)) {
+ for (const card of await this.cards(swimlaneId)) {
await card.move(boardId, swimlaneId, listId);
}
},
- cards(swimlaneId) {
+ async cards(swimlaneId) {
const selector = {
listId: this._id,
archived: false,
};
if (swimlaneId) selector.swimlaneId = swimlaneId;
- const ret = ReactiveCache.getCards(Filter.mongoSelector(selector), { sort: ['sort'] });
+ const ret = await ReactiveCache.getCards(Filter.mongoSelector(selector), { sort: ['sort'] });
return ret;
},
- cardsUnfiltered(swimlaneId) {
+ async cardsUnfiltered(swimlaneId) {
const selector = {
listId: this._id,
archived: false,
};
if (swimlaneId) selector.swimlaneId = swimlaneId;
- const ret = ReactiveCache.getCards(selector, { sort: ['sort'] });
+ const ret = await ReactiveCache.getCards(selector, { sort: ['sort'] });
return ret;
},
- allCards() {
- const ret = ReactiveCache.getCards({ listId: this._id });
+ async allCards() {
+ const ret = await ReactiveCache.getCards({ listId: this._id });
return ret;
},
- board() {
- return ReactiveCache.getBoard(this.boardId);
+ async board() {
+ return await ReactiveCache.getBoard(this.boardId);
},
- getWipLimit(option) {
- const list = ReactiveCache.getList(this._id);
+ async getWipLimit(option) {
+ const list = await ReactiveCache.getList(this._id);
if (!list.wipLimit) {
// Necessary check to avoid exceptions for the case where the doc doesn't have the wipLimit field yet set
return 0;
@@ -310,9 +311,9 @@ Lists.helpers({
return this.starred === true;
},
- isCollapsed() {
+ async isCollapsed() {
if (Meteor.isClient) {
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
// Logged-in users: prefer profile/cookie-backed state
if (user && user.getCollapsedListFromStorage) {
const stored = user.getCollapsedListFromStorage(this.boardId, this._id);
@@ -331,13 +332,13 @@ Lists.helpers({
return this.collapsed === true;
},
- absoluteUrl() {
- const card = ReactiveCache.getCard({ listId: this._id });
- return card && card.absoluteUrl();
+ async absoluteUrl() {
+ const card = await ReactiveCache.getCard({ listId: this._id });
+ return card && (await card.absoluteUrl());
},
- originRelativeUrl() {
- const card = ReactiveCache.getCard({ listId: this._id });
- return card && card.originRelativeUrl();
+ async originRelativeUrl() {
+ const card = await ReactiveCache.getCard({ listId: this._id });
+ return card && (await card.originRelativeUrl());
},
async remove() {
return await Lists.removeAsync({ _id: this._id });
@@ -361,7 +362,7 @@ Lists.helpers({
async archive() {
if (this.isTemplateList()) {
- for (const card of this.cards()) {
+ for (const card of await this.cards()) {
await card.archive();
}
}
@@ -370,7 +371,7 @@ Lists.helpers({
async restore() {
if (this.isTemplateList()) {
- for (const card of this.allCards()) {
+ for (const card of await this.allCards()) {
await card.restore();
}
}
@@ -394,23 +395,25 @@ Lists.helpers({
},
});
-Lists.userArchivedLists = userId => {
- return ReactiveCache.getLists({
- boardId: { $in: Boards.userBoardIds(userId, null) },
+Lists.userArchivedLists = async userId => {
+ return await ReactiveCache.getLists({
+ boardId: { $in: await Boards.userBoardIds(userId, null) },
archived: true,
})
};
-Lists.userArchivedListIds = () => {
- return Lists.userArchivedLists().map(list => { return list._id; });
+Lists.userArchivedListIds = async () => {
+ const lists = await Lists.userArchivedLists();
+ return lists.map(list => { return list._id; });
};
-Lists.archivedLists = () => {
- return ReactiveCache.getLists({ archived: true });
+Lists.archivedLists = async () => {
+ return await ReactiveCache.getLists({ archived: true });
};
-Lists.archivedListIds = () => {
- return Lists.archivedLists().map(list => {
+Lists.archivedListIds = async () => {
+ const lists = await Lists.archivedLists();
+ return lists.map(list => {
return list._id;
});
};
@@ -424,12 +427,12 @@ Meteor.methods({
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
- const list = ReactiveCache.getList(listId);
+ const list = await ReactiveCache.getList(listId);
if (!list) {
throw new Meteor.Error('list-not-found', 'List not found');
}
- const board = ReactiveCache.getBoard(list.boardId);
+ const board = await ReactiveCache.getBoard(list.boardId);
if (!board || !board.hasAdmin(this.userId)) {
throw new Meteor.Error('not-authorized', 'You must be a board admin to modify WIP limits.');
}
@@ -447,63 +450,62 @@ Meteor.methods({
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
- const list = ReactiveCache.getList(listId);
+ const list = await ReactiveCache.getList(listId);
if (!list) {
throw new Meteor.Error('list-not-found', 'List not found');
}
- const board = ReactiveCache.getBoard(list.boardId);
+ const board = await ReactiveCache.getBoard(list.boardId);
if (!board || !board.hasAdmin(this.userId)) {
throw new Meteor.Error('not-authorized', 'You must be a board admin to modify WIP limits.');
}
- if (list.getWipLimit('value') === 0) {
+ if ((await list.getWipLimit('value')) === 0) {
await list.setWipLimit(1);
}
- list.toggleWipLimit(!list.getWipLimit('enabled'));
+ await list.toggleWipLimit(!(await list.getWipLimit('enabled')));
},
- enableSoftLimit(listId) {
+ async enableSoftLimit(listId) {
check(listId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
- const list = ReactiveCache.getList(listId);
+
+ const list = await ReactiveCache.getList(listId);
if (!list) {
throw new Meteor.Error('list-not-found', 'List not found');
}
-
- const board = ReactiveCache.getBoard(list.boardId);
+
+ const board = await ReactiveCache.getBoard(list.boardId);
if (!board || !board.hasAdmin(this.userId)) {
throw new Meteor.Error('not-authorized', 'You must be a board admin to modify WIP limits.');
}
-
- list.toggleSoftLimit(!list.getWipLimit('soft'));
+
+ await list.toggleSoftLimit(!(await list.getWipLimit('soft')));
},
- myLists() {
+ async myLists() {
// my lists
- return _.uniq(
- ReactiveCache.getLists(
- {
- boardId: { $in: Boards.userBoardIds(this.userId) },
- archived: false,
- },
- {
- fields: { title: 1 },
- },
- ).map(list => list.title),
- ).sort();
+ const lists = await ReactiveCache.getLists(
+ {
+ boardId: { $in: Boards.userBoardIds(this.userId) },
+ archived: false,
+ },
+ {
+ fields: { title: 1 },
+ },
+ );
+ return _.uniq(lists.map(list => list.title)).sort();
},
- updateListSort(listId, boardId, updateData) {
+ async updateListSort(listId, boardId, updateData) {
check(listId, String);
check(boardId, String);
check(updateData, Object);
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found');
}
@@ -516,7 +518,7 @@ Meteor.methods({
}
}
- const list = ReactiveCache.getList(listId);
+ const list = await ReactiveCache.getList(listId);
if (!list) {
throw new Meteor.Error('list-not-found', 'List not found');
}
@@ -529,13 +531,13 @@ Meteor.methods({
});
if (updateData.swimlaneId) {
- const swimlane = ReactiveCache.getSwimlane(updateData.swimlaneId);
+ const swimlane = await ReactiveCache.getSwimlane(updateData.swimlaneId);
if (!swimlane || swimlane.boardId !== boardId) {
throw new Meteor.Error('invalid-swimlane', 'Invalid swimlane for this board');
}
}
- Lists.update(
+ await Lists.updateAsync(
{ _id: listId, boardId },
{
$set: {
@@ -583,14 +585,14 @@ Lists.after.insert((userId, doc) => {
}, 100);
});
-Lists.before.remove((userId, doc) => {
- const cards = ReactiveCache.getCards({ listId: doc._id });
+Lists.before.remove(async (userId, doc) => {
+ const cards = await ReactiveCache.getCards({ listId: doc._id });
if (cards) {
- cards.forEach(card => {
- Cards.remove(card._id);
- });
+ for (const card of cards) {
+ await Cards.removeAsync(card._id);
+ }
}
- Activities.insert({
+ await Activities.insertAsync({
userId,
type: 'list',
activityType: 'removeList',
@@ -722,12 +724,12 @@ if (Meteor.isServer) {
* @param {string} title the title of the List
* @return_type {_id: string}
*/
- JsonRoutes.add('POST', '/api/boards/:boardId/lists', function(req, res) {
+ JsonRoutes.add('POST', '/api/boards/:boardId/lists', async function(req, res) {
try {
const paramBoardId = req.params.boardId;
Authentication.checkBoardWriteAccess(req.userId, paramBoardId);
- const board = ReactiveCache.getBoard(paramBoardId);
- const id = Lists.insert({
+ const board = await ReactiveCache.getBoard(paramBoardId);
+ const id = await Lists.insertAsync({
title: req.body.title,
boardId: paramBoardId,
sort: board.lists().length,
@@ -763,7 +765,7 @@ if (Meteor.isServer) {
* @param {boolean} [collapsed] whether the list is collapsed
* @return_type {_id: string}
*/
- JsonRoutes.add('PUT', '/api/boards/:boardId/lists/:listId', function(
+ JsonRoutes.add('PUT', '/api/boards/:boardId/lists/:listId', async function(
req,
res,
) {
@@ -773,7 +775,7 @@ if (Meteor.isServer) {
let updated = false;
Authentication.checkBoardWriteAccess(req.userId, paramBoardId);
- const list = ReactiveCache.getList({
+ const list = await ReactiveCache.getList({
_id: paramListId,
boardId: paramBoardId,
archived: false,
diff --git a/models/lockoutSettings.js b/models/lockoutSettings.js
index 9020f6227..23e4acda6 100644
--- a/models/lockoutSettings.js
+++ b/models/lockoutSettings.js
@@ -48,8 +48,8 @@ LockoutSettings.attachSchema(
);
LockoutSettings.allow({
- update(userId) {
- const user = ReactiveCache.getUser(userId);
+ async update(userId) {
+ const user = await ReactiveCache.getUser(userId);
return user && user.isAdmin;
},
});
diff --git a/models/org.js b/models/org.js
index 41bdb47b4..21ac40f76 100644
--- a/models/org.js
+++ b/models/org.js
@@ -87,8 +87,8 @@ Org.attachSchema(
if (Meteor.isServer) {
Org.allow({
- insert(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async insert(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -96,8 +96,8 @@ if (Meteor.isServer) {
}
return doc._id === userId;
},
- update(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async update(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -105,8 +105,8 @@ if (Meteor.isServer) {
}
return doc._id === userId;
},
- remove(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async remove(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -119,7 +119,7 @@ if (Meteor.isServer) {
Meteor.methods({
- setCreateOrg(
+ async setCreateOrg(
orgDisplayName,
orgDesc,
orgShortName,
@@ -127,7 +127,7 @@ if (Meteor.isServer) {
orgWebsite,
orgIsActive,
) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(orgDisplayName, String);
check(orgDesc, String);
check(orgShortName, String);
@@ -135,7 +135,7 @@ if (Meteor.isServer) {
check(orgWebsite, String);
check(orgIsActive, Boolean);
- const nOrgNames = ReactiveCache.getOrgs({ orgShortName }).length;
+ const nOrgNames = (await ReactiveCache.getOrgs({ orgShortName })).length;
if (nOrgNames > 0) {
throw new Meteor.Error('orgname-already-taken');
} else {
@@ -150,7 +150,7 @@ if (Meteor.isServer) {
}
}
},
- setCreateOrgFromOidc(
+ async setCreateOrgFromOidc(
orgDisplayName,
orgDesc,
orgShortName,
@@ -165,7 +165,7 @@ if (Meteor.isServer) {
check(orgWebsite, String);
check(orgIsActive, Boolean);
- const nOrgNames = ReactiveCache.getOrgs({ orgShortName }).length;
+ const nOrgNames = (await ReactiveCache.getOrgs({ orgShortName })).length;
if (nOrgNames > 0) {
throw new Meteor.Error('orgname-already-taken');
} else {
@@ -179,19 +179,19 @@ if (Meteor.isServer) {
});
}
},
- setOrgDisplayName(org, orgDisplayName) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setOrgDisplayName(org, orgDisplayName) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(org, Object);
check(orgDisplayName, String);
Org.update(org, {
$set: { orgDisplayName: orgDisplayName },
});
- Meteor.call('setUsersOrgsOrgDisplayName', org._id, orgDisplayName);
+ await Meteor.callAsync('setUsersOrgsOrgDisplayName', org._id, orgDisplayName);
}
},
- setOrgDesc(org, orgDesc) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setOrgDesc(org, orgDesc) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(org, Object);
check(orgDesc, String);
Org.update(org, {
@@ -200,8 +200,8 @@ if (Meteor.isServer) {
}
},
- setOrgShortName(org, orgShortName) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setOrgShortName(org, orgShortName) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(org, Object);
check(orgShortName, String);
Org.update(org, {
@@ -210,8 +210,8 @@ if (Meteor.isServer) {
}
},
- setAutoAddUsersWithDomainName(org, orgAutoAddUsersWithDomainName) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setAutoAddUsersWithDomainName(org, orgAutoAddUsersWithDomainName) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(org, Object);
check(orgAutoAddUsersWithDomainName, String);
Org.update(org, {
@@ -220,8 +220,8 @@ if (Meteor.isServer) {
}
},
- setOrgIsActive(org, orgIsActive) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setOrgIsActive(org, orgIsActive) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(org, Object);
check(orgIsActive, Boolean);
Org.update(org, {
@@ -229,7 +229,7 @@ if (Meteor.isServer) {
});
}
},
- setOrgAllFieldsFromOidc(
+ async setOrgAllFieldsFromOidc(
org,
orgDisplayName,
orgDesc,
@@ -255,9 +255,9 @@ if (Meteor.isServer) {
orgIsActive: orgIsActive,
},
});
- Meteor.call('setUsersOrgsOrgDisplayName', org._id, orgDisplayName);
+ await Meteor.callAsync('setUsersOrgsOrgDisplayName', org._id, orgDisplayName);
},
- setOrgAllFields(
+ async setOrgAllFields(
org,
orgDisplayName,
orgDesc,
@@ -266,7 +266,7 @@ if (Meteor.isServer) {
orgWebsite,
orgIsActive,
) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(org, Object);
check(orgDisplayName, String);
check(orgDesc, String);
@@ -284,7 +284,7 @@ if (Meteor.isServer) {
orgIsActive: orgIsActive,
},
});
- Meteor.call('setUsersOrgsOrgDisplayName', org._id, orgDisplayName);
+ await Meteor.callAsync('setUsersOrgsOrgDisplayName', org._id, orgDisplayName);
}
},
});
diff --git a/models/rules.js b/models/rules.js
index ea1ba571f..127e8fb3c 100644
--- a/models/rules.js
+++ b/models/rules.js
@@ -54,32 +54,32 @@ Rules.helpers({
async rename(description) {
return await Rules.updateAsync(this._id, { $set: { description } });
},
- getAction() {
- return ReactiveCache.getAction(this.actionId);
+ async getAction() {
+ return await ReactiveCache.getAction(this.actionId);
},
- getTrigger() {
- return ReactiveCache.getTrigger(this.triggerId);
+ async getTrigger() {
+ return await ReactiveCache.getTrigger(this.triggerId);
},
- board() {
- return ReactiveCache.getBoard(this.boardId);
+ async board() {
+ return await ReactiveCache.getBoard(this.boardId);
},
- trigger() {
- return ReactiveCache.getTrigger(this.triggerId);
+ async trigger() {
+ return await ReactiveCache.getTrigger(this.triggerId);
},
- action() {
- return ReactiveCache.getAction(this.actionId);
+ async action() {
+ return await ReactiveCache.getAction(this.actionId);
},
});
Rules.allow({
- insert(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async insert(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
- update(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async update(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
- remove(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async remove(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
});
diff --git a/models/server/ExporterCardPDF.js b/models/server/ExporterCardPDF.js
index 37551e6cb..454c17f4c 100644
--- a/models/server/ExporterCardPDF.js
+++ b/models/server/ExporterCardPDF.js
@@ -640,8 +640,8 @@ class ExporterCardPDF {
}
- canExport(user) {
- const board = ReactiveCache.getBoard(this._boardId);
+ async canExport(user) {
+ const board = await ReactiveCache.getBoard(this._boardId);
return board && board.isVisibleBy(user);
}
}
diff --git a/models/server/ExporterExcel.js b/models/server/ExporterExcel.js
index 66684917e..55d27011e 100644
--- a/models/server/ExporterExcel.js
+++ b/models/server/ExporterExcel.js
@@ -31,7 +31,7 @@ class ExporterExcel {
this.userLanguage = userLanguage;
}
- build(res) {
+ async build(res) {
const fs = Npm.require('fs');
const os = Npm.require('os');
const path = Npm.require('path');
@@ -56,16 +56,16 @@ class ExporterExcel {
};
_.extend(
result,
- ReactiveCache.getBoard(this._boardId, {
+ await ReactiveCache.getBoard(this._boardId, {
fields: {
stars: 0,
},
}),
);
- result.lists = ReactiveCache.getLists(byBoard, noBoardId);
- result.cards = ReactiveCache.getCards(byBoardNoLinked, noBoardId);
- result.swimlanes = ReactiveCache.getSwimlanes(byBoard, noBoardId);
- result.customFields = ReactiveCache.getCustomFields(
+ result.lists = await ReactiveCache.getLists(byBoard, noBoardId);
+ result.cards = await ReactiveCache.getCards(byBoardNoLinked, noBoardId);
+ result.swimlanes = await ReactiveCache.getSwimlanes(byBoard, noBoardId);
+ result.customFields = await ReactiveCache.getCustomFields(
{
boardIds: {
$in: [this.boardId],
@@ -77,34 +77,34 @@ class ExporterExcel {
},
},
);
- result.comments = ReactiveCache.getCardComments(byBoard, noBoardId);
- result.activities = ReactiveCache.getActivities(byBoard, noBoardId);
- result.rules = ReactiveCache.getRules(byBoard, noBoardId);
+ result.comments = await ReactiveCache.getCardComments(byBoard, noBoardId);
+ result.activities = await ReactiveCache.getActivities(byBoard, noBoardId);
+ result.rules = await ReactiveCache.getRules(byBoard, noBoardId);
result.checklists = [];
result.checklistItems = [];
result.subtaskItems = [];
result.triggers = [];
result.actions = [];
- result.cards.forEach((card) => {
+ for (const card of result.cards) {
result.checklists.push(
- ...ReactiveCache.getChecklists({
+ ...await ReactiveCache.getChecklists({
cardId: card._id,
}),
);
result.checklistItems.push(
- ...ReactiveCache.getChecklistItems({
+ ...await ReactiveCache.getChecklistItems({
cardId: card._id,
}),
);
result.subtaskItems.push(
- ...ReactiveCache.getCards({
+ ...await ReactiveCache.getCards({
parentId: card._id,
}),
);
- });
- result.rules.forEach((rule) => {
+ }
+ for (const rule of result.rules) {
result.triggers.push(
- ...ReactiveCache.getTriggers(
+ ...await ReactiveCache.getTriggers(
{
_id: rule.triggerId,
},
@@ -112,14 +112,14 @@ class ExporterExcel {
),
);
result.actions.push(
- ...ReactiveCache.getActions(
+ ...await ReactiveCache.getActions(
{
_id: rule.actionId,
},
noBoardId,
),
);
- });
+ }
// we also have to export some user data - as the other elements only
// include id but we have to be careful:
@@ -169,7 +169,7 @@ class ExporterExcel {
'profile.avatarUrl': 1,
},
};
- result.users = ReactiveCache.getUsers(byUserIds, userFields)
+ result.users = (await ReactiveCache.getUsers(byUserIds, userFields))
.map((user) => {
// user avatar is stored as a relative url, we export absolute
if ((user.profile || {}).avatarUrl) {
@@ -905,8 +905,8 @@ class ExporterExcel {
workbook.xlsx.write(res).then(function () {});
}
- canExport(user) {
- const board = ReactiveCache.getBoard(this._boardId);
+ async canExport(user) {
+ const board = await ReactiveCache.getBoard(this._boardId);
return board && board.isVisibleBy(user);
}
}
diff --git a/models/server/metrics.js b/models/server/metrics.js
index 669bbbf92..af4c9eca0 100644
--- a/models/server/metrics.js
+++ b/models/server/metrics.js
@@ -57,12 +57,12 @@ const getBoardTitleWithMostActivities = (dateWithXdaysAgo, nbLimit) => {
);
};
-const getBoards = (boardIds) => {
- const ret = ReactiveCache.getBoards({ _id: { $in: boardIds } });
+const getBoards = async (boardIds) => {
+ const ret = await ReactiveCache.getBoards({ _id: { $in: boardIds } });
return ret;
};
Meteor.startup(() => {
- WebApp.connectHandlers.use('/metrics', (req, res, next) => {
+ WebApp.connectHandlers.use('/metrics', async (req, res, next) => {
try {
const ipAddress =
req.headers['x-forwarded-for'] || req.socket.remoteAddress;
@@ -95,7 +95,7 @@ Meteor.startup(() => {
metricsRes += '# Number of registered users\n';
// Get number of registered user
- resCount = ReactiveCache.getUsers({}).length; // KPI 2
+ resCount = (await ReactiveCache.getUsers({})).length; // KPI 2
metricsRes += 'wekan_registeredUsers ' + resCount + '\n';
resCount = 0;
@@ -103,7 +103,7 @@ Meteor.startup(() => {
metricsRes += '# Number of registered boards\n';
// Get number of registered boards
- resCount = ReactiveCache.getBoards({ archived: false, type: 'board' }).length; // KPI 3
+ resCount = (await ReactiveCache.getBoards({ archived: false, type: 'board' })).length; // KPI 3
metricsRes += 'wekan_registeredboards ' + resCount + '\n';
resCount = 0;
@@ -112,8 +112,8 @@ Meteor.startup(() => {
// Get number of registered boards by registered users
resCount =
- ReactiveCache.getBoards({ archived: false, type: 'board' }).length /
- ReactiveCache.getUsers({}).length; // KPI 4
+ (await ReactiveCache.getBoards({ archived: false, type: 'board' })).length /
+ (await ReactiveCache.getUsers({})).length; // KPI 4
metricsRes +=
'wekan_registeredboardsBysRegisteredUsers ' + resCount + '\n';
resCount = 0;
@@ -122,11 +122,11 @@ Meteor.startup(() => {
metricsRes += '# Number of registered boards\n';
// Get board numbers with only one member
- resCount = ReactiveCache.getBoards({
+ resCount = (await ReactiveCache.getBoards({
archived: false,
type: 'board',
members: { $size: 1 },
- }).length; // KPI 5
+ })).length; // KPI 5
metricsRes +=
'wekan_registeredboardsWithOnlyOneMember ' + resCount + '\n';
resCount = 0;
@@ -144,9 +144,9 @@ Meteor.startup(() => {
let dateWithXdaysAgo = new Date(
new Date() - xdays * 24 * 60 * 60 * 1000,
);
- resCount = ReactiveCache.getUsers({
+ resCount = (await ReactiveCache.getUsers({
lastConnectionDate: { $gte: dateWithXdaysAgo },
- }).length; // KPI 5
+ })).length; // KPI 5
metricsRes +=
'wekan_usersWithLastConnectionDated5DaysAgo ' + resCount + '\n';
resCount = 0;
@@ -157,9 +157,9 @@ Meteor.startup(() => {
// Get number of users with last connection dated 10 days ago
xdays = 10;
dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);
- resCount = ReactiveCache.getUsers({
+ resCount = (await ReactiveCache.getUsers({
lastConnectionDate: { $gte: dateWithXdaysAgo },
- }).length; // KPI 5
+ })).length; // KPI 5
metricsRes +=
'wekan_usersWithLastConnectionDated10DaysAgo ' + resCount + '\n';
resCount = 0;
@@ -170,9 +170,9 @@ Meteor.startup(() => {
// Get number of users with last connection dated 20 days ago
xdays = 20;
dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);
- resCount = ReactiveCache.getUsers({
+ resCount = (await ReactiveCache.getUsers({
lastConnectionDate: { $gte: dateWithXdaysAgo },
- }).length; // KPI 5
+ })).length; // KPI 5
metricsRes +=
'wekan_usersWithLastConnectionDated20DaysAgo ' + resCount + '\n';
resCount = 0;
@@ -183,9 +183,9 @@ Meteor.startup(() => {
// Get number of users with last connection dated 20 days ago
xdays = 30;
dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);
- resCount = ReactiveCache.getUsers({
+ resCount = (await ReactiveCache.getUsers({
lastConnectionDate: { $gte: dateWithXdaysAgo },
- }).length; // KPI 5
+ })).length; // KPI 5
metricsRes +=
'wekan_usersWithLastConnectionDated30DaysAgo ' + resCount + '\n';
resCount = 0;
diff --git a/models/settings.js b/models/settings.js
index 00107b8e4..df0f71af9 100644
--- a/models/settings.js
+++ b/models/settings.js
@@ -195,8 +195,8 @@ Settings.helpers({
},
});
Settings.allow({
- update(userId) {
- const user = ReactiveCache.getUser(userId);
+ async update(userId) {
+ const user = await ReactiveCache.getUser(userId);
return user && user.isAdmin;
},
});
@@ -204,7 +204,7 @@ Settings.allow({
if (Meteor.isServer) {
Meteor.startup(async () => {
await Settings._collection.createIndexAsync({ modifiedAt: -1 });
- const setting = ReactiveCache.getCurrentSetting();
+ const setting = await ReactiveCache.getCurrentSetting();
if (!setting) {
const now = new Date();
const domain = process.env.ROOT_URL.match(
@@ -230,7 +230,7 @@ if (Meteor.isServer) {
}
if (isSandstorm) {
// At Sandstorm, Admin Panel has SMTP settings
- const newSetting = ReactiveCache.getCurrentSetting();
+ const newSetting = await ReactiveCache.getCurrentSetting();
if (!process.env.MAIL_URL && newSetting.mailUrl())
process.env.MAIL_URL = newSetting.mailUrl();
Accounts.emailTemplates.from = process.env.MAIL_FROM
@@ -284,15 +284,16 @@ if (Meteor.isServer) {
return config;
}
- function sendInvitationEmail(_id) {
- const icode = ReactiveCache.getInvitationCode(_id);
- const author = ReactiveCache.getCurrentUser();
+ async function sendInvitationEmail(_id) {
+ const icode = await ReactiveCache.getInvitationCode(_id);
+ const author = await ReactiveCache.getCurrentUser();
try {
- const fullName = ReactiveCache.getUser(icode.authorId)?.profile?.fullname || "";
+ const authorUser = await ReactiveCache.getUser(icode.authorId);
+ const fullName = authorUser?.profile?.fullname || "";
const params = {
email: icode.email,
- inviter: fullName != "" ? fullName + " (" + ReactiveCache.getUser(icode.authorId).username + " )" : ReactiveCache.getUser(icode.authorId).username,
+ inviter: fullName != "" ? fullName + " (" + authorUser.username + " )" : authorUser.username,
user: icode.email.split('@')[0],
icode: icode.code,
url: FlowRouter.url('sign-up'),
@@ -323,8 +324,8 @@ if (Meteor.isServer) {
}
}
- function isNonAdminAllowedToSendMail(currentUser){
- const currSett = ReactiveCache.getCurrentSetting();
+ async function isNonAdminAllowedToSendMail(currentUser){
+ const currSett = await ReactiveCache.getCurrentSetting();
let isAllowed = false;
if(currSett && currSett != undefined && currSett.disableRegistration && currSett.mailDomainName !== undefined && currSett.mailDomainName != ""){
for(let i = 0; i < currentUser.emails.length; i++) {
@@ -361,20 +362,20 @@ if (Meteor.isServer) {
}
Meteor.methods({
- sendInvitation(emails, boards) {
+ async sendInvitation(emails, boards) {
let rc = 0;
check(emails, [String]);
check(boards, [String]);
- const user = ReactiveCache.getCurrentUser();
- if (!user.isAdmin && !isNonAdminAllowedToSendMail(user)) {
+ const user = await ReactiveCache.getCurrentUser();
+ if (!user.isAdmin && !(await isNonAdminAllowedToSendMail(user))) {
rc = -1;
throw new Meteor.Error('not-allowed');
}
- emails.forEach(email => {
+ for (const email of emails) {
if (email && SimpleSchema.RegEx.Email.test(email)) {
// Checks if the email is already link to an account.
- const userExist = ReactiveCache.getUser({ email });
+ const userExist = await ReactiveCache.getUser({ email });
if (userExist) {
rc = -1;
throw new Meteor.Error(
@@ -383,12 +384,12 @@ if (Meteor.isServer) {
);
}
// Checks if the email is already link to an invitation.
- const invitation = ReactiveCache.getInvitationCode({ email });
+ const invitation = await ReactiveCache.getInvitationCode({ email });
if (invitation) {
InvitationCodes.update(invitation, {
$set: { boardsToBeInvited: boards },
});
- sendInvitationEmail(invitation._id);
+ await sendInvitationEmail(invitation._id);
} else {
const code = getRandomNum(100000, 999999);
InvitationCodes.insert(
@@ -399,9 +400,9 @@ if (Meteor.isServer) {
createdAt: new Date(),
authorId: Meteor.userId(),
},
- function(err, _id) {
+ async function(err, _id) {
if (!err && _id) {
- sendInvitationEmail(_id);
+ await sendInvitationEmail(_id);
} else {
rc = -1;
throw new Meteor.Error(
@@ -413,15 +414,15 @@ if (Meteor.isServer) {
);
}
}
- });
+ }
return rc;
},
- sendSMTPTestEmail() {
+ async sendSMTPTestEmail() {
if (!Meteor.userId()) {
throw new Meteor.Error('invalid-user');
}
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
if (!user.emails || !user.emails[0] || !user.emails[0].address) {
throw new Meteor.Error('email-invalid');
}
@@ -471,8 +472,8 @@ if (Meteor.isServer) {
};
},
- getCustomUI() {
- const setting = ReactiveCache.getCurrentSetting();
+ async getCustomUI() {
+ const setting = await ReactiveCache.getCurrentSetting();
if (!setting.productName) {
return {
productName: '',
@@ -484,8 +485,8 @@ if (Meteor.isServer) {
}
},
- isDisableRegistration() {
- const setting = ReactiveCache.getCurrentSetting();
+ async isDisableRegistration() {
+ const setting = await ReactiveCache.getCurrentSetting();
if (setting.disableRegistration === true) {
return true;
} else {
@@ -493,8 +494,8 @@ if (Meteor.isServer) {
}
},
- isDisableForgotPassword() {
- const setting = ReactiveCache.getCurrentSetting();
+ async isDisableForgotPassword() {
+ const setting = await ReactiveCache.getCurrentSetting();
if (setting.disableForgotPassword === true) {
return true;
} else {
diff --git a/models/swimlanes.js b/models/swimlanes.js
index 6eda75982..0bf1bd99e 100644
--- a/models/swimlanes.js
+++ b/models/swimlanes.js
@@ -131,28 +131,28 @@ Swimlanes.attachSchema(
);
Swimlanes.allow({
- insert(userId, doc) {
+ async insert(userId, doc) {
// ReadOnly and CommentOnly users cannot create swimlanes
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
},
- update(userId, doc) {
+ async update(userId, doc) {
// ReadOnly and CommentOnly users cannot edit swimlanes
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
},
- remove(userId, doc) {
+ async remove(userId, doc) {
// ReadOnly and CommentOnly users cannot delete swimlanes
- return allowIsBoardMemberWithWriteAccess(userId, ReactiveCache.getBoard(doc.boardId));
+ return allowIsBoardMemberWithWriteAccess(userId, await ReactiveCache.getBoard(doc.boardId));
},
fetch: ['boardId'],
});
Swimlanes.helpers({
- copy(boardId) {
+ async copy(boardId) {
const oldId = this._id;
const oldBoardId = this.boardId;
this.boardId = boardId;
delete this._id;
- const _id = Swimlanes.insert(this);
+ const _id = await Swimlanes.insertAsync(this);
const query = {
swimlaneId: { $in: [oldId, ''] },
@@ -163,17 +163,18 @@ Swimlanes.helpers({
}
// Copy all lists in swimlane
- ReactiveCache.getLists(query).forEach(list => {
+ const lists = await ReactiveCache.getLists(query);
+ for (const list of lists) {
list.type = 'list';
list.swimlaneId = oldId;
list.boardId = boardId;
- list.copy(boardId, _id);
- });
+ await list.copy(boardId, _id);
+ }
},
async move(toBoardId) {
- for (const list of this.lists()) {
- const toList = ReactiveCache.getList({
+ for (const list of await this.lists()) {
+ const toList = await ReactiveCache.getList({
boardId: toBoardId,
title: list.title,
archived: false,
@@ -193,7 +194,7 @@ Swimlanes.helpers({
});
}
- const cards = ReactiveCache.getCards({
+ const cards = await ReactiveCache.getCards({
listId: list._id,
swimlaneId: this._id,
});
@@ -209,11 +210,11 @@ Swimlanes.helpers({
});
// make sure there is a default swimlane
- this.board().getDefaultSwimline();
+ (await this.board()).getDefaultSwimline();
},
- cards() {
- const ret = ReactiveCache.getCards(
+ async cards() {
+ const ret = await ReactiveCache.getCards(
Filter.mongoSelector({
swimlaneId: this._id,
archived: false,
@@ -223,12 +224,12 @@ Swimlanes.helpers({
return ret;
},
- lists() {
- return this.draggableLists();
+ async lists() {
+ return await this.draggableLists();
},
- newestLists() {
+ async newestLists() {
// Revert to shared lists across swimlanes: filter by board only
- return ReactiveCache.getLists(
+ return await ReactiveCache.getLists(
{
boardId: this.boardId,
archived: false,
@@ -236,9 +237,9 @@ Swimlanes.helpers({
{ sort: { modifiedAt: -1 } },
);
},
- draggableLists() {
+ async draggableLists() {
// Revert to shared lists across swimlanes: filter by board only
- return ReactiveCache.getLists(
+ return await ReactiveCache.getLists(
{
boardId: this.boardId,
//archived: false,
@@ -247,10 +248,10 @@ Swimlanes.helpers({
);
},
- myLists() {
+ async myLists() {
// Return per-swimlane lists: provide lists specific to this swimlane
- return ReactiveCache.getLists(
- {
+ return await ReactiveCache.getLists(
+ {
boardId: this.boardId,
swimlaneId: this._id,
archived: false
@@ -259,14 +260,14 @@ Swimlanes.helpers({
);
},
- allCards() {
- const ret = ReactiveCache.getCards({ swimlaneId: this._id });
+ async allCards() {
+ const ret = await ReactiveCache.getCards({ swimlaneId: this._id });
return ret;
},
- isCollapsed() {
+ async isCollapsed() {
if (Meteor.isClient) {
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
if (user && user.getCollapsedSwimlaneFromStorage) {
const stored = user.getCollapsedSwimlaneFromStorage(this.boardId, this._id);
if (typeof stored === 'boolean') {
@@ -283,8 +284,8 @@ Swimlanes.helpers({
return this.collapsed === true;
},
- board() {
- return ReactiveCache.getBoard(this.boardId);
+ async board() {
+ return await ReactiveCache.getBoard(this.boardId);
},
colorClass() {
@@ -300,18 +301,18 @@ Swimlanes.helpers({
return this.type === 'template-container';
},
- isListTemplatesSwimlane() {
- const user = ReactiveCache.getCurrentUser();
+ async isListTemplatesSwimlane() {
+ const user = await ReactiveCache.getCurrentUser();
return (user.profile || {}).listTemplatesSwimlaneId === this._id;
},
- isCardTemplatesSwimlane() {
- const user = ReactiveCache.getCurrentUser();
+ async isCardTemplatesSwimlane() {
+ const user = await ReactiveCache.getCurrentUser();
return (user.profile || {}).cardTemplatesSwimlaneId === this._id;
},
- isBoardTemplatesSwimlane() {
- const user = ReactiveCache.getCurrentUser();
+ async isBoardTemplatesSwimlane() {
+ const user = await ReactiveCache.getCurrentUser();
return (user.profile || {}).boardTemplatesSwimlaneId === this._id;
},
@@ -328,7 +329,7 @@ Swimlanes.helpers({
async archive() {
if (this.isTemplateSwimlane()) {
- for (const list of this.myLists()) {
+ for (const list of await this.myLists()) {
await list.archive();
}
}
@@ -337,7 +338,7 @@ Swimlanes.helpers({
async restore() {
if (this.isTemplateSwimlane()) {
- for (const list of this.myLists()) {
+ for (const list of await this.myLists()) {
await list.restore();
}
}
@@ -349,23 +350,25 @@ Swimlanes.helpers({
},
});
-Swimlanes.userArchivedSwimlanes = userId => {
- return ReactiveCache.getSwimlanes({
- boardId: { $in: Boards.userBoardIds(userId, null) },
+Swimlanes.userArchivedSwimlanes = async userId => {
+ return await ReactiveCache.getSwimlanes({
+ boardId: { $in: await Boards.userBoardIds(userId, null) },
archived: true,
})
};
-Swimlanes.userArchivedSwimlaneIds = () => {
- return Swimlanes.userArchivedSwimlanes().map(swim => { return swim._id; });
+Swimlanes.userArchivedSwimlaneIds = async () => {
+ const swimlanes = await Swimlanes.userArchivedSwimlanes();
+ return swimlanes.map(swim => { return swim._id; });
};
-Swimlanes.archivedSwimlanes = () => {
- return ReactiveCache.getSwimlanes({ archived: true });
+Swimlanes.archivedSwimlanes = async () => {
+ return await ReactiveCache.getSwimlanes({ archived: true });
};
-Swimlanes.archivedSwimlaneIds = () => {
- return Swimlanes.archivedSwimlanes().map(swim => {
+Swimlanes.archivedSwimlaneIds = async () => {
+ const swimlanes = await Swimlanes.archivedSwimlanes();
+ return swimlanes.map(swim => {
return swim._id;
});
};
@@ -396,8 +399,8 @@ if (Meteor.isServer) {
}, 100);
});
- Swimlanes.before.remove(function(userId, doc) {
- const lists = ReactiveCache.getLists(
+ Swimlanes.before.remove(async function(userId, doc) {
+ const lists = await ReactiveCache.getLists(
{
boardId: doc.boardId,
swimlaneId: { $in: [doc._id, ''] },
@@ -407,14 +410,14 @@ if (Meteor.isServer) {
);
if (lists.length < 2) {
- lists.forEach(list => {
- list.remove();
- });
+ for (const list of lists) {
+ await list.remove();
+ }
} else {
- Cards.remove({ swimlaneId: doc._id });
+ await Cards.removeAsync({ swimlaneId: doc._id });
}
- Activities.insert({
+ await Activities.insertAsync({
userId,
type: 'swimlane',
activityType: 'removeSwimlane',
@@ -473,14 +476,15 @@ if (Meteor.isServer) {
* @return_type [{_id: string,
* title: string}]
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/swimlanes', function(req, res) {
+ JsonRoutes.add('GET', '/api/boards/:boardId/swimlanes', async function(req, res) {
try {
const paramBoardId = req.params.boardId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
+ const swimlanes = await ReactiveCache.getSwimlanes({ boardId: paramBoardId, archived: false });
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getSwimlanes({ boardId: paramBoardId, archived: false }).map(
+ data: swimlanes.map(
function(doc) {
return {
_id: doc._id,
@@ -506,7 +510,7 @@ if (Meteor.isServer) {
* @param {string} swimlaneId the ID of the swimlane
* @return_type Swimlanes
*/
- JsonRoutes.add('GET', '/api/boards/:boardId/swimlanes/:swimlaneId', function(
+ JsonRoutes.add('GET', '/api/boards/:boardId/swimlanes/:swimlaneId', async function(
req,
res,
) {
@@ -517,7 +521,7 @@ if (Meteor.isServer) {
JsonRoutes.sendResult(res, {
code: 200,
- data: ReactiveCache.getSwimlane({
+ data: await ReactiveCache.getSwimlane({
_id: paramSwimlaneId,
boardId: paramBoardId,
archived: false,
@@ -540,13 +544,13 @@ if (Meteor.isServer) {
* @param {string} title the new title of the swimlane
* @return_type {_id: string}
*/
- JsonRoutes.add('POST', '/api/boards/:boardId/swimlanes', function(req, res) {
+ JsonRoutes.add('POST', '/api/boards/:boardId/swimlanes', async function(req, res) {
try {
const paramBoardId = req.params.boardId;
Authentication.checkBoardWriteAccess(req.userId, paramBoardId);
- const board = ReactiveCache.getBoard(paramBoardId);
- const id = Swimlanes.insert({
+ const board = await ReactiveCache.getBoard(paramBoardId);
+ const id = await Swimlanes.insertAsync({
title: req.body.title,
boardId: paramBoardId,
sort: board.swimlanes().length,
@@ -575,13 +579,13 @@ if (Meteor.isServer) {
* @param {string} title the new title of the swimlane
* @return_type {_id: string}
*/
- JsonRoutes.add('PUT', '/api/boards/:boardId/swimlanes/:swimlaneId', function(req, res) {
+ JsonRoutes.add('PUT', '/api/boards/:boardId/swimlanes/:swimlaneId', async function(req, res) {
try {
const paramBoardId = req.params.boardId;
const paramSwimlaneId = req.params.swimlaneId;
Authentication.checkBoardWriteAccess(req.userId, paramBoardId);
- const board = ReactiveCache.getBoard(paramBoardId);
- const swimlane = ReactiveCache.getSwimlane({
+ const board = await ReactiveCache.getBoard(paramBoardId);
+ const swimlane = await ReactiveCache.getSwimlane({
_id: paramSwimlaneId,
boardId: paramBoardId,
});
diff --git a/models/tableVisibilityModeSettings.js b/models/tableVisibilityModeSettings.js
index b68cd971b..e6b10566e 100644
--- a/models/tableVisibilityModeSettings.js
+++ b/models/tableVisibilityModeSettings.js
@@ -45,8 +45,8 @@ TableVisibilityModeSettings.attachSchema(
);
TableVisibilityModeSettings.allow({
- update(userId) {
- const user = ReactiveCache.getUser(userId);
+ async update(userId) {
+ const user = await ReactiveCache.getUser(userId);
return user && user.isAdmin;
},
});
diff --git a/models/team.js b/models/team.js
index 57fbf315a..a38f703cd 100644
--- a/models/team.js
+++ b/models/team.js
@@ -78,8 +78,8 @@ Team.attachSchema(
if (Meteor.isServer) {
Team.allow({
- insert(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async insert(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -87,8 +87,8 @@ if (Meteor.isServer) {
}
return doc._id === userId;
},
- update(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async update(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -96,8 +96,8 @@ if (Meteor.isServer) {
}
return doc._id === userId;
},
- remove(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async remove(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -109,21 +109,21 @@ if (Meteor.isServer) {
});
Meteor.methods({
- setCreateTeam(
+ async setCreateTeam(
teamDisplayName,
teamDesc,
teamShortName,
teamWebsite,
teamIsActive,
) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(teamDisplayName, String);
check(teamDesc, String);
check(teamShortName, String);
check(teamWebsite, String);
check(teamIsActive, Boolean);
- const nTeamNames = ReactiveCache.getTeams({ teamShortName }).length;
+ const nTeamNames = (await ReactiveCache.getTeams({ teamShortName })).length;
if (nTeamNames > 0) {
throw new Meteor.Error('teamname-already-taken');
} else {
@@ -137,7 +137,7 @@ if (Meteor.isServer) {
}
}
},
- setCreateTeamFromOidc(
+ async setCreateTeamFromOidc(
teamDisplayName,
teamDesc,
teamShortName,
@@ -149,7 +149,7 @@ if (Meteor.isServer) {
check(teamShortName, String);
check(teamWebsite, String);
check(teamIsActive, Boolean);
- const nTeamNames = ReactiveCache.getTeams({ teamShortName }).length;
+ const nTeamNames = (await ReactiveCache.getTeams({ teamShortName })).length;
if (nTeamNames > 0) {
throw new Meteor.Error('teamname-already-taken');
} else {
@@ -162,19 +162,19 @@ if (Meteor.isServer) {
});
}
},
- setTeamDisplayName(team, teamDisplayName) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setTeamDisplayName(team, teamDisplayName) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(team, Object);
check(teamDisplayName, String);
Team.update(team, {
$set: { teamDisplayName: teamDisplayName },
});
- Meteor.call('setUsersTeamsTeamDisplayName', team._id, teamDisplayName);
+ await Meteor.callAsync('setUsersTeamsTeamDisplayName', team._id, teamDisplayName);
}
},
- setTeamDesc(team, teamDesc) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setTeamDesc(team, teamDesc) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(team, Object);
check(teamDesc, String);
Team.update(team, {
@@ -183,8 +183,8 @@ if (Meteor.isServer) {
}
},
- setTeamShortName(team, teamShortName) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setTeamShortName(team, teamShortName) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(team, Object);
check(teamShortName, String);
Team.update(team, {
@@ -193,8 +193,8 @@ if (Meteor.isServer) {
}
},
- setTeamIsActive(team, teamIsActive) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ async setTeamIsActive(team, teamIsActive) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(team, Object);
check(teamIsActive, Boolean);
Team.update(team, {
@@ -202,7 +202,7 @@ if (Meteor.isServer) {
});
}
},
- setTeamAllFieldsFromOidc(
+ async setTeamAllFieldsFromOidc(
team,
teamDisplayName,
teamDesc,
@@ -225,9 +225,9 @@ if (Meteor.isServer) {
teamIsActive: teamIsActive,
},
});
- Meteor.call('setUsersTeamsTeamDisplayName', team._id, teamDisplayName);
+ await Meteor.callAsync('setUsersTeamsTeamDisplayName', team._id, teamDisplayName);
},
- setTeamAllFields(
+ async setTeamAllFields(
team,
teamDisplayName,
teamDesc,
@@ -235,7 +235,7 @@ if (Meteor.isServer) {
teamWebsite,
teamIsActive,
) {
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
check(team, Object);
check(teamDisplayName, String);
check(teamDesc, String);
@@ -251,7 +251,7 @@ if (Meteor.isServer) {
teamIsActive: teamIsActive,
},
});
- Meteor.call('setUsersTeamsTeamDisplayName', team._id, teamDisplayName);
+ await Meteor.callAsync('setUsersTeamsTeamDisplayName', team._id, teamDisplayName);
}
},
});
diff --git a/models/translation.js b/models/translation.js
index a901c3eeb..b71099628 100644
--- a/models/translation.js
+++ b/models/translation.js
@@ -58,8 +58,8 @@ Translation.attachSchema(
if (Meteor.isServer) {
Translation.allow({
- insert(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async insert(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -67,8 +67,8 @@ if (Meteor.isServer) {
}
return doc._id === userId;
},
- update(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async update(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -76,8 +76,8 @@ if (Meteor.isServer) {
}
return doc._id === userId;
},
- remove(userId, doc) {
- const user = ReactiveCache.getUser(userId) || ReactiveCache.getCurrentUser();
+ async remove(userId, doc) {
+ const user = await ReactiveCache.getUser(userId) || await ReactiveCache.getCurrentUser();
if (user?.isAdmin)
return true;
if (!user) {
@@ -89,7 +89,7 @@ if (Meteor.isServer) {
});
Meteor.methods({
- setCreateTranslation(
+ async setCreateTranslation(
language,
text,
translationText,
@@ -98,11 +98,11 @@ if (Meteor.isServer) {
check(text, String);
check(translationText, String);
- if (!ReactiveCache.getCurrentUser()?.isAdmin) {
+ if (!(await ReactiveCache.getCurrentUser())?.isAdmin) {
throw new Meteor.Error('not-authorized');
}
- const nTexts = ReactiveCache.getTranslations({ language, text }).length;
+ const nTexts = (await ReactiveCache.getTranslations({ language, text })).length;
if (nTexts > 0) {
throw new Meteor.Error('text-already-taken');
} else {
@@ -113,11 +113,11 @@ if (Meteor.isServer) {
});
}
},
- setTranslationText(translation, translationText) {
+ async setTranslationText(translation, translationText) {
check(translation, Object);
check(translationText, String);
- if (!ReactiveCache.getCurrentUser()?.isAdmin) {
+ if (!(await ReactiveCache.getCurrentUser())?.isAdmin) {
throw new Meteor.Error('not-authorized');
}
@@ -125,10 +125,10 @@ if (Meteor.isServer) {
$set: { translationText: translationText },
});
},
- deleteTranslation(translationId) {
+ async deleteTranslation(translationId) {
check(translationId, String);
- if (!ReactiveCache.getCurrentUser()?.isAdmin) {
+ if (!(await ReactiveCache.getCurrentUser())?.isAdmin) {
throw new Meteor.Error('not-authorized');
}
diff --git a/models/trelloCreator.js b/models/trelloCreator.js
index a16a7d491..1ee3cae9c 100644
--- a/models/trelloCreator.js
+++ b/models/trelloCreator.js
@@ -775,7 +775,7 @@ export class TrelloCreator {
Meteor.settings.public &&
Meteor.settings.public.sandstorm;
if (isSandstorm && currentBoardId) {
- const currentBoard = ReactiveCache.getBoard(currentBoardId);
+ const currentBoard = await ReactiveCache.getBoard(currentBoardId);
await currentBoard.archive();
}
this.parseActions(board.actions);
diff --git a/models/triggers.js b/models/triggers.js
index 58da64ee9..4173ce5f8 100644
--- a/models/triggers.js
+++ b/models/triggers.js
@@ -14,14 +14,14 @@ Triggers.before.update((userId, doc, fieldNames, modifier) => {
});
Triggers.allow({
- insert(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async insert(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
- update(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async update(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
- remove(userId, doc) {
- return allowIsBoardAdmin(userId, ReactiveCache.getBoard(doc.boardId));
+ async remove(userId, doc) {
+ return allowIsBoardAdmin(userId, await ReactiveCache.getBoard(doc.boardId));
},
});
@@ -36,20 +36,20 @@ Triggers.helpers({
return this.desc;
},
- getRule() {
- return ReactiveCache.getRule({ triggerId: this._id });
+ async getRule() {
+ return await ReactiveCache.getRule({ triggerId: this._id });
},
- fromList() {
- return ReactiveCache.getList(this.fromId);
+ async fromList() {
+ return await ReactiveCache.getList(this.fromId);
},
- toList() {
- return ReactiveCache.getList(this.toId);
+ async toList() {
+ return await ReactiveCache.getList(this.toId);
},
- findList(title) {
- return ReactiveCache.getList({
+ async findList(title) {
+ return await ReactiveCache.getList({
title,
});
},
diff --git a/models/userPositionHistory.js b/models/userPositionHistory.js
index 8dba36e3e..b961b30c5 100644
--- a/models/userPositionHistory.js
+++ b/models/userPositionHistory.js
@@ -174,17 +174,17 @@ UserPositionHistory.helpers({
/**
* Can this change be undone?
*/
- canUndo() {
+ async canUndo() {
// Can undo if the entity still exists
switch (this.entityType) {
case 'card':
- return !!ReactiveCache.getCard(this.entityId);
+ return !!(await ReactiveCache.getCard(this.entityId));
case 'list':
- return !!ReactiveCache.getList(this.entityId);
+ return !!(await ReactiveCache.getList(this.entityId));
case 'swimlane':
- return !!ReactiveCache.getSwimlane(this.entityId);
+ return !!(await ReactiveCache.getSwimlane(this.entityId));
case 'checklist':
- return !!ReactiveCache.getChecklist(this.entityId);
+ return !!(await ReactiveCache.getChecklist(this.entityId));
case 'checklistItem':
return !!ChecklistItems.findOne(this.entityId);
default:
@@ -195,23 +195,23 @@ UserPositionHistory.helpers({
/**
* Undo this change
*/
- undo() {
- if (!this.canUndo()) {
+ async undo() {
+ if (!(await this.canUndo())) {
throw new Meteor.Error('cannot-undo', 'Entity no longer exists');
}
const userId = this.userId;
-
+
switch (this.entityType) {
case 'card': {
- const card = ReactiveCache.getCard(this.entityId);
+ const card = await ReactiveCache.getCard(this.entityId);
if (card) {
// Restore previous position
const boardId = this.previousBoardId || card.boardId;
const swimlaneId = this.previousSwimlaneId || card.swimlaneId;
const listId = this.previousListId || card.listId;
const sort = this.previousSort !== undefined ? this.previousSort : card.sort;
-
+
Cards.update(card._id, {
$set: {
boardId,
@@ -224,11 +224,11 @@ UserPositionHistory.helpers({
break;
}
case 'list': {
- const list = ReactiveCache.getList(this.entityId);
+ const list = await ReactiveCache.getList(this.entityId);
if (list) {
const sort = this.previousSort !== undefined ? this.previousSort : list.sort;
const swimlaneId = this.previousSwimlaneId || list.swimlaneId;
-
+
Lists.update(list._id, {
$set: {
sort,
@@ -239,10 +239,10 @@ UserPositionHistory.helpers({
break;
}
case 'swimlane': {
- const swimlane = ReactiveCache.getSwimlane(this.entityId);
+ const swimlane = await ReactiveCache.getSwimlane(this.entityId);
if (swimlane) {
const sort = this.previousSort !== undefined ? this.previousSort : swimlane.sort;
-
+
Swimlanes.update(swimlane._id, {
$set: {
sort,
@@ -252,10 +252,10 @@ UserPositionHistory.helpers({
break;
}
case 'checklist': {
- const checklist = ReactiveCache.getChecklist(this.entityId);
+ const checklist = await ReactiveCache.getChecklist(this.entityId);
if (checklist) {
const sort = this.previousSort !== undefined ? this.previousSort : checklist.sort;
-
+
Checklists.update(checklist._id, {
$set: {
sort,
@@ -270,7 +270,7 @@ UserPositionHistory.helpers({
if (item) {
const sort = this.previousSort !== undefined ? this.previousSort : item.sort;
const checklistId = this.previousState?.checklistId || item.checklistId;
-
+
ChecklistItems.update(item._id, {
$set: {
sort,
@@ -411,19 +411,19 @@ Meteor.methods({
});
},
- 'userPositionHistory.undo'(historyId) {
+ async 'userPositionHistory.undo'(historyId) {
check(historyId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
-
+
const history = UserPositionHistory.findOne({ _id: historyId, userId: this.userId });
if (!history) {
throw new Meteor.Error('not-found', 'History entry not found');
}
-
- return history.undo();
+
+ return await history.undo();
},
'userPositionHistory.getRecent'(boardId, limit = 50) {
@@ -453,23 +453,23 @@ Meteor.methods({
).fetch();
},
- 'userPositionHistory.restoreToCheckpoint'(checkpointId) {
+ async 'userPositionHistory.restoreToCheckpoint'(checkpointId) {
check(checkpointId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
-
- const checkpoint = UserPositionHistory.findOne({
- _id: checkpointId,
+
+ const checkpoint = UserPositionHistory.findOne({
+ _id: checkpointId,
userId: this.userId,
isCheckpoint: true,
});
-
+
if (!checkpoint) {
throw new Meteor.Error('not-found', 'Checkpoint not found');
}
-
+
// Find all changes after this checkpoint and undo them in reverse order
const changesToUndo = UserPositionHistory.find(
{
@@ -480,19 +480,19 @@ Meteor.methods({
},
{ sort: { createdAt: -1 } }
).fetch();
-
+
let undoneCount = 0;
- changesToUndo.forEach(change => {
+ for (const change of changesToUndo) {
try {
- if (change.canUndo()) {
- change.undo();
+ if (await change.canUndo()) {
+ await change.undo();
undoneCount++;
}
} catch (e) {
console.warn('Failed to undo change:', change._id, e);
}
- });
-
+ }
+
return { undoneCount, totalChanges: changesToUndo.length };
},
});
diff --git a/models/users.js b/models/users.js
index 732fa5bd0..ade8039ef 100644
--- a/models/users.js
+++ b/models/users.js
@@ -902,10 +902,10 @@ if (Meteor.isClient) {
return board && board.hasWorker(this._id);
},
- isBoardAdmin(boardId) {
+ async isBoardAdmin(boardId) {
let board;
if (boardId) {
- board = ReactiveCache.getBoard(boardId);
+ board = await ReactiveCache.getBoard(boardId);
} else {
board = Utils.getCurrentBoard();
}
@@ -1798,7 +1798,7 @@ Users.helpers({
Meteor.methods({
// Secure user removal method with proper authorization checks
- removeUser(targetUserId) {
+ async removeUser(targetUserId) {
check(targetUserId, String);
const currentUserId = Meteor.userId();
@@ -1806,12 +1806,12 @@ Meteor.methods({
throw new Meteor.Error('not-authorized', 'User must be logged in');
}
- const currentUser = ReactiveCache.getUser(currentUserId);
+ const currentUser = await ReactiveCache.getUser(currentUserId);
if (!currentUser) {
throw new Meteor.Error('not-authorized', 'Current user not found');
}
- const targetUser = ReactiveCache.getUser(targetUserId);
+ const targetUser = await ReactiveCache.getUser(targetUserId);
if (!targetUser) {
throw new Meteor.Error('user-not-found', 'Target user not found');
}
@@ -1829,9 +1829,9 @@ Meteor.methods({
}
// Check if target user is the last admin
- const adminsNumber = ReactiveCache.getUsers({
+ const adminsNumber = (await ReactiveCache.getUsers({
isAdmin: true,
- }).length;
+ })).length;
if (adminsNumber === 1 && targetUser.isAdmin) {
throw new Meteor.Error('not-authorized', 'Cannot delete the last administrator');
@@ -1841,7 +1841,7 @@ Meteor.methods({
Users.remove(targetUserId);
return { success: true, message: 'User deleted successfully' };
},
- editUser(targetUserId, updateData) {
+ async editUser(targetUserId, updateData) {
check(targetUserId, String);
check(updateData, Object);
@@ -1850,7 +1850,7 @@ Meteor.methods({
throw new Meteor.Error('not-authorized', 'User must be logged in');
}
- const currentUser = ReactiveCache.getUser(currentUserId);
+ const currentUser = await ReactiveCache.getUser(currentUserId);
if (!currentUser) {
throw new Meteor.Error('not-authorized', 'Current user not found');
}
@@ -1860,7 +1860,7 @@ Meteor.methods({
throw new Meteor.Error('not-authorized', 'Only administrators can edit other users');
}
- const targetUser = ReactiveCache.getUser(targetUserId);
+ const targetUser = await ReactiveCache.getUser(targetUserId);
if (!targetUser) {
throw new Meteor.Error('user-not-found', 'Target user not found');
}
@@ -1894,9 +1894,9 @@ Meteor.methods({
Users.update(targetUserId, { $set: updateObject });
},
- setListSortBy(value) {
+ async setListSortBy(value) {
check(value, String);
- ReactiveCache.getCurrentUser().setListSortBy(value);
+ (await ReactiveCache.getCurrentUser()).setListSortBy(value);
},
setAvatarUrl(avatarUrl) {
check(avatarUrl, String);
@@ -1943,8 +1943,8 @@ Meteor.methods({
Users.update(this.userId, { $set: { 'profile.GreyIcons': newValue } });
return newValue;
},
- toggleDesktopDragHandles() {
- const user = ReactiveCache.getCurrentUser();
+ async toggleDesktopDragHandles() {
+ const user = await ReactiveCache.getCurrentUser();
user.toggleDesktopHandles(user.hasShowDesktopDragHandles());
},
// Spaces: create a new space under parentId (or root when null)
@@ -2015,16 +2015,16 @@ Meteor.methods({
});
return true;
},
- toggleHideCheckedItems() {
- const user = ReactiveCache.getCurrentUser();
+ async toggleHideCheckedItems() {
+ const user = await ReactiveCache.getCurrentUser();
user.toggleHideCheckedItems();
},
- toggleCustomFieldsGrid() {
- const user = ReactiveCache.getCurrentUser();
+ async toggleCustomFieldsGrid() {
+ const user = await ReactiveCache.getCurrentUser();
user.toggleFieldsGrid(user.hasCustomFieldsGrid());
},
- toggleCardMaximized() {
- const user = ReactiveCache.getCurrentUser();
+ async toggleCardMaximized() {
+ const user = await ReactiveCache.getCurrentUser();
user.toggleCardMaximized(user.hasCardMaximized());
},
setCardCollapsed(value) {
@@ -2032,32 +2032,32 @@ Meteor.methods({
if (!this.userId) throw new Meteor.Error('not-logged-in');
Users.update(this.userId, { $set: { 'profile.cardCollapsed': value } });
},
- toggleMinicardLabelText() {
- const user = ReactiveCache.getCurrentUser();
+ async toggleMinicardLabelText() {
+ const user = await ReactiveCache.getCurrentUser();
user.toggleLabelText(user.hasHiddenMinicardLabelText());
},
- toggleRescueCardDescription() {
- const user = ReactiveCache.getCurrentUser();
+ async toggleRescueCardDescription() {
+ const user = await ReactiveCache.getCurrentUser();
user.toggleRescueCardDescription(user.hasRescuedCardDescription());
},
- changeLimitToShowCardsCount(limit) {
+ async changeLimitToShowCardsCount(limit) {
check(limit, Number);
- ReactiveCache.getCurrentUser().setShowCardsCountAt(limit);
+ (await ReactiveCache.getCurrentUser()).setShowCardsCountAt(limit);
},
- changeStartDayOfWeek(startDay) {
+ async changeStartDayOfWeek(startDay) {
check(startDay, Number);
- ReactiveCache.getCurrentUser().setStartDayOfWeek(startDay);
+ (await ReactiveCache.getCurrentUser()).setStartDayOfWeek(startDay);
},
- changeDateFormat(dateFormat) {
+ async changeDateFormat(dateFormat) {
check(dateFormat, String);
- ReactiveCache.getCurrentUser().setDateFormat(dateFormat);
+ (await ReactiveCache.getCurrentUser()).setDateFormat(dateFormat);
},
- applyListWidth(boardId, listId, width, constraint) {
+ async applyListWidth(boardId, listId, width, constraint) {
check(boardId, String);
check(listId, String);
check(width, Number);
check(constraint, Number);
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
user.setListWidth(boardId, listId, width);
user.setListConstraint(boardId, listId, constraint);
},
@@ -2081,11 +2081,11 @@ Meteor.methods({
},
});
},
- applySwimlaneHeight(boardId, swimlaneId, height) {
+ async applySwimlaneHeight(boardId, swimlaneId, height) {
check(boardId, String);
check(swimlaneId, String);
check(height, Number);
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
user.setSwimlaneHeight(boardId, swimlaneId, height);
},
@@ -2110,42 +2110,42 @@ Meteor.methods({
});
},
- applySwimlaneHeightToStorage(boardId, swimlaneId, height) {
+ async applySwimlaneHeightToStorage(boardId, swimlaneId, height) {
check(boardId, String);
check(swimlaneId, String);
check(height, Number);
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
if (user) {
user.setSwimlaneHeightToStorage(boardId, swimlaneId, height);
}
// For non-logged-in users, the client-side code will handle localStorage
},
- applyListWidthToStorage(boardId, listId, width, constraint) {
+ async applyListWidthToStorage(boardId, listId, width, constraint) {
check(boardId, String);
check(listId, String);
check(width, Number);
check(constraint, Number);
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
if (user) {
user.setListWidthToStorage(boardId, listId, width);
user.setListConstraintToStorage(boardId, listId, constraint);
}
// For non-logged-in users, the client-side code will handle localStorage
},
- setZoomLevel(level) {
+ async setZoomLevel(level) {
check(level, Number);
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
user.setZoomLevel(level);
},
- setMobileMode(enabled) {
+ async setMobileMode(enabled) {
check(enabled, Boolean);
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
user.setMobileMode(enabled);
},
- setBoardView(view) {
+ async setBoardView(view) {
check(view, String);
- const user = ReactiveCache.getCurrentUser();
+ const user = await ReactiveCache.getCurrentUser();
if (!user) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
@@ -2155,7 +2155,7 @@ Meteor.methods({
if (Meteor.isServer) {
Meteor.methods({
- setCreateUser(
+ async setCreateUser(
fullname,
username,
initials,
@@ -2185,13 +2185,13 @@ if (Meteor.isServer) {
initials.includes('/')) {
return false;
}
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
- const nUsersWithUsername = ReactiveCache.getUsers({
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
+ const nUsersWithUsername = (await ReactiveCache.getUsers({
username,
- }).length;
- const nUsersWithEmail = ReactiveCache.getUsers({
+ })).length;
+ const nUsersWithEmail = (await ReactiveCache.getUsers({
email,
- }).length;
+ })).length;
if (nUsersWithUsername > 0) {
throw new Meteor.Error('username-already-taken');
} else if (nUsersWithEmail > 0) {
@@ -2206,8 +2206,8 @@ if (Meteor.isServer) {
from: 'admin',
});
const user =
- ReactiveCache.getUser(username) ||
- ReactiveCache.getUser({ username });
+ await ReactiveCache.getUser(username) ||
+ await ReactiveCache.getUser({ username });
if (user) {
Users.update(user._id, {
$set: {
@@ -2222,7 +2222,7 @@ if (Meteor.isServer) {
}
}
},
- setUsername(username, userId) {
+ async setUsername(username, userId) {
check(username, String);
check(userId, String);
// Prevent Hyperlink Injection https://github.com/wekan/wekan/issues/5176
@@ -2231,10 +2231,10 @@ if (Meteor.isServer) {
userId.includes('/')) {
return false;
}
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
- const nUsersWithUsername = ReactiveCache.getUsers({
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
+ const nUsersWithUsername = (await ReactiveCache.getUsers({
username,
- }).length;
+ })).length;
if (nUsersWithUsername > 0) {
throw new Meteor.Error('username-already-taken');
} else {
@@ -2246,7 +2246,7 @@ if (Meteor.isServer) {
}
}
},
- setEmail(email, userId) {
+ async setEmail(email, userId) {
check(email, String);
check(username, String);
// Prevent Hyperlink Injection https://github.com/wekan/wekan/issues/5176
@@ -2255,11 +2255,11 @@ if (Meteor.isServer) {
email.includes('/')) {
return false;
}
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
if (Array.isArray(email)) {
email = email.shift();
}
- const existingUser = ReactiveCache.getUser(
+ const existingUser = await ReactiveCache.getUser(
{
'emails.address': email,
},
@@ -2285,7 +2285,7 @@ if (Meteor.isServer) {
}
}
},
- setUsernameAndEmail(username, email, userId) {
+ async setUsernameAndEmail(username, email, userId) {
check(username, String);
check(email, String);
check(userId, String);
@@ -2296,22 +2296,22 @@ if (Meteor.isServer) {
userId.includes('/')) {
return false;
}
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
if (Array.isArray(email)) {
email = email.shift();
}
- Meteor.call('setUsername', username, userId);
- Meteor.call('setEmail', email, userId);
+ await Meteor.callAsync('setUsername', username, userId);
+ await Meteor.callAsync('setEmail', email, userId);
}
},
- setPassword(newPassword, userId) {
+ async setPassword(newPassword, userId) {
check(userId, String);
check(newPassword, String);
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
Accounts.setPassword(userId, newPassword);
}
},
- setEmailVerified(email, verified, userId) {
+ async setEmailVerified(email, verified, userId) {
check(email, String);
check(verified, Boolean);
check(userId, String);
@@ -2321,7 +2321,7 @@ if (Meteor.isServer) {
userId.includes('/')) {
return false;
}
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
Users.update(userId, {
$set: {
emails: [
@@ -2334,7 +2334,7 @@ if (Meteor.isServer) {
});
}
},
- setInitials(initials, userId) {
+ async setInitials(initials, userId) {
check(initials, String);
check(userId, String);
// Prevent Hyperlink Injection https://github.com/wekan/wekan/issues/5176
@@ -2343,7 +2343,7 @@ if (Meteor.isServer) {
userId.includes('/')) {
return false;
}
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
Users.update(userId, {
$set: {
'profile.initials': initials,
@@ -2352,7 +2352,7 @@ if (Meteor.isServer) {
}
},
// we accept userId, username, email
- inviteUserToBoard(username, boardId) {
+ async inviteUserToBoard(username, boardId) {
check(username, String);
check(boardId, String);
// Prevent Hyperlink Injection https://github.com/wekan/wekan/issues/5176
@@ -2361,8 +2361,8 @@ if (Meteor.isServer) {
boardId.includes('/')) {
return false;
}
- const inviter = ReactiveCache.getCurrentUser();
- const board = ReactiveCache.getBoard(boardId);
+ const inviter = await ReactiveCache.getCurrentUser();
+ const board = await ReactiveCache.getBoard(boardId);
const member = _.find(board.members, function(member) { return member.userId === inviter._id; });
if (!member) throw new Meteor.Error('error-board-notAMember');
const allowInvite = member.isActive;
@@ -2375,7 +2375,7 @@ if (Meteor.isServer) {
const posAt = username.indexOf('@');
let user = null;
if (posAt >= 0) {
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
emails: {
$elemMatch: {
address: username,
@@ -2384,15 +2384,15 @@ if (Meteor.isServer) {
});
} else {
user =
- ReactiveCache.getUser(username) ||
- ReactiveCache.getUser({ username });
+ await ReactiveCache.getUser(username) ||
+ await ReactiveCache.getUser({ username });
}
if (user) {
if (user._id === inviter._id)
throw new Meteor.Error('error-user-notAllowSelf');
} else {
if (posAt <= 0) throw new Meteor.Error('error-user-doesNotExist');
- if (ReactiveCache.getCurrentSetting().disableRegistration) {
+ if ((await ReactiveCache.getCurrentSetting()).disableRegistration) {
throw new Meteor.Error('error-user-notCreated');
}
// Set in lowercase email before creating account
@@ -2418,7 +2418,7 @@ if (Meteor.isServer) {
});
}
Accounts.sendEnrollmentEmail(newUserId);
- user = ReactiveCache.getUser(newUserId);
+ user = await ReactiveCache.getUser(newUserId);
}
const memberIndex = board.members.findIndex(m => m.userId === user._id);
@@ -2431,7 +2431,7 @@ if (Meteor.isServer) {
//Check if there is a subtasks board
if (board.subtasksDefaultBoardId) {
- const subBoard = ReactiveCache.getBoard(board.subtasksDefaultBoardId);
+ const subBoard = await ReactiveCache.getBoard(board.subtasksDefaultBoardId);
//If there is, also add user to that board
if (subBoard) {
const subMemberIndex = subBoard.members.findIndex(m => m.userId === user._id);
@@ -2495,35 +2495,35 @@ if (Meteor.isServer) {
email: user.emails[0].address,
};
},
- impersonate(userId) {
+ async impersonate(userId) {
check(userId, String);
- if (!ReactiveCache.getUser(userId))
+ if (!(await ReactiveCache.getUser(userId)))
throw new Meteor.Error(404, 'User not found');
- if (!ReactiveCache.getCurrentUser().isAdmin)
+ if (!(await ReactiveCache.getCurrentUser()).isAdmin)
throw new Meteor.Error(403, 'Permission denied');
ImpersonatedUsers.insert({
- adminId: ReactiveCache.getCurrentUser()._id,
+ adminId: (await ReactiveCache.getCurrentUser())._id,
userId: userId,
reason: 'clickedImpersonate',
});
this.setUserId(userId);
},
- isImpersonated(userId) {
+ async isImpersonated(userId) {
check(userId, String);
- const isImpersonated = ReactiveCache.getImpersonatedUser({ userId: userId });
+ const isImpersonated = await ReactiveCache.getImpersonatedUser({ userId: userId });
return isImpersonated;
},
- setUsersTeamsTeamDisplayName(teamId, teamDisplayName) {
+ async setUsersTeamsTeamDisplayName(teamId, teamDisplayName) {
check(teamId, String);
check(teamDisplayName, String);
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
- ReactiveCache.getUsers({
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
+ for (const user of await ReactiveCache.getUsers({
teams: {
$elemMatch: { teamId: teamId },
},
- }).forEach((user) => {
+ })) {
Users.update(
{
_id: user._id,
@@ -2537,18 +2537,18 @@ if (Meteor.isServer) {
},
},
);
- });
+ }
}
},
- setUsersOrgsOrgDisplayName(orgId, orgDisplayName) {
+ async setUsersOrgsOrgDisplayName(orgId, orgDisplayName) {
check(orgId, String);
check(orgDisplayName, String);
- if (ReactiveCache.getCurrentUser()?.isAdmin) {
- ReactiveCache.getUsers({
+ if ((await ReactiveCache.getCurrentUser())?.isAdmin) {
+ for (const user of await ReactiveCache.getUsers({
orgs: {
$elemMatch: { orgId: orgId },
},
- }).forEach((user) => {
+ })) {
Users.update(
{
_id: user._id,
@@ -2562,12 +2562,12 @@ if (Meteor.isServer) {
},
},
);
- });
+ }
}
},
});
- Accounts.onCreateUser((options, user) => {
- const userCount = ReactiveCache.getUsers({}, {}, true).count();
+ Accounts.onCreateUser(async (options, user) => {
+ const userCount = (await ReactiveCache.getUsers({}, {}, true)).count();
user.isAdmin = userCount === 0;
if (user.services.oidc) {
@@ -2607,7 +2607,7 @@ if (Meteor.isServer) {
user.authenticationMethod = 'oauth2';
// see if any existing user has this email address or username, otherwise create new
- const existingUser = ReactiveCache.getUser({
+ const existingUser = await ReactiveCache.getUser({
$or: [
{
'emails.address': email,
@@ -2641,7 +2641,7 @@ if (Meteor.isServer) {
return user;
}
- const disableRegistration = ReactiveCache.getCurrentSetting().disableRegistration;
+ const disableRegistration = (await ReactiveCache.getCurrentSetting()).disableRegistration;
// If this is the first Authentication by the ldap and self registration disabled
if (disableRegistration && options && options.ldap) {
user.authenticationMethod = 'ldap';
@@ -2659,7 +2659,7 @@ if (Meteor.isServer) {
'The invitation code is required',
);
}
- const invitationCode = ReactiveCache.getInvitationCode({
+ const invitationCode = await ReactiveCache.getInvitationCode({
code: options.profile.invitationcode,
email: options.email,
valid: true,
@@ -2702,8 +2702,8 @@ const addCronJob = _.debounce(
SyncedCron.add({
name: 'notification_cleanup',
schedule: (parser) => parser.text('every 1 days'),
- job: () => {
- for (const user of ReactiveCache.getUsers()) {
+ job: async () => {
+ for (const user of await ReactiveCache.getUsers()) {
if (!user.profile || !user.profile.notifications) continue;
for (const notification of user.profile.notifications) {
if (notification.read) {
@@ -2938,9 +2938,9 @@ if (Meteor.isServer) {
});
}
- Users.after.insert((userId, doc) => {
+ Users.after.insert(async (userId, doc) => {
// HACK
- doc = ReactiveCache.getUser(doc._id);
+ doc = await ReactiveCache.getUser(doc._id);
if (doc.createdThroughApi) {
// The admin user should be able to create a user despite disabling registration because
// it is two different things (registration and creation).
@@ -2957,19 +2957,19 @@ if (Meteor.isServer) {
}
//invite user to corresponding boards
- const disableRegistration = ReactiveCache.getCurrentSetting().disableRegistration;
+ const disableRegistration = (await ReactiveCache.getCurrentSetting()).disableRegistration;
// If ldap, bypass the inviation code if the self registration isn't allowed.
// TODO : pay attention if ldap field in the user model change to another content ex : ldap field to connection_type
if (doc.authenticationMethod !== 'ldap' && disableRegistration) {
let invitationCode = null;
if (doc.authenticationMethod.toLowerCase() == 'oauth2') {
// OIDC authentication mode
- invitationCode = ReactiveCache.getInvitationCode({
+ invitationCode = await ReactiveCache.getInvitationCode({
email: doc.emails[0].address.toLowerCase(),
valid: true,
});
} else {
- invitationCode = ReactiveCache.getInvitationCode({
+ invitationCode = await ReactiveCache.getInvitationCode({
code: doc.profile.icode,
valid: true,
});
@@ -2977,15 +2977,15 @@ if (Meteor.isServer) {
if (!invitationCode) {
throw new Meteor.Error('error-invitation-code-not-exist');
} else {
- invitationCode.boardsToBeInvited.forEach((boardId) => {
- const board = ReactiveCache.getBoard(boardId);
+ for (const boardId of invitationCode.boardsToBeInvited) {
+ const board = await ReactiveCache.getBoard(boardId);
const memberIndex = board.members.findIndex(m => m.userId === doc._id);
if (memberIndex >= 0) {
Boards.update(boardId, { $set: { [`members.${memberIndex}.isActive`]: true } });
} else {
Boards.update(boardId, { $push: { members: { userId: doc._id, isAdmin: false, isActive: true, isNoComments: false, isCommentOnly: false, isWorker: false, isNormalAssignedOnly: false, isCommentAssignedOnly: false, isReadOnly: false, isReadAssignedOnly: false } } });
}
- });
+ }
if (!doc.profile) {
doc.profile = {};
}
@@ -3026,16 +3026,16 @@ if (Meteor.isServer) {
* @summary returns the current user
* @return_type Users
*/
- JsonRoutes.add('GET', '/api/user', function (req, res) {
+ JsonRoutes.add('GET', '/api/user', async function (req, res) {
try {
Authentication.checkLoggedIn(req.userId);
- const data = ReactiveCache.getUser({
+ const data = await ReactiveCache.getUser({
_id: req.userId,
});
delete data.services;
// get all boards where the user is member of
- let boards = ReactiveCache.getBoards(
+ let boards = await ReactiveCache.getBoards(
{
type: 'board',
'members.userId': req.userId,
@@ -3106,22 +3106,22 @@ if (Meteor.isServer) {
* @param {string} userId the user ID or username
* @return_type Users
*/
- JsonRoutes.add('GET', '/api/users/:userId', function (req, res) {
+ JsonRoutes.add('GET', '/api/users/:userId', async function (req, res) {
try {
Authentication.checkUserId(req.userId);
let id = req.params.userId;
- let user = ReactiveCache.getUser({
+ let user = await ReactiveCache.getUser({
_id: id,
});
if (!user) {
- user = ReactiveCache.getUser({
+ user = await ReactiveCache.getUser({
username: id,
});
id = user._id;
}
// get all boards where the user is member of
- let boards = ReactiveCache.getBoards(
+ let boards = await ReactiveCache.getBoards(
{
type: 'board',
'members.userId': id,
@@ -3175,12 +3175,12 @@ if (Meteor.isServer) {
Authentication.checkUserId(req.userId);
const id = req.params.userId;
const action = req.body.action;
- let data = ReactiveCache.getUser({
+ let data = await ReactiveCache.getUser({
_id: id,
});
if (data !== undefined) {
if (action === 'takeOwnership') {
- const boards = ReactiveCache.getBoards(
+ const boards = await ReactiveCache.getBoards(
{
'members.userId': id,
'members.isAdmin': true,
@@ -3227,7 +3227,7 @@ if (Meteor.isServer) {
},
);
}
- data = ReactiveCache.getUser(id);
+ data = await ReactiveCache.getUser(id);
}
}
JsonRoutes.sendResult(res, {
@@ -3270,19 +3270,19 @@ if (Meteor.isServer) {
JsonRoutes.add(
'POST',
'/api/boards/:boardId/members/:userId/add',
- function (req, res) {
+ async function (req, res) {
try {
Authentication.checkUserId(req.userId);
const userId = req.params.userId;
const boardId = req.params.boardId;
const action = req.body.action;
const { isAdmin, isNoComments, isCommentOnly, isWorker, isNormalAssignedOnly, isCommentAssignedOnly, isReadOnly, isReadAssignedOnly } = req.body;
- let data = ReactiveCache.getUser(userId);
+ let data = await ReactiveCache.getUser(userId);
if (data !== undefined) {
if (action === 'add') {
- data = ReactiveCache.getBoards({
+ data = (await ReactiveCache.getBoards({
_id: boardId,
- }).map(function (board) {
+ })).map(function (board) {
const hasMember = board.members.some(m => m.userId === userId && m.isActive);
if (!hasMember) {
const memberIndex = board.members.findIndex(m => m.userId === userId);
@@ -3345,18 +3345,18 @@ if (Meteor.isServer) {
JsonRoutes.add(
'POST',
'/api/boards/:boardId/members/:userId/remove',
- function (req, res) {
+ async function (req, res) {
try {
Authentication.checkUserId(req.userId);
const userId = req.params.userId;
const boardId = req.params.boardId;
const action = req.body.action;
- let data = ReactiveCache.getUser(userId);
+ let data = await ReactiveCache.getUser(userId);
if (data !== undefined) {
if (action === 'remove') {
- data = ReactiveCache.getBoards({
+ data = (await ReactiveCache.getBoards({
_id: boardId,
- }).map(function (board) {
+ })).map(function (board) {
const hasMember = board.members.some(m => m.userId === userId && m.isActive);
if (hasMember) {
const memberIndex = board.members.findIndex(m => m.userId === userId);
@@ -3591,7 +3591,7 @@ if (Meteor.isServer) {
check(userData, Object);
return sanitizeUserForSearch(userData);
},
- searchUsers(query, boardId) {
+ async searchUsers(query, boardId) {
check(query, String);
check(boardId, String);
@@ -3599,8 +3599,8 @@ if (Meteor.isServer) {
throw new Meteor.Error('not-logged-in', 'User must be logged in');
}
- const currentUser = ReactiveCache.getCurrentUser();
- const board = ReactiveCache.getBoard(boardId);
+ const currentUser = await ReactiveCache.getCurrentUser();
+ const board = await ReactiveCache.getBoard(boardId);
// Check if current user is a member of the board
const member = _.find(board.members, function(member) { return member.userId === currentUser._id; });
@@ -3613,7 +3613,7 @@ if (Meteor.isServer) {
}
const searchRegex = new RegExp(query, 'i');
- const users = ReactiveCache.getUsers({
+ const users = await ReactiveCache.getUsers({
$or: [
{ username: searchRegex },
{ 'profile.fullname': searchRegex },
diff --git a/models/wekanCreator.js b/models/wekanCreator.js
index 0580ca139..a37ceb0c8 100644
--- a/models/wekanCreator.js
+++ b/models/wekanCreator.js
@@ -244,14 +244,14 @@ export class WekanCreator {
]);
}
- getMembersToMap(data) {
+ async getMembersToMap(data) {
// we will work on the list itself (an ordered array of objects) when a
// mapping is done, we add a 'wekan' field to the object representing the
// imported member
const membersToMap = data.members;
const users = data.users;
// auto-map based on username
- membersToMap.forEach(importedMember => {
+ for (const importedMember of membersToMap) {
importedMember.id = importedMember.userId;
delete importedMember.userId;
const user = users.filter(user => {
@@ -261,11 +261,11 @@ export class WekanCreator {
importedMember.fullName = user.profile.fullname;
}
importedMember.username = user.username;
- const wekanUser = ReactiveCache.getUser({ username: importedMember.username });
+ const wekanUser = await ReactiveCache.getUser({ username: importedMember.username });
if (wekanUser) {
importedMember.wekanId = wekanUser._id;
}
- });
+ }
return membersToMap;
}
@@ -665,8 +665,8 @@ export class WekanCreator {
});
}
- createSubtasks(wekanCards) {
- wekanCards.forEach(card => {
+ async createSubtasks(wekanCards) {
+ for (const card of wekanCards) {
// get new id of card (in created / new board)
const cardIdInNewBoard = this.cards[card._id];
@@ -683,7 +683,7 @@ export class WekanCreator {
: card.parentId;
//if the parent card exists, proceed
- if (ReactiveCache.getCard(parentIdInNewBoard)) {
+ if (await ReactiveCache.getCard(parentIdInNewBoard)) {
//set parent id of the card in the new board to the new id of the parent
Cards.direct.update(cardIdInNewBoard, {
$set: {
@@ -691,7 +691,7 @@ export class WekanCreator {
},
});
}
- });
+ }
}
createChecklists(wekanChecklists) {
@@ -978,7 +978,7 @@ export class WekanCreator {
Meteor.settings.public &&
Meteor.settings.public.sandstorm;
if (isSandstorm && currentBoardId) {
- const currentBoard = ReactiveCache.getBoard(currentBoardId);
+ const currentBoard = await ReactiveCache.getBoard(currentBoardId);
await currentBoard.archive();
}
this.parseActivities(board);
@@ -987,7 +987,7 @@ export class WekanCreator {
this.createSwimlanes(board.swimlanes, boardId);
this.createCustomFields(board.customFields, boardId);
this.createCards(board.cards, boardId);
- this.createSubtasks(board.cards);
+ await this.createSubtasks(board.cards);
this.createChecklists(board.checklists);
this.createChecklistItems(board.checklistItems);
this.importActivities(board.activities, boardId);
diff --git a/models/wekanmapper.js b/models/wekanmapper.js
index 3dc449c7a..be849af7c 100644
--- a/models/wekanmapper.js
+++ b/models/wekanmapper.js
@@ -1,13 +1,13 @@
import { ReactiveCache } from '/imports/reactiveCache';
-export function getMembersToMap(data) {
+export async function getMembersToMap(data) {
// we will work on the list itself (an ordered array of objects) when a
// mapping is done, we add a 'wekan' field to the object representing the
// imported member
const membersToMap = data.members;
const users = data.users;
// auto-map based on username
- membersToMap.forEach(importedMember => {
+ for (const importedMember of membersToMap) {
importedMember.id = importedMember.userId;
delete importedMember.userId;
const user = users.filter(user => {
@@ -17,10 +17,10 @@ export function getMembersToMap(data) {
importedMember.fullName = user.profile.fullname;
}
importedMember.username = user.username;
- const wekanUser = ReactiveCache.getUser({ username: importedMember.username });
+ const wekanUser = await ReactiveCache.getUser({ username: importedMember.username });
if (wekanUser) {
importedMember.wekanId = wekanUser._id;
}
- });
+ }
return membersToMap;
}
diff --git a/server/attachmentApi.js b/server/attachmentApi.js
index 148753548..a0cafd198 100644
--- a/server/attachmentApi.js
+++ b/server/attachmentApi.js
@@ -12,7 +12,7 @@ import { ObjectID } from 'bson';
if (Meteor.isServer) {
Meteor.methods({
// Upload attachment via API
- 'api.attachment.upload'(boardId, swimlaneId, listId, cardId, fileData, fileName, fileType, storageBackend) {
+ async 'api.attachment.upload'(boardId, swimlaneId, listId, cardId, fileData, fileName, fileType, storageBackend) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
@@ -23,12 +23,12 @@ if (Meteor.isServer) {
}
// Check if user has permission to modify the card
- const card = ReactiveCache.getCard(cardId);
+ const card = await ReactiveCache.getCard(cardId);
if (!card) {
throw new Meteor.Error('card-not-found', 'Card not found');
}
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found');
}
@@ -114,19 +114,19 @@ if (Meteor.isServer) {
},
// Download attachment via API
- 'api.attachment.download'(attachmentId) {
+ async 'api.attachment.download'(attachmentId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
// Get attachment
- const attachment = ReactiveCache.getAttachment(attachmentId);
+ const attachment = await ReactiveCache.getAttachment(attachmentId);
if (!attachment) {
throw new Meteor.Error('attachment-not-found', 'Attachment not found');
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board || !board.isBoardMember(this.userId)) {
throw new Meteor.Error('not-authorized', 'You do not have permission to access this attachment');
}
@@ -173,13 +173,13 @@ if (Meteor.isServer) {
},
// List attachments for board, swimlane, list, or card
- 'api.attachment.list'(boardId, swimlaneId, listId, cardId) {
+ async 'api.attachment.list'(boardId, swimlaneId, listId, cardId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
// Check permissions
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.isBoardMember(this.userId)) {
throw new Meteor.Error('not-authorized', 'You do not have permission to access this board');
}
@@ -199,7 +199,7 @@ if (Meteor.isServer) {
query['meta.cardId'] = cardId;
}
- const attachments = ReactiveCache.getAttachments(query);
+ const attachments = await ReactiveCache.getAttachments(query);
const attachmentList = attachments.map(attachment => {
const strategy = fileStoreStrategyFactory.getFileStrategy(attachment, 'original');
@@ -230,25 +230,25 @@ if (Meteor.isServer) {
},
// Copy attachment to another card
- 'api.attachment.copy'(attachmentId, targetBoardId, targetSwimlaneId, targetListId, targetCardId) {
+ async 'api.attachment.copy'(attachmentId, targetBoardId, targetSwimlaneId, targetListId, targetCardId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
// Get source attachment
- const sourceAttachment = ReactiveCache.getAttachment(attachmentId);
+ const sourceAttachment = await ReactiveCache.getAttachment(attachmentId);
if (!sourceAttachment) {
throw new Meteor.Error('attachment-not-found', 'Source attachment not found');
}
// Check source permissions
- const sourceBoard = ReactiveCache.getBoard(sourceAttachment.meta.boardId);
+ const sourceBoard = await ReactiveCache.getBoard(sourceAttachment.meta.boardId);
if (!sourceBoard || !sourceBoard.isBoardMember(this.userId)) {
throw new Meteor.Error('not-authorized', 'You do not have permission to access the source attachment');
}
// Check target permissions
- const targetBoard = ReactiveCache.getBoard(targetBoardId);
+ const targetBoard = await ReactiveCache.getBoard(targetBoardId);
if (!targetBoard || !targetBoard.isBoardMember(this.userId)) {
throw new Meteor.Error('not-authorized', 'You do not have permission to modify the target card');
}
@@ -328,25 +328,25 @@ if (Meteor.isServer) {
},
// Move attachment to another card
- 'api.attachment.move'(attachmentId, targetBoardId, targetSwimlaneId, targetListId, targetCardId) {
+ async 'api.attachment.move'(attachmentId, targetBoardId, targetSwimlaneId, targetListId, targetCardId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
// Get source attachment
- const sourceAttachment = ReactiveCache.getAttachment(attachmentId);
+ const sourceAttachment = await ReactiveCache.getAttachment(attachmentId);
if (!sourceAttachment) {
throw new Meteor.Error('attachment-not-found', 'Source attachment not found');
}
// Check source permissions
- const sourceBoard = ReactiveCache.getBoard(sourceAttachment.meta.boardId);
+ const sourceBoard = await ReactiveCache.getBoard(sourceAttachment.meta.boardId);
if (!sourceBoard || !sourceBoard.isBoardMember(this.userId)) {
throw new Meteor.Error('not-authorized', 'You do not have permission to access the source attachment');
}
// Check target permissions
- const targetBoard = ReactiveCache.getBoard(targetBoardId);
+ const targetBoard = await ReactiveCache.getBoard(targetBoardId);
if (!targetBoard || !targetBoard.isBoardMember(this.userId)) {
throw new Meteor.Error('not-authorized', 'You do not have permission to modify the target card');
}
@@ -385,19 +385,19 @@ if (Meteor.isServer) {
},
// Delete attachment via API
- 'api.attachment.delete'(attachmentId) {
+ async 'api.attachment.delete'(attachmentId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
// Get attachment
- const attachment = ReactiveCache.getAttachment(attachmentId);
+ const attachment = await ReactiveCache.getAttachment(attachmentId);
if (!attachment) {
throw new Meteor.Error('attachment-not-found', 'Attachment not found');
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board || !board.isBoardMember(this.userId)) {
throw new Meteor.Error('not-authorized', 'You do not have permission to delete this attachment');
}
@@ -419,19 +419,19 @@ if (Meteor.isServer) {
},
// Get attachment info via API
- 'api.attachment.info'(attachmentId) {
+ async 'api.attachment.info'(attachmentId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
// Get attachment
- const attachment = ReactiveCache.getAttachment(attachmentId);
+ const attachment = await ReactiveCache.getAttachment(attachmentId);
if (!attachment) {
throw new Meteor.Error('attachment-not-found', 'Attachment not found');
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board || !board.isBoardMember(this.userId)) {
throw new Meteor.Error('not-authorized', 'You do not have permission to access this attachment');
}
diff --git a/server/attachmentMigration.js b/server/attachmentMigration.js
index 318893067..f9dc87b4f 100644
--- a/server/attachmentMigration.js
+++ b/server/attachmentMigration.js
@@ -119,13 +119,13 @@ class AttachmentMigrationService {
async migrateAttachment(attachment) {
try {
// Get the card to find board and list information
- const card = ReactiveCache.getCard(attachment.cardId);
+ const card = await ReactiveCache.getCard(attachment.cardId);
if (!card) {
console.warn(`Card not found for attachment ${attachment._id}`);
return;
}
- const list = ReactiveCache.getList(card.listId);
+ const list = await ReactiveCache.getList(card.listId);
if (!list) {
console.warn(`List not found for attachment ${attachment._id}`);
return;
@@ -203,17 +203,17 @@ const attachmentMigrationService = new AttachmentMigrationService();
Meteor.methods({
async 'attachmentMigration.migrateBoardAttachments'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- const board = ReactiveCache.getBoard(boardId);
+
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found');
}
-
- const user = ReactiveCache.getUser(this.userId);
+
+ const user = await ReactiveCache.getUser(this.userId);
const isBoardAdmin = board.hasAdmin(this.userId);
const isInstanceAdmin = user && user.isAdmin;
@@ -224,14 +224,14 @@ Meteor.methods({
return await attachmentMigrationService.migrateBoardAttachments(boardId);
},
- 'attachmentMigration.getProgress'(boardId) {
+ async 'attachmentMigration.getProgress'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- const board = ReactiveCache.getBoard(boardId);
+
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
@@ -239,14 +239,14 @@ Meteor.methods({
return attachmentMigrationService.getMigrationProgress(boardId);
},
- 'attachmentMigration.getUnconvertedAttachments'(boardId) {
+ async 'attachmentMigration.getUnconvertedAttachments'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- const board = ReactiveCache.getBoard(boardId);
+
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
@@ -254,14 +254,14 @@ Meteor.methods({
return attachmentMigrationService.getUnconvertedAttachments(boardId);
},
- 'attachmentMigration.isBoardMigrated'(boardId) {
+ async 'attachmentMigration.isBoardMigrated'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- const board = ReactiveCache.getBoard(boardId);
+
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
diff --git a/server/authentication.js b/server/authentication.js
index 5b7ad2ee6..77aac7f9f 100644
--- a/server/authentication.js
+++ b/server/authentication.js
@@ -15,13 +15,13 @@ Meteor.startup(() => {
Authentication = {};
- Authentication.checkUserId = function(userId) {
+ Authentication.checkUserId = async function(userId) {
if (userId === undefined) {
const error = new Meteor.Error('Unauthorized', 'Unauthorized');
error.statusCode = 401;
throw error;
}
- const admin = ReactiveCache.getUser({ _id: userId, isAdmin: true });
+ const admin = await ReactiveCache.getUser({ _id: userId, isAdmin: true });
if (admin === undefined) {
const error = new Meteor.Error('Forbidden', 'Forbidden');
@@ -42,9 +42,9 @@ Meteor.startup(() => {
// An admin should be authorized to access everything, so we use a separate check for admins
// This throws an error if otherReq is false and the user is not an admin
- Authentication.checkAdminOrCondition = function(userId, otherReq) {
+ Authentication.checkAdminOrCondition = async function(userId, otherReq) {
if (otherReq) return;
- const admin = ReactiveCache.getUser({ _id: userId, isAdmin: true });
+ const admin = await ReactiveCache.getUser({ _id: userId, isAdmin: true });
if (admin === undefined) {
const error = new Meteor.Error('Forbidden', 'Forbidden');
error.statusCode = 403;
@@ -53,19 +53,19 @@ Meteor.startup(() => {
};
// Helper function. Will throw an error if the user is not active BoardAdmin or active Normal user of the board.
- Authentication.checkBoardAccess = function(userId, boardId) {
+ Authentication.checkBoardAccess = async function(userId, boardId) {
Authentication.checkLoggedIn(userId);
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
const normalAccess = board.members.some(e => e.userId === userId && e.isActive && !e.isNoComments && !e.isCommentOnly && !e.isWorker);
- Authentication.checkAdminOrCondition(userId, normalAccess);
+ await Authentication.checkAdminOrCondition(userId, normalAccess);
};
// Helper function. Will throw an error if the user does not have write access to the board (excludes read-only users).
- Authentication.checkBoardWriteAccess = function(userId, boardId) {
+ Authentication.checkBoardWriteAccess = async function(userId, boardId) {
Authentication.checkLoggedIn(userId);
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
const writeAccess = board.members.some(e => e.userId === userId && e.isActive && !e.isNoComments && !e.isCommentOnly && !e.isWorker && !e.isReadOnly && !e.isReadAssignedOnly);
- Authentication.checkAdminOrCondition(userId, writeAccess);
+ await Authentication.checkAdminOrCondition(userId, writeAccess);
};
if (Meteor.isServer) {
diff --git a/server/cronMigrationManager.js b/server/cronMigrationManager.js
index ffb5801bc..580d1d0d6 100644
--- a/server/cronMigrationManager.js
+++ b/server/cronMigrationManager.js
@@ -1782,134 +1782,134 @@ Meteor.startup(() => {
// Meteor methods for client-server communication
Meteor.methods({
- 'cron.startAllMigrations'() {
+ async 'cron.startAllMigrations'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.startAllMigrations();
},
- 'cron.startSpecificMigration'(migrationIndex) {
+ async 'cron.startSpecificMigration'(migrationIndex) {
check(migrationIndex, Number);
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.startSpecificMigration(migrationIndex);
},
- 'cron.startJob'(cronName) {
+ async 'cron.startJob'(cronName) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.startCronJob(cronName);
},
- 'cron.stopJob'(cronName) {
+ async 'cron.stopJob'(cronName) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.stopCronJob(cronName);
},
- 'cron.pauseJob'(cronName) {
+ async 'cron.pauseJob'(cronName) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.pauseCronJob(cronName);
},
- 'cron.resumeJob'(cronName) {
+ async 'cron.resumeJob'(cronName) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.resumeCronJob(cronName);
},
- 'cron.removeJob'(cronName) {
+ async 'cron.removeJob'(cronName) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.removeCronJob(cronName);
},
- 'cron.addJob'(jobData) {
+ async 'cron.addJob'(jobData) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.addCronJob(jobData);
},
- 'cron.getJobs'() {
+ async 'cron.getJobs'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.getAllCronJobs();
},
- 'cron.getMigrationProgress'() {
+ async 'cron.getMigrationProgress'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return {
progress: cronMigrationProgress.get(),
status: cronMigrationStatus.get(),
@@ -1921,337 +1921,337 @@ Meteor.methods({
};
},
- 'cron.pauseAllMigrations'() {
+ async 'cron.pauseAllMigrations'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.pauseAllMigrations();
},
- 'cron.resumeAllMigrations'() {
+ async 'cron.resumeAllMigrations'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.resumeAllMigrations();
},
- 'cron.retryFailedMigrations'() {
+ async 'cron.retryFailedMigrations'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.retryFailedMigrations();
},
- 'cron.getAllMigrationErrors'(limit = 50) {
+ async 'cron.getAllMigrationErrors'(limit = 50) {
check(limit, Match.Optional(Number));
-
+
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.getAllMigrationErrors(limit);
},
- 'cron.getJobErrors'(jobId, options = {}) {
+ async 'cron.getJobErrors'(jobId, options = {}) {
check(jobId, String);
check(options, Match.Optional(Object));
-
+
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.getJobErrors(jobId, options);
},
- 'cron.getMigrationStats'() {
+ async 'cron.getMigrationStats'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.getMigrationStats();
},
- 'cron.startBoardOperation'(boardId, operationType, operationData) {
+ async 'cron.startBoardOperation'(boardId, operationType, operationData) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
-
+
// Check if user is global admin OR board admin
- const user = ReactiveCache.getUser(userId);
- const board = ReactiveCache.getBoard(boardId);
-
+ const user = await ReactiveCache.getUser(userId);
+ const board = await ReactiveCache.getBoard(boardId);
+
if (!user) {
throw new Meteor.Error('not-authorized', 'User not found');
}
-
+
if (!board) {
throw new Meteor.Error('not-found', 'Board not found');
}
-
+
// Check global admin or board admin
const isGlobalAdmin = user.isAdmin;
- const isBoardAdmin = board.members && board.members.some(member =>
+ const isBoardAdmin = board.members && board.members.some(member =>
member.userId === userId && member.isAdmin
);
-
+
if (!isGlobalAdmin && !isBoardAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required for this board');
}
-
+
return cronMigrationManager.startBoardOperation(boardId, operationType, operationData);
},
- 'cron.getBoardOperations'(boardId) {
+ async 'cron.getBoardOperations'(boardId) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
-
+
// Check if user is global admin OR board admin
- const user = ReactiveCache.getUser(userId);
- const board = ReactiveCache.getBoard(boardId);
-
+ const user = await ReactiveCache.getUser(userId);
+ const board = await ReactiveCache.getBoard(boardId);
+
if (!user) {
throw new Meteor.Error('not-authorized', 'User not found');
}
-
+
if (!board) {
throw new Meteor.Error('not-found', 'Board not found');
}
-
+
// Check global admin or board admin
const isGlobalAdmin = user.isAdmin;
- const isBoardAdmin = board.members && board.members.some(member =>
+ const isBoardAdmin = board.members && board.members.some(member =>
member.userId === userId && member.isAdmin
);
-
+
if (!isGlobalAdmin && !isBoardAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required for this board');
}
-
+
return cronMigrationManager.getBoardOperations(boardId);
},
- 'cron.getAllBoardOperations'(page, limit, searchTerm) {
+ async 'cron.getAllBoardOperations'(page, limit, searchTerm) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.getAllBoardOperations(page, limit, searchTerm);
},
- 'cron.getBoardOperationStats'() {
+ async 'cron.getBoardOperationStats'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.getBoardOperationStats();
},
- 'cron.getJobDetails'(jobId) {
+ async 'cron.getJobDetails'(jobId) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronJobStorage.getJobDetails(jobId);
},
- 'cron.getQueueStats'() {
+ async 'cron.getQueueStats'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronJobStorage.getQueueStats();
},
- 'cron.getSystemResources'() {
+ async 'cron.getSystemResources'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronJobStorage.getSystemResources();
},
- 'cron.clearAllJobs'() {
+ async 'cron.clearAllJobs'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronMigrationManager.clearAllCronJobs();
},
- 'cron.pauseJob'(jobId) {
+ async 'cron.pauseJob'(jobId) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
cronJobStorage.updateQueueStatus(jobId, 'paused');
cronJobStorage.saveJobStatus(jobId, { status: 'paused' });
return { success: true };
},
- 'cron.resumeJob'(jobId) {
+ async 'cron.resumeJob'(jobId) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
cronJobStorage.updateQueueStatus(jobId, 'pending');
cronJobStorage.saveJobStatus(jobId, { status: 'pending' });
return { success: true };
},
- 'cron.stopJob'(jobId) {
+ async 'cron.stopJob'(jobId) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
cronJobStorage.updateQueueStatus(jobId, 'stopped');
- cronJobStorage.saveJobStatus(jobId, {
+ cronJobStorage.saveJobStatus(jobId, {
status: 'stopped',
stoppedAt: new Date()
});
return { success: true };
},
- 'cron.cleanupOldJobs'(daysOld) {
+ async 'cron.cleanupOldJobs'(daysOld) {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
return cronJobStorage.cleanupOldJobs(daysOld);
},
- 'cron.pauseAllMigrations'() {
+ async 'cron.pauseAllMigrations'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
// Pause all running jobs in the queue
const runningJobs = cronJobStorage.getIncompleteJobs().filter(job => job.status === 'running');
runningJobs.forEach(job => {
cronJobStorage.updateQueueStatus(job.jobId, 'paused');
cronJobStorage.saveJobStatus(job.jobId, { status: 'paused' });
});
-
+
cronMigrationStatus.set('All migrations paused');
return { success: true, message: 'All migrations paused' };
},
- 'cron.stopAllMigrations'() {
+ async 'cron.stopAllMigrations'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
// Clear monitor interval first to prevent status override
if (cronMigrationManager.monitorInterval) {
Meteor.clearInterval(cronMigrationManager.monitorInterval);
cronMigrationManager.monitorInterval = null;
}
-
+
// Stop all running and pending jobs
const incompleteJobs = cronJobStorage.getIncompleteJobs();
incompleteJobs.forEach(job => {
cronJobStorage.updateQueueStatus(job.jobId, 'stopped', { stoppedAt: new Date() });
- cronJobStorage.saveJobStatus(job.jobId, {
+ cronJobStorage.saveJobStatus(job.jobId, {
status: 'stopped',
stoppedAt: new Date()
});
});
-
+
// Reset migration state immediately
cronMigrationManager.isRunning = false;
cronIsMigrating.set(false);
@@ -2260,40 +2260,40 @@ Meteor.methods({
cronMigrationCurrentStepNum.set(0);
cronMigrationTotalSteps.set(0);
cronMigrationStatus.set('All migrations stopped');
-
+
// Clear status message after delay
setTimeout(() => {
cronMigrationStatus.set('');
}, 3000);
-
+
return { success: true, message: 'All migrations stopped' };
},
- 'cron.getBoardMigrationStats'() {
+ async 'cron.getBoardMigrationStats'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
// Import the board migration detector
const { boardMigrationDetector } = require('./boardMigrationDetector');
return boardMigrationDetector.getMigrationStats();
},
- 'cron.forceBoardMigrationScan'() {
+ async 'cron.forceBoardMigrationScan'() {
const userId = this.userId;
if (!userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin access required');
}
-
+
// Import the board migration detector
const { boardMigrationDetector } = require('./boardMigrationDetector');
return boardMigrationDetector.forceScan();
diff --git a/server/lib/emailLocalization.js b/server/lib/emailLocalization.js
index 4c8bd0b17..19f0e8992 100644
--- a/server/lib/emailLocalization.js
+++ b/server/lib/emailLocalization.js
@@ -17,13 +17,13 @@ EmailLocalization = {
* @param {String} options.language - Language code to use (if not provided, will try to detect)
* @param {String} options.userId - User ID to determine language (if not provided with language)
*/
- sendEmail(options) {
+ async sendEmail(options) {
// Determine the language to use
let lang = options.language;
// If no language is specified but we have a userId, try to get the user's language
if (!lang && options.userId) {
- const user = ReactiveCache.getUser(options.userId);
+ const user = await ReactiveCache.getUser(options.userId);
if (user) {
lang = user.getLanguage();
}
diff --git a/server/methods/fixDuplicateLists.js b/server/methods/fixDuplicateLists.js
index 8f2cb9e77..1fbc1b2c9 100644
--- a/server/methods/fixDuplicateLists.js
+++ b/server/methods/fixDuplicateLists.js
@@ -11,12 +11,12 @@ import { ReactiveCache } from '/imports/reactiveCache';
* This method identifies and removes duplicate lists while preserving cards
*/
Meteor.methods({
- 'fixDuplicateLists.fixAllBoards'() {
+ async 'fixDuplicateLists.fixAllBoards'() {
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
- if (!ReactiveCache.getUser(this.userId).isAdmin) {
+ if (!(await ReactiveCache.getUser(this.userId)).isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin required');
}
@@ -53,14 +53,14 @@ Meteor.methods({
};
},
- 'fixDuplicateLists.fixBoard'(boardId) {
+ async 'fixDuplicateLists.fixBoard'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.hasAdmin(this.userId)) {
throw new Meteor.Error('not-authorized');
}
@@ -208,12 +208,12 @@ function fixDuplicateLists(boardId) {
}
Meteor.methods({
- 'fixDuplicateLists.getReport'() {
+ async 'fixDuplicateLists.getReport'() {
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
- if (!ReactiveCache.getUser(this.userId).isAdmin) {
+ if (!(await ReactiveCache.getUser(this.userId)).isAdmin) {
throw new Meteor.Error('not-authorized', 'Admin required');
}
diff --git a/server/methods/lockedUsers.js b/server/methods/lockedUsers.js
index a5de5075b..7458b832e 100644
--- a/server/methods/lockedUsers.js
+++ b/server/methods/lockedUsers.js
@@ -8,7 +8,7 @@ Meteor.methods({
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
@@ -56,7 +56,7 @@ Meteor.methods({
if (!adminId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user');
}
- const admin = ReactiveCache.getUser(adminId);
+ const admin = await ReactiveCache.getUser(adminId);
if (!admin || !admin.isAdmin) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
@@ -86,7 +86,7 @@ Meteor.methods({
if (!adminId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user');
}
- const admin = ReactiveCache.getUser(adminId);
+ const admin = await ReactiveCache.getUser(adminId);
if (!admin || !admin.isAdmin) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
diff --git a/server/methods/lockoutSettings.js b/server/methods/lockoutSettings.js
index cf12b083a..70b8efead 100644
--- a/server/methods/lockoutSettings.js
+++ b/server/methods/lockoutSettings.js
@@ -9,7 +9,7 @@ Meteor.methods({
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user');
}
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
diff --git a/server/methods/positionHistory.js b/server/methods/positionHistory.js
index 704b3b9d6..63369cfca 100644
--- a/server/methods/positionHistory.js
+++ b/server/methods/positionHistory.js
@@ -13,294 +13,294 @@ Meteor.methods({
/**
* Track original position for a swimlane
*/
- 'positionHistory.trackSwimlane'(swimlaneId) {
+ async 'positionHistory.trackSwimlane'(swimlaneId) {
check(swimlaneId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const swimlane = Swimlanes.findOne(swimlaneId);
if (!swimlane) {
throw new Meteor.Error('swimlane-not-found', 'Swimlane not found');
}
-
- const board = ReactiveCache.getBoard(swimlane.boardId);
+
+ const board = await ReactiveCache.getBoard(swimlane.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return swimlane.trackOriginalPosition();
},
/**
* Track original position for a list
*/
- 'positionHistory.trackList'(listId) {
+ async 'positionHistory.trackList'(listId) {
check(listId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const list = Lists.findOne(listId);
if (!list) {
throw new Meteor.Error('list-not-found', 'List not found');
}
-
- const board = ReactiveCache.getBoard(list.boardId);
+
+ const board = await ReactiveCache.getBoard(list.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return list.trackOriginalPosition();
},
/**
* Track original position for a card
*/
- 'positionHistory.trackCard'(cardId) {
+ async 'positionHistory.trackCard'(cardId) {
check(cardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const card = Cards.findOne(cardId);
if (!card) {
throw new Meteor.Error('card-not-found', 'Card not found');
}
-
- const board = ReactiveCache.getBoard(card.boardId);
+
+ const board = await ReactiveCache.getBoard(card.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return card.trackOriginalPosition();
},
/**
* Get original position for a swimlane
*/
- 'positionHistory.getSwimlaneOriginalPosition'(swimlaneId) {
+ async 'positionHistory.getSwimlaneOriginalPosition'(swimlaneId) {
check(swimlaneId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const swimlane = Swimlanes.findOne(swimlaneId);
if (!swimlane) {
throw new Meteor.Error('swimlane-not-found', 'Swimlane not found');
}
-
- const board = ReactiveCache.getBoard(swimlane.boardId);
+
+ const board = await ReactiveCache.getBoard(swimlane.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return swimlane.getOriginalPosition();
},
/**
* Get original position for a list
*/
- 'positionHistory.getListOriginalPosition'(listId) {
+ async 'positionHistory.getListOriginalPosition'(listId) {
check(listId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const list = Lists.findOne(listId);
if (!list) {
throw new Meteor.Error('list-not-found', 'List not found');
}
-
- const board = ReactiveCache.getBoard(list.boardId);
+
+ const board = await ReactiveCache.getBoard(list.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return list.getOriginalPosition();
},
/**
* Get original position for a card
*/
- 'positionHistory.getCardOriginalPosition'(cardId) {
+ async 'positionHistory.getCardOriginalPosition'(cardId) {
check(cardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const card = Cards.findOne(cardId);
if (!card) {
throw new Meteor.Error('card-not-found', 'Card not found');
}
-
- const board = ReactiveCache.getBoard(card.boardId);
+
+ const board = await ReactiveCache.getBoard(card.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return card.getOriginalPosition();
},
/**
* Check if a swimlane has moved from its original position
*/
- 'positionHistory.hasSwimlaneMoved'(swimlaneId) {
+ async 'positionHistory.hasSwimlaneMoved'(swimlaneId) {
check(swimlaneId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const swimlane = Swimlanes.findOne(swimlaneId);
if (!swimlane) {
throw new Meteor.Error('swimlane-not-found', 'Swimlane not found');
}
-
- const board = ReactiveCache.getBoard(swimlane.boardId);
+
+ const board = await ReactiveCache.getBoard(swimlane.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return swimlane.hasMovedFromOriginalPosition();
},
/**
* Check if a list has moved from its original position
*/
- 'positionHistory.hasListMoved'(listId) {
+ async 'positionHistory.hasListMoved'(listId) {
check(listId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const list = Lists.findOne(listId);
if (!list) {
throw new Meteor.Error('list-not-found', 'List not found');
}
-
- const board = ReactiveCache.getBoard(list.boardId);
+
+ const board = await ReactiveCache.getBoard(list.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return list.hasMovedFromOriginalPosition();
},
/**
* Check if a card has moved from its original position
*/
- 'positionHistory.hasCardMoved'(cardId) {
+ async 'positionHistory.hasCardMoved'(cardId) {
check(cardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const card = Cards.findOne(cardId);
if (!card) {
throw new Meteor.Error('card-not-found', 'Card not found');
}
-
- const board = ReactiveCache.getBoard(card.boardId);
+
+ const board = await ReactiveCache.getBoard(card.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return card.hasMovedFromOriginalPosition();
},
/**
* Get original position description for a swimlane
*/
- 'positionHistory.getSwimlaneDescription'(swimlaneId) {
+ async 'positionHistory.getSwimlaneDescription'(swimlaneId) {
check(swimlaneId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const swimlane = Swimlanes.findOne(swimlaneId);
if (!swimlane) {
throw new Meteor.Error('swimlane-not-found', 'Swimlane not found');
}
-
- const board = ReactiveCache.getBoard(swimlane.boardId);
+
+ const board = await ReactiveCache.getBoard(swimlane.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return swimlane.getOriginalPositionDescription();
},
/**
* Get original position description for a list
*/
- 'positionHistory.getListDescription'(listId) {
+ async 'positionHistory.getListDescription'(listId) {
check(listId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const list = Lists.findOne(listId);
if (!list) {
throw new Meteor.Error('list-not-found', 'List not found');
}
-
- const board = ReactiveCache.getBoard(list.boardId);
+
+ const board = await ReactiveCache.getBoard(list.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return list.getOriginalPositionDescription();
},
/**
* Get original position description for a card
*/
- 'positionHistory.getCardDescription'(cardId) {
+ async 'positionHistory.getCardDescription'(cardId) {
check(cardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
+
const card = Cards.findOne(cardId);
if (!card) {
throw new Meteor.Error('card-not-found', 'Card not found');
}
-
- const board = ReactiveCache.getBoard(card.boardId);
+
+ const board = await ReactiveCache.getBoard(card.boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return card.getOriginalPositionDescription();
},
/**
* Get all position history for a board
*/
- 'positionHistory.getBoardHistory'(boardId) {
+ async 'positionHistory.getBoardHistory'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
- const board = ReactiveCache.getBoard(boardId);
+
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
return PositionHistory.find({
boardId: boardId,
}, {
@@ -311,23 +311,23 @@ Meteor.methods({
/**
* Get position history by entity type for a board
*/
- 'positionHistory.getBoardHistoryByType'(boardId, entityType) {
+ async 'positionHistory.getBoardHistoryByType'(boardId, entityType) {
check(boardId, String);
check(entityType, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in.');
}
-
- const board = ReactiveCache.getBoard(boardId);
+
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.isVisibleBy({ _id: this.userId })) {
throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
}
-
+
if (!['swimlane', 'list', 'card'].includes(entityType)) {
throw new Meteor.Error('invalid-entity-type', 'Entity type must be swimlane, list, or card');
}
-
+
return PositionHistory.find({
boardId: boardId,
entityType: entityType,
diff --git a/server/migrations/comprehensiveBoardMigration.js b/server/migrations/comprehensiveBoardMigration.js
index 23ecd2f2e..aad2ca7e1 100644
--- a/server/migrations/comprehensiveBoardMigration.js
+++ b/server/migrations/comprehensiveBoardMigration.js
@@ -41,9 +41,9 @@ class ComprehensiveBoardMigration {
/**
* Check if migration is needed for a board
*/
- needsMigration(boardId) {
+ async needsMigration(boardId) {
try {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) return false;
// Check if board has already been processed
@@ -52,7 +52,7 @@ class ComprehensiveBoardMigration {
}
// Check for various issues that need migration
- const issues = this.detectMigrationIssues(boardId);
+ const issues = await this.detectMigrationIssues(boardId);
return issues.length > 0;
} catch (error) {
@@ -64,13 +64,13 @@ class ComprehensiveBoardMigration {
/**
* Detect all migration issues in a board
*/
- detectMigrationIssues(boardId) {
+ async detectMigrationIssues(boardId) {
const issues = [];
-
+
try {
- const cards = ReactiveCache.getCards({ boardId });
- const lists = ReactiveCache.getLists({ boardId });
- const swimlanes = ReactiveCache.getSwimlanes({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const swimlanes = await ReactiveCache.getSwimlanes({ boardId });
// Issue 1: Cards with missing swimlaneId
const cardsWithoutSwimlane = cards.filter(card => !card.swimlaneId);
@@ -157,7 +157,7 @@ class ComprehensiveBoardMigration {
console.log(`Starting comprehensive board migration for board ${boardId}`);
}
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Error(`Board ${boardId} not found`);
}
@@ -288,7 +288,7 @@ class ComprehensiveBoardMigration {
* Step 1: Analyze board structure
*/
async analyzeBoardStructure(boardId) {
- const issues = this.detectMigrationIssues(boardId);
+ const issues = await this.detectMigrationIssues(boardId);
return {
issues,
issueCount: issues.length,
@@ -300,9 +300,9 @@ class ComprehensiveBoardMigration {
* Step 2: Fix orphaned cards (cards with missing swimlaneId or listId)
*/
async fixOrphanedCards(boardId, progressCallback = null) {
- const cards = ReactiveCache.getCards({ boardId });
- const swimlanes = ReactiveCache.getSwimlanes({ boardId });
- const lists = ReactiveCache.getLists({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
+ const swimlanes = await ReactiveCache.getSwimlanes({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
let cardsFixed = 0;
const defaultSwimlane = swimlanes.find(s => s.title === 'Default') || swimlanes[0];
@@ -370,9 +370,9 @@ class ComprehensiveBoardMigration {
* Step 3: Convert shared lists to per-swimlane lists
*/
async convertSharedListsToPerSwimlane(boardId, progressCallback = null) {
- const cards = ReactiveCache.getCards({ boardId });
- const lists = ReactiveCache.getLists({ boardId });
- const swimlanes = ReactiveCache.getSwimlanes({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const swimlanes = await ReactiveCache.getSwimlanes({ boardId });
let listsProcessed = 0;
let listsCreated = 0;
@@ -475,8 +475,8 @@ class ComprehensiveBoardMigration {
* Step 4: Ensure all lists are per-swimlane
*/
async ensurePerSwimlaneLists(boardId) {
- const lists = ReactiveCache.getLists({ boardId });
- const swimlanes = ReactiveCache.getSwimlanes({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const swimlanes = await ReactiveCache.getSwimlanes({ boardId });
const defaultSwimlane = swimlanes.find(s => s.title === 'Default') || swimlanes[0];
let listsProcessed = 0;
@@ -501,8 +501,8 @@ class ComprehensiveBoardMigration {
* Step 5: Cleanup empty lists (lists with no cards)
*/
async cleanupEmptyLists(boardId) {
- const lists = ReactiveCache.getLists({ boardId });
- const cards = ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
let listsRemoved = 0;
@@ -527,9 +527,9 @@ class ComprehensiveBoardMigration {
* Step 6: Validate migration
*/
async validateMigration(boardId) {
- const issues = this.detectMigrationIssues(boardId);
- const cards = ReactiveCache.getCards({ boardId });
- const lists = ReactiveCache.getLists({ boardId });
+ const issues = await this.detectMigrationIssues(boardId);
+ const cards = await ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
// Check that all cards have valid swimlaneId and listId
const validCards = cards.filter(card => card.swimlaneId && card.listId);
@@ -555,7 +555,7 @@ class ComprehensiveBoardMigration {
* Step 7: Fix avatar URLs (remove problematic auth parameters and fix URL formats)
*/
async fixAvatarUrls() {
- const users = ReactiveCache.getUsers({});
+ const users = await ReactiveCache.getUsers({});
let avatarsFixed = 0;
for (const user of users) {
@@ -610,7 +610,7 @@ class ComprehensiveBoardMigration {
* Step 8: Fix attachment URLs (remove problematic auth parameters and fix URL formats)
*/
async fixAttachmentUrls() {
- const attachments = ReactiveCache.getAttachments({});
+ const attachments = await ReactiveCache.getAttachments({});
let attachmentsFixed = 0;
for (const attachment of attachments) {
@@ -669,24 +669,24 @@ class ComprehensiveBoardMigration {
/**
* Get migration status for a board
*/
- getMigrationStatus(boardId) {
+ async getMigrationStatus(boardId) {
try {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
return { status: 'board_not_found' };
}
if (board.comprehensiveMigrationCompleted) {
- return {
+ return {
status: 'completed',
completedAt: board.comprehensiveMigrationCompletedAt,
results: board.comprehensiveMigrationResults
};
}
- const needsMigration = this.needsMigration(boardId);
- const issues = this.detectMigrationIssues(boardId);
-
+ const needsMigration = await this.needsMigration(boardId);
+ const issues = await this.detectMigrationIssues(boardId);
+
return {
status: needsMigration ? 'needed' : 'not_needed',
issues,
@@ -705,82 +705,82 @@ export const comprehensiveBoardMigration = new ComprehensiveBoardMigration();
// Meteor methods
Meteor.methods({
- 'comprehensiveBoardMigration.check'(boardId) {
+ async 'comprehensiveBoardMigration.check'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- return comprehensiveBoardMigration.getMigrationStatus(boardId);
+
+ return await comprehensiveBoardMigration.getMigrationStatus(boardId);
},
- 'comprehensiveBoardMigration.execute'(boardId) {
+ async 'comprehensiveBoardMigration.execute'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- const user = ReactiveCache.getUser(this.userId);
- const board = ReactiveCache.getBoard(boardId);
+
+ const user = await ReactiveCache.getUser(this.userId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found');
}
-
+
const isBoardAdmin = board.hasAdmin(this.userId);
const isInstanceAdmin = user && user.isAdmin;
-
+
if (!isBoardAdmin && !isInstanceAdmin) {
throw new Meteor.Error('not-authorized', 'You must be a board admin or instance admin to perform this action.');
}
-
- return comprehensiveBoardMigration.executeMigration(boardId);
+
+ return await comprehensiveBoardMigration.executeMigration(boardId);
},
- 'comprehensiveBoardMigration.needsMigration'(boardId) {
+ async 'comprehensiveBoardMigration.needsMigration'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- return comprehensiveBoardMigration.needsMigration(boardId);
+
+ return await comprehensiveBoardMigration.needsMigration(boardId);
},
- 'comprehensiveBoardMigration.detectIssues'(boardId) {
+ async 'comprehensiveBoardMigration.detectIssues'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- return comprehensiveBoardMigration.detectMigrationIssues(boardId);
+
+ return await comprehensiveBoardMigration.detectMigrationIssues(boardId);
},
- 'comprehensiveBoardMigration.fixAvatarUrls'() {
+ async 'comprehensiveBoardMigration.fixAvatarUrls'() {
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- const user = ReactiveCache.getUser(this.userId);
+
+ const user = await ReactiveCache.getUser(this.userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Only instance admins can perform this action.');
}
-
- return comprehensiveBoardMigration.fixAvatarUrls();
+
+ return await comprehensiveBoardMigration.fixAvatarUrls();
},
- 'comprehensiveBoardMigration.fixAttachmentUrls'() {
+ async 'comprehensiveBoardMigration.fixAttachmentUrls'() {
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- const user = ReactiveCache.getUser(this.userId);
+
+ const user = await ReactiveCache.getUser(this.userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Only instance admins can perform this action.');
}
-
- return comprehensiveBoardMigration.fixAttachmentUrls();
+
+ return await comprehensiveBoardMigration.fixAttachmentUrls();
}
});
diff --git a/server/migrations/deleteDuplicateEmptyLists.js b/server/migrations/deleteDuplicateEmptyLists.js
index dadbd5391..f0eff66bf 100644
--- a/server/migrations/deleteDuplicateEmptyLists.js
+++ b/server/migrations/deleteDuplicateEmptyLists.js
@@ -26,10 +26,10 @@ class DeleteDuplicateEmptyListsMigration {
/**
* Check if migration is needed for a board
*/
- needsMigration(boardId) {
+ async needsMigration(boardId) {
try {
- const lists = ReactiveCache.getLists({ boardId });
- const cards = ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
// Check if there are any empty lists that have a duplicate with the same title containing cards
for (const list of lists) {
@@ -104,9 +104,9 @@ class DeleteDuplicateEmptyListsMigration {
* Convert shared lists (lists without swimlaneId) to per-swimlane lists
*/
async convertSharedListsToPerSwimlane(boardId) {
- const lists = ReactiveCache.getLists({ boardId });
- const swimlanes = ReactiveCache.getSwimlanes({ boardId, archived: false });
- const cards = ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const swimlanes = await ReactiveCache.getSwimlanes({ boardId, archived: false });
+ const cards = await ReactiveCache.getCards({ boardId });
let listsConverted = 0;
@@ -206,8 +206,8 @@ class DeleteDuplicateEmptyListsMigration {
* 3. Have a duplicate list with the same title on the same board that contains cards
*/
async deleteEmptyPerSwimlaneLists(boardId) {
- const lists = ReactiveCache.getLists({ boardId });
- const cards = ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
let listsDeleted = 0;
@@ -268,8 +268,8 @@ class DeleteDuplicateEmptyListsMigration {
* Get detailed status of empty lists
*/
async getStatus(boardId) {
- const lists = ReactiveCache.getLists({ boardId });
- const cards = ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
const sharedLists = [];
const emptyPerSwimlaneLists = [];
@@ -319,30 +319,30 @@ const deleteDuplicateEmptyListsMigration = new DeleteDuplicateEmptyListsMigratio
// Register Meteor methods
Meteor.methods({
- 'deleteDuplicateEmptyLists.needsMigration'(boardId) {
+ async 'deleteDuplicateEmptyLists.needsMigration'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
- return deleteDuplicateEmptyListsMigration.needsMigration(boardId);
+ return await deleteDuplicateEmptyListsMigration.needsMigration(boardId);
},
- 'deleteDuplicateEmptyLists.execute'(boardId) {
+ async 'deleteDuplicateEmptyLists.execute'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
// Check if user is board admin
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found');
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user) {
throw new Meteor.Error('user-not-found', 'User not found');
}
@@ -356,17 +356,17 @@ Meteor.methods({
throw new Meteor.Error('not-authorized', 'Only board administrators can run migrations');
}
- return deleteDuplicateEmptyListsMigration.executeMigration(boardId);
+ return await deleteDuplicateEmptyListsMigration.executeMigration(boardId);
},
- 'deleteDuplicateEmptyLists.getStatus'(boardId) {
+ async 'deleteDuplicateEmptyLists.getStatus'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
- return deleteDuplicateEmptyListsMigration.getStatus(boardId);
+ return await deleteDuplicateEmptyListsMigration.getStatus(boardId);
}
});
diff --git a/server/migrations/fixAllFileUrls.js b/server/migrations/fixAllFileUrls.js
index f713ac8ae..f1b3d77db 100644
--- a/server/migrations/fixAllFileUrls.js
+++ b/server/migrations/fixAllFileUrls.js
@@ -22,17 +22,17 @@ class FixAllFileUrlsMigration {
/**
* Check if migration is needed for a board
*/
- needsMigration(boardId) {
+ async needsMigration(boardId) {
// Get all users who are members of this board
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.members) {
return false;
}
-
+
const memberIds = board.members.map(m => m.userId);
-
+
// Check for problematic avatar URLs for board members
- const users = ReactiveCache.getUsers({ _id: { $in: memberIds } });
+ const users = await ReactiveCache.getUsers({ _id: { $in: memberIds } });
for (const user of users) {
if (user.profile && user.profile.avatarUrl) {
const avatarUrl = user.profile.avatarUrl;
@@ -43,9 +43,9 @@ class FixAllFileUrlsMigration {
}
// Check for problematic attachment URLs on this board
- const cards = ReactiveCache.getCards({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
const cardIds = cards.map(c => c._id);
- const attachments = ReactiveCache.getAttachments({ cardId: { $in: cardIds } });
+ const attachments = await ReactiveCache.getAttachments({ cardId: { $in: cardIds } });
for (const attachment of attachments) {
if (attachment.url && this.hasProblematicUrl(attachment.url)) {
@@ -133,13 +133,13 @@ class FixAllFileUrlsMigration {
* Fix avatar URLs in user profiles for board members
*/
async fixAvatarUrls(boardId) {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.members) {
return 0;
}
-
+
const memberIds = board.members.map(m => m.userId);
- const users = ReactiveCache.getUsers({ _id: { $in: memberIds } });
+ const users = await ReactiveCache.getUsers({ _id: { $in: memberIds } });
let avatarsFixed = 0;
for (const user of users) {
@@ -189,9 +189,9 @@ class FixAllFileUrlsMigration {
* Fix attachment URLs in attachment records for this board
*/
async fixAttachmentUrls(boardId) {
- const cards = ReactiveCache.getCards({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
const cardIds = cards.map(c => c._id);
- const attachments = ReactiveCache.getAttachments({ cardId: { $in: cardIds } });
+ const attachments = await ReactiveCache.getAttachments({ cardId: { $in: cardIds } });
let attachmentsFixed = 0;
for (const attachment of attachments) {
@@ -229,9 +229,9 @@ class FixAllFileUrlsMigration {
* Fix attachment URLs in the Attachments collection for this board
*/
async fixCardAttachmentUrls(boardId) {
- const cards = ReactiveCache.getCards({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
const cardIds = cards.map(c => c._id);
- const attachments = ReactiveCache.getAttachments({ cardId: { $in: cardIds } });
+ const attachments = await ReactiveCache.getAttachments({ cardId: { $in: cardIds } });
let attachmentsFixed = 0;
for (const attachment of attachments) {
@@ -270,20 +270,20 @@ export const fixAllFileUrlsMigration = new FixAllFileUrlsMigration();
// Meteor methods
Meteor.methods({
- 'fixAllFileUrls.execute'(boardId) {
+ async 'fixAllFileUrls.execute'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
// Check if user is board admin
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found');
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user) {
throw new Meteor.Error('user-not-found', 'User not found');
}
@@ -296,17 +296,17 @@ Meteor.methods({
if (!isBoardAdmin && !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Only board administrators can run migrations');
}
-
- return fixAllFileUrlsMigration.execute(boardId);
+
+ return await fixAllFileUrlsMigration.execute(boardId);
},
- 'fixAllFileUrls.needsMigration'(boardId) {
+ async 'fixAllFileUrls.needsMigration'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
-
- return fixAllFileUrlsMigration.needsMigration(boardId);
+
+ return await fixAllFileUrlsMigration.needsMigration(boardId);
}
});
diff --git a/server/migrations/fixAvatarUrls.js b/server/migrations/fixAvatarUrls.js
index 82677eb48..0b6c27f7b 100644
--- a/server/migrations/fixAvatarUrls.js
+++ b/server/migrations/fixAvatarUrls.js
@@ -19,15 +19,15 @@ class FixAvatarUrlsMigration {
/**
* Check if migration is needed for a board
*/
- needsMigration(boardId) {
+ async needsMigration(boardId) {
// Get all users who are members of this board
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.members) {
return false;
}
-
+
const memberIds = board.members.map(m => m.userId);
- const users = ReactiveCache.getUsers({ _id: { $in: memberIds } });
+ const users = await ReactiveCache.getUsers({ _id: { $in: memberIds } });
for (const user of users) {
if (user.profile && user.profile.avatarUrl) {
@@ -46,16 +46,16 @@ class FixAvatarUrlsMigration {
*/
async execute(boardId) {
// Get all users who are members of this board
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.members) {
return {
success: false,
error: 'Board not found or has no members'
};
}
-
+
const memberIds = board.members.map(m => m.userId);
- const users = ReactiveCache.getUsers({ _id: { $in: memberIds } });
+ const users = await ReactiveCache.getUsers({ _id: { $in: memberIds } });
let avatarsFixed = 0;
console.log(`Starting avatar URL fix migration for board ${boardId}...`);
@@ -131,20 +131,20 @@ export const fixAvatarUrlsMigration = new FixAvatarUrlsMigration();
// Meteor method
Meteor.methods({
- 'fixAvatarUrls.execute'(boardId) {
+ async 'fixAvatarUrls.execute'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
// Check if user is board admin
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found');
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user) {
throw new Meteor.Error('user-not-found', 'User not found');
}
@@ -157,17 +157,17 @@ Meteor.methods({
if (!isBoardAdmin && !user.isAdmin) {
throw new Meteor.Error('not-authorized', 'Only board administrators can run migrations');
}
-
- return fixAvatarUrlsMigration.execute(boardId);
+
+ return await fixAvatarUrlsMigration.execute(boardId);
},
- 'fixAvatarUrls.needsMigration'(boardId) {
+ async 'fixAvatarUrls.needsMigration'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
-
- return fixAvatarUrlsMigration.needsMigration(boardId);
+
+ return await fixAvatarUrlsMigration.needsMigration(boardId);
}
});
diff --git a/server/migrations/fixMissingListsMigration.js b/server/migrations/fixMissingListsMigration.js
index 22e5b16de..05de463d6 100644
--- a/server/migrations/fixMissingListsMigration.js
+++ b/server/migrations/fixMissingListsMigration.js
@@ -31,9 +31,9 @@ class FixMissingListsMigration {
/**
* Check if migration is needed for a board
*/
- needsMigration(boardId) {
+ async needsMigration(boardId) {
try {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) return false;
// Check if board has already been processed
@@ -42,8 +42,8 @@ class FixMissingListsMigration {
}
// Check if there are cards with mismatched listId/swimlaneId
- const cards = ReactiveCache.getCards({ boardId });
- const lists = ReactiveCache.getLists({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
// Create a map of listId -> swimlaneId for existing lists
const listSwimlaneMap = new Map();
@@ -77,15 +77,15 @@ class FixMissingListsMigration {
if (process.env.DEBUG === 'true') {
console.log(`Starting fix missing lists migration for board ${boardId}`);
}
-
- const board = ReactiveCache.getBoard(boardId);
+
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Error(`Board ${boardId} not found`);
}
- const cards = ReactiveCache.getCards({ boardId });
- const lists = ReactiveCache.getLists({ boardId });
- const swimlanes = ReactiveCache.getSwimlanes({ boardId });
+ const cards = await ReactiveCache.getCards({ boardId });
+ const lists = await ReactiveCache.getLists({ boardId });
+ const swimlanes = await ReactiveCache.getSwimlanes({ boardId });
// Create maps for efficient lookup
const listSwimlaneMap = new Map();
@@ -214,21 +214,21 @@ class FixMissingListsMigration {
/**
* Get migration status for a board
*/
- getMigrationStatus(boardId) {
+ async getMigrationStatus(boardId) {
try {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
return { status: 'board_not_found' };
}
if (board.fixMissingListsCompleted) {
- return {
+ return {
status: 'completed',
completedAt: board.fixMissingListsCompletedAt
};
}
- const needsMigration = this.needsMigration(boardId);
+ const needsMigration = await this.needsMigration(boardId);
return {
status: needsMigration ? 'needed' : 'not_needed'
};
@@ -245,33 +245,33 @@ export const fixMissingListsMigration = new FixMissingListsMigration();
// Meteor methods
Meteor.methods({
- 'fixMissingListsMigration.check'(boardId) {
+ async 'fixMissingListsMigration.check'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- return fixMissingListsMigration.getMigrationStatus(boardId);
+
+ return await fixMissingListsMigration.getMigrationStatus(boardId);
},
- 'fixMissingListsMigration.execute'(boardId) {
+ async 'fixMissingListsMigration.execute'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- return fixMissingListsMigration.executeMigration(boardId);
+
+ return await fixMissingListsMigration.executeMigration(boardId);
},
- 'fixMissingListsMigration.needsMigration'(boardId) {
+ async 'fixMissingListsMigration.needsMigration'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
-
- return fixMissingListsMigration.needsMigration(boardId);
+
+ return await fixMissingListsMigration.needsMigration(boardId);
}
});
diff --git a/server/migrations/migrateAttachments.js b/server/migrations/migrateAttachments.js
index 55ffdb0c7..5ff8dcce5 100644
--- a/server/migrations/migrateAttachments.js
+++ b/server/migrations/migrateAttachments.js
@@ -14,7 +14,7 @@ if (Meteor.isServer) {
* @param {string} attachmentId - The old attachment ID
* @returns {Object} - Migration result
*/
- migrateAttachment(attachmentId) {
+ async migrateAttachment(attachmentId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
@@ -27,7 +27,7 @@ if (Meteor.isServer) {
}
// Check if already migrated
- const existingAttachment = ReactiveCache.getAttachment(attachmentId);
+ const existingAttachment = await ReactiveCache.getAttachment(attachmentId);
if (existingAttachment) {
return { success: true, message: 'Already migrated', attachmentId };
}
@@ -72,7 +72,7 @@ if (Meteor.isServer) {
* @param {string} cardId - The card ID
* @returns {Object} - Migration results
*/
- migrateCardAttachments(cardId) {
+ async migrateCardAttachments(cardId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
@@ -85,7 +85,7 @@ if (Meteor.isServer) {
try {
// Get all old attachments for this card
- const oldAttachments = ReactiveCache.getAttachments({ 'meta.cardId': cardId });
+ const oldAttachments = await ReactiveCache.getAttachments({ 'meta.cardId': cardId });
for (const attachment of oldAttachments) {
const result = Meteor.call('migrateAttachment', attachment._id);
@@ -113,14 +113,14 @@ if (Meteor.isServer) {
* @param {string} cardId - The card ID (optional)
* @returns {Object} - Migration status
*/
- getAttachmentMigrationStatus(cardId) {
+ async getAttachmentMigrationStatus(cardId) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
try {
const selector = cardId ? { 'meta.cardId': cardId } : {};
- const allAttachments = ReactiveCache.getAttachments(selector);
+ const allAttachments = await ReactiveCache.getAttachments(selector);
const status = {
total: allAttachments.length,
diff --git a/server/migrations/restoreAllArchived.js b/server/migrations/restoreAllArchived.js
index 825f9a2f4..92f9b41fe 100644
--- a/server/migrations/restoreAllArchived.js
+++ b/server/migrations/restoreAllArchived.js
@@ -24,11 +24,11 @@ class RestoreAllArchivedMigration {
/**
* Check if migration is needed for a board
*/
- needsMigration(boardId) {
+ async needsMigration(boardId) {
try {
- const archivedSwimlanes = ReactiveCache.getSwimlanes({ boardId, archived: true });
- const archivedLists = ReactiveCache.getLists({ boardId, archived: true });
- const archivedCards = ReactiveCache.getCards({ boardId, archived: true });
+ const archivedSwimlanes = await ReactiveCache.getSwimlanes({ boardId, archived: true });
+ const archivedLists = await ReactiveCache.getLists({ boardId, archived: true });
+ const archivedCards = await ReactiveCache.getCards({ boardId, archived: true });
return archivedSwimlanes.length > 0 || archivedLists.length > 0 || archivedCards.length > 0;
} catch (error) {
@@ -50,19 +50,19 @@ class RestoreAllArchivedMigration {
errors: []
};
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Error('Board not found');
}
// Get archived items
- const archivedSwimlanes = ReactiveCache.getSwimlanes({ boardId, archived: true });
- const archivedLists = ReactiveCache.getLists({ boardId, archived: true });
- const archivedCards = ReactiveCache.getCards({ boardId, archived: true });
+ const archivedSwimlanes = await ReactiveCache.getSwimlanes({ boardId, archived: true });
+ const archivedLists = await ReactiveCache.getLists({ boardId, archived: true });
+ const archivedCards = await ReactiveCache.getCards({ boardId, archived: true });
// Get active items for reference
- const activeSwimlanes = ReactiveCache.getSwimlanes({ boardId, archived: false });
- const activeLists = ReactiveCache.getLists({ boardId, archived: false });
+ const activeSwimlanes = await ReactiveCache.getSwimlanes({ boardId, archived: false });
+ const activeLists = await ReactiveCache.getLists({ boardId, archived: false });
// Restore all archived swimlanes
for (const swimlane of archivedSwimlanes) {
@@ -101,7 +101,7 @@ class RestoreAllArchivedMigration {
updatedAt: new Date(),
archived: false
});
- targetSwimlane = ReactiveCache.getSwimlane(swimlaneId);
+ targetSwimlane = await ReactiveCache.getSwimlane(swimlaneId);
}
updateFields.swimlaneId = targetSwimlane._id;
@@ -123,8 +123,8 @@ class RestoreAllArchivedMigration {
}
// Refresh lists after restoration
- const allLists = ReactiveCache.getLists({ boardId, archived: false });
- const allSwimlanes = ReactiveCache.getSwimlanes({ boardId, archived: false });
+ const allLists = await ReactiveCache.getLists({ boardId, archived: false });
+ const allSwimlanes = await ReactiveCache.getSwimlanes({ boardId, archived: false });
// Restore all archived cards and fix missing IDs
for (const card of archivedCards) {
@@ -153,7 +153,7 @@ class RestoreAllArchivedMigration {
updatedAt: new Date(),
archived: false
});
- targetList = ReactiveCache.getList(listId);
+ targetList = await ReactiveCache.getList(listId);
}
updateFields.listId = targetList._id;
@@ -222,30 +222,30 @@ const restoreAllArchivedMigration = new RestoreAllArchivedMigration();
// Register Meteor methods
Meteor.methods({
- 'restoreAllArchived.needsMigration'(boardId) {
+ async 'restoreAllArchived.needsMigration'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
- return restoreAllArchivedMigration.needsMigration(boardId);
+ return await restoreAllArchivedMigration.needsMigration(boardId);
},
- 'restoreAllArchived.execute'(boardId) {
+ async 'restoreAllArchived.execute'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
// Check if user is board admin
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found');
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user) {
throw new Meteor.Error('user-not-found', 'User not found');
}
@@ -259,7 +259,7 @@ Meteor.methods({
throw new Meteor.Error('not-authorized', 'Only board administrators can run migrations');
}
- return restoreAllArchivedMigration.executeMigration(boardId);
+ return await restoreAllArchivedMigration.executeMigration(boardId);
}
});
diff --git a/server/migrations/restoreLostCards.js b/server/migrations/restoreLostCards.js
index 781caa0fb..a844f2866 100644
--- a/server/migrations/restoreLostCards.js
+++ b/server/migrations/restoreLostCards.js
@@ -24,10 +24,10 @@ class RestoreLostCardsMigration {
/**
* Check if migration is needed for a board
*/
- needsMigration(boardId) {
+ async needsMigration(boardId) {
try {
- const cards = ReactiveCache.getCards({ boardId, archived: false });
- const lists = ReactiveCache.getLists({ boardId, archived: false });
+ const cards = await ReactiveCache.getCards({ boardId, archived: false });
+ const lists = await ReactiveCache.getLists({ boardId, archived: false });
// Check for cards missing swimlaneId or listId
const lostCards = cards.filter(card => !card.swimlaneId || !card.listId);
@@ -70,15 +70,15 @@ class RestoreLostCardsMigration {
errors: []
};
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Error('Board not found');
}
// Get all non-archived items
- const cards = ReactiveCache.getCards({ boardId, archived: false });
- const lists = ReactiveCache.getLists({ boardId, archived: false });
- const swimlanes = ReactiveCache.getSwimlanes({ boardId, archived: false });
+ const cards = await ReactiveCache.getCards({ boardId, archived: false });
+ const lists = await ReactiveCache.getLists({ boardId, archived: false });
+ const swimlanes = await ReactiveCache.getSwimlanes({ boardId, archived: false });
// Detect items to restore BEFORE creating anything
const lostLists = lists.filter(list => !list.swimlaneId);
@@ -116,7 +116,7 @@ class RestoreLostCardsMigration {
updatedAt: new Date(),
archived: false
});
- lostCardsSwimlane = ReactiveCache.getSwimlane(swimlaneId);
+ lostCardsSwimlane = await ReactiveCache.getSwimlane(swimlaneId);
results.lostCardsSwimlaneCreated = true;
if (process.env.DEBUG === 'true') {
console.log(`Created "Lost Cards" swimlane for board ${boardId}`);
@@ -156,7 +156,7 @@ class RestoreLostCardsMigration {
updatedAt: new Date(),
archived: false
});
- defaultList = ReactiveCache.getList(listId);
+ defaultList = await ReactiveCache.getList(listId);
if (process.env.DEBUG === 'true') {
console.log(`Created default list in Lost Cards swimlane`);
}
@@ -215,30 +215,30 @@ const restoreLostCardsMigration = new RestoreLostCardsMigration();
// Register Meteor methods
Meteor.methods({
- 'restoreLostCards.needsMigration'(boardId) {
+ async 'restoreLostCards.needsMigration'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
- return restoreLostCardsMigration.needsMigration(boardId);
+ return await restoreLostCardsMigration.needsMigration(boardId);
},
- 'restoreLostCards.execute'(boardId) {
+ async 'restoreLostCards.execute'(boardId) {
check(boardId, String);
-
+
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'You must be logged in');
}
// Check if user is board admin
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
throw new Meteor.Error('board-not-found', 'Board not found');
}
- const user = ReactiveCache.getUser(this.userId);
+ const user = await ReactiveCache.getUser(this.userId);
if (!user) {
throw new Meteor.Error('user-not-found', 'User not found');
}
@@ -252,7 +252,7 @@ Meteor.methods({
throw new Meteor.Error('not-authorized', 'Only board administrators can run migrations');
}
- return restoreLostCardsMigration.executeMigration(boardId);
+ return await restoreLostCardsMigration.executeMigration(boardId);
}
});
diff --git a/server/notifications/email.js b/server/notifications/email.js
index 7b1bf9a42..3b9706402 100644
--- a/server/notifications/email.js
+++ b/server/notifications/email.js
@@ -33,8 +33,8 @@ Meteor.startup(() => {
// Meteor.setTimeout(func, delay) does not accept args :-(
// so we pass userId with closure
const userId = user._id;
- Meteor.setTimeout(() => {
- const user = ReactiveCache.getUser(userId);
+ Meteor.setTimeout(async () => {
+ const user = await ReactiveCache.getUser(userId);
// for each user, in the timed period, only the first call will get the cached content,
// other calls will get nothing
diff --git a/server/notifications/notifications.js b/server/notifications/notifications.js
index 0d9b5259b..000603560 100644
--- a/server/notifications/notifications.js
+++ b/server/notifications/notifications.js
@@ -19,12 +19,12 @@ Notifications = {
delete notifyServices[serviceName];
},
- getUsers: watchers => {
+ getUsers: async watchers => {
const users = [];
- watchers.forEach(userId => {
- const user = ReactiveCache.getUser(userId);
+ for (const userId of watchers) {
+ const user = await ReactiveCache.getUser(userId);
if (user && user._id) users.push(user);
- });
+ }
return users;
},
diff --git a/server/notifications/outgoing.js b/server/notifications/outgoing.js
index ff5123946..1703b1ead 100644
--- a/server/notifications/outgoing.js
+++ b/server/notifications/outgoing.js
@@ -70,20 +70,20 @@ if (Meteor.isServer) {
'label',
'attachmentId',
];
- const responseFunc = data => {
+ const responseFunc = async data => {
const paramCommentId = data.commentId;
const paramCardId = data.cardId;
const paramBoardId = data.boardId;
const newComment = data.comment;
if (paramCardId && paramBoardId && newComment) {
// only process data with the cardid, boardid and comment text, TODO can expand other functions here to react on returned data
- const comment = ReactiveCache.getCardComment({
+ const comment = await ReactiveCache.getCardComment({
_id: paramCommentId,
cardId: paramCardId,
boardId: paramBoardId,
});
- const board = ReactiveCache.getBoard(paramBoardId);
- const card = ReactiveCache.getCard(paramCardId);
+ const board = await ReactiveCache.getBoard(paramBoardId);
+ const card = await ReactiveCache.getCard(paramCardId);
if (board && card) {
if (comment) {
Lock.set(comment._id, newComment);
@@ -108,8 +108,8 @@ if (Meteor.isServer) {
}
};
Meteor.methods({
- outgoingWebhooks(integration, description, params) {
- if (ReactiveCache.getCurrentUser()) {
+ async outgoingWebhooks(integration, description, params) {
+ if (await ReactiveCache.getCurrentUser()) {
check(integration, Object);
check(description, String);
check(params, Object);
@@ -137,7 +137,7 @@ if (Meteor.isServer) {
});
const userId = params.userId ? params.userId : integrations[0].userId;
- const user = ReactiveCache.getUser(userId);
+ const user = await ReactiveCache.getUser(userId);
const descriptionText = TAPi18n.__(
description,
quoteParams,
@@ -171,7 +171,7 @@ if (Meteor.isServer) {
data: is2way ? { description, ...clonedParams } : value,
};
- if (!ReactiveCache.getIntegration({ url: integration.url })) return;
+ if (!(await ReactiveCache.getIntegration({ url: integration.url }))) return;
const url = integration.url;
@@ -198,7 +198,7 @@ if (Meteor.isServer) {
const data = response.data; // only an JSON encoded response will be actioned
if (data) {
try {
- responseFunc(data);
+ await responseFunc(data);
} catch (e) {
throw new Meteor.Error('error-process-data');
}
diff --git a/server/notifications/watch.js b/server/notifications/watch.js
index 3b4907220..cb9cf5029 100644
--- a/server/notifications/watch.js
+++ b/server/notifications/watch.js
@@ -11,17 +11,17 @@ Meteor.methods({
let watchableObj = null;
let board = null;
if (watchableType === 'board') {
- watchableObj = ReactiveCache.getBoard(id);
+ watchableObj = await ReactiveCache.getBoard(id);
if (!watchableObj) throw new Meteor.Error('error-board-doesNotExist');
board = watchableObj;
} else if (watchableType === 'list') {
- watchableObj = ReactiveCache.getList(id);
+ watchableObj = await ReactiveCache.getList(id);
if (!watchableObj) throw new Meteor.Error('error-list-doesNotExist');
- board = watchableObj.board();
+ board = await watchableObj.board();
} else if (watchableType === 'card') {
- watchableObj = ReactiveCache.getCard(id);
+ watchableObj = await ReactiveCache.getCard(id);
if (!watchableObj) throw new Meteor.Error('error-card-doesNotExist');
- board = watchableObj.board();
+ board = await watchableObj.board();
} else {
throw new Meteor.Error('error-json-schema');
}
diff --git a/server/publications/activities.js b/server/publications/activities.js
index 8c3e17d69..65a931631 100644
--- a/server/publications/activities.js
+++ b/server/publications/activities.js
@@ -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 },
diff --git a/server/publications/attachments.js b/server/publications/attachments.js
index d618012f8..a25c82487 100644
--- a/server/publications/attachments.js
+++ b/server/publications/attachments.js
@@ -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;
});
diff --git a/server/publications/avatars.js b/server/publications/avatars.js
index 47f9f0bdd..d7ca862f4 100644
--- a/server/publications/avatars.js
+++ b/server/publications/avatars.js
@@ -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;
});
diff --git a/server/publications/boards.js b/server/publications/boards.js
index c070949ba..a202bf67d 100644
--- a/server/publications/boards.js
+++ b/server/publications/boards.js
@@ -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];
diff --git a/server/publications/cards.js b/server/publications/cards.js
index e9d8fcf6e..b5c576936 100644
--- a/server/publications/cards.js
+++ b/server/publications/cards.js
@@ -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,
];
}
diff --git a/server/publications/notifications.js b/server/publications/notifications.js
index 1d9db198e..bc6998a4c 100644
--- a/server/publications/notifications.js
+++ b/server/publications/notifications.js
@@ -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 },
},
diff --git a/server/publications/org.js b/server/publications/org.js
index adf7f33d0..e7569a396 100644
--- a/server/publications/org.js
+++ b/server/publications/org.js
@@ -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 },
diff --git a/server/publications/people.js b/server/publications/people.js
index 7135cb820..57602757f 100644
--- a/server/publications/people.js
+++ b/server/publications/people.js
@@ -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: {
diff --git a/server/publications/rules.js b/server/publications/rules.js
index 45d949e7b..78c2f5896 100644
--- a/server/publications/rules.js
+++ b/server/publications/rules.js
@@ -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;
});
diff --git a/server/publications/settings.js b/server/publications/settings.js
index e2365d523..6a06f5b7a 100644
--- a/server/publications/settings.js
+++ b/server/publications/settings.js
@@ -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) {
diff --git a/server/publications/swimlanes.js b/server/publications/swimlanes.js
index fec6958c0..dc8f295bf 100644
--- a/server/publications/swimlanes.js
+++ b/server/publications/swimlanes.js
@@ -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) {
diff --git a/server/publications/team.js b/server/publications/team.js
index 37a161793..6a8437c02 100644
--- a/server/publications/team.js
+++ b/server/publications/team.js
@@ -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 },
diff --git a/server/publications/translation.js b/server/publications/translation.js
index 2868329f0..09b79fb5d 100644
--- a/server/publications/translation.js
+++ b/server/publications/translation.js
@@ -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 },
diff --git a/server/publications/users.js b/server/publications/users.js
index 4730a3d35..f929c5db1 100644
--- a/server/publications/users.js
+++ b/server/publications/users.js
@@ -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 },
diff --git a/server/routes/attachmentApi.js b/server/routes/attachmentApi.js
index 490c54f7f..568b930ea 100644
--- a/server/routes/attachmentApi.js
+++ b/server/routes/attachmentApi.js
@@ -48,7 +48,7 @@ if (Meteor.isServer) {
}
// Upload attachment endpoint
- WebApp.connectHandlers.use('/api/attachment/upload', (req, res, next) => {
+ WebApp.connectHandlers.use('/api/attachment/upload', async (req, res, next) => {
if (req.method !== 'POST') {
return next();
}
@@ -75,11 +75,11 @@ if (Meteor.isServer) {
}
});
- req.on('end', () => {
+ req.on('end', async () => {
if (bodyComplete) return; // Already processed
bodyComplete = true;
clearTimeout(timeout);
-
+
try {
const data = JSON.parse(body);
const { boardId, swimlaneId, listId, cardId, fileData, fileName, fileType, storageBackend } = data;
@@ -90,12 +90,12 @@ if (Meteor.isServer) {
}
// Check if user has permission to modify the card
- const card = ReactiveCache.getCard(cardId);
+ const card = await ReactiveCache.getCard(cardId);
if (!card) {
return sendErrorResponse(res, 404, 'Card not found');
}
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board) {
return sendErrorResponse(res, 404, 'Board not found');
}
@@ -207,7 +207,7 @@ if (Meteor.isServer) {
});
// Download attachment endpoint
- WebApp.connectHandlers.use('/api/attachment/download/([^/]+)', (req, res, next) => {
+ WebApp.connectHandlers.use('/api/attachment/download/([^/]+)', async (req, res, next) => {
if (req.method !== 'GET') {
return next();
}
@@ -217,13 +217,13 @@ if (Meteor.isServer) {
const attachmentId = req.params[0];
// Get attachment
- const attachment = ReactiveCache.getAttachment(attachmentId);
+ const attachment = await ReactiveCache.getAttachment(attachmentId);
if (!attachment) {
return sendErrorResponse(res, 404, 'Attachment not found');
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board || !board.isBoardMember(userId)) {
return sendErrorResponse(res, 403, 'You do not have permission to access this attachment');
}
@@ -267,7 +267,7 @@ if (Meteor.isServer) {
});
// List attachments endpoint
- WebApp.connectHandlers.use('/api/attachment/list/([^/]+)/([^/]+)/([^/]+)/([^/]+)', (req, res, next) => {
+ WebApp.connectHandlers.use('/api/attachment/list/([^/]+)/([^/]+)/([^/]+)/([^/]+)', async (req, res, next) => {
if (req.method !== 'GET') {
return next();
}
@@ -280,14 +280,14 @@ if (Meteor.isServer) {
const cardId = req.params[3];
// Check permissions
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (!board || !board.isBoardMember(userId)) {
return sendErrorResponse(res, 403, 'You do not have permission to access this board');
}
// If cardId is provided, verify it belongs to the board
if (cardId && cardId !== 'null') {
- const card = ReactiveCache.getCard(cardId);
+ const card = await ReactiveCache.getCard(cardId);
if (!card || card.boardId !== boardId) {
return sendErrorResponse(res, 404, 'Card not found or does not belong to the specified board');
}
@@ -307,7 +307,7 @@ if (Meteor.isServer) {
query['meta.cardId'] = cardId;
}
- const attachments = ReactiveCache.getAttachments(query);
+ const attachments = await ReactiveCache.getAttachments(query);
const attachmentList = attachments.map(attachment => {
const strategy = fileStoreStrategyFactory.getFileStrategy(attachment, 'original');
@@ -337,7 +337,7 @@ if (Meteor.isServer) {
});
// Copy attachment endpoint
- WebApp.connectHandlers.use('/api/attachment/copy', (req, res, next) => {
+ WebApp.connectHandlers.use('/api/attachment/copy', async (req, res, next) => {
if (req.method !== 'POST') {
return next();
}
@@ -350,10 +350,10 @@ if (Meteor.isServer) {
try {
const userId = authenticateApiRequest(req);
-
+
let body = '';
let bodyComplete = false;
-
+
req.on('data', chunk => {
body += chunk.toString();
if (body.length > 10 * 1024 * 1024) { // 10MB limit for metadata
@@ -362,35 +362,35 @@ if (Meteor.isServer) {
}
});
- req.on('end', () => {
+ req.on('end', async () => {
if (bodyComplete) return;
bodyComplete = true;
clearTimeout(timeout);
-
+
try {
const data = JSON.parse(body);
const { attachmentId, targetBoardId, targetSwimlaneId, targetListId, targetCardId } = data;
// Get source attachment
- const sourceAttachment = ReactiveCache.getAttachment(attachmentId);
+ const sourceAttachment = await ReactiveCache.getAttachment(attachmentId);
if (!sourceAttachment) {
return sendErrorResponse(res, 404, 'Source attachment not found');
}
// Check source permissions
- const sourceBoard = ReactiveCache.getBoard(sourceAttachment.meta.boardId);
+ const sourceBoard = await ReactiveCache.getBoard(sourceAttachment.meta.boardId);
if (!sourceBoard || !sourceBoard.isBoardMember(userId)) {
return sendErrorResponse(res, 403, 'You do not have permission to access the source attachment');
}
// Check target permissions
- const targetBoard = ReactiveCache.getBoard(targetBoardId);
+ const targetBoard = await ReactiveCache.getBoard(targetBoardId);
if (!targetBoard || !targetBoard.isBoardMember(userId)) {
return sendErrorResponse(res, 403, 'You do not have permission to modify the target card');
}
// Verify that the target card belongs to the target board
- const targetCard = ReactiveCache.getCard(targetCardId);
+ const targetCard = await ReactiveCache.getCard(targetCardId);
if (!targetCard) {
return sendErrorResponse(res, 404, 'Target card not found');
}
@@ -493,7 +493,7 @@ if (Meteor.isServer) {
});
// Move attachment endpoint
- WebApp.connectHandlers.use('/api/attachment/move', (req, res, next) => {
+ WebApp.connectHandlers.use('/api/attachment/move', async (req, res, next) => {
if (req.method !== 'POST') {
return next();
}
@@ -506,10 +506,10 @@ if (Meteor.isServer) {
try {
const userId = authenticateApiRequest(req);
-
+
let body = '';
let bodyComplete = false;
-
+
req.on('data', chunk => {
body += chunk.toString();
if (body.length > 10 * 1024 * 1024) {
@@ -518,35 +518,35 @@ if (Meteor.isServer) {
}
});
- req.on('end', () => {
+ req.on('end', async () => {
if (bodyComplete) return;
bodyComplete = true;
clearTimeout(timeout);
-
+
try {
const data = JSON.parse(body);
const { attachmentId, targetBoardId, targetSwimlaneId, targetListId, targetCardId } = data;
// Get source attachment
- const sourceAttachment = ReactiveCache.getAttachment(attachmentId);
+ const sourceAttachment = await ReactiveCache.getAttachment(attachmentId);
if (!sourceAttachment) {
return sendErrorResponse(res, 404, 'Source attachment not found');
}
// Check source permissions
- const sourceBoard = ReactiveCache.getBoard(sourceAttachment.meta.boardId);
+ const sourceBoard = await ReactiveCache.getBoard(sourceAttachment.meta.boardId);
if (!sourceBoard || !sourceBoard.isBoardMember(userId)) {
return sendErrorResponse(res, 403, 'You do not have permission to access the source attachment');
}
// Check target permissions
- const targetBoard = ReactiveCache.getBoard(targetBoardId);
+ const targetBoard = await ReactiveCache.getBoard(targetBoardId);
if (!targetBoard || !targetBoard.isBoardMember(userId)) {
return sendErrorResponse(res, 403, 'You do not have permission to modify the target card');
}
// Verify that the target card belongs to the target board
- const targetCard = ReactiveCache.getCard(targetCardId);
+ const targetCard = await ReactiveCache.getCard(targetCardId);
if (!targetCard) {
return sendErrorResponse(res, 404, 'Target card not found');
}
@@ -610,7 +610,7 @@ if (Meteor.isServer) {
});
// Delete attachment endpoint
- WebApp.connectHandlers.use('/api/attachment/delete/([^/]+)', (req, res, next) => {
+ WebApp.connectHandlers.use('/api/attachment/delete/([^/]+)', async (req, res, next) => {
if (req.method !== 'DELETE') {
return next();
}
@@ -620,13 +620,13 @@ if (Meteor.isServer) {
const attachmentId = req.params[0];
// Get attachment
- const attachment = ReactiveCache.getAttachment(attachmentId);
+ const attachment = await ReactiveCache.getAttachment(attachmentId);
if (!attachment) {
return sendErrorResponse(res, 404, 'Attachment not found');
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board || !board.isBoardMember(userId)) {
return sendErrorResponse(res, 403, 'You do not have permission to delete this attachment');
}
@@ -646,7 +646,7 @@ if (Meteor.isServer) {
});
// Get attachment info endpoint
- WebApp.connectHandlers.use('/api/attachment/info/([^/]+)', (req, res, next) => {
+ WebApp.connectHandlers.use('/api/attachment/info/([^/]+)', async (req, res, next) => {
if (req.method !== 'GET') {
return next();
}
@@ -656,13 +656,13 @@ if (Meteor.isServer) {
const attachmentId = req.params[0];
// Get attachment
- const attachment = ReactiveCache.getAttachment(attachmentId);
+ const attachment = await ReactiveCache.getAttachment(attachmentId);
if (!attachment) {
return sendErrorResponse(res, 404, 'Attachment not found');
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board || !board.isBoardMember(userId)) {
return sendErrorResponse(res, 403, 'You do not have permission to access this attachment');
}
diff --git a/server/routes/avatarServer.js b/server/routes/avatarServer.js
index 008ea573a..9463e6130 100644
--- a/server/routes/avatarServer.js
+++ b/server/routes/avatarServer.js
@@ -13,14 +13,14 @@ import path from 'path';
if (Meteor.isServer) {
// Handle avatar file downloads
- WebApp.connectHandlers.use('/cdn/storage/avatars/([^/]+)', (req, res, next) => {
+ WebApp.connectHandlers.use('/cdn/storage/avatars/([^/]+)', async (req, res, next) => {
if (req.method !== 'GET') {
return next();
}
try {
const fileName = req.params[0];
-
+
if (!fileName) {
res.writeHead(400);
res.end('Invalid avatar file name');
@@ -29,7 +29,7 @@ if (Meteor.isServer) {
// Extract file ID from filename (format: fileId-original-filename)
const fileId = fileName.split('-original-')[0];
-
+
if (!fileId) {
res.writeHead(400);
res.end('Invalid avatar file format');
@@ -37,7 +37,7 @@ if (Meteor.isServer) {
}
// Get avatar file from database
- const avatar = ReactiveCache.getAvatar(fileId);
+ const avatar = await ReactiveCache.getAvatar(fileId);
if (!avatar) {
res.writeHead(404);
res.end('Avatar not found');
diff --git a/server/routes/legacyAttachments.js b/server/routes/legacyAttachments.js
index e36986a7a..2925babd9 100644
--- a/server/routes/legacyAttachments.js
+++ b/server/routes/legacyAttachments.js
@@ -58,7 +58,7 @@ function buildContentDispositionHeader(disposition, sanitizedFilename) {
if (Meteor.isServer) {
// Handle legacy attachment downloads
- WebApp.connectHandlers.use('/cfs/files/attachments', (req, res, next) => {
+ WebApp.connectHandlers.use('/cfs/files/attachments', async (req, res, next) => {
const attachmentId = req.url.split('/').pop();
if (!attachmentId) {
@@ -78,7 +78,7 @@ if (Meteor.isServer) {
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board) {
res.writeHead(404);
res.end('Board not found');
diff --git a/server/routes/universalFileServer.js b/server/routes/universalFileServer.js
index 5d4f05051..1c797bb2f 100644
--- a/server/routes/universalFileServer.js
+++ b/server/routes/universalFileServer.js
@@ -172,7 +172,7 @@ if (Meteor.isServer) {
* - Else if avatar's owner belongs to at least one public board -> allow
* - Otherwise -> deny
*/
- function isAuthorizedForAvatar(req, avatar) {
+ async function isAuthorizedForAvatar(req, avatar) {
try {
if (!avatar) return false;
@@ -180,7 +180,7 @@ if (Meteor.isServer) {
const q = parseQuery(req);
const boardId = q.boardId || q.board || q.b;
if (boardId) {
- const board = ReactiveCache.getBoard(boardId);
+ const board = await ReactiveCache.getBoard(boardId);
if (board && board.isPublic && board.isPublic()) return true;
// If private board is specified, require membership of requester
@@ -297,7 +297,7 @@ if (Meteor.isServer) {
* - Public boards: allow
* - Private boards: require valid user who is a member
*/
- function isAuthorizedForBoard(req, board) {
+ async function isAuthorizedForBoard(req, board) {
try {
if (!board) return false;
if (board.isPublic && board.isPublic()) return true;
@@ -389,14 +389,14 @@ if (Meteor.isServer) {
* Serve attachments from new Meteor-Files structure
* Route: /cdn/storage/attachments/{fileId} or /cdn/storage/attachments/{fileId}/original/{filename}
*/
- WebApp.connectHandlers.use('/cdn/storage/attachments', (req, res, next) => {
+ WebApp.connectHandlers.use('/cdn/storage/attachments', async (req, res, next) => {
if (req.method !== 'GET') {
return next();
}
try {
const fileId = extractFirstIdFromUrl(req, '/cdn/storage/attachments');
-
+
if (!fileId) {
res.writeHead(400);
res.end('Invalid attachment file ID');
@@ -412,7 +412,7 @@ if (Meteor.isServer) {
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board) {
res.writeHead(404);
res.end('Board not found');
@@ -420,7 +420,7 @@ if (Meteor.isServer) {
}
// Enforce cookie/header/query-based auth for private boards
- if (!isAuthorizedForBoard(req, board)) {
+ if (!(await isAuthorizedForBoard(req, board))) {
res.writeHead(403);
res.end('Access denied');
return;
@@ -476,14 +476,14 @@ if (Meteor.isServer) {
* Serve avatars from new Meteor-Files structure
* Route: /cdn/storage/avatars/{fileId} or /cdn/storage/avatars/{fileId}/original/{filename}
*/
- WebApp.connectHandlers.use('/cdn/storage/avatars', (req, res, next) => {
+ WebApp.connectHandlers.use('/cdn/storage/avatars', async (req, res, next) => {
if (req.method !== 'GET') {
return next();
}
try {
const fileId = extractFirstIdFromUrl(req, '/cdn/storage/avatars');
-
+
if (!fileId) {
res.writeHead(400);
res.end('Invalid avatar file ID');
@@ -491,7 +491,7 @@ if (Meteor.isServer) {
}
// Get avatar from database
- const avatar = ReactiveCache.getAvatar(fileId);
+ const avatar = await ReactiveCache.getAvatar(fileId);
if (!avatar) {
res.writeHead(404);
res.end('Avatar not found');
@@ -499,7 +499,7 @@ if (Meteor.isServer) {
}
// Enforce visibility: avatars are public only in the context of public boards
- if (!isAuthorizedForAvatar(req, avatar)) {
+ if (!(await isAuthorizedForAvatar(req, avatar))) {
res.writeHead(403);
res.end('Access denied');
return;
@@ -541,14 +541,14 @@ if (Meteor.isServer) {
* Serve legacy attachments from CollectionFS structure
* Route: /cfs/files/attachments/{attachmentId}
*/
- WebApp.connectHandlers.use('/cfs/files/attachments', (req, res, next) => {
+ WebApp.connectHandlers.use('/cfs/files/attachments', async (req, res, next) => {
if (req.method !== 'GET') {
return next();
}
try {
const attachmentId = extractFirstIdFromUrl(req, '/cfs/files/attachments');
-
+
if (!attachmentId) {
res.writeHead(400);
res.end('Invalid attachment ID');
@@ -564,7 +564,7 @@ if (Meteor.isServer) {
}
// Check permissions
- const board = ReactiveCache.getBoard(attachment.meta.boardId);
+ const board = await ReactiveCache.getBoard(attachment.meta.boardId);
if (!board) {
res.writeHead(404);
res.end('Board not found');
@@ -572,7 +572,7 @@ if (Meteor.isServer) {
}
// Enforce cookie/header/query-based auth for private boards
- if (!isAuthorizedForBoard(req, board)) {
+ if (!(await isAuthorizedForBoard(req, board))) {
res.writeHead(403);
res.end('Access denied');
return;
@@ -617,14 +617,14 @@ if (Meteor.isServer) {
* Serve legacy avatars from CollectionFS structure
* Route: /cfs/files/avatars/{avatarId}
*/
- WebApp.connectHandlers.use('/cfs/files/avatars', (req, res, next) => {
+ WebApp.connectHandlers.use('/cfs/files/avatars', async (req, res, next) => {
if (req.method !== 'GET') {
return next();
}
try {
const avatarId = extractFirstIdFromUrl(req, '/cfs/files/avatars');
-
+
if (!avatarId) {
res.writeHead(400);
res.end('Invalid avatar ID');
@@ -632,8 +632,8 @@ if (Meteor.isServer) {
}
// Try to get avatar from database (new structure first)
- let avatar = ReactiveCache.getAvatar(avatarId);
-
+ let avatar = await ReactiveCache.getAvatar(avatarId);
+
// If not found in new structure, try to handle legacy format
if (!avatar) {
// For legacy avatars, we might need to handle different ID formats
@@ -644,7 +644,7 @@ if (Meteor.isServer) {
}
// Enforce visibility for legacy avatars as well
- if (!isAuthorizedForAvatar(req, avatar)) {
+ if (!(await isAuthorizedForAvatar(req, avatar))) {
res.writeHead(403);
res.end('Access denied');
return;
diff --git a/server/rulesHelper.js b/server/rulesHelper.js
index b783b407d..3d5317c3a 100644
--- a/server/rulesHelper.js
+++ b/server/rulesHelper.js
@@ -10,14 +10,14 @@ RulesHelper = {
}
}
},
- findMatchingRules(activity) {
+ async findMatchingRules(activity) {
const activityType = activity.activityType;
if (TriggersDef[activityType] === undefined) {
return [];
}
const matchingFields = TriggersDef[activityType].matchingFields;
- const matchingMap = this.buildMatchingFieldsMap(activity, matchingFields);
- const matchingTriggers = ReactiveCache.getTriggers(matchingMap);
+ const matchingMap = await this.buildMatchingFieldsMap(activity, matchingFields);
+ const matchingTriggers = await ReactiveCache.getTriggers(matchingMap);
const matchingRules = [];
matchingTriggers.forEach(function(trigger) {
const rule = trigger.getRule();
@@ -29,20 +29,20 @@ RulesHelper = {
});
return matchingRules;
},
- buildMatchingFieldsMap(activity, matchingFields) {
+ async buildMatchingFieldsMap(activity, matchingFields) {
const matchingMap = { activityType: activity.activityType };
- matchingFields.forEach(field => {
+ for (const field of matchingFields) {
// Creating a matching map with the actual field of the activity
// and with the wildcard (for example: trigger when a card is added
// in any [*] board
let value = activity[field];
if (field === 'oldListName') {
- const oldList = ReactiveCache.getList(activity.oldListId);
+ const oldList = await ReactiveCache.getList(activity.oldListId);
if (oldList) {
value = oldList.title;
}
} else if (field === 'oldSwimlaneName') {
- const oldSwimlane = ReactiveCache.getSwimlane(activity.oldSwimlaneId);
+ const oldSwimlane = await ReactiveCache.getSwimlane(activity.oldSwimlaneId);
if (oldSwimlane) {
value = oldSwimlane.title;
}
@@ -54,11 +54,11 @@ RulesHelper = {
matchingMap[field] = {
$in: matchesList,
};
- });
+ }
return matchingMap;
},
async performAction(activity, action) {
- const card = ReactiveCache.getCard(activity.cardId);
+ const card = await ReactiveCache.getCard(activity.cardId);
const boardId = activity.boardId;
if (
action.actionType === 'moveCardToTop' ||
@@ -69,10 +69,10 @@ RulesHelper = {
if (action.listName === '*') {
list = card.list();
if (boardId !== action.boardId) {
- list = ReactiveCache.getList({ title: list.title, boardId: action.boardId });
+ list = await ReactiveCache.getList({ title: list.title, boardId: action.boardId });
}
} else {
- list = ReactiveCache.getList({
+ list = await ReactiveCache.getList({
title: action.listName,
boardId: action.boardId,
});
@@ -86,24 +86,24 @@ RulesHelper = {
let swimlane;
let swimlaneId;
if (action.swimlaneName === '*') {
- swimlane = ReactiveCache.getSwimlane(card.swimlaneId);
+ swimlane = await ReactiveCache.getSwimlane(card.swimlaneId);
if (boardId !== action.boardId) {
- swimlane = ReactiveCache.getSwimlane({
+ swimlane = await ReactiveCache.getSwimlane({
title: swimlane.title,
boardId: action.boardId,
});
}
} else {
- swimlane = ReactiveCache.getSwimlane({
+ swimlane = await ReactiveCache.getSwimlane({
title: action.swimlaneName,
boardId: action.boardId,
});
}
if (swimlane === undefined) {
- swimlaneId = ReactiveCache.getSwimlane({
+ swimlaneId = (await ReactiveCache.getSwimlane({
title: 'Default',
boardId: action.boardId,
- })._id;
+ }))._id;
} else {
swimlaneId = swimlane._id;
}
@@ -132,7 +132,7 @@ RulesHelper = {
// Check if recipient is a Wekan user to get their language
if (to && to.includes('@')) {
- recipientUser = ReactiveCache.getUser({ 'emails.address': to.toLowerCase() });
+ recipientUser = await ReactiveCache.getUser({ 'emails.address': to.toLowerCase() });
if (recipientUser && typeof recipientUser.getLanguage === 'function') {
recipientLang = recipientUser.getLanguage();
}
@@ -262,7 +262,7 @@ RulesHelper = {
card.removeLabel(action.labelId);
}
if (action.actionType === 'addMember') {
- const memberId = ReactiveCache.getUser({ username: action.username })._id;
+ const memberId = (await ReactiveCache.getUser({ username: action.username }))._id;
card.assignMember(memberId);
}
if (action.actionType === 'removeMember') {
@@ -272,41 +272,41 @@ RulesHelper = {
card.unassignMember(members[i]);
}
} else {
- const memberId = ReactiveCache.getUser({ username: action.username })._id;
+ const memberId = (await ReactiveCache.getUser({ username: action.username }))._id;
card.unassignMember(memberId);
}
}
if (action.actionType === 'checkAll') {
- const checkList = ReactiveCache.getChecklist({
+ const checkList = await ReactiveCache.getChecklist({
title: action.checklistName,
cardId: card._id,
});
await checkList.checkAllItems();
}
if (action.actionType === 'uncheckAll') {
- const checkList = ReactiveCache.getChecklist({
+ const checkList = await ReactiveCache.getChecklist({
title: action.checklistName,
cardId: card._id,
});
await checkList.uncheckAllItems();
}
if (action.actionType === 'checkItem') {
- const checkList = ReactiveCache.getChecklist({
+ const checkList = await ReactiveCache.getChecklist({
title: action.checklistName,
cardId: card._id,
});
- const checkItem = ReactiveCache.getChecklistItem({
+ const checkItem = await ReactiveCache.getChecklistItem({
title: action.checkItemName,
checkListId: checkList._id,
});
await checkItem.check();
}
if (action.actionType === 'uncheckItem') {
- const checkList = ReactiveCache.getChecklist({
+ const checkList = await ReactiveCache.getChecklist({
title: action.checklistName,
cardId: card._id,
});
- const checkItem = ReactiveCache.getChecklistItem({
+ const checkItem = await ReactiveCache.getChecklistItem({
title: action.checkItemName,
checkListId: checkList._id,
});
@@ -340,7 +340,7 @@ RulesHelper = {
sort: 0,
});
const itemsArray = action.checklistItems.split(',');
- const checkList = ReactiveCache.getChecklist(checkListId);
+ const checkList = await ReactiveCache.getChecklist(checkListId);
for (let i = 0; i < itemsArray.length; i++) {
ChecklistItems.insert({
title: itemsArray[i],
@@ -351,10 +351,10 @@ RulesHelper = {
}
}
if (action.actionType === 'createCard') {
- const list = ReactiveCache.getList({ title: action.listName, boardId });
+ const list = await ReactiveCache.getList({ title: action.listName, boardId });
let listId = '';
let swimlaneId = '';
- const swimlane = ReactiveCache.getSwimlane({
+ const swimlane = await ReactiveCache.getSwimlane({
title: action.swimlaneName,
boardId,
});
@@ -364,7 +364,7 @@ RulesHelper = {
listId = list._id;
}
if (swimlane === undefined) {
- swimlaneId = ReactiveCache.getSwimlane({ title: 'Default', boardId })._id;
+ swimlaneId = (await ReactiveCache.getSwimlane({ title: 'Default', boardId }))._id;
} else {
swimlaneId = swimlane._id;
}
@@ -377,11 +377,11 @@ RulesHelper = {
});
}
if (action.actionType === 'linkCard') {
- const list = ReactiveCache.getList({ title: action.listName, boardId: action.boardId });
- const card = ReactiveCache.getCard(activity.cardId);
+ const list = await ReactiveCache.getList({ title: action.listName, boardId: action.boardId });
+ const card = await ReactiveCache.getCard(activity.cardId);
let listId = '';
let swimlaneId = '';
- const swimlane = ReactiveCache.getSwimlane({
+ const swimlane = await ReactiveCache.getSwimlane({
title: action.swimlaneName,
boardId: action.boardId,
});
@@ -391,7 +391,7 @@ RulesHelper = {
listId = list._id;
}
if (swimlane === undefined) {
- swimlaneId = ReactiveCache.getSwimlane({ title: 'Default', boardId: action.boardId })._id;
+ swimlaneId = (await ReactiveCache.getSwimlane({ title: 'Default', boardId: action.boardId }))._id;
} else {
swimlaneId = swimlane._id;
}