Added setup_cli.php to allow to setup via the command line via interactive prompts and non intertactive by argument switches this allows for better automation of installing itflow in places like docker, ansible, HestiaCP Auto Install scripts etc

This commit is contained in:
johnnyq 2024-12-07 14:09:15 -05:00
parent 6501fc528e
commit 0a59ab33b9
1 changed files with 386 additions and 0 deletions

386
setup_cli.php Normal file
View File

@ -0,0 +1,386 @@
#!/usr/bin/env php
<?php
// Example
//php setup_cli.php --help
//php setup_cli.php --host=localhost --username=itflow --password=secret --database=itflow --base-url=example.com/itflow --locale=en_US --timezone=UTC --currency=USD --company-name="My Company" --country="US" --user-name="John Doe" --user-email="john@example.com" --user-password="admin123" --non-interactive
// Ensure we're running from command line
if (php_sapi_name() !== 'cli') {
die("This setup script must be run from the command line.\n");
}
// Define required arguments
$required_args = [
'host' => 'Database host',
'username' => 'Database username',
'password' => 'Database password',
'database' => 'Database name',
'base-url' => 'Base URL (without protocol, e.g. example.com/itflow)',
'locale' => 'Locale (e.g. en_US)',
'timezone' => 'Timezone (e.g. UTC)',
'currency' => 'Currency code (e.g. USD)',
'company-name' => 'Company name',
'country' => 'Company country (e.g. United States)',
'user-name' => 'Admin user full name',
'user-email' => 'Admin user email',
'user-password'=> 'Admin user password (min 8 chars)'
];
// Additional optional arguments
// address, city, state, zip, phone, company-email, website
// These are optional and don't need error checks if missing.
$optional_args = [
'address' => 'Company address (optional)',
'city' => 'Company city (optional)',
'state' => 'Company state (optional)',
'zip' => 'Company postal code (optional)',
'phone' => 'Company phone (optional)',
'company-email' => 'Company email (optional)',
'website' => 'Company website (optional)'
];
// Parse command line options
$shortopts = "";
$longopts = [
"help",
"host:",
"username:",
"password:",
"database:",
"base-url:",
"locale:",
"timezone:",
"currency:",
"company-name:",
"country:",
"address::",
"city::",
"state::",
"zip::",
"phone::",
"company-email::",
"website::",
"user-name:",
"user-email:",
"user-password:",
"non-interactive"
];
$options = getopt($shortopts, $longopts);
// If --help is set, print usage and exit
if (isset($options['help'])) {
echo "ITFlow CLI Setup Script\n\n";
echo "Usage:\n";
echo " php setup_cli.php [options]\n\n";
echo "Options:\n";
foreach ($required_args as $arg => $desc) {
echo " --$arg\t$desc (required)\n";
}
foreach ($optional_args as $arg => $desc) {
echo " --$arg\t$desc\n";
}
echo " --non-interactive\tRun in non-interactive mode (fail if required args missing)\n";
echo " --help\t\tShow this help message\n\n";
echo "If running interactively (without --non-interactive), any missing required arguments will be prompted.\n";
echo "If running non-interactively, all required arguments must be provided.\n\n";
exit(0);
}
if (file_exists("config.php")) {
include "config.php";
}
include "functions.php";
include "database_version.php";
if (!isset($config_enable_setup)) {
$config_enable_setup = 1;
}
if ($config_enable_setup == 0) {
echo "Setup is disabled. Please delete or modify config.php if you need to re-run the setup.\n";
exit;
}
$errorLog = ini_get('error_log') ?: "/var/log/apache2/error.log";
$timezones = DateTimeZone::listIdentifiers();
function prompt($message) {
echo $message . ": ";
return trim(fgets(STDIN));
}
$non_interactive = isset($options['non-interactive']);
function getOptionOrPrompt($key, $promptMessage, $required = false, $default = '', $optionsGlobal = []) {
global $options, $non_interactive;
if (isset($options[$key])) {
return $options[$key];
} else {
if ($non_interactive && $required) {
die("Missing required argument: --$key\n");
}
$val = prompt($promptMessage . (strlen($default) ? " [$default]" : ''));
if (empty($val) && !empty($default)) {
$val = $default;
}
if ($required && empty($val)) {
die("Error: $promptMessage is required.\n");
}
return $val;
}
}
// Start setup
echo "Welcome to the ITFlow CLI Setup.\n";
// If config exists, abort
if (file_exists('config.php')) {
echo "Database is already configured in config.php.\n";
echo "To re-run the setup, remove config.php and run this script again.\n";
exit;
}
// If non-interactive is set, ensure all required arguments are present
if ($non_interactive) {
foreach (array_keys($required_args) as $arg) {
if (!isset($options[$arg])) {
die("Missing required argument: --$arg\n");
}
}
}
// Database Setup
echo "\n=== Database Setup ===\n";
$database = getOptionOrPrompt('database', "Enter the database name", true);
$host = getOptionOrPrompt('host', "Enter the database host", true, 'localhost');
if (empty($host)) $host = "localhost";
$username = getOptionOrPrompt('username', "Enter the database username", true);
$password = getOptionOrPrompt('password', "Enter the database password", true);
// Base URL
$base_url = getOptionOrPrompt('base-url', "Enter the base URL (e.g. example.com/itflow)", true);
$base_url = rtrim($base_url, '/');
// Locale, Timezone, Currency
echo "\n=== Localization ===\n";
$locale = getOptionOrPrompt('locale', "Enter the locale (e.g. en_US)", true);
$timezone = getOptionOrPrompt('timezone', "Enter the timezone (e.g. UTC)", true);
$currency_code = getOptionOrPrompt('currency', "Enter the currency code (e.g. USD)", true);
// Company Details
echo "\n=== Company Details ===\n";
$company_name = getOptionOrPrompt('company-name', "Company Name", true);
$country = getOptionOrPrompt('country', "Country", true);
$address = getOptionOrPrompt('address', "Address (optional)", false);
$city = getOptionOrPrompt('city', "City (optional)", false);
$state = getOptionOrPrompt('state', "State/Province (optional)", false);
$zip = getOptionOrPrompt('zip', "Postal Code (optional)", false);
$phone = getOptionOrPrompt('phone', "Phone (optional)", false);
$phone = preg_replace("/[^0-9]/", '', $phone);
$company_email = getOptionOrPrompt('company-email', "Company Email (optional)", false);
$website = getOptionOrPrompt('website', "Website (optional)", false);
// User Setup
echo "\n=== Create First User ===\n";
$user_name = getOptionOrPrompt('user-name', "Full Name", true);
$user_email = getOptionOrPrompt('user-email', "Email Address", true);
while (!filter_var($user_email, FILTER_VALIDATE_EMAIL)) {
echo "Invalid email.\n";
if ($non_interactive) {
die("Invalid email address: $user_email\n");
}
$user_email = prompt("Email Address");
}
$user_password_plain = getOptionOrPrompt('user-password', "Password (at least 8 chars)", true);
if (strlen($user_password_plain) < 8) {
if ($non_interactive) {
die("Password must be at least 8 characters.\n");
}
while (strlen($user_password_plain) < 8) {
echo "Password too short. Try again.\n";
$user_password_plain = prompt("Password");
}
}
if (!preg_match('/^[a-zA-Z0-9.\-\/]+$/', $host)) {
die("Invalid host format.\n");
}
// Test Database
$conn = @mysqli_connect($host, $username, $password, $database);
if (!$conn) {
die("Database connection failed - " . mysqli_connect_error() . "\n");
}
$installation_id = randomString(32);
$new_config = "<?php\n\n";
$new_config .= "\$dbhost = " . var_export($host, true) . ";\n";
$new_config .= "\$dbusername = " . var_export($username, true) . ";\n";
$new_config .= "\$dbpassword = " . var_export($password, true) . ";\n";
$new_config .= "\$database = " . var_export($database, true) . ";\n";
$new_config .= "\$mysqli = mysqli_connect(\$dbhost, \$dbusername, \$dbpassword, \$database) or die('Database Connection Failed');\n";
$new_config .= "\$config_app_name = 'ITFlow';\n";
$new_config .= "\$config_base_url = '" . addslashes($base_url) . "';\n";
$new_config .= "\$config_https_only = TRUE;\n";
$new_config .= "\$repo_branch = 'master';\n";
$new_config .= "\$installation_id = '$installation_id';\n";
if (file_put_contents("config.php", $new_config) === false) {
die("Failed to write config.php. Check file permissions.\n");
}
if (!file_exists('config.php')) {
die("config.php does not exist after write attempt.\n");
}
include "config.php";
// Import DB Schema
echo "Importing database schema...\n";
$filename = 'db.sql';
if (!file_exists($filename)) {
die("db.sql file not found.\n");
}
$templine = '';
$lines = file($filename);
foreach ($lines as $line) {
if (substr($line, 0, 2) == '--' || trim($line) == '')
continue;
$templine .= $line;
if (substr(trim($line), -1, 1) == ';') {
mysqli_query($mysqli, $templine) or die("Error performing query: $templine\n" . mysqli_error($mysqli) . "\n");
$templine = '';
}
}
echo "Database imported successfully.\n";
// Create User
$password_hash = password_hash(trim($user_password_plain), PASSWORD_DEFAULT);
$site_encryption_master_key = randomString();
$user_specific_encryption_ciphertext = setupFirstUserSpecificKey($user_password_plain, $site_encryption_master_key);
mysqli_query($mysqli,"INSERT INTO users SET user_name = '$user_name', user_email = '$user_email', user_password = '$password_hash', user_specific_encryption_ciphertext = '$user_specific_encryption_ciphertext'");
mysqli_query($mysqli,"INSERT INTO user_settings SET user_id = 1, user_role = 3");
echo "User $user_name created successfully.\n";
// Company Details
mysqli_query($mysqli,"INSERT INTO companies SET company_name = '$company_name', company_address = '$address', company_city = '$city', company_state = '$state', company_zip = '$zip', company_country = '$country', company_phone = '$phone', company_email = '$company_email', company_website = '$website', company_locale = '$locale', company_currency = '$currency_code'");
// Insert default settings and categories
$latest_database_version = LATEST_DATABASE_VERSION;
mysqli_query($mysqli,"INSERT INTO settings SET company_id = 1, config_current_database_version = '$latest_database_version', config_invoice_prefix = 'INV-', config_invoice_next_number = 1, config_recurring_prefix = 'REC-', config_recurring_next_number = 1, config_invoice_overdue_reminders = '1,3,7', config_quote_prefix = 'QUO-', config_quote_next_number = 1, config_default_net_terms = 30, config_ticket_next_number = 1, config_ticket_prefix = 'TCK-'");
// Categories
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Office Supplies', category_type = 'Expense', category_color = 'blue'");
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Travel', category_type = 'Expense', category_color = 'red'");
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Advertising', category_type = 'Expense', category_color = 'green'");
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Service', category_type = 'Income', category_color = 'blue'");
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Friend', category_type = 'Referral', category_color = 'blue'");
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Search Engine', category_type = 'Referral', category_color = 'red'");
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Cash', category_type = 'Payment Method', category_color = 'blue'");
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Check', category_type = 'Payment Method', category_color = 'red'");
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Bank Transfer', category_type = 'Payment Method', category_color = 'green'");
// Calendar
mysqli_query($mysqli,"INSERT INTO calendars SET calendar_name = 'Default', calendar_color = 'blue'");
// Ticket Statuses
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'New', ticket_status_color = '#dc3545'");
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Open', ticket_status_color = '#007bff'");
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'On Hold', ticket_status_color = '#28a745'");
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Resolved', ticket_status_color = '#343a40'");
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Closed', ticket_status_color = '#343a40'");
// Modules
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_client', module_description = 'General client & contact management'");
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_support', module_description = 'Access to ticketing, assets and documentation'");
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_credential', module_description = 'Access to client credentials - usernames, passwords and 2FA codes'");
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_sales', module_description = 'Access to quotes, invoices and products'");
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_financial', module_description = 'Access to payments, accounts, expenses and budgets'");
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_reporting', module_description = 'Access to all reports'");
// Roles
mysqli_query($mysqli, "INSERT INTO user_roles SET user_role_id = 1, user_role_name = 'Accountant', user_role_description = 'Built-in - Limited access to financial-focused modules'");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 1, user_role_permission_level = 1");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 2, user_role_permission_level = 1");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 4, user_role_permission_level = 1");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 5, user_role_permission_level = 2");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 6, user_role_permission_level = 1");
mysqli_query($mysqli, "INSERT INTO user_roles SET user_role_id = 2, user_role_name = 'Technician', user_role_description = 'Built-in - Limited access to technical-focused modules'");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 2, module_id = 1, user_role_permission_level = 2");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 2, module_id = 2, user_role_permission_level = 2");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 2, module_id = 3, user_role_permission_level = 2");
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 2, module_id = 4, user_role_permission_level = 2");
mysqli_query($mysqli, "INSERT INTO user_roles SET user_role_id = 3, user_role_name = 'Administrator', user_role_description = 'Built-in - Full administrative access', user_role_is_admin = 1");
// Custom Links
mysqli_query($mysqli,"INSERT INTO custom_links SET custom_link_name = 'Docs', custom_link_uri = 'https://docs.itflow.org', custom_link_new_tab = 1, custom_link_icon = 'question-circle'");
// Finalizing
mysqli_query($mysqli,"UPDATE companies SET company_locale = '$locale', company_currency = '$currency_code' WHERE company_id = 1");
mysqli_query($mysqli,"UPDATE settings SET config_timezone = '$timezone', config_phone_mask = 1 WHERE company_id = 1");
mysqli_query($mysqli,"INSERT INTO accounts SET account_name = 'Cash', account_currency_code = '$currency_code'");
// Telemetry (optional if interactive)
if (!$non_interactive) {
echo "\n=== Telemetry ===\n";
echo "Would you like to share anonymous usage data with the project maintainers? [y/N]: ";
$share = strtolower(trim(fgets(STDIN)));
if ($share === 'y') {
mysqli_query($mysqli,"UPDATE settings SET config_telemetry = 2");
echo "Any comments to include? Press Enter if none: ";
$comments = trim(fgets(STDIN));
$sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1");
$row = mysqli_fetch_array($sql);
$company_name_db = $row['company_name'];
$website_db = $row['company_website'];
$city_db = $row['company_city'];
$state_db = $row['company_state'];
$country_db = $row['company_country'];
$currency_db = $row['company_currency'];
$postdata = http_build_query([
'installation_id' => "$installation_id",
'company_name' => "$company_name_db",
'website' => "$website_db",
'city' => "$city_db",
'state' => "$state_db",
'country' => "$country_db",
'currency' => "$currency_db",
'comments' => "$comments",
'collection_method' => 1
]);
$opts = ['http' =>
[
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
]
];
$context = stream_context_create($opts);
$result = @file_get_contents('https://telemetry.itflow.org', false, $context);
echo "Telemetry response: $result\n";
}
}
// finalize config
$myfile = fopen("config.php", "a");
$txt = "\$config_enable_setup = 0;\n\n";
fwrite($myfile, $txt);
fclose($myfile);
echo "\nSetup complete!\n";
echo "You can now log in with the user you created at: https://$base_url/login.php\n";
exit(0);