mirror of
https://github.com/wekan/wekan.git
synced 2026-02-21 07:24:07 +01:00
Update ReactiveCache call sites to use async/await for Meteor 3.0
Part 3 of ReactiveCache async migration: - Add await before all ReactiveCache.getX() calls - Make functions containing ReactiveCache calls async - Convert forEach/map/filter loops with async callbacks to for...of - Update model helpers, Meteor methods, JsonRoutes handlers - Update collection hooks (.before/.after insert/update/remove) - Update .allow() callbacks to async Files updated across models/ and server/ directories: - Model files: cards, boards, lists, swimlanes, activities, users, checklists, checklistItems, customFields, attachments, integrations, cardComments, settings files, creators, exporters, and more - Server files: publications, methods, notifications, routes, migrations
This commit is contained in:
parent
2f6e34c5f5
commit
71eb01e233
81 changed files with 2218 additions and 2148 deletions
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue