Major additions: - Web-based setup wizard (setup.php, setup_wizard.php, setup-wizard.js) - Production Docker configuration (docker-compose.prod.yml, .env.production) - Database initialization SQL files (deploy/init_settings.sql) - Template builder system with drag-and-drop UI - Advanced features (OAuth, CDN, enhanced analytics, monetization) - Comprehensive documentation (deployment guides, quick start, feature docs) - Design system with accessibility and responsive layout - Deployment automation scripts (deploy.ps1, generate-secrets.ps1) Setup wizard allows customization of: - Platform name and branding - Domain configuration - Membership tiers and pricing - Admin credentials - Feature toggles Database includes 270+ tables for complete video streaming platform with advanced features for analytics, moderation, template building, and monetization. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
306 lines
12 KiB
PHP
306 lines
12 KiB
PHP
<?php
|
|
/*******************************************************************************************************************
|
|
| Software Name : EasyStream - Setup Wizard Backend
|
|
| Software Description : Handles setup wizard logic and database configuration
|
|
| Software Author : (c) Sami Ahmed
|
|
|*******************************************************************************************************************/
|
|
|
|
class SetupWizard {
|
|
private $pdo;
|
|
private $config;
|
|
|
|
public function __construct() {
|
|
$this->loadDatabaseConnection();
|
|
$this->config = [];
|
|
}
|
|
|
|
private function loadDatabaseConnection() {
|
|
try {
|
|
$db_host = getenv('DB_HOST') ?: 'db';
|
|
$db_name = getenv('DB_NAME') ?: 'easystream';
|
|
$db_user = getenv('DB_USER') ?: 'easystream';
|
|
$db_pass = getenv('DB_PASS') ?: 'easystream';
|
|
|
|
$this->pdo = new PDO(
|
|
"mysql:host=$db_host;dbname=$db_name;charset=utf8mb4",
|
|
$db_user,
|
|
$db_pass,
|
|
[
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
PDO::ATTR_EMULATE_PREPARES => false
|
|
]
|
|
);
|
|
} catch (PDOException $e) {
|
|
error_log("Setup Wizard DB Connection Error: " . $e->getMessage());
|
|
throw new Exception("Database connection failed. Please check your configuration.");
|
|
}
|
|
}
|
|
|
|
public function testDatabaseConnection($data) {
|
|
try {
|
|
// Test if tables exist
|
|
$stmt = $this->pdo->query("SHOW TABLES");
|
|
$tables = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
$tableCount = count($tables);
|
|
|
|
// Check if db_settings table exists
|
|
$hasSettings = in_array('db_settings', $tables);
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => "Database connected successfully",
|
|
'tableCount' => $tableCount,
|
|
'hasSettings' => $hasSettings
|
|
];
|
|
} catch (Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
public function saveConfiguration($data) {
|
|
try {
|
|
// Validate required fields
|
|
$required = ['platformName', 'domainName', 'contactEmail'];
|
|
foreach ($required as $field) {
|
|
if (empty($data[$field])) {
|
|
throw new Exception("Missing required field: $field");
|
|
}
|
|
}
|
|
|
|
// Save configuration to database
|
|
$settings = [
|
|
'site_name' => $data['platformName'],
|
|
'site_tagline' => $data['platformTagline'] ?? '',
|
|
'site_url' => $data['domainName'],
|
|
'site_email' => $data['contactEmail'],
|
|
'site_timezone' => $data['timezone'] ?? 'UTC',
|
|
|
|
// Branding
|
|
'theme_primary_color' => $data['primaryColor'] ?? '#667eea',
|
|
'theme_secondary_color' => $data['secondaryColor'] ?? '#764ba2',
|
|
'theme_default' => $data['defaultTheme'] ?? 'light',
|
|
'theme_allow_switching' => !empty($data['enableTheming']) ? '1' : '0',
|
|
|
|
// Membership tiers
|
|
'tier_free_name' => $data['tier1Name'] ?? 'Free',
|
|
'tier_free_upload_limit' => $data['tier1Upload'] ?? 100,
|
|
'tier_free_storage_limit' => $data['tier1Storage'] ?? 5,
|
|
|
|
'tier_premium_name' => $data['tier2Name'] ?? 'Premium',
|
|
'tier_premium_upload_limit' => $data['tier2Upload'] ?? 500,
|
|
'tier_premium_storage_limit' => $data['tier2Storage'] ?? 50,
|
|
'tier_premium_price' => $data['tier2Price'] ?? 9.99,
|
|
|
|
'tier_enterprise_name' => $data['tier3Name'] ?? 'Enterprise',
|
|
'tier_enterprise_upload_limit' => $data['tier3Upload'] ?? 2048,
|
|
'tier_enterprise_storage_limit' => $data['tier3Storage'] ?? 500,
|
|
'tier_enterprise_price' => $data['tier3Price'] ?? 49.99,
|
|
|
|
// Features
|
|
'feature_registration' => !empty($data['enableRegistration']) ? '1' : '0',
|
|
'feature_email_verification' => !empty($data['enableEmailVerification']) ? '1' : '0',
|
|
'feature_live_streaming' => !empty($data['enableLiveStreaming']) ? '1' : '0',
|
|
'feature_comments' => !empty($data['enableComments']) ? '1' : '0',
|
|
'feature_downloads' => !empty($data['enableDownloads']) ? '1' : '0',
|
|
'feature_monetization' => !empty($data['enableMonetization']) ? '1' : '0',
|
|
'feature_template_builder' => !empty($data['enableTemplateBuilder']) ? '1' : '0',
|
|
'feature_analytics' => !empty($data['enableAnalytics']) ? '1' : '0',
|
|
|
|
// Meta
|
|
'setup_completed' => '1',
|
|
'setup_date' => date('Y-m-d H:i:s'),
|
|
'setup_version' => '2.0'
|
|
];
|
|
|
|
// Check if db_settings table exists
|
|
$stmt = $this->pdo->query("SHOW TABLES LIKE 'db_settings'");
|
|
if ($stmt->rowCount() === 0) {
|
|
// Table doesn't exist yet, create it
|
|
$this->createSettingsTable();
|
|
}
|
|
|
|
// Insert or update settings
|
|
foreach ($settings as $key => $value) {
|
|
$stmt = $this->pdo->prepare("
|
|
INSERT INTO db_settings (cfg_name, cfg_value)
|
|
VALUES (?, ?)
|
|
ON DUPLICATE KEY UPDATE cfg_value = VALUES(cfg_value)
|
|
");
|
|
$stmt->execute([$key, $value]);
|
|
}
|
|
|
|
// Also write to config file for quick access
|
|
$this->writeConfigFile($settings);
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => 'Configuration saved successfully'
|
|
];
|
|
} catch (Exception $e) {
|
|
error_log("Setup Wizard Save Config Error: " . $e->getMessage());
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
public function createAdminUser($data) {
|
|
try {
|
|
// Validate required fields
|
|
if (empty($data['adminUsername']) || empty($data['adminEmail']) || empty($data['adminPassword'])) {
|
|
throw new Exception("All admin fields are required");
|
|
}
|
|
|
|
// Validate password match
|
|
if ($data['adminPassword'] !== $data['adminPasswordConfirm']) {
|
|
throw new Exception("Passwords do not match");
|
|
}
|
|
|
|
// Validate password strength
|
|
if (strlen($data['adminPassword']) < 8) {
|
|
throw new Exception("Password must be at least 8 characters long");
|
|
}
|
|
|
|
// Hash password
|
|
$passwordHash = password_hash($data['adminPassword'], PASSWORD_BCRYPT);
|
|
|
|
// Check if db_accountuser table exists
|
|
$stmt = $this->pdo->query("SHOW TABLES LIKE 'db_accountuser'");
|
|
if ($stmt->rowCount() === 0) {
|
|
throw new Exception("User table not found. Database may not be properly initialized.");
|
|
}
|
|
|
|
// Check if admin already exists
|
|
$stmt = $this->pdo->prepare("SELECT usr_id FROM db_accountuser WHERE usr_user = :username OR usr_email = :email");
|
|
$stmt->execute([
|
|
'username' => $data['adminUsername'],
|
|
'email' => $data['adminEmail']
|
|
]);
|
|
|
|
if ($stmt->rowCount() > 0) {
|
|
// Update existing admin
|
|
$stmt = $this->pdo->prepare("
|
|
UPDATE db_accountuser
|
|
SET usr_password = :password,
|
|
usr_email = :email,
|
|
usr_dname = :displayname,
|
|
usr_role = 'admin',
|
|
usr_status = 1,
|
|
usr_verified = 1
|
|
WHERE usr_user = :username OR usr_email = :email
|
|
");
|
|
} else {
|
|
// Insert new admin - use SET sql_mode to allow more flexible inserts
|
|
$this->pdo->exec("SET sql_mode=''");
|
|
|
|
$stmt = $this->pdo->prepare("
|
|
INSERT INTO db_accountuser (
|
|
usr_key, usr_user, usr_password, usr_email, usr_dname, usr_role, usr_status, usr_verified,
|
|
usr_IP, usr_logins, usr_lastlogin, usr_joindate, live_key
|
|
) VALUES (
|
|
1, :username, :password, :email, :displayname, 'admin', 1, 1,
|
|
'127.0.0.1', 0, NOW(), NOW(), ''
|
|
)
|
|
");
|
|
}
|
|
|
|
$stmt->execute([
|
|
'username' => $data['adminUsername'],
|
|
'password' => $passwordHash,
|
|
'email' => $data['adminEmail'],
|
|
'displayname' => $data['adminDisplayName'] ?? 'Administrator'
|
|
]);
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => 'Admin user created successfully'
|
|
];
|
|
} catch (Exception $e) {
|
|
error_log("Setup Wizard Create Admin Error: " . $e->getMessage());
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
public function finalizeSetup($data) {
|
|
try {
|
|
// Create .setup_complete file to prevent re-running setup
|
|
file_put_contents('.setup_complete', json_encode([
|
|
'completed_at' => date('Y-m-d H:i:s'),
|
|
'platform_name' => $data['platformName'] ?? 'EasyStream',
|
|
'domain' => $data['domainName'] ?? 'localhost',
|
|
'version' => '2.0'
|
|
]));
|
|
|
|
// Update Caddyfile with domain
|
|
if (!empty($data['domainName']) && $data['domainName'] !== 'localhost') {
|
|
$this->updateCaddyfile($data['domainName']);
|
|
}
|
|
|
|
// Clear any cached config
|
|
if (function_exists('opcache_reset')) {
|
|
opcache_reset();
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => 'Setup completed successfully',
|
|
'redirect' => '/'
|
|
];
|
|
} catch (Exception $e) {
|
|
error_log("Setup Wizard Finalize Error: " . $e->getMessage());
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
private function createSettingsTable() {
|
|
$sql = "CREATE TABLE IF NOT EXISTS `db_settings` (
|
|
`cfg_name` VARCHAR(100) NOT NULL PRIMARY KEY,
|
|
`cfg_value` TEXT
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
|
|
|
|
$this->pdo->exec($sql);
|
|
}
|
|
|
|
private function writeConfigFile($settings) {
|
|
$configContent = "<?php\n";
|
|
$configContent .= "// Auto-generated setup configuration\n";
|
|
$configContent .= "// Generated on " . date('Y-m-d H:i:s') . "\n\n";
|
|
|
|
foreach ($settings as $key => $value) {
|
|
$safeValue = addslashes($value);
|
|
$constantName = 'SETUP_' . strtoupper($key);
|
|
$configContent .= "define('$constantName', '$safeValue');\n";
|
|
}
|
|
|
|
// Write to f_core/config.setup.php
|
|
$configFile = __DIR__ . '/f_core/config.setup.php';
|
|
@file_put_contents($configFile, $configContent);
|
|
}
|
|
|
|
private function updateCaddyfile($domain) {
|
|
$caddyfile = __DIR__ . '/Caddyfile';
|
|
|
|
if (file_exists($caddyfile)) {
|
|
$content = @file_get_contents($caddyfile);
|
|
|
|
// Replace localhost with actual domain
|
|
$content = preg_replace('/http:\/\/localhost:\d+/', "https://$domain", $content);
|
|
$content = preg_replace('/^:80\s*\{/', "$domain {\n encode gzip", $content);
|
|
|
|
@file_put_contents($caddyfile, $content);
|
|
}
|
|
}
|
|
}
|
|
?>
|