UNPKG

wp-host

Version:

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

485 lines 18.7 kB
"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 }); exports.ConfigParser = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); class ConfigParser { /** * Parse configuration file (JSON or CSV) */ static async parseConfig(configPath) { const ext = path.extname(configPath).toLowerCase(); if (ext === '.json') { return this.parseJsonConfig(configPath); } else if (ext === '.csv') { return this.parseCsvConfig(configPath); } else { throw new Error(`Unsupported configuration file format: ${ext}. Supported formats: .json, .csv`); } } /** * Parse JSON configuration file */ static async parseJsonConfig(configPath) { try { const content = await fs.readFile(configPath, 'utf-8'); const config = JSON.parse(content); // Auto-generate missing database names and users this.autoGenerateDbInfo(config); this.validateConfig(config); return config; } catch (error) { if (error instanceof SyntaxError) { throw new Error(`Invalid JSON in configuration file: ${error.message}`); } throw error; } } /** * Parse CSV configuration file */ static async parseCsvConfig(configPath) { try { const content = await fs.readFile(configPath, 'utf-8'); const lines = content.trim().split('\n'); if (lines.length < 2) { throw new Error('CSV file must have at least a header row and one data row'); } const headers = lines[0].split(',').map(h => h.trim()); // Check if this is the comprehensive format (includes MySQL and WordPress config) const isComprehensiveFormat = headers.some(h => h.toLowerCase() === 'mysql host' || h === 'mysql_host') && headers.some(h => h.toLowerCase() === 'wordpress admin password' || h === 'wordpress_admin_password'); if (isComprehensiveFormat) { return this.parseComprehensiveCSV(lines, headers); } else { return this.parseSimpleCSV(lines, headers); } } catch (error) { throw new Error(`Error parsing CSV file: ${error instanceof Error ? error.message : String(error)}`); } } /** * Parse comprehensive CSV format with all configuration included */ static parseComprehensiveCSV(lines, headers) { // Create header mapping for both technical and user-friendly headers const headerMap = this.createHeaderMap(headers); const requiredFields = [ 'site_name', 'directory_path', 'wordpress_site_title', 'wordpress_admin_username', 'mysql_host', 'mysql_port', 'mysql_root_user', 'mysql_root_password', 'mysql_shared_db_password', 'wordpress_admin_password', 'wordpress_admin_email' ]; // Check for required headers (using mapped names) for (const required of requiredFields) { if (!headerMap[required]) { throw new Error(`Missing required CSV header: ${required} (or its user-friendly equivalent)`); } } const sites = []; let mysqlConfig = null; let wordpressConfig = null; for (let i = 1; i < lines.length; i++) { const values = lines[i].split(',').map(v => v.trim()); if (values.length !== headers.length) { throw new Error(`Row ${i + 1}: Expected ${headers.length} columns, got ${values.length}`); } const row = {}; headers.forEach((header, index) => { row[header] = values[index]; }); // Map headers to standardized field names const mappedRow = this.mapRowData(row, headerMap); // Extract MySQL config from first row (assuming all rows have same config) if (!mysqlConfig) { mysqlConfig = { host: mappedRow.mysql_host, port: parseInt(mappedRow.mysql_port), rootUser: mappedRow.mysql_root_user, rootPassword: mappedRow.mysql_root_password, sharedDbPassword: mappedRow.mysql_shared_db_password }; } // Extract WordPress config from first row (shared settings) if (!wordpressConfig) { wordpressConfig = { adminPassword: mappedRow.wordpress_admin_password, adminEmail: mappedRow.wordpress_admin_email, adminUsername: 'admin', // Default, will be overridden per site siteTitle: 'WordPress Site' // Default, will be overridden per site }; } // Create site config with per-site WordPress settings const site = { site_name: mappedRow.site_name, directory_path: mappedRow.directory_path, database_name: `${mappedRow.site_name}_db`, db_user: `${mappedRow.site_name}_user`, wordpress_site_title: mappedRow.wordpress_site_title, wordpress_admin_username: mappedRow.wordpress_admin_username }; sites.push(site); } const config = { mysql: mysqlConfig, wordpress: wordpressConfig, sites }; this.validateConfig(config); return config; } /** * Parse simple CSV format (legacy support - requires environment variables) */ static parseSimpleCSV(lines, headers) { const requiredHeaders = ['site_name', 'directory_path']; // Validate headers for (const required of requiredHeaders) { if (!headers.includes(required)) { throw new Error(`Missing required CSV header: ${required}`); } } const sites = []; for (let i = 1; i < lines.length; i++) { const values = lines[i].split(',').map(v => v.trim()); if (values.length !== headers.length) { throw new Error(`Row ${i + 1}: Expected ${headers.length} columns, got ${values.length}`); } const site = { site_name: '', directory_path: '' }; headers.forEach((header, index) => { const value = values[index]; switch (header) { case 'site_name': site.site_name = value; break; case 'directory_path': site.directory_path = value; break; case 'database_name': site.database_name = value; break; case 'db_user': site.db_user = value; break; } }); sites.push(site); } // For simple CSV, use default or environment-based config const config = { mysql: this.getDefaultMySQLConfig(), wordpress: this.getDefaultWordPressConfig(), sites }; // Auto-generate missing database names and users this.autoGenerateDbInfo(config); this.validateConfig(config); return config; } /** * Auto-generate database names and users if not provided */ static autoGenerateDbInfo(config) { config.sites.forEach(site => { // Auto-generate database name if not provided if (!site.database_name) { site.database_name = `${site.site_name}_db`; } // Auto-generate database user if not provided if (!site.db_user) { site.db_user = `${site.site_name}_user`; } }); } /** * Create header mapping for both technical and user-friendly headers */ static createHeaderMap(headers) { const headerMap = {}; // Header mapping from user-friendly to technical names const mappings = { 'Site Name': 'site_name', 'site_name': 'site_name', 'Directory Path': 'directory_path', 'directory_path': 'directory_path', 'MySQL Host': 'mysql_host', 'mysql_host': 'mysql_host', 'MySQL Port': 'mysql_port', 'mysql_port': 'mysql_port', 'MySQL Username': 'mysql_root_user', 'mysql_root_user': 'mysql_root_user', 'MySQL Password': 'mysql_root_password', 'mysql_root_password': 'mysql_root_password', 'Database Password': 'mysql_shared_db_password', 'mysql_shared_db_password': 'mysql_shared_db_password', 'WordPress Site Title': 'wordpress_site_title', 'wordpress_site_title': 'wordpress_site_title', 'WordPress Admin Username': 'wordpress_admin_username', 'wordpress_admin_username': 'wordpress_admin_username', 'WordPress Admin Password': 'wordpress_admin_password', 'wordpress_admin_password': 'wordpress_admin_password', 'WordPress Admin Email': 'wordpress_admin_email', 'wordpress_admin_email': 'wordpress_admin_email' }; // Create reverse mapping from technical names to actual headers headers.forEach(header => { const technicalName = mappings[header]; if (technicalName) { headerMap[technicalName] = header; } }); return headerMap; } /** * Map row data using header mapping */ static mapRowData(row, headerMap) { const mappedRow = {}; Object.keys(headerMap).forEach(technicalName => { const actualHeader = headerMap[technicalName]; mappedRow[technicalName] = row[actualHeader]; }); return mappedRow; } /** * Validate configuration structure and data */ static validateConfig(config) { const errors = []; // Validate MySQL config is provided if (!config.mysql) { errors.push({ field: 'mysql', message: 'MySQL configuration is required' }); } else { this.validateMySQLConfig(config.mysql, errors); } // Validate WordPress config is provided if (!config.wordpress) { errors.push({ field: 'wordpress', message: 'WordPress configuration is required' }); } else { this.validateWordPressConfig(config.wordpress, errors); } // Validate sites array exists if (!config.sites || !Array.isArray(config.sites)) { errors.push({ field: 'sites', message: 'Configuration must contain a "sites" array' }); throw new Error(`Configuration validation failed:\n${errors.map(e => `- ${e.field}: ${e.message}`).join('\n')}`); } // Validate sites array is not empty if (config.sites.length === 0) { errors.push({ field: 'sites', message: 'Sites array cannot be empty' }); } // Validate each site configuration config.sites.forEach((site, index) => { this.validateSiteConfig(site, index, errors); }); // Check for duplicate site names and database names this.checkDuplicates(config.sites, errors); if (errors.length > 0) { throw new Error(`Configuration validation failed:\n${errors.map(e => e.siteIndex !== undefined ? `- Site ${e.siteIndex + 1} (${e.field}): ${e.message}` : `- ${e.field}: ${e.message}`).join('\n')}`); } } /** * Validate individual site configuration */ static validateSiteConfig(site, index, errors) { // Required fields if (!site.site_name || site.site_name.trim() === '') { errors.push({ field: 'site_name', message: 'Site name is required and cannot be empty', siteIndex: index }); } if (!site.directory_path || site.directory_path.trim() === '') { errors.push({ field: 'directory_path', message: 'Directory path is required and cannot be empty', siteIndex: index }); } // Validate site name format (alphanumeric, underscore, hyphen) if (site.site_name && !/^[a-zA-Z0-9_-]+$/.test(site.site_name)) { errors.push({ field: 'site_name', message: 'Site name can only contain letters, numbers, underscores, and hyphens', siteIndex: index }); } // Validate database name format (MySQL naming rules) - auto-generated, so should be valid if (site.database_name && !/^[a-zA-Z0-9_]+$/.test(site.database_name)) { errors.push({ field: 'database_name', message: 'Database name can only contain letters, numbers, and underscores', siteIndex: index }); } } /** * Validate MySQL configuration */ static validateMySQLConfig(mysql, errors) { if (!mysql.host || mysql.host.trim() === '') { errors.push({ field: 'mysql.host', message: 'MySQL host is required' }); } if (!mysql.port || mysql.port < 1 || mysql.port > 65535) { errors.push({ field: 'mysql.port', message: 'MySQL port must be between 1 and 65535' }); } if (!mysql.rootUser || mysql.rootUser.trim() === '') { errors.push({ field: 'mysql.rootUser', message: 'MySQL root user is required' }); } if (!mysql.rootPassword || mysql.rootPassword.trim() === '') { errors.push({ field: 'mysql.rootPassword', message: 'MySQL root password is required' }); } if (!mysql.sharedDbPassword || mysql.sharedDbPassword.trim() === '') { errors.push({ field: 'mysql.sharedDbPassword', message: 'Shared database password is required' }); } } /** * Validate WordPress configuration */ static validateWordPressConfig(wordpress, errors) { if (!wordpress.adminPassword || wordpress.adminPassword.trim() === '') { errors.push({ field: 'wordpress.adminPassword', message: 'WordPress admin password is required' }); } if (!wordpress.adminEmail || wordpress.adminEmail.trim() === '') { errors.push({ field: 'wordpress.adminEmail', message: 'WordPress admin email is required' }); } // Validate email format if (wordpress.adminEmail && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(wordpress.adminEmail)) { errors.push({ field: 'wordpress.adminEmail', message: 'Invalid email format' }); } } /** * Check for duplicate site names and database names */ static checkDuplicates(sites, errors) { const siteNames = new Set(); const dbNames = new Set(); sites.forEach((site, index) => { if (siteNames.has(site.site_name)) { errors.push({ field: 'site_name', message: `Duplicate site name: ${site.site_name}`, siteIndex: index }); } else { siteNames.add(site.site_name); } if (site.database_name && dbNames.has(site.database_name)) { errors.push({ field: 'database_name', message: `Duplicate database name: ${site.database_name}`, siteIndex: index }); } else if (site.database_name) { dbNames.add(site.database_name); } }); } /** * Get default MySQL configuration */ static getDefaultMySQLConfig() { return { host: 'localhost', port: 3306, rootUser: 'root', rootPassword: 'your_mysql_root_password', sharedDbPassword: 'shared_db_password_123' }; } /** * Get default WordPress configuration */ static getDefaultWordPressConfig() { return { adminPassword: 'wp_admin_password_123', adminEmail: 'admin@example.com', adminUsername: 'admin', siteTitle: 'My WordPress Site' }; } } exports.ConfigParser = ConfigParser; //# sourceMappingURL=config-parser.js.map