123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /**
- * Server-side Attachment Migration System
- * Handles migration of attachments from old structure to new structure
- */
- import { Meteor } from 'meteor/meteor';
- import { ReactiveVar } from 'meteor/reactive-var';
- import { ReactiveCache } from '/imports/reactiveCache';
- // Reactive variables for tracking migration progress
- const migrationProgress = new ReactiveVar(0);
- const migrationStatus = new ReactiveVar('');
- const unconvertedAttachments = new ReactiveVar([]);
- class AttachmentMigrationService {
- constructor() {
- this.migrationCache = new Map();
- }
- /**
- * Migrate all attachments for a board
- * @param {string} boardId - The board ID
- */
- async migrateBoardAttachments(boardId) {
- try {
- console.log(`Starting attachment migration for board: ${boardId}`);
-
- // Get all attachments for the board
- const attachments = Attachments.find({
- 'meta.boardId': boardId
- }).fetch();
- const totalAttachments = attachments.length;
- let migratedCount = 0;
- migrationStatus.set(`Migrating ${totalAttachments} attachments...`);
- migrationProgress.set(0);
- for (const attachment of attachments) {
- try {
- // Check if attachment needs migration
- if (this.needsMigration(attachment)) {
- await this.migrateAttachment(attachment);
- this.migrationCache.set(attachment._id, true);
- }
-
- migratedCount++;
- const progress = Math.round((migratedCount / totalAttachments) * 100);
- migrationProgress.set(progress);
- migrationStatus.set(`Migrated ${migratedCount}/${totalAttachments} attachments...`);
-
- } catch (error) {
- console.error(`Error migrating attachment ${attachment._id}:`, error);
- }
- }
- // Update unconverted attachments list
- const remainingUnconverted = this.getUnconvertedAttachments(boardId);
- unconvertedAttachments.set(remainingUnconverted);
- migrationStatus.set('Attachment migration completed');
- migrationProgress.set(100);
- console.log(`Attachment migration completed for board: ${boardId}`);
- } catch (error) {
- console.error(`Error migrating attachments for board ${boardId}:`, error);
- migrationStatus.set(`Migration failed: ${error.message}`);
- throw error;
- }
- }
- /**
- * Check if an attachment needs migration
- * @param {Object} attachment - The attachment object
- * @returns {boolean} - True if attachment needs migration
- */
- needsMigration(attachment) {
- if (this.migrationCache.has(attachment._id)) {
- return false; // Already migrated
- }
- // Check if attachment has old structure
- return !attachment.meta ||
- !attachment.meta.cardId ||
- !attachment.meta.boardId ||
- !attachment.meta.listId;
- }
- /**
- * Migrate a single attachment
- * @param {Object} attachment - The attachment object
- */
- async migrateAttachment(attachment) {
- try {
- // Get the card to find board and list information
- const card = ReactiveCache.getCard(attachment.cardId);
- if (!card) {
- console.warn(`Card not found for attachment ${attachment._id}`);
- return;
- }
- const list = ReactiveCache.getList(card.listId);
- if (!list) {
- console.warn(`List not found for attachment ${attachment._id}`);
- return;
- }
- // Update attachment with new structure
- const updateData = {
- meta: {
- cardId: attachment.cardId,
- boardId: list.boardId,
- listId: card.listId,
- userId: attachment.userId,
- createdAt: attachment.createdAt || new Date(),
- migratedAt: new Date()
- }
- };
- // Preserve existing meta data if it exists
- if (attachment.meta) {
- updateData.meta = {
- ...attachment.meta,
- ...updateData.meta
- };
- }
- Attachments.update(attachment._id, { $set: updateData });
- console.log(`Migrated attachment ${attachment._id}`);
- } catch (error) {
- console.error(`Error migrating attachment ${attachment._id}:`, error);
- throw error;
- }
- }
- /**
- * Get unconverted attachments for a board
- * @param {string} boardId - The board ID
- * @returns {Array} - Array of unconverted attachments
- */
- getUnconvertedAttachments(boardId) {
- try {
- const attachments = Attachments.find({
- 'meta.boardId': boardId
- }).fetch();
- return attachments.filter(attachment => this.needsMigration(attachment));
- } catch (error) {
- console.error('Error getting unconverted attachments:', error);
- return [];
- }
- }
- /**
- * Get migration progress
- * @param {string} boardId - The board ID
- * @returns {Object} - Migration progress data
- */
- getMigrationProgress(boardId) {
- const progress = migrationProgress.get();
- const status = migrationStatus.get();
- const unconverted = this.getUnconvertedAttachments(boardId);
- return {
- progress,
- status,
- unconvertedAttachments: unconverted
- };
- }
- }
- const attachmentMigrationService = new AttachmentMigrationService();
- // Meteor methods
- Meteor.methods({
- 'attachmentMigration.migrateBoardAttachments'(boardId) {
- if (!this.userId) {
- throw new Meteor.Error('not-authorized');
- }
- return attachmentMigrationService.migrateBoardAttachments(boardId);
- },
- 'attachmentMigration.getProgress'(boardId) {
- if (!this.userId) {
- throw new Meteor.Error('not-authorized');
- }
- return attachmentMigrationService.getMigrationProgress(boardId);
- },
- 'attachmentMigration.getUnconvertedAttachments'(boardId) {
- if (!this.userId) {
- throw new Meteor.Error('not-authorized');
- }
- return attachmentMigrationService.getUnconvertedAttachments(boardId);
- }
- });
- export { attachmentMigrationService };
|