mirror of
https://github.com/whyour/qinglong.git
synced 2025-12-15 16:35:39 +08:00
Add data migration script and comprehensive migration guide
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
This commit is contained in:
parent
5c798a0e93
commit
d42074f76a
252
MIGRATION_GUIDE.md
Normal file
252
MIGRATION_GUIDE.md
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
# Multi-User Data Migration Guide
|
||||||
|
|
||||||
|
This document explains how to migrate existing data to the multi-user system.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
When upgrading to the multi-user version of Qinglong, all existing data (cron tasks, environment variables, subscriptions, and dependencies) will be treated as "legacy data" that is accessible to all users.
|
||||||
|
|
||||||
|
To properly isolate data between users, you need to migrate existing data to specific user accounts.
|
||||||
|
|
||||||
|
## Migration Script
|
||||||
|
|
||||||
|
The `migrate-to-multiuser.js` script helps you assign existing legacy data to specific users.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Node.js installed
|
||||||
|
- Sequelize and dotenv packages (already included in the project)
|
||||||
|
- At least one user created in the User Management interface
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
#### 1. List All Users
|
||||||
|
|
||||||
|
First, see all available users in your system:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --list-users
|
||||||
|
```
|
||||||
|
|
||||||
|
Output example:
|
||||||
|
```
|
||||||
|
Users in the system:
|
||||||
|
ID Username Role Status
|
||||||
|
-- -------- ---- ------
|
||||||
|
1 admin Admin Enabled
|
||||||
|
2 user1 User Enabled
|
||||||
|
3 user2 User Enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Preview Migration (Dry Run)
|
||||||
|
|
||||||
|
Before making changes, preview what will be migrated:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --userId=1 --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
Or by username:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --username=admin --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
Output example:
|
||||||
|
```
|
||||||
|
Legacy Data Statistics:
|
||||||
|
Cron tasks: 15
|
||||||
|
Environment variables: 8
|
||||||
|
Subscriptions: 3
|
||||||
|
Dependencies: 5
|
||||||
|
|
||||||
|
DRY RUN: No changes will be made.
|
||||||
|
|
||||||
|
Would assign all legacy data to user ID 1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Perform Migration
|
||||||
|
|
||||||
|
Once you're ready, run the migration without `--dry-run`:
|
||||||
|
|
||||||
|
**By User ID:**
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --userId=1
|
||||||
|
```
|
||||||
|
|
||||||
|
**By Username:**
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --username=admin
|
||||||
|
```
|
||||||
|
|
||||||
|
Output example:
|
||||||
|
```
|
||||||
|
Found user 'admin' with ID 1
|
||||||
|
|
||||||
|
Legacy Data Statistics:
|
||||||
|
Cron tasks: 15
|
||||||
|
Environment variables: 8
|
||||||
|
Subscriptions: 3
|
||||||
|
Dependencies: 5
|
||||||
|
|
||||||
|
Migrating data to user ID 1...
|
||||||
|
✓ Migrated 15 cron tasks
|
||||||
|
✓ Migrated 8 environment variables
|
||||||
|
✓ Migrated 3 subscriptions
|
||||||
|
✓ Migrated 5 dependencies
|
||||||
|
|
||||||
|
✓ Migration completed successfully!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Line Options
|
||||||
|
|
||||||
|
| Option | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `--userId=<id>` | Assign all legacy data to user with this ID |
|
||||||
|
| `--username=<name>` | Assign all legacy data to user with this username |
|
||||||
|
| `--list-users` | List all users in the system |
|
||||||
|
| `--dry-run` | Show what would be changed without making changes |
|
||||||
|
| `--help` | Show help message |
|
||||||
|
|
||||||
|
## Migration Strategy
|
||||||
|
|
||||||
|
### Scenario 1: Single User to Multi-User
|
||||||
|
|
||||||
|
If you're upgrading from single-user to multi-user and want to keep all existing data under one admin account:
|
||||||
|
|
||||||
|
1. Create an admin user in the User Management interface
|
||||||
|
2. Run migration: `node migrate-to-multiuser.js --username=admin`
|
||||||
|
|
||||||
|
### Scenario 2: Distribute Data to Multiple Users
|
||||||
|
|
||||||
|
If you want to distribute existing data to different users:
|
||||||
|
|
||||||
|
1. Create all necessary user accounts first
|
||||||
|
2. Identify which data belongs to which user (you may need to do this manually by checking the database)
|
||||||
|
3. For each user, manually update the `userId` field in the database tables (`Crontabs`, `Envs`, `Subscriptions`, `Dependences`)
|
||||||
|
|
||||||
|
**SQL Example:**
|
||||||
|
```sql
|
||||||
|
-- Assign specific cron tasks to user ID 2
|
||||||
|
UPDATE Crontabs
|
||||||
|
SET userId = 2
|
||||||
|
WHERE name LIKE '%user2%' AND userId IS NULL;
|
||||||
|
|
||||||
|
-- Assign specific environment variables to user ID 2
|
||||||
|
UPDATE Envs
|
||||||
|
SET userId = 2
|
||||||
|
WHERE name LIKE '%USER2%' AND userId IS NULL;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scenario 3: Keep as Shared Data
|
||||||
|
|
||||||
|
If you want certain data to remain accessible to all users:
|
||||||
|
|
||||||
|
- Simply don't run the migration script
|
||||||
|
- Data with `userId = NULL` remains as "legacy data" accessible to everyone
|
||||||
|
- This is useful for shared cron tasks or environment variables
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
1. **Backup First**: Always backup your database before running migration scripts
|
||||||
|
```bash
|
||||||
|
cp data/database.sqlite data/database.sqlite.backup
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Test in Dry Run**: Always use `--dry-run` first to see what will change
|
||||||
|
|
||||||
|
3. **One-Time Operation**: The script only migrates data where `userId` is NULL
|
||||||
|
- Already migrated data won't be changed
|
||||||
|
- You can run it multiple times safely
|
||||||
|
|
||||||
|
4. **Transaction Safety**: The migration uses database transactions
|
||||||
|
- If any error occurs, all changes are rolled back
|
||||||
|
- Your data remains safe
|
||||||
|
|
||||||
|
5. **User Must Exist**: The target user must exist before migration
|
||||||
|
- Create users in the User Management interface first
|
||||||
|
- Use `--list-users` to verify users exist
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Error: "User not found"
|
||||||
|
|
||||||
|
**Problem:** The specified user doesn't exist in the database.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Run `node migrate-to-multiuser.js --list-users` to see available users
|
||||||
|
2. Create the user in User Management interface if needed
|
||||||
|
3. Use correct user ID or username
|
||||||
|
|
||||||
|
### Error: "Database connection failed"
|
||||||
|
|
||||||
|
**Problem:** Cannot connect to the database.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Check that `data/database.sqlite` exists
|
||||||
|
2. Verify database file permissions
|
||||||
|
3. Check `QL_DATA_DIR` environment variable if using custom path
|
||||||
|
|
||||||
|
### Error: "Migration failed"
|
||||||
|
|
||||||
|
**Problem:** An error occurred during migration.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Check the error message for details
|
||||||
|
2. Verify database is not corrupted
|
||||||
|
3. Restore from backup if needed
|
||||||
|
4. Check database file permissions
|
||||||
|
|
||||||
|
## Manual Migration
|
||||||
|
|
||||||
|
If you prefer to migrate data manually using SQL:
|
||||||
|
|
||||||
|
### Connect to Database
|
||||||
|
```bash
|
||||||
|
sqlite3 data/database.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Legacy Data
|
||||||
|
```sql
|
||||||
|
-- Count legacy cron tasks
|
||||||
|
SELECT COUNT(*) FROM Crontabs WHERE userId IS NULL;
|
||||||
|
|
||||||
|
-- View legacy cron tasks
|
||||||
|
SELECT id, name, command FROM Crontabs WHERE userId IS NULL;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migrate Data
|
||||||
|
```sql
|
||||||
|
-- Migrate all legacy data to user ID 1
|
||||||
|
UPDATE Crontabs SET userId = 1 WHERE userId IS NULL;
|
||||||
|
UPDATE Envs SET userId = 1 WHERE userId IS NULL;
|
||||||
|
UPDATE Subscriptions SET userId = 1 WHERE userId IS NULL;
|
||||||
|
UPDATE Dependences SET userId = 1 WHERE userId IS NULL;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify Migration
|
||||||
|
```sql
|
||||||
|
-- Check if any legacy data remains
|
||||||
|
SELECT
|
||||||
|
(SELECT COUNT(*) FROM Crontabs WHERE userId IS NULL) as legacy_crons,
|
||||||
|
(SELECT COUNT(*) FROM Envs WHERE userId IS NULL) as legacy_envs,
|
||||||
|
(SELECT COUNT(*) FROM Subscriptions WHERE userId IS NULL) as legacy_subs,
|
||||||
|
(SELECT COUNT(*) FROM Dependences WHERE userId IS NULL) as legacy_deps;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
If you encounter issues with data migration:
|
||||||
|
|
||||||
|
1. Check this guide for solutions
|
||||||
|
2. Review the error messages carefully
|
||||||
|
3. Ensure you have a recent backup
|
||||||
|
4. Open an issue on GitHub with:
|
||||||
|
- Error messages
|
||||||
|
- Migration command used
|
||||||
|
- Database statistics (from dry run)
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [MULTI_USER_GUIDE.md](./MULTI_USER_GUIDE.md) - Complete multi-user feature guide
|
||||||
|
- [README.md](./README.md) - Main project documentation
|
||||||
|
|
@ -90,6 +90,48 @@ DELETE /api/user-management
|
||||||
- Minimum password length is 6 characters
|
- Minimum password length is 6 characters
|
||||||
- Strong passwords are recommended
|
- Strong passwords are recommended
|
||||||
|
|
||||||
|
## 数据迁移 (Data Migration)
|
||||||
|
|
||||||
|
### 迁移工具 (Migration Tool)
|
||||||
|
|
||||||
|
项目提供了数据迁移脚本,可以将现有数据分配给特定用户。
|
||||||
|
|
||||||
|
A migration script is provided to assign existing data to specific users.
|
||||||
|
|
||||||
|
#### 使用方法 (Usage)
|
||||||
|
|
||||||
|
1. **列出所有用户 (List all users)**
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --list-users
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **预览迁移(不实际执行)(Dry run)**
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --userId=1 --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **将数据迁移到指定用户ID (Migrate to user ID)**
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --userId=1
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **将数据迁移到指定用户名 (Migrate to username)**
|
||||||
|
```bash
|
||||||
|
node migrate-to-multiuser.js --username=admin
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 注意事项 (Important Notes)
|
||||||
|
|
||||||
|
- 迁移脚本只会处理 `userId` 为空的数据(遗留数据)
|
||||||
|
- 已分配给用户的数据不会被修改
|
||||||
|
- 建议先使用 `--dry-run` 预览变更
|
||||||
|
- 迁移过程中如果出错会自动回滚
|
||||||
|
|
||||||
|
- The script only migrates data where `userId` is NULL (legacy data)
|
||||||
|
- Data already assigned to users will not be changed
|
||||||
|
- It's recommended to use `--dry-run` first to preview changes
|
||||||
|
- Changes are automatically rolled back if an error occurs
|
||||||
|
|
||||||
## 向后兼容 (Backward Compatibility)
|
## 向后兼容 (Backward Compatibility)
|
||||||
|
|
||||||
- 原有的单用户系统管理员账号继续有效
|
- 原有的单用户系统管理员账号继续有效
|
||||||
|
|
@ -103,10 +145,10 @@ DELETE /api/user-management
|
||||||
|
|
||||||
1. **首次使用**:首次使用多用户功能时,建议先创建一个管理员账号作为备份
|
1. **首次使用**:首次使用多用户功能时,建议先创建一个管理员账号作为备份
|
||||||
2. **密码管理**:请妥善保管用户密码,忘记密码需要管理员重置
|
2. **密码管理**:请妥善保管用户密码,忘记密码需要管理员重置
|
||||||
3. **数据迁移**:如需将现有数据分配给特定用户,请联系管理员手动更新数据库
|
3. **数据迁移**:使用提供的 `migrate-to-multiuser.js` 脚本将现有数据分配给特定用户
|
||||||
4. **权限控制**:删除用户不会删除该用户的数据,数据会变为遗留数据
|
4. **权限控制**:删除用户不会删除该用户的数据,数据会变为遗留数据
|
||||||
|
|
||||||
1. **First Use**: When first using multi-user functionality, it's recommended to create an admin account as a backup
|
1. **First Use**: When first using multi-user functionality, it's recommended to create an admin account as a backup
|
||||||
2. **Password Management**: Please keep user passwords safe; forgotten passwords need admin reset
|
2. **Password Management**: Please keep user passwords safe; forgotten passwords need admin reset
|
||||||
3. **Data Migration**: To assign existing data to specific users, contact admin for manual database update
|
3. **Data Migration**: Use the provided `migrate-to-multiuser.js` script to assign existing data to specific users
|
||||||
4. **Permission Control**: Deleting a user doesn't delete their data; the data becomes legacy data
|
4. **Permission Control**: Deleting a user doesn't delete their data; the data becomes legacy data
|
||||||
|
|
|
||||||
317
migrate-to-multiuser.js
Executable file
317
migrate-to-multiuser.js
Executable file
|
|
@ -0,0 +1,317 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi-User Data Migration Script
|
||||||
|
*
|
||||||
|
* This script migrates existing data (Cron, Env, Subscription, Dependence)
|
||||||
|
* to be associated with specific users.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* node migrate-to-multiuser.js --userId=1
|
||||||
|
* node migrate-to-multiuser.js --username=admin
|
||||||
|
* node migrate-to-multiuser.js --list-users
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
* --userId=<id> Assign all legacy data to user with this ID
|
||||||
|
* --username=<name> Assign all legacy data to user with this username
|
||||||
|
* --list-users List all users in the system
|
||||||
|
* --dry-run Show what would be changed without making changes
|
||||||
|
* --help Show this help message
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const Sequelize = require('sequelize');
|
||||||
|
|
||||||
|
// Load environment variables
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const config = {
|
||||||
|
dbPath: process.env.QL_DATA_DIR || path.join(__dirname, '../data'),
|
||||||
|
rootPath: __dirname,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize Sequelize
|
||||||
|
const sequelize = new Sequelize({
|
||||||
|
dialect: 'sqlite',
|
||||||
|
storage: path.join(config.dbPath, 'database.sqlite'),
|
||||||
|
logging: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define models
|
||||||
|
const UserModel = sequelize.define('User', {
|
||||||
|
username: Sequelize.STRING,
|
||||||
|
password: Sequelize.STRING,
|
||||||
|
role: Sequelize.NUMBER,
|
||||||
|
status: Sequelize.NUMBER,
|
||||||
|
});
|
||||||
|
|
||||||
|
const CrontabModel = sequelize.define('Crontab', {
|
||||||
|
name: Sequelize.STRING,
|
||||||
|
command: Sequelize.STRING,
|
||||||
|
schedule: Sequelize.STRING,
|
||||||
|
userId: Sequelize.NUMBER,
|
||||||
|
});
|
||||||
|
|
||||||
|
const EnvModel = sequelize.define('Env', {
|
||||||
|
name: Sequelize.STRING,
|
||||||
|
value: Sequelize.STRING,
|
||||||
|
userId: Sequelize.NUMBER,
|
||||||
|
});
|
||||||
|
|
||||||
|
const SubscriptionModel = sequelize.define('Subscription', {
|
||||||
|
name: Sequelize.STRING,
|
||||||
|
url: Sequelize.STRING,
|
||||||
|
userId: Sequelize.NUMBER,
|
||||||
|
});
|
||||||
|
|
||||||
|
const DependenceModel = sequelize.define('Dependence', {
|
||||||
|
name: Sequelize.STRING,
|
||||||
|
type: Sequelize.NUMBER,
|
||||||
|
userId: Sequelize.NUMBER,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Parse command line arguments
|
||||||
|
function parseArgs() {
|
||||||
|
const args = {
|
||||||
|
userId: null,
|
||||||
|
username: null,
|
||||||
|
listUsers: false,
|
||||||
|
dryRun: false,
|
||||||
|
help: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
process.argv.slice(2).forEach(arg => {
|
||||||
|
if (arg.startsWith('--userId=')) {
|
||||||
|
args.userId = parseInt(arg.split('=')[1]);
|
||||||
|
} else if (arg.startsWith('--username=')) {
|
||||||
|
args.username = arg.split('=')[1];
|
||||||
|
} else if (arg === '--list-users') {
|
||||||
|
args.listUsers = true;
|
||||||
|
} else if (arg === '--dry-run') {
|
||||||
|
args.dryRun = true;
|
||||||
|
} else if (arg === '--help' || arg === '-h') {
|
||||||
|
args.help = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show help
|
||||||
|
function showHelp() {
|
||||||
|
console.log(`
|
||||||
|
Multi-User Data Migration Script
|
||||||
|
|
||||||
|
This script migrates existing data (Cron, Env, Subscription, Dependence)
|
||||||
|
to be associated with specific users.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
node migrate-to-multiuser.js --userId=1
|
||||||
|
node migrate-to-multiuser.js --username=admin
|
||||||
|
node migrate-to-multiuser.js --list-users
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--userId=<id> Assign all legacy data to user with this ID
|
||||||
|
--username=<name> Assign all legacy data to user with this username
|
||||||
|
--list-users List all users in the system
|
||||||
|
--dry-run Show what would be changed without making changes
|
||||||
|
--help Show this help message
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
# List all users
|
||||||
|
node migrate-to-multiuser.js --list-users
|
||||||
|
|
||||||
|
# Migrate all data to user ID 1 (dry run)
|
||||||
|
node migrate-to-multiuser.js --userId=1 --dry-run
|
||||||
|
|
||||||
|
# Migrate all data to user 'admin'
|
||||||
|
node migrate-to-multiuser.js --username=admin
|
||||||
|
|
||||||
|
Note: This script will only migrate data where userId is NULL or undefined.
|
||||||
|
Data already assigned to users will not be changed.
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all users
|
||||||
|
async function listUsers() {
|
||||||
|
const users = await UserModel.findAll();
|
||||||
|
|
||||||
|
if (users.length === 0) {
|
||||||
|
console.log('\nNo users found in the database.');
|
||||||
|
console.log('Please create users first using the User Management interface.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\nUsers in the system:');
|
||||||
|
console.log('ID\tUsername\tRole\t\tStatus');
|
||||||
|
console.log('--\t--------\t----\t\t------');
|
||||||
|
|
||||||
|
users.forEach(user => {
|
||||||
|
const role = user.role === 0 ? 'Admin' : 'User';
|
||||||
|
const status = user.status === 0 ? 'Enabled' : 'Disabled';
|
||||||
|
console.log(`${user.id}\t${user.username}\t\t${role}\t\t${status}`);
|
||||||
|
});
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get statistics of legacy data
|
||||||
|
async function getStatistics() {
|
||||||
|
const stats = {
|
||||||
|
crons: await CrontabModel.count({ where: { userId: null } }),
|
||||||
|
envs: await EnvModel.count({ where: { userId: null } }),
|
||||||
|
subscriptions: await SubscriptionModel.count({ where: { userId: null } }),
|
||||||
|
dependences: await DependenceModel.count({ where: { userId: null } }),
|
||||||
|
};
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate data to a specific user
|
||||||
|
async function migrateData(userId, dryRun = false) {
|
||||||
|
const stats = await getStatistics();
|
||||||
|
|
||||||
|
console.log('\nLegacy Data Statistics:');
|
||||||
|
console.log(` Cron tasks: ${stats.crons}`);
|
||||||
|
console.log(` Environment variables: ${stats.envs}`);
|
||||||
|
console.log(` Subscriptions: ${stats.subscriptions}`);
|
||||||
|
console.log(` Dependencies: ${stats.dependences}`);
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
if (stats.crons + stats.envs + stats.subscriptions + stats.dependences === 0) {
|
||||||
|
console.log('No legacy data found. All data is already assigned to users.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun) {
|
||||||
|
console.log('DRY RUN: No changes will be made.\n');
|
||||||
|
console.log(`Would assign all legacy data to user ID ${userId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Migrating data to user ID ${userId}...`);
|
||||||
|
|
||||||
|
const transaction = await sequelize.transaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Migrate crons
|
||||||
|
if (stats.crons > 0) {
|
||||||
|
await CrontabModel.update(
|
||||||
|
{ userId },
|
||||||
|
{ where: { userId: null }, transaction }
|
||||||
|
);
|
||||||
|
console.log(`✓ Migrated ${stats.crons} cron tasks`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate envs
|
||||||
|
if (stats.envs > 0) {
|
||||||
|
await EnvModel.update(
|
||||||
|
{ userId },
|
||||||
|
{ where: { userId: null }, transaction }
|
||||||
|
);
|
||||||
|
console.log(`✓ Migrated ${stats.envs} environment variables`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate subscriptions
|
||||||
|
if (stats.subscriptions > 0) {
|
||||||
|
await SubscriptionModel.update(
|
||||||
|
{ userId },
|
||||||
|
{ where: { userId: null }, transaction }
|
||||||
|
);
|
||||||
|
console.log(`✓ Migrated ${stats.subscriptions} subscriptions`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate dependences
|
||||||
|
if (stats.dependences > 0) {
|
||||||
|
await DependenceModel.update(
|
||||||
|
{ userId },
|
||||||
|
{ where: { userId: null }, transaction }
|
||||||
|
);
|
||||||
|
console.log(`✓ Migrated ${stats.dependences} dependencies`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await transaction.commit();
|
||||||
|
console.log('\n✓ Migration completed successfully!');
|
||||||
|
} catch (error) {
|
||||||
|
await transaction.rollback();
|
||||||
|
console.error('\n✗ Migration failed:', error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function
|
||||||
|
async function main() {
|
||||||
|
const args = parseArgs();
|
||||||
|
|
||||||
|
if (args.help) {
|
||||||
|
showHelp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Test database connection
|
||||||
|
await sequelize.authenticate();
|
||||||
|
console.log('Database connection established.');
|
||||||
|
|
||||||
|
if (args.listUsers) {
|
||||||
|
await listUsers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate arguments
|
||||||
|
if (!args.userId && !args.username) {
|
||||||
|
console.error('\nError: You must specify either --userId or --username');
|
||||||
|
console.log('Use --help for usage information.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user ID
|
||||||
|
let userId = args.userId;
|
||||||
|
|
||||||
|
if (args.username) {
|
||||||
|
const user = await UserModel.findOne({
|
||||||
|
where: { username: args.username }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
console.error(`\nError: User '${args.username}' not found.`);
|
||||||
|
console.log('Use --list-users to see available users.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
userId = user.id;
|
||||||
|
console.log(`Found user '${args.username}' with ID ${userId}`);
|
||||||
|
} else {
|
||||||
|
// Verify user exists
|
||||||
|
const user = await UserModel.findByPk(userId);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
console.error(`\nError: User with ID ${userId} not found.`);
|
||||||
|
console.log('Use --list-users to see available users.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Found user '${user.username}' with ID ${userId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform migration
|
||||||
|
await migrateData(userId, args.dryRun);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('\nError:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
} finally {
|
||||||
|
await sequelize.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the script
|
||||||
|
if (require.main === module) {
|
||||||
|
main().catch(error => {
|
||||||
|
console.error('Fatal error:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { main, listUsers, migrateData, getStatistics };
|
||||||
Loading…
Reference in New Issue
Block a user