mirror of
https://github.com/whyour/qinglong.git
synced 2025-12-13 07:25:05 +08:00
318 lines
8.3 KiB
JavaScript
Executable File
318 lines
8.3 KiB
JavaScript
Executable File
#!/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 };
|