UNPKG

wp-host

Version:

Automated WordPress hosting deployment tool for bulk site creation with MySQL database management

1,045 lines โ€ข 50.8 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const commander_1 = require("commander"); const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const config_parser_1 = require("./config-parser"); const mysql_manager_1 = require("./mysql-manager"); const database_manager_1 = require("./database-manager"); const wordpress_manager_1 = require("./wordpress-manager"); const config_manager_1 = require("./config-manager"); const permissions_manager_1 = require("./permissions-manager"); const app_password_manager_1 = require("./app-password-manager"); const export_manager_1 = require("./export-manager"); const prompt_service_1 = require("./prompt-service"); const program = new commander_1.Command(); program .name("wp-hosting-automation") .description("WordPress Batch Hosting Tool - Deploy multiple WordPress sites with MySQL databases") .version("1.0.0"); program .command("deploy") .description("Deploy WordPress sites with interactive options") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("-v, --verbose", "Enable verbose logging") .option("--skip-prompts", "Skip interactive prompts (non-interactive mode)") .option("--app-passwords", "Generate application passwords automatically") .option("--export [path]", "Export deployment results to CSV") .option("--no-db-suffix", "Use site names as database names without _db suffix") .option("--use-existing-databases", "Use existing databases instead of dropping and recreating them") .action(async (options) => { const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); console.log("\n๐Ÿ’ก Create a configuration file with your site details:"); console.log(" - JSON format: sites.json"); console.log(" - CSV format: sites.csv"); process.exit(1); } try { // Set database suffix preference if (options.noDbSuffix) { config_parser_1.ConfigParser.setNoDbSuffix(true); } console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); if (options.verbose) { console.log(`โœ… Configuration loaded successfully:`); console.log(` - Found ${config.sites.length} site(s) to deploy`); console.log(` - MySQL: ${config.mysql.host}:${config.mysql.port}`); console.log(` - WordPress Admin: ${config.wordpress.adminEmail}`); } // Initialize prompt service const promptService = new prompt_service_1.PromptService(); // Get deployment options (interactive or from CLI flags) let deploymentOptions; if (options.skipPrompts) { deploymentOptions = { cleanAllDirectories: false, // Default to false for non-interactive mode generateAppPasswords: !!options.appPasswords, generateExport: !!options.export, exportPath: typeof options.export === "string" ? options.export : undefined, }; } else { deploymentOptions = await promptService.promptDeploymentOptions(); } // Show deployment preview and get confirmation if (!options.skipPrompts) { const confirmed = await promptService.promptDeploymentPreview(config.sites.length, deploymentOptions); if (!confirmed) { console.log("โŒ Deployment cancelled by user"); process.exit(0); } } console.log("\n๐Ÿ”„ Starting deployment process..."); // Step 1: Create databases console.log("\n๐Ÿ“Š Step 1: Creating databases and users..."); const databaseManager = new database_manager_1.DatabaseManager(config); await databaseManager.initialize(); const dbResults = await databaseManager.createAllDatabases(options.useExistingDatabases); const dbSummary = databaseManager.getSummary(dbResults); if (dbSummary.failed > 0) { console.error(`โŒ Database creation failed for ${dbSummary.failed} sites. Aborting deployment.`); await databaseManager.close(); process.exit(1); } console.log(`โœ… Databases created successfully (${dbSummary.successful}/${dbSummary.total})`); await databaseManager.close(); // Step 2: WordPress installation and setup console.log("\n๐ŸŒ Step 2: Installing and configuring WordPress..."); const wordpressManager = new wordpress_manager_1.WordPressManager(config); const wpResults = await wordpressManager.installAllSites(deploymentOptions.cleanAllDirectories); const wpSummary = wordpressManager.getSummary(wpResults); if (wpSummary.failed > 0) { console.error(`โŒ WordPress installation failed for ${wpSummary.failed} sites. Deployment incomplete.`); process.exit(1); } console.log(`โœ… WordPress installed and configured successfully (${wpSummary.successful}/${wpSummary.total})`); // Step 3: Set file permissions console.log("\n๐Ÿ”’ Step 3: Setting file permissions..."); const permissionsManager = new permissions_manager_1.PermissionsManager(config); const permissionResults = await permissionsManager.setAllPermissions(); const permissionSummary = permissionsManager.getSummary(permissionResults); if (permissionSummary.failed > 0) { console.error(`โŒ Permission setting failed for ${permissionSummary.failed} sites. Deployment incomplete.`); process.exit(1); } console.log(`โœ… File permissions set successfully (${permissionSummary.successful}/${permissionSummary.total})`); // Step 4: Generate application passwords (optional) let appPasswordResults; if (deploymentOptions.generateAppPasswords) { console.log("\n๐Ÿ”‘ Step 4: Generating application passwords..."); const appPasswordManager = new app_password_manager_1.AppPasswordManager(config); appPasswordResults = await appPasswordManager.generateAllAppPasswords(); appPasswordManager.displaySummary(appPasswordResults); } // Step 5: Export deployment results (optional) let exportPath; if (deploymentOptions.generateExport) { console.log("\n๐Ÿ“Š Step 5: Exporting deployment results..."); const exportManager = new export_manager_1.ExportManager(config); exportPath = await exportManager.generateDeploymentExport(wpResults, appPasswordResults, deploymentOptions.exportPath); } // Show completion summary const totalSuccessful = Math.min(dbSummary.successful, wpSummary.successful, permissionSummary.successful); promptService.displayCompletionSummary(totalSuccessful, config.sites.length, !!appPasswordResults, !!exportPath, exportPath); if (options.verbose) { console.log("\n๐Ÿ“‹ Detailed Results:"); for (const site of config.sites) { const siteResult = wpResults.find((r) => r.site_name === site.site_name); console.log(`\n๐Ÿ“ฆ Site: ${site.site_name}`); console.log(` Directory: ${site.directory_path}`); console.log(` Database: ${site.database_name}`); console.log(` DB User: ${site.db_user}`); console.log(` Admin User: ${site.wordpress_admin_username || "admin"}`); console.log(` Admin Email: ${config.wordpress.adminEmail}`); if (siteResult?.wordpress_info) { console.log(` Site URL: ${siteResult.wordpress_info.site_url}`); } if (appPasswordResults) { const appResult = appPasswordResults.find((r) => r.site_name === site.site_name); if (appResult) { console.log(` App Password: ${appResult.app_password}`); } } } } } catch (error) { console.error(`โŒ Configuration error: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("validate") .description("Validate configuration file without deploying") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("-v, --verbose", "Enable verbose logging") .option("--no-db-suffix", "Use site names as database names without _db suffix") .action(async (options) => { console.log("๐Ÿ” WordPress Configuration Validator"); console.log("==================================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { // Set database suffix preference if (options.noDbSuffix) { config_parser_1.ConfigParser.setNoDbSuffix(true); } console.log(`๐Ÿ“‹ Validating configuration: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); console.log("โœ… Configuration is valid!"); console.log(`\n๐Ÿ“Š Summary:`); console.log(` - Sites to deploy: ${config.sites.length}`); console.log(` - MySQL: ${config.mysql.host}:${config.mysql.port}`); console.log(` - WordPress Admin: ${config.wordpress.adminEmail}`); if (options.verbose) { console.log("\n๐Ÿ“‹ Site Details:"); config.sites.forEach((site, index) => { console.log(` ${index + 1}. ${site.site_name}`); console.log(` Path: ${site.directory_path}`); console.log(` Database: ${site.database_name}`); if (site.db_user) console.log(` DB User: ${site.db_user}`); }); console.log("\n๐Ÿ—„๏ธ MySQL Configuration:"); console.log(` Host: ${config.mysql.host}`); console.log(` Port: ${config.mysql.port}`); console.log(` Root User: ${config.mysql.rootUser}`); console.log(` Root Password: ${"*".repeat(config.mysql.rootPassword.length)}`); console.log(` Shared DB Password: ${"*".repeat(config.mysql.sharedDbPassword.length)}`); console.log("\n๐ŸŒ WordPress Configuration:"); console.log(` Admin Email: ${config.wordpress.adminEmail}`); console.log(` Admin Password: ${"*".repeat(config.wordpress.adminPassword.length)}`); } } catch (error) { console.error(`โŒ Validation failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("test-connection") .description("Test MySQL connection using configuration file") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .action(async (options) => { console.log("๐Ÿงช MySQL Connection Tester"); console.log("=========================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading MySQL configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); const mysqlManager = new mysql_manager_1.MySQLManager(config.mysql); // Test connection const isConnected = await mysqlManager.testConnection(); if (isConnected) { // Get server info if connection successful await mysqlManager.connect(); const serverInfo = await mysqlManager.getServerInfo(); await mysqlManager.disconnect(); console.log("\n๐Ÿ“Š MySQL Server Information:"); console.log(` Version: ${serverInfo.version}`); console.log(` Host: ${serverInfo.host}:${serverInfo.port}`); console.log("\nโœ… MySQL connection is working correctly!"); console.log("๐Ÿš€ You can now run deployment commands."); } else { console.log("\nโŒ MySQL connection failed!"); console.log("๐Ÿ’ก Please check:"); console.log(" - MySQL server is running"); console.log(" - Host and port are correct"); console.log(" - Root username and password are correct"); process.exit(1); } } catch (error) { console.error(`โŒ Connection test failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("create-databases") .description("Create MySQL databases and users for all sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("-v, --verbose", "Enable verbose logging") .option("--no-db-suffix", "Use site names as database names without _db suffix") .option("--use-existing-databases", "Use existing databases instead of dropping and recreating them") .action(async (options) => { console.log("๐Ÿ—„๏ธ WordPress Database Creator"); console.log("=============================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } let databaseManager = null; try { // Set database suffix preference if (options.noDbSuffix) { config_parser_1.ConfigParser.setNoDbSuffix(true); } console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); if (options.verbose) { console.log(`โœ… Configuration loaded: ${config.sites.length} site(s) found`); } // Initialize database manager databaseManager = new database_manager_1.DatabaseManager(config); await databaseManager.initialize(); // Create all databases const results = await databaseManager.createAllDatabases(options.useExistingDatabases); // Show summary const summary = databaseManager.getSummary(results); console.log("\n๐Ÿ“Š Database Creation Summary"); console.log("============================"); console.log(`Total Sites: ${summary.total}`); console.log(`โœ… Successful: ${summary.successful}`); console.log(`โŒ Failed: ${summary.failed}`); console.log(`โญ๏ธ Skipped: ${summary.skipped}`); if (summary.failed > 0) { console.log("\nโš ๏ธ Some databases failed to create. Check the errors above."); process.exit(1); } else { console.log("\n๐ŸŽ‰ All databases created successfully!"); console.log("โœ… Ready for WordPress installation."); } } catch (error) { console.error(`โŒ Database creation failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } finally { if (databaseManager) { await databaseManager.close(); } } }); program .command("check-databases") .description("Check status of databases and users for all sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("--no-db-suffix", "Use site names as database names without _db suffix") .action(async (options) => { console.log("๐Ÿ” WordPress Database Status Checker"); console.log("===================================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } let databaseManager = null; try { // Set database suffix preference if (options.noDbSuffix) { config_parser_1.ConfigParser.setNoDbSuffix(true); } console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize database manager databaseManager = new database_manager_1.DatabaseManager(config); await databaseManager.initialize(); // Generate report await databaseManager.generateReport(); } catch (error) { console.error(`โŒ Database check failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } finally { if (databaseManager) { await databaseManager.close(); } } }); program .command("reset-wordpress") .description("Reset WordPress tables in databases (keeps databases and users intact)") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("--confirm", "Skip confirmation prompt") .action(async (options) => { console.log("๐Ÿ”„ WordPress Table Reset"); console.log("========================"); console.log("โš ๏ธ WARNING: This will delete all WordPress data but keep databases and users!"); if (!options.confirm) { console.log("\nโŒ This is a destructive operation. Use --confirm flag to proceed."); console.log("Example: wp-hosting-automation reset-wordpress --confirm"); process.exit(1); } const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } let databaseManager = null; try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize database manager databaseManager = new database_manager_1.DatabaseManager(config); await databaseManager.initialize(); // Reset WordPress tables await databaseManager.resetWordPressTables(); console.log("\nโœ… WordPress reset completed successfully!"); console.log("๐Ÿš€ You can now run deployment again for a fresh WordPress setup."); } catch (error) { console.error(`โŒ WordPress reset failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } finally { if (databaseManager) { await databaseManager.close(); } } }); program .command("cleanup-databases") .description("Remove all databases and users (WARNING: DESTRUCTIVE!)") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("--confirm", "Skip confirmation prompt") .option("--no-db-suffix", "Use site names as database names without _db suffix") .action(async (options) => { console.log("๐Ÿงน WordPress Database Cleanup"); console.log("============================="); console.log("โš ๏ธ WARNING: This will permanently delete all databases and users!"); if (!options.confirm) { console.log("\nโŒ This is a destructive operation. Use --confirm flag to proceed."); console.log("Example: wp-hosting-automation cleanup-databases --confirm"); process.exit(1); } const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } let databaseManager = null; try { // Set database suffix preference if (options.noDbSuffix) { config_parser_1.ConfigParser.setNoDbSuffix(true); } console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize database manager databaseManager = new database_manager_1.DatabaseManager(config); await databaseManager.initialize(); // Cleanup all databases await databaseManager.cleanupAllDatabases(); } catch (error) { console.error(`โŒ Database cleanup failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } finally { if (databaseManager) { await databaseManager.close(); } } }); program .command("install-wordpress") .description("Download and install WordPress for all sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("-v, --verbose", "Enable verbose logging") .action(async (options) => { console.log("๐ŸŒ WordPress Installer"); console.log("======================"); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } let wordpressManager = null; try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); if (options.verbose) { console.log(`โœ… Configuration loaded: ${config.sites.length} site(s) found`); } // Initialize WordPress manager wordpressManager = new wordpress_manager_1.WordPressManager(config); // Install WordPress for all sites const results = await wordpressManager.installAllSites(); // Show summary const summary = wordpressManager.getSummary(results); console.log("\n๐Ÿ“Š WordPress Installation Summary"); console.log("=================================="); console.log(`Total Sites: ${summary.total}`); console.log(`โœ… Successful: ${summary.successful}`); console.log(`โŒ Failed: ${summary.failed}`); console.log(`โญ๏ธ Skipped: ${summary.skipped}`); if (summary.failed > 0) { console.log("\nโš ๏ธ Some WordPress installations failed. Check the errors above."); process.exit(1); } else { console.log("\n๐ŸŽ‰ All WordPress installations completed successfully!"); console.log("โœ… Ready for configuration."); } } catch (error) { console.error(`โŒ WordPress installation failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("check-wordpress") .description("Check status of WordPress installations for all sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .action(async (options) => { console.log("๐Ÿ” WordPress Status Checker"); console.log("==========================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize WordPress manager const wordpressManager = new wordpress_manager_1.WordPressManager(config); // Generate report await wordpressManager.generateReport(); } catch (error) { console.error(`โŒ WordPress check failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("cleanup-wordpress") .description("Remove all WordPress installations (WARNING: DESTRUCTIVE!)") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("--confirm", "Skip confirmation prompt") .action(async (options) => { console.log("๐Ÿงน WordPress Cleanup"); console.log("===================="); console.log("โš ๏ธ WARNING: This will permanently delete all WordPress installations!"); if (!options.confirm) { console.log("\nโŒ This is a destructive operation. Use --confirm flag to proceed."); console.log("Example: wp-hosting-automation cleanup-wordpress --confirm"); process.exit(1); } const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize WordPress manager const wordpressManager = new wordpress_manager_1.WordPressManager(config); // Cleanup all installations await wordpressManager.cleanupAllInstallations(); } catch (error) { console.error(`โŒ WordPress cleanup failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("generate-config") .description("Generate wp-config.php files for all sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("-v, --verbose", "Enable verbose logging") .action(async (options) => { console.log("โš™๏ธ WordPress Configuration Generator"); console.log("===================================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); if (options.verbose) { console.log(`โœ… Configuration loaded: ${config.sites.length} site(s) found`); } // Initialize config manager const configManager = new config_manager_1.ConfigManager(config); // Generate wp-config.php for all sites const results = await configManager.generateAllConfigs(); // Show summary const summary = configManager.getSummary(results); console.log("\n๐Ÿ“Š wp-config.php Generation Summary"); console.log("==================================="); console.log(`Total Sites: ${summary.total}`); console.log(`โœ… Successful: ${summary.successful}`); console.log(`โŒ Failed: ${summary.failed}`); console.log(`โญ๏ธ Skipped: ${summary.skipped}`); if (summary.failed > 0) { console.log("\nโš ๏ธ Some wp-config.php files failed to generate. Check the errors above."); process.exit(1); } else { console.log("\n๐ŸŽ‰ All wp-config.php files generated successfully!"); console.log("โœ… WordPress sites are ready to use."); } } catch (error) { console.error(`โŒ Configuration generation failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("check-config") .description("Check status of wp-config.php files for all sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .action(async (options) => { console.log("๐Ÿ” wp-config.php Status Checker"); console.log("================================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize config manager const configManager = new config_manager_1.ConfigManager(config); // Generate report await configManager.checkAllConfigs(); } catch (error) { console.error(`โŒ Configuration check failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("cleanup-config") .description("Remove all wp-config.php files (WARNING: DESTRUCTIVE!)") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("--confirm", "Skip confirmation prompt") .action(async (options) => { console.log("๐Ÿงน wp-config.php Cleanup"); console.log("========================="); console.log("โš ๏ธ WARNING: This will permanently delete all wp-config.php files!"); if (!options.confirm) { console.log("\nโŒ This is a destructive operation. Use --confirm flag to proceed."); console.log("Example: wp-hosting-automation cleanup-config --confirm"); process.exit(1); } const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize config manager const configManager = new config_manager_1.ConfigManager(config); // Cleanup all configurations await configManager.cleanupAllConfigs(); } catch (error) { console.error(`โŒ Configuration cleanup failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("set-permissions") .description("Set appropriate file permissions for all WordPress sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("-v, --verbose", "Enable verbose logging") .action(async (options) => { console.log("๐Ÿ”’ WordPress Permissions Manager"); console.log("================================"); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); if (options.verbose) { console.log(`โœ… Configuration loaded: ${config.sites.length} site(s) found`); } // Initialize permissions manager const permissionsManager = new permissions_manager_1.PermissionsManager(config); // Set permissions for all sites const results = await permissionsManager.setAllPermissions(); // Show summary const summary = permissionsManager.getSummary(results); console.log("\n๐Ÿ“Š Permissions Setting Summary"); console.log("=============================="); console.log(`Total Sites: ${summary.total}`); console.log(`โœ… Successful: ${summary.successful}`); console.log(`โŒ Failed: ${summary.failed}`); if (summary.failed > 0) { console.log("\nโš ๏ธ Some sites failed permission setting. Check the errors above."); process.exit(1); } else { console.log("\n๐ŸŽ‰ All file permissions set successfully!"); console.log("โœ… WordPress sites are properly secured."); } } catch (error) { console.error(`โŒ Permission setting failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("check-permissions") .description("Check file permissions status for all WordPress sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .action(async (options) => { console.log("๐Ÿ” WordPress Permissions Checker"); console.log("================================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize permissions manager const permissionsManager = new permissions_manager_1.PermissionsManager(config); // Generate report await permissionsManager.checkAllPermissions(); } catch (error) { console.error(`โŒ Permission check failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("fix-permissions") .description("Fix file permissions for all WordPress sites") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .action(async (options) => { console.log("๐Ÿ”ง WordPress Permissions Fixer"); console.log("==============================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize permissions manager const permissionsManager = new permissions_manager_1.PermissionsManager(config); // Fix all permissions await permissionsManager.fixAllPermissions(); } catch (error) { console.error(`โŒ Permission fix failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("generate-app-passwords") .description("Generate WordPress application passwords for API access") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .action(async (options) => { console.log("๐Ÿ”‘ WordPress Application Password Generator"); console.log("==========================================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize app password manager const appPasswordManager = new app_password_manager_1.AppPasswordManager(config); // Generate application passwords const results = await appPasswordManager.generateAllAppPasswords(); appPasswordManager.displaySummary(results); } catch (error) { console.error(`โŒ Application password generation failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("export-deployment") .description("Export deployment information to CSV spreadsheet") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("-o, --output <file>", "Export file path (must end with .csv)") .option("--include-app-passwords", "Include application passwords in export") .action(async (options) => { console.log("๐Ÿ“Š Deployment Export Generator"); console.log("=============================="); const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize export manager const exportManager = new export_manager_1.ExportManager(config); // Mock deployment results (since this is a standalone export) const mockResults = config.sites.map((site) => ({ site_name: site.site_name, status: "success", wordpress_path: site.directory_path, wordpress_info: { site_url: exportManager["generateSiteUrl"](site.directory_path), admin_user: site.wordpress_admin_username || "admin", admin_password: config.wordpress.adminPassword, admin_email: config.wordpress.adminEmail, }, })); // Generate app passwords if requested let appPasswordResults; if (options.includeAppPasswords) { console.log("\n๐Ÿ”‘ Generating application passwords for export..."); const appPasswordManager = new app_password_manager_1.AppPasswordManager(config); appPasswordResults = await appPasswordManager.generateAllAppPasswords(); } // Generate export const exportPath = await exportManager.generateDeploymentExport(mockResults, appPasswordResults, options.output); console.log("\nโœ… Export completed successfully!"); console.log(`๐Ÿ“ File saved to: ${exportPath}`); } catch (error) { console.error(`โŒ Export failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("update-permalinks") .description("Update permalink structure for existing WordPress sites (for wp-json API support)") .option("-c, --config <file>", "Configuration file path (JSON or CSV)") .option("-s, --structure <structure>", "Permalink structure pattern", "/%postname%/") .option("--confirm", "Skip confirmation prompt") .action(async (options) => { console.log("๐Ÿ”— WordPress Permalink Structure Updater"); console.log("========================================"); console.log(`๐Ÿ“ New structure: ${options.structure}`); // Auto-detect configuration file if not specified let configPath; if (options.config) { configPath = path.resolve(options.config); } else { // CSV-first approach: look for CSV files first, then JSON const possibleFiles = ["sites.csv", "template.csv", "sites.json"]; let foundFile = null; for (const file of possibleFiles) { if (await fs.pathExists(file)) { foundFile = file; break; } } if (!foundFile) { console.error("โŒ No configuration file found."); console.error("๐Ÿ’ก Please create sites.csv or specify a file with -c flag"); console.error(" Example: wp-host update-permalinks -c my-sites.csv"); process.exit(1); } configPath = path.resolve(foundFile); } if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); console.error("๐Ÿ’ก Make sure the file exists or use -c flag to specify a different file"); process.exit(1); } try { console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Interactive confirmation if --confirm flag not provided if (!options.confirm) { console.log("\nโš ๏ธ This will update the permalink structure for all sites in your configuration."); console.log(" This operation is designed for existing WordPress installations."); console.log(" It uses WP-CLI to safely update permalinks and flush rewrite rules."); console.log(`\n๐Ÿ“Š Sites to update: ${config.sites.length}`); console.log(`๐Ÿ”— New permalink structure: ${options.structure}`); const { PromptService } = await Promise.resolve().then(() => __importStar(require("./prompt-service"))); const promptService = new PromptService(); const shouldProceed = await promptService.promptConfirmation("Do you want to proceed with updating permalinks?", [ "Update permalink structure for all configured sites", "Use WP-CLI to safely modify WordPress settings", "Flush rewrite rules to ensure changes take effect", ], false); if (!shouldProceed) { console.log("\nโŒ Operation cancelled by user."); process.exit(0); } } // Initialize WordPress manager const wordpressManager = new wordpress_manager_1.WordPressManager(config); // Update permalinks for all sites const results = await wordpressManager.updateAllPermalinks(options.structure); const summary = wordpressManager.getSummary(results); if (summary.failed > 0) { console.log("\nโš ๏ธ Some sites failed to update. Check the errors above."); console.log("๐Ÿ’ก Note: This only works on existing WordPress installations with WP-CLI."); process.exit(1); } else if (summary.successful === 0) { console.log("\nโš ๏ธ No sites were updated."); console.log("๐Ÿ’ก Make sure your sites have WordPress installed and configured."); process.exit(1); } else { console.log("\n๐ŸŽ‰ Permalink structure updated successfully!"); console.log(`โœ… ${summary.successful} sites now use: ${options.structure}`); console.log("\n๐Ÿ’ก Your wp-json API endpoints should now work properly."); console.log(" Example: https://yoursite.com/wp-json/wp/v2/posts"); } } catch (error) { console.error(`โŒ Permalink update failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); program .command("cleanup-nosuffix-databases") .description("Remove databases created without _db suffix (for fixing accidental creation)") .option("-c, --config <file>", "Configuration file path (JSON or CSV)", "sites.json") .option("--confirm", "Skip confirmation prompt") .action(async (options) => { console.log("๐Ÿงน WordPress Database Cleanup (No Suffix)"); console.log("========================================="); console.log("โš ๏ธ WARNING: This will remove databases created WITHOUT _db suffix!"); console.log(" This is for cleaning up accidentally created databases."); console.log(" Your actual databases with _db suffix will NOT be touched."); if (!options.confirm) { console.log("\nโŒ This is a destructive operation. Use --confirm flag to proceed."); console.log("Example: wp-host cleanup-nosuffix-databases --confirm"); process.exit(1); } const configPath = path.resolve(options.config); if (!(await fs.pathExists(configPath))) { console.error(`โŒ Configuration file not found: ${configPath}`); process.exit(1); } let mysqlManager = null; try { // IMPORTANT: Set no-db-suffix to true to target databases without suffix config_parser_1.ConfigParser.setNoDbSuffix(true); console.log(`๐Ÿ“‹ Reading configuration from: ${configPath}`); const config = await config_parser_1.ConfigParser.parseConfig(configPath); // Initialize MySQL manager directly mysqlManager = new mysql_manager_1.MySQLManager(config.mysql); await mysqlManager.connect(); console.log("\n๐Ÿ” Cleaning up databases without _db suffix..."); let cleanedCount = 0; for (const site of config.sites) { const databaseName = site.site_name; // This should NOT have _db suffix try { // Check if database exists (without _db suffix) const dbExists = await mysqlManager.databaseExists(databaseName); if (dbExists) { console.log(`\n๐Ÿ—‘๏ธ Found database without suffix: ${databaseName}`); // Drop the database await mysqlManager.executeQuery(`DROP DATABASE IF EXISTS \`${databaseName}\``); console.log(` โœ… Dropped database: ${databaseName}`); // Also try to drop associated user const username = `${site.site_name}_user`; await mysqlManager.executeQuery(`DROP USER IF EXISTS \`${username}\`@\`localhost\``); console.log(` โœ… Dropped user: ${username}@localhost`); cleanedCount++; } } catch (error) { console.error(` โŒ Error cleaning up ${site.site_name}: ${error instanceof Error ? error.message : String(error)}`); } } // Flush privileges after cleanup await mysqlManager.executeQuery("FLUSH PRIVILEGES"); if (cleanedCount > 0) { console.log(`\nโœ… Cleanup completed. Removed ${cleanedCount} databases without _db suffix.`); console.log("๐Ÿš€ You can now use regular commands to work with your _db suffixed databases."); } else { console.log("\nโœ… No databases without _db suffix found. Nothing to clean up."); } } catch (error) { console.error(`โŒ Database cleanup failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } finally { if (mysqlManager) { await mysqlManager.disconnect(); } } }); // Add help examples program.on("--help", () => { console.log(""); console.log("Examples:"); console.log(" # Validation and testing"); console.log(" $ wp-hosting-automation validate"); console.log(" $ wp-hosting-automation test-connection"); console.log(""); console.log(" # Full deployment (interactive)"); console.log(" $ wp-hosting-automation deploy"); console.log(" $ wp-hosting-automation deploy -c my-sites.csv -v"); console.log(""); console.log(" # Non-interactive deployment with options"); console.log(" $ wp-hosting-automation deploy --skip-prompts --app-passwords --export"); console.log(" $ wp-hosting-automation deploy --skip-prompts --export /path/to/results.csv"); console.log(""); console.log(" # Individual operations"); console.log(" $ wp-hosting-automation create-databases"); console.log(" $ wp-hosting-automation install-wordpress"); console.log(" $ wp-hosting-automation generate-config"); console.log(" $ wp-hosting-automation set-permissions"); console.log(""); console.log(" # Optional features"); console.log(" $ wp-hosting-automation generate-app-passwords"); console.log(" $ wp-hosting-automation export-deployment --include-app-passwords"); console.log(" $ wp-hosting-automation export-deployment -o my-deployment.csv"); console.log(""); console.log(" # Update existing sites"); console.log(" $ wp-hosting-automation update-permalinks --confirm"); console.log(' $ wp-hosting-automation update-permalinks --structure="/%year%/%postname%/" --confirm'); console.log(""); console.log(" # Status checking"); console.log(" $ wp-hosting-automation check-databases"); console.log(" $ wp-hosting-automation check-wordpress"); console.log(" $ wp-hosting-automation check-config"); console.log(" $ wp-hosting-automation check-permissions"); console.log(""); console.log(" # Database suffix management"); console.log(" $ wp-hosting-automation deploy --no-db-suffix # Use site names without _db suffix"); console.log(" $ wp-hosting-automation cleanup-nosuffix-databases --confirm # Clean up databases without _db suffix"); console.log(""); console.log(" # Using existing databases (for migrations)"); console.log(" $ wp-hosting-automation deploy --use-existing-databases # Use existing databases without dropping"); console.log(" $ wp-hosting-automation create-databases --use-existing-databases # Setup users for existing DBs"); console.log(""); console.log("Configuration file formats:"); console.log(" ๐Ÿ“„ CSV (recommended): Use template.csv for user-friendly column headers"); console.log(' ๐Ÿ“„ JSON: { "mysql": {...}, "wordpress": {...}, "sites": [...] }'); console.log(""); console.log("Features:"); console.log(" ๐Ÿ”ง Complete WordPress automation (databases + installation + con