mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 07:20:12 +01:00
404 lines
12 KiB
JavaScript
404 lines
12 KiB
JavaScript
/**
|
|
* Server-side Migration Runner
|
|
* Handles actual execution of database migrations with progress tracking
|
|
*/
|
|
|
|
import { Meteor } from 'meteor/meteor';
|
|
import { Migrations } from 'meteor/percolate:migrations';
|
|
import { ReactiveVar } from 'meteor/reactive-var';
|
|
|
|
// Server-side reactive variables for migration progress
|
|
export const serverMigrationProgress = new ReactiveVar(0);
|
|
export const serverMigrationStatus = new ReactiveVar('');
|
|
export const serverMigrationCurrentStep = new ReactiveVar('');
|
|
export const serverMigrationSteps = new ReactiveVar([]);
|
|
export const serverIsMigrating = new ReactiveVar(false);
|
|
|
|
class ServerMigrationRunner {
|
|
constructor() {
|
|
this.migrationSteps = this.initializeMigrationSteps();
|
|
this.currentStepIndex = 0;
|
|
this.startTime = null;
|
|
}
|
|
|
|
/**
|
|
* Initialize migration steps with their actual migration functions
|
|
*/
|
|
initializeMigrationSteps() {
|
|
return [
|
|
{
|
|
id: 'board-background-color',
|
|
name: 'Board Background Colors',
|
|
description: 'Setting up board background colors',
|
|
weight: 1,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runBoardBackgroundColorMigration
|
|
},
|
|
{
|
|
id: 'add-cardcounterlist-allowed',
|
|
name: 'Card Counter List Settings',
|
|
description: 'Adding card counter list permissions',
|
|
weight: 1,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runCardCounterListMigration
|
|
},
|
|
{
|
|
id: 'add-boardmemberlist-allowed',
|
|
name: 'Board Member List Settings',
|
|
description: 'Adding board member list permissions',
|
|
weight: 1,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runBoardMemberListMigration
|
|
},
|
|
{
|
|
id: 'lowercase-board-permission',
|
|
name: 'Board Permission Standardization',
|
|
description: 'Converting board permissions to lowercase',
|
|
weight: 1,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runLowercaseBoardPermissionMigration
|
|
},
|
|
{
|
|
id: 'change-attachments-type-for-non-images',
|
|
name: 'Attachment Type Standardization',
|
|
description: 'Updating attachment types for non-images',
|
|
weight: 2,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runAttachmentTypeMigration
|
|
},
|
|
{
|
|
id: 'card-covers',
|
|
name: 'Card Covers System',
|
|
description: 'Setting up card cover functionality',
|
|
weight: 2,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runCardCoversMigration
|
|
},
|
|
{
|
|
id: 'use-css-class-for-boards-colors',
|
|
name: 'Board Color CSS Classes',
|
|
description: 'Converting board colors to CSS classes',
|
|
weight: 2,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runBoardColorCSSMigration
|
|
},
|
|
{
|
|
id: 'denormalize-star-number-per-board',
|
|
name: 'Board Star Counts',
|
|
description: 'Calculating star counts per board',
|
|
weight: 3,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runStarNumberMigration
|
|
},
|
|
{
|
|
id: 'add-member-isactive-field',
|
|
name: 'Member Activity Status',
|
|
description: 'Adding member activity tracking',
|
|
weight: 2,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runMemberIsActiveMigration
|
|
},
|
|
{
|
|
id: 'add-sort-checklists',
|
|
name: 'Checklist Sorting',
|
|
description: 'Adding sort order to checklists',
|
|
weight: 2,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runSortChecklistsMigration
|
|
},
|
|
{
|
|
id: 'add-swimlanes',
|
|
name: 'Swimlanes System',
|
|
description: 'Setting up swimlanes functionality',
|
|
weight: 4,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runSwimlanesMigration
|
|
},
|
|
{
|
|
id: 'add-views',
|
|
name: 'Board Views',
|
|
description: 'Adding board view options',
|
|
weight: 2,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runViewsMigration
|
|
},
|
|
{
|
|
id: 'add-checklist-items',
|
|
name: 'Checklist Items',
|
|
description: 'Setting up checklist items system',
|
|
weight: 3,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runChecklistItemsMigration
|
|
},
|
|
{
|
|
id: 'add-card-types',
|
|
name: 'Card Types',
|
|
description: 'Adding card type functionality',
|
|
weight: 2,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runCardTypesMigration
|
|
},
|
|
{
|
|
id: 'add-custom-fields-to-cards',
|
|
name: 'Custom Fields',
|
|
description: 'Adding custom fields to cards',
|
|
weight: 3,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runCustomFieldsMigration
|
|
},
|
|
{
|
|
id: 'migrate-attachments-collectionFS-to-ostrioFiles',
|
|
name: 'Migrate Attachments to Meteor-Files',
|
|
description: 'Migrating attachments from CollectionFS to Meteor-Files',
|
|
weight: 8,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runAttachmentMigration
|
|
},
|
|
{
|
|
id: 'migrate-avatars-collectionFS-to-ostrioFiles',
|
|
name: 'Migrate Avatars to Meteor-Files',
|
|
description: 'Migrating avatars from CollectionFS to Meteor-Files',
|
|
weight: 6,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runAvatarMigration
|
|
},
|
|
{
|
|
id: 'migrate-lists-to-per-swimlane',
|
|
name: 'Migrate Lists to Per-Swimlane',
|
|
description: 'Migrating lists to per-swimlane structure',
|
|
weight: 5,
|
|
completed: false,
|
|
progress: 0,
|
|
migrationFunction: this.runListsToPerSwimlaneMigration
|
|
}
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Start migration process
|
|
*/
|
|
async startMigration() {
|
|
if (serverIsMigrating.get()) {
|
|
return; // Already migrating
|
|
}
|
|
|
|
serverIsMigrating.set(true);
|
|
serverMigrationSteps.set([...this.migrationSteps]);
|
|
this.startTime = Date.now();
|
|
|
|
try {
|
|
for (let i = 0; i < this.migrationSteps.length; i++) {
|
|
const step = this.migrationSteps[i];
|
|
this.currentStepIndex = i;
|
|
|
|
if (step.completed) {
|
|
continue; // Skip already completed steps
|
|
}
|
|
|
|
serverMigrationCurrentStep.set(step.name);
|
|
serverMigrationStatus.set(`Running: ${step.description}`);
|
|
|
|
// Run the migration step
|
|
await this.runMigrationStep(step);
|
|
|
|
// Mark as completed
|
|
step.completed = true;
|
|
step.progress = 100;
|
|
|
|
// Update progress
|
|
this.updateProgress();
|
|
|
|
// Allow other processes to run
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
// Migration completed
|
|
serverMigrationStatus.set('All migrations completed successfully!');
|
|
serverMigrationProgress.set(100);
|
|
serverMigrationCurrentStep.set('');
|
|
|
|
// Clear status after delay
|
|
setTimeout(() => {
|
|
serverIsMigrating.set(false);
|
|
serverMigrationStatus.set('');
|
|
serverMigrationProgress.set(0);
|
|
}, 3000);
|
|
|
|
} catch (error) {
|
|
console.error('Migration failed:', error);
|
|
serverMigrationStatus.set(`Migration failed: ${error.message}`);
|
|
serverIsMigrating.set(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run a single migration step
|
|
*/
|
|
async runMigrationStep(step) {
|
|
try {
|
|
// Update progress during migration
|
|
const progressSteps = 10;
|
|
for (let i = 0; i <= progressSteps; i++) {
|
|
step.progress = (i / progressSteps) * 100;
|
|
this.updateProgress();
|
|
|
|
// Run actual migration function
|
|
if (i === progressSteps) {
|
|
await step.migrationFunction.call(this);
|
|
}
|
|
|
|
// Allow other processes to run
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
} catch (error) {
|
|
console.error(`Migration step ${step.name} failed:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update progress variables
|
|
*/
|
|
updateProgress() {
|
|
const totalWeight = this.migrationSteps.reduce((total, step) => total + step.weight, 0);
|
|
const completedWeight = this.migrationSteps.reduce((total, step) => {
|
|
return total + (step.completed ? step.weight : step.progress * step.weight / 100);
|
|
}, 0);
|
|
const progress = Math.round((completedWeight / totalWeight) * 100);
|
|
|
|
serverMigrationProgress.set(progress);
|
|
serverMigrationSteps.set([...this.migrationSteps]);
|
|
}
|
|
|
|
// Individual migration functions
|
|
async runBoardBackgroundColorMigration() {
|
|
// Implementation for board background color migration
|
|
console.log('Running board background color migration');
|
|
}
|
|
|
|
async runCardCounterListMigration() {
|
|
// Implementation for card counter list migration
|
|
console.log('Running card counter list migration');
|
|
}
|
|
|
|
async runBoardMemberListMigration() {
|
|
// Implementation for board member list migration
|
|
console.log('Running board member list migration');
|
|
}
|
|
|
|
async runLowercaseBoardPermissionMigration() {
|
|
// Implementation for lowercase board permission migration
|
|
console.log('Running lowercase board permission migration');
|
|
}
|
|
|
|
async runAttachmentTypeMigration() {
|
|
// Implementation for attachment type migration
|
|
console.log('Running attachment type migration');
|
|
}
|
|
|
|
async runCardCoversMigration() {
|
|
// Implementation for card covers migration
|
|
console.log('Running card covers migration');
|
|
}
|
|
|
|
async runBoardColorCSSMigration() {
|
|
// Implementation for board color CSS migration
|
|
console.log('Running board color CSS migration');
|
|
}
|
|
|
|
async runStarNumberMigration() {
|
|
// Implementation for star number migration
|
|
console.log('Running star number migration');
|
|
}
|
|
|
|
async runMemberIsActiveMigration() {
|
|
// Implementation for member is active migration
|
|
console.log('Running member is active migration');
|
|
}
|
|
|
|
async runSortChecklistsMigration() {
|
|
// Implementation for sort checklists migration
|
|
console.log('Running sort checklists migration');
|
|
}
|
|
|
|
async runSwimlanesMigration() {
|
|
// Implementation for swimlanes migration
|
|
console.log('Running swimlanes migration');
|
|
}
|
|
|
|
async runViewsMigration() {
|
|
// Implementation for views migration
|
|
console.log('Running views migration');
|
|
}
|
|
|
|
async runChecklistItemsMigration() {
|
|
// Implementation for checklist items migration
|
|
console.log('Running checklist items migration');
|
|
}
|
|
|
|
async runCardTypesMigration() {
|
|
// Implementation for card types migration
|
|
console.log('Running card types migration');
|
|
}
|
|
|
|
async runCustomFieldsMigration() {
|
|
// Implementation for custom fields migration
|
|
console.log('Running custom fields migration');
|
|
}
|
|
|
|
async runAttachmentMigration() {
|
|
// Implementation for attachment migration from CollectionFS to Meteor-Files
|
|
console.log('Running attachment migration from CollectionFS to Meteor-Files');
|
|
}
|
|
|
|
async runAvatarMigration() {
|
|
// Implementation for avatar migration from CollectionFS to Meteor-Files
|
|
console.log('Running avatar migration from CollectionFS to Meteor-Files');
|
|
}
|
|
|
|
async runListsToPerSwimlaneMigration() {
|
|
// Implementation for lists to per-swimlane migration
|
|
console.log('Running lists to per-swimlane migration');
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const serverMigrationRunner = new ServerMigrationRunner();
|
|
|
|
// Meteor methods for client-server communication
|
|
Meteor.methods({
|
|
'migration.start'() {
|
|
if (!this.userId) {
|
|
throw new Meteor.Error('not-authorized');
|
|
}
|
|
|
|
return serverMigrationRunner.startMigration();
|
|
},
|
|
|
|
'migration.getProgress'() {
|
|
return {
|
|
progress: serverMigrationProgress.get(),
|
|
status: serverMigrationStatus.get(),
|
|
currentStep: serverMigrationCurrentStep.get(),
|
|
steps: serverMigrationSteps.get(),
|
|
isMigrating: serverIsMigrating.get()
|
|
};
|
|
}
|
|
});
|