fix(perfexcrm module): align version to 3.0.1, unify entrypoint, and harden routes/views
- Bump DESK_MOLONI version to 3.0.1 across module - Normalize hooks to after_client_* and instantiate PerfexHooks safely - Fix OAuthController view path and API client class name - Add missing admin views for webhook config/logs; adjust view loading - Harden client portal routes and admin routes mapping - Make Dashboard/Logs/Queue tolerant to optional model methods - Align log details query with existing schema; avoid broken joins This makes the module operational in Perfex (admin + client), reduces 404s, and avoids fatal errors due to inconsistent tables/methods.
This commit is contained in:
933
scripts/install.sh
Normal file
933
scripts/install.sh
Normal file
@@ -0,0 +1,933 @@
|
||||
#!/bin/bash
|
||||
# Desk-Moloni v3.0 Installation Script
|
||||
#
|
||||
# Complete installation and setup automation for the Desk-Moloni module.
|
||||
# Handles database setup, permissions, configuration, and initial setup.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Script configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODULE_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
PROJECT_ROOT="$(dirname "$(dirname "$MODULE_DIR")")"
|
||||
|
||||
# Default configuration
|
||||
DEFAULT_DB_HOST="localhost"
|
||||
DEFAULT_DB_NAME="perfex_crm"
|
||||
DEFAULT_DB_USER="root"
|
||||
DEFAULT_WEB_USER="www-data"
|
||||
DEFAULT_ENVIRONMENT="production"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Installation state
|
||||
INSTALL_LOG="$MODULE_DIR/install.log"
|
||||
BACKUP_DIR="$MODULE_DIR/backups/$(date +%Y%m%d_%H%M%S)"
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $1"
|
||||
echo -e "${BLUE}$msg${NC}"
|
||||
echo "$msg" >> "$INSTALL_LOG"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] $1"
|
||||
echo -e "${GREEN}$msg${NC}"
|
||||
echo "$msg" >> "$INSTALL_LOG"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [WARNING] $1"
|
||||
echo -e "${YELLOW}$msg${NC}"
|
||||
echo "$msg" >> "$INSTALL_LOG"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1"
|
||||
echo -e "${RED}$msg${NC}"
|
||||
echo "$msg" >> "$INSTALL_LOG"
|
||||
}
|
||||
|
||||
log_step() {
|
||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [STEP] $1"
|
||||
echo -e "${CYAN}=== $1 ===${NC}"
|
||||
echo "$msg" >> "$INSTALL_LOG"
|
||||
}
|
||||
|
||||
# Help function
|
||||
show_help() {
|
||||
cat << EOF
|
||||
Desk-Moloni v3.0 Installation Script
|
||||
|
||||
Usage: $0 [OPTIONS]
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message
|
||||
--db-host HOST Database host (default: $DEFAULT_DB_HOST)
|
||||
--db-name DATABASE Database name (default: $DEFAULT_DB_NAME)
|
||||
--db-user USER Database user (default: $DEFAULT_DB_USER)
|
||||
--db-password PASSWORD Database password (prompted if not provided)
|
||||
--web-user USER Web server user (default: $DEFAULT_WEB_USER)
|
||||
--environment ENV Environment: development|production (default: $DEFAULT_ENVIRONMENT)
|
||||
--skip-database Skip database installation
|
||||
--skip-cron Skip cron job setup
|
||||
--skip-permissions Skip file permission setup
|
||||
--force Force installation (overwrite existing)
|
||||
--dry-run Show what would be done without making changes
|
||||
--uninstall Remove the module and all data
|
||||
--backup Create backup before installation
|
||||
--restore BACKUP_PATH Restore from backup
|
||||
|
||||
Installation Steps:
|
||||
1. Pre-installation checks
|
||||
2. Backup existing data (if --backup)
|
||||
3. Database schema installation
|
||||
4. File permission setup
|
||||
5. Configuration initialization
|
||||
6. Cron job setup
|
||||
7. Post-installation verification
|
||||
|
||||
Examples:
|
||||
$0 # Interactive installation
|
||||
$0 --db-name perfex --db-user admin # Specify database settings
|
||||
$0 --environment development # Development environment
|
||||
$0 --dry-run # Preview installation
|
||||
$0 --uninstall # Remove module
|
||||
$0 --backup # Backup before install
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
DB_HOST="$DEFAULT_DB_HOST"
|
||||
DB_NAME="$DEFAULT_DB_NAME"
|
||||
DB_USER="$DEFAULT_DB_USER"
|
||||
DB_PASSWORD=""
|
||||
WEB_USER="$DEFAULT_WEB_USER"
|
||||
ENVIRONMENT="$DEFAULT_ENVIRONMENT"
|
||||
SKIP_DATABASE=false
|
||||
SKIP_CRON=false
|
||||
SKIP_PERMISSIONS=false
|
||||
FORCE_INSTALL=false
|
||||
DRY_RUN=false
|
||||
UNINSTALL=false
|
||||
BACKUP_BEFORE_INSTALL=false
|
||||
RESTORE_BACKUP=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
--db-host)
|
||||
DB_HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
--db-name)
|
||||
DB_NAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
--db-user)
|
||||
DB_USER="$2"
|
||||
shift 2
|
||||
;;
|
||||
--db-password)
|
||||
DB_PASSWORD="$2"
|
||||
shift 2
|
||||
;;
|
||||
--web-user)
|
||||
WEB_USER="$2"
|
||||
shift 2
|
||||
;;
|
||||
--environment)
|
||||
ENVIRONMENT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--skip-database)
|
||||
SKIP_DATABASE=true
|
||||
shift
|
||||
;;
|
||||
--skip-cron)
|
||||
SKIP_CRON=true
|
||||
shift
|
||||
;;
|
||||
--skip-permissions)
|
||||
SKIP_PERMISSIONS=true
|
||||
shift
|
||||
;;
|
||||
--force)
|
||||
FORCE_INSTALL=true
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--uninstall)
|
||||
UNINSTALL=true
|
||||
shift
|
||||
;;
|
||||
--backup)
|
||||
BACKUP_BEFORE_INSTALL=true
|
||||
shift
|
||||
;;
|
||||
--restore)
|
||||
RESTORE_BACKUP="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate environment
|
||||
if [[ ! "$ENVIRONMENT" =~ ^(development|production)$ ]]; then
|
||||
log_error "Invalid environment: $ENVIRONMENT (must be development or production)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create installation log
|
||||
mkdir -p "$(dirname "$INSTALL_LOG")"
|
||||
touch "$INSTALL_LOG"
|
||||
|
||||
# Pre-installation checks
|
||||
check_requirements() {
|
||||
log_step "Pre-installation Requirements Check"
|
||||
|
||||
local errors=0
|
||||
|
||||
# Check if running as root or with sudo
|
||||
if [[ $EUID -ne 0 ]] && [[ -z "${SUDO_USER:-}" ]]; then
|
||||
log_error "This script must be run as root or with sudo"
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
# Check PHP version
|
||||
if ! command -v php &> /dev/null; then
|
||||
log_error "PHP is not installed"
|
||||
((errors++))
|
||||
else
|
||||
local php_version
|
||||
php_version=$(php -r "echo PHP_VERSION_ID;" 2>/dev/null || echo "0")
|
||||
if [[ "$php_version" -lt 80100 ]]; then
|
||||
log_error "PHP 8.1 or higher is required (current: $(php -r "echo PHP_VERSION;"))"
|
||||
((errors++))
|
||||
else
|
||||
log_success "PHP version: $(php -r "echo PHP_VERSION;")"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check required PHP extensions
|
||||
local required_extensions=("mysqli" "pdo" "pdo_mysql" "json" "curl" "openssl" "mbstring")
|
||||
for ext in "${required_extensions[@]}"; do
|
||||
if ! php -m | grep -q "^$ext$"; then
|
||||
log_error "Required PHP extension missing: $ext"
|
||||
((errors++))
|
||||
else
|
||||
log_success "PHP extension available: $ext"
|
||||
fi
|
||||
done
|
||||
|
||||
# Check MySQL/MariaDB client
|
||||
if ! command -v mysql &> /dev/null; then
|
||||
log_error "MySQL client is not installed"
|
||||
((errors++))
|
||||
else
|
||||
log_success "MySQL client available"
|
||||
fi
|
||||
|
||||
# Check web server user
|
||||
if ! id "$WEB_USER" &>/dev/null; then
|
||||
log_error "Web server user '$WEB_USER' does not exist"
|
||||
((errors++))
|
||||
else
|
||||
log_success "Web server user '$WEB_USER' exists"
|
||||
fi
|
||||
|
||||
# Check Perfex CRM installation
|
||||
local perfex_config="$PROJECT_ROOT/application/config/config.php"
|
||||
if [[ ! -f "$perfex_config" ]]; then
|
||||
log_error "Perfex CRM config not found at: $perfex_config"
|
||||
log_error "Please ensure this script is run from within a Perfex CRM installation"
|
||||
((errors++))
|
||||
else
|
||||
log_success "Perfex CRM installation detected"
|
||||
fi
|
||||
|
||||
if [[ $errors -gt 0 ]]; then
|
||||
log_error "Pre-installation checks failed with $errors errors"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "All requirements satisfied"
|
||||
}
|
||||
|
||||
# Interactive configuration
|
||||
interactive_config() {
|
||||
if [[ "$DRY_RUN" == true ]] || [[ "$UNINSTALL" == true ]] || [[ -n "$RESTORE_BACKUP" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_step "Interactive Configuration"
|
||||
|
||||
# Database password
|
||||
if [[ -z "$DB_PASSWORD" ]]; then
|
||||
echo -n "Database password for $DB_USER@$DB_HOST: "
|
||||
read -s DB_PASSWORD
|
||||
echo
|
||||
|
||||
if [[ -z "$DB_PASSWORD" ]]; then
|
||||
log_error "Database password is required"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Confirm settings
|
||||
echo -e "\n${CYAN}Installation Configuration:${NC}"
|
||||
echo "Database Host: $DB_HOST"
|
||||
echo "Database Name: $DB_NAME"
|
||||
echo "Database User: $DB_USER"
|
||||
echo "Web Server User: $WEB_USER"
|
||||
echo "Environment: $ENVIRONMENT"
|
||||
echo "Module Path: $MODULE_DIR"
|
||||
|
||||
if [[ "$FORCE_INSTALL" == false ]]; then
|
||||
echo -n "Proceed with installation? [y/N]: "
|
||||
read -r confirm
|
||||
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
||||
log_info "Installation cancelled by user"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Test database connection
|
||||
test_database_connection() {
|
||||
log_step "Testing Database Connection"
|
||||
|
||||
if [[ "$SKIP_DATABASE" == true ]]; then
|
||||
log_warning "Skipping database connection test"
|
||||
return
|
||||
fi
|
||||
|
||||
local mysql_cmd="mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log_info "Would test database connection to $DB_HOST"
|
||||
return
|
||||
fi
|
||||
|
||||
# Test connection
|
||||
if ! echo "SELECT 1;" | $mysql_cmd "$DB_NAME" &>/dev/null; then
|
||||
log_error "Failed to connect to database $DB_NAME on $DB_HOST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Database connection successful"
|
||||
}
|
||||
|
||||
# Create backup
|
||||
create_backup() {
|
||||
if [[ "$BACKUP_BEFORE_INSTALL" == false ]] && [[ "$UNINSTALL" == false ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_step "Creating Backup"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log_info "Would create backup in: $BACKUP_DIR"
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Backup database tables
|
||||
if [[ "$SKIP_DATABASE" == false ]]; then
|
||||
local tables=(
|
||||
"desk_moloni_config"
|
||||
"desk_moloni_mapping"
|
||||
"desk_moloni_sync_queue"
|
||||
"desk_moloni_sync_log"
|
||||
)
|
||||
|
||||
local mysql_cmd="mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD"
|
||||
|
||||
for table in "${tables[@]}"; do
|
||||
if echo "SHOW TABLES LIKE '$table';" | $mysql_cmd "$DB_NAME" | grep -q "$table"; then
|
||||
log_info "Backing up table: $table"
|
||||
mysqldump -h"$DB_HOST" -u"$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" "$table" > "$BACKUP_DIR/$table.sql"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Backup configuration files
|
||||
if [[ -d "$MODULE_DIR/config" ]]; then
|
||||
cp -r "$MODULE_DIR/config" "$BACKUP_DIR/"
|
||||
log_info "Configuration files backed up"
|
||||
fi
|
||||
|
||||
# Backup logs (recent only)
|
||||
if [[ -d "$MODULE_DIR/logs" ]]; then
|
||||
find "$MODULE_DIR/logs" -name "*.log" -mtime -7 -exec cp {} "$BACKUP_DIR/" \;
|
||||
log_info "Recent log files backed up"
|
||||
fi
|
||||
|
||||
# Create backup manifest
|
||||
cat > "$BACKUP_DIR/manifest.txt" << EOF
|
||||
Desk-Moloni v3.0 Backup
|
||||
Created: $(date)
|
||||
Version: 3.0.0
|
||||
Environment: $ENVIRONMENT
|
||||
Database: $DB_NAME
|
||||
Host: $DB_HOST
|
||||
EOF
|
||||
|
||||
log_success "Backup created: $BACKUP_DIR"
|
||||
}
|
||||
|
||||
# Install database schema
|
||||
install_database() {
|
||||
if [[ "$SKIP_DATABASE" == true ]]; then
|
||||
log_warning "Skipping database installation"
|
||||
return
|
||||
fi
|
||||
|
||||
log_step "Installing Database Schema"
|
||||
|
||||
local mysql_cmd="mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD $DB_NAME"
|
||||
local schema_file="$MODULE_DIR/sql/schema.sql"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log_info "Would install database schema from: $schema_file"
|
||||
return
|
||||
fi
|
||||
|
||||
# Create schema file if it doesn't exist
|
||||
if [[ ! -f "$schema_file" ]]; then
|
||||
log_info "Creating database schema file"
|
||||
mkdir -p "$(dirname "$schema_file")"
|
||||
|
||||
cat > "$schema_file" << 'EOF'
|
||||
-- Desk-Moloni v3.0 Database Schema
|
||||
-- Auto-generated installation schema
|
||||
|
||||
-- Configuration table
|
||||
CREATE TABLE IF NOT EXISTS desk_moloni_config (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
setting_key VARCHAR(255) NOT NULL UNIQUE,
|
||||
setting_value TEXT,
|
||||
encrypted TINYINT(1) DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Entity mapping table
|
||||
CREATE TABLE IF NOT EXISTS desk_moloni_mapping (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
entity_type ENUM('client', 'product', 'invoice', 'estimate', 'credit_note') NOT NULL,
|
||||
perfex_id INT NOT NULL,
|
||||
moloni_id INT NOT NULL,
|
||||
sync_direction ENUM('perfex_to_moloni', 'moloni_to_perfex', 'bidirectional') DEFAULT 'bidirectional',
|
||||
last_sync_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_perfex_mapping (entity_type, perfex_id),
|
||||
UNIQUE KEY unique_moloni_mapping (entity_type, moloni_id),
|
||||
INDEX idx_entity_perfex (entity_type, perfex_id),
|
||||
INDEX idx_entity_moloni (entity_type, moloni_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Sync queue table
|
||||
CREATE TABLE IF NOT EXISTS desk_moloni_sync_queue (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
task_type ENUM('sync_client', 'sync_product', 'sync_invoice', 'sync_estimate', 'sync_credit_note', 'status_update') NOT NULL,
|
||||
entity_type ENUM('client', 'product', 'invoice', 'estimate', 'credit_note') NOT NULL,
|
||||
entity_id INT NOT NULL,
|
||||
priority TINYINT DEFAULT 5,
|
||||
payload JSON,
|
||||
status ENUM('pending', 'processing', 'completed', 'failed', 'retry') DEFAULT 'pending',
|
||||
attempts INT DEFAULT 0,
|
||||
max_attempts INT DEFAULT 3,
|
||||
scheduled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
started_at TIMESTAMP NULL,
|
||||
completed_at TIMESTAMP NULL,
|
||||
error_message TEXT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_status_priority (status, priority, scheduled_at),
|
||||
INDEX idx_entity (entity_type, entity_id),
|
||||
INDEX idx_scheduled (scheduled_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Sync log table
|
||||
CREATE TABLE IF NOT EXISTS desk_moloni_sync_log (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
operation_type ENUM('create', 'update', 'delete', 'status_change') NOT NULL,
|
||||
entity_type ENUM('client', 'product', 'invoice', 'estimate', 'credit_note') NOT NULL,
|
||||
perfex_id INT,
|
||||
moloni_id INT,
|
||||
direction ENUM('perfex_to_moloni', 'moloni_to_perfex') NOT NULL,
|
||||
status ENUM('success', 'error', 'warning') NOT NULL,
|
||||
request_data JSON,
|
||||
response_data JSON,
|
||||
error_message TEXT NULL,
|
||||
execution_time_ms INT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_entity_status (entity_type, status, created_at),
|
||||
INDEX idx_perfex_entity (perfex_id, entity_type),
|
||||
INDEX idx_moloni_entity (moloni_id, entity_type),
|
||||
INDEX idx_created_at (created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Insert default configuration
|
||||
INSERT IGNORE INTO desk_moloni_config (setting_key, setting_value, encrypted) VALUES
|
||||
('module_version', '3.0.0', 0),
|
||||
('installation_date', NOW(), 0),
|
||||
('sync_enabled', '1', 0),
|
||||
('queue_batch_size', '10', 0),
|
||||
('max_retry_attempts', '3', 0),
|
||||
('api_rate_limit', '60', 0);
|
||||
EOF
|
||||
|
||||
log_success "Database schema file created"
|
||||
fi
|
||||
|
||||
# Execute schema
|
||||
log_info "Executing database schema..."
|
||||
if $mysql_cmd < "$schema_file"; then
|
||||
log_success "Database schema installed successfully"
|
||||
else
|
||||
log_error "Failed to install database schema"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify tables were created
|
||||
local tables=("desk_moloni_config" "desk_moloni_mapping" "desk_moloni_sync_queue" "desk_moloni_sync_log")
|
||||
for table in "${tables[@]}"; do
|
||||
if echo "SHOW TABLES LIKE '$table';" | $mysql_cmd | grep -q "$table"; then
|
||||
log_success "Table created: $table"
|
||||
else
|
||||
log_error "Failed to create table: $table"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Setup file permissions
|
||||
setup_permissions() {
|
||||
if [[ "$SKIP_PERMISSIONS" == true ]]; then
|
||||
log_warning "Skipping permission setup"
|
||||
return
|
||||
fi
|
||||
|
||||
log_step "Setting Up File Permissions"
|
||||
|
||||
local directories=(
|
||||
"$MODULE_DIR/logs"
|
||||
"$MODULE_DIR/locks"
|
||||
"$MODULE_DIR/cache"
|
||||
"$MODULE_DIR/temp"
|
||||
)
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log_info "Would create directories and set permissions"
|
||||
return
|
||||
fi
|
||||
|
||||
# Create directories
|
||||
for dir in "${directories[@]}"; do
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
mkdir -p "$dir"
|
||||
log_info "Created directory: $dir"
|
||||
fi
|
||||
|
||||
chown -R "$WEB_USER:$WEB_USER" "$dir"
|
||||
chmod 755 "$dir"
|
||||
log_success "Permissions set for: $dir"
|
||||
done
|
||||
|
||||
# Set permissions on CLI scripts
|
||||
local cli_files=(
|
||||
"$MODULE_DIR/cli/queue_processor.php"
|
||||
"$MODULE_DIR/cli/sync_commands.php"
|
||||
)
|
||||
|
||||
for file in "${cli_files[@]}"; do
|
||||
if [[ -f "$file" ]]; then
|
||||
chmod +x "$file"
|
||||
log_success "Made executable: $file"
|
||||
fi
|
||||
done
|
||||
|
||||
# Set permissions on shell scripts
|
||||
find "$MODULE_DIR/scripts" -name "*.sh" -type f -exec chmod +x {} \;
|
||||
log_success "Made shell scripts executable"
|
||||
}
|
||||
|
||||
# Initialize configuration
|
||||
initialize_config() {
|
||||
log_step "Initializing Configuration"
|
||||
|
||||
local config_dir="$MODULE_DIR/config"
|
||||
local config_file="$config_dir/config.php"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log_info "Would initialize configuration files"
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "$config_dir"
|
||||
|
||||
# Create main configuration file
|
||||
cat > "$config_file" << EOF
|
||||
<?php
|
||||
/**
|
||||
* Desk-Moloni v3.0 Configuration
|
||||
* Auto-generated during installation on $(date)
|
||||
*/
|
||||
|
||||
return [
|
||||
'environment' => '$ENVIRONMENT',
|
||||
'version' => '3.0.0',
|
||||
'installation_date' => '$(date -u +%Y-%m-%dT%H:%M:%SZ)',
|
||||
|
||||
// Database configuration
|
||||
'database' => [
|
||||
'host' => '$DB_HOST',
|
||||
'database' => '$DB_NAME',
|
||||
'username' => '$DB_USER',
|
||||
// Password stored securely in Perfex config
|
||||
],
|
||||
|
||||
// Queue configuration
|
||||
'queue' => [
|
||||
'batch_size' => 10,
|
||||
'max_attempts' => 3,
|
||||
'retry_delay' => 300, // 5 minutes
|
||||
'max_execution_time' => 300, // 5 minutes
|
||||
],
|
||||
|
||||
// API configuration
|
||||
'api' => [
|
||||
'rate_limit' => 60, // requests per minute
|
||||
'timeout' => 30, // seconds
|
||||
'retry_attempts' => 3,
|
||||
],
|
||||
|
||||
// Logging configuration
|
||||
'logging' => [
|
||||
'level' => '$ENVIRONMENT' === 'development' ? 'debug' : 'info',
|
||||
'retention_days' => 30,
|
||||
'max_file_size' => '10M',
|
||||
],
|
||||
|
||||
// Security configuration
|
||||
'security' => [
|
||||
'encryption_method' => 'AES-256-GCM',
|
||||
'token_refresh_threshold' => 300, // 5 minutes before expiry
|
||||
],
|
||||
];
|
||||
EOF
|
||||
|
||||
chown "$WEB_USER:$WEB_USER" "$config_file"
|
||||
chmod 644 "$config_file"
|
||||
log_success "Configuration file created: $config_file"
|
||||
|
||||
# Create environment-specific config
|
||||
local env_config="$config_dir/config.$ENVIRONMENT.php"
|
||||
cat > "$env_config" << EOF
|
||||
<?php
|
||||
/**
|
||||
* Desk-Moloni v3.0 Environment Configuration ($ENVIRONMENT)
|
||||
*/
|
||||
|
||||
return [
|
||||
'debug' => $([ "$ENVIRONMENT" == "development" ] && echo "true" || echo "false"),
|
||||
'log_level' => '$([ "$ENVIRONMENT" == "development" ] && echo "debug" || echo "info")',
|
||||
'api_timeout' => $([ "$ENVIRONMENT" == "development" ] && echo "60" || echo "30"),
|
||||
];
|
||||
EOF
|
||||
|
||||
chown "$WEB_USER:$WEB_USER" "$env_config"
|
||||
chmod 644 "$env_config"
|
||||
log_success "Environment configuration created: $env_config"
|
||||
}
|
||||
|
||||
# Setup cron jobs
|
||||
setup_cron_jobs() {
|
||||
if [[ "$SKIP_CRON" == true ]]; then
|
||||
log_warning "Skipping cron job setup"
|
||||
return
|
||||
fi
|
||||
|
||||
log_step "Setting Up Cron Jobs"
|
||||
|
||||
local cron_script="$MODULE_DIR/scripts/setup_cron.sh"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log_info "Would setup cron jobs using: $cron_script"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -f "$cron_script" ]]; then
|
||||
chmod +x "$cron_script"
|
||||
|
||||
# Run cron setup script
|
||||
if "$cron_script" --user "$WEB_USER"; then
|
||||
log_success "Cron jobs installed successfully"
|
||||
else
|
||||
log_error "Failed to install cron jobs"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_warning "Cron setup script not found: $cron_script"
|
||||
fi
|
||||
}
|
||||
|
||||
# Post-installation verification
|
||||
verify_installation() {
|
||||
log_step "Post-Installation Verification"
|
||||
|
||||
local errors=0
|
||||
|
||||
# Verify database tables
|
||||
if [[ "$SKIP_DATABASE" == false ]]; then
|
||||
local mysql_cmd="mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD $DB_NAME"
|
||||
local required_tables=("desk_moloni_config" "desk_moloni_mapping" "desk_moloni_sync_queue" "desk_moloni_sync_log")
|
||||
|
||||
for table in "${required_tables[@]}"; do
|
||||
if echo "SHOW TABLES LIKE '$table';" | $mysql_cmd | grep -q "$table"; then
|
||||
log_success "✓ Table exists: $table"
|
||||
else
|
||||
log_error "✗ Table missing: $table"
|
||||
((errors++))
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Verify file permissions
|
||||
local required_dirs=("$MODULE_DIR/logs" "$MODULE_DIR/locks")
|
||||
for dir in "${required_dirs[@]}"; do
|
||||
if [[ -d "$dir" ]] && [[ -w "$dir" ]]; then
|
||||
log_success "✓ Directory writable: $dir"
|
||||
else
|
||||
log_error "✗ Directory not writable: $dir"
|
||||
((errors++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Verify CLI commands
|
||||
local cli_files=("$MODULE_DIR/cli/queue_processor.php" "$MODULE_DIR/cli/sync_commands.php")
|
||||
for file in "${cli_files[@]}"; do
|
||||
if [[ -f "$file" ]] && [[ -x "$file" ]]; then
|
||||
log_success "✓ CLI command executable: $(basename "$file")"
|
||||
else
|
||||
log_error "✗ CLI command not executable: $(basename "$file")"
|
||||
((errors++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Test basic functionality
|
||||
if [[ "$DRY_RUN" == false ]]; then
|
||||
local health_cmd="php $MODULE_DIR/cli/sync_commands.php health"
|
||||
if $health_cmd &>/dev/null; then
|
||||
log_success "✓ Health check command works"
|
||||
else
|
||||
log_warning "⚠ Health check command failed (may be expected on first run)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $errors -eq 0 ]]; then
|
||||
log_success "All verification checks passed"
|
||||
else
|
||||
log_error "Verification failed with $errors errors"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Uninstallation
|
||||
uninstall_module() {
|
||||
log_step "Uninstalling Desk-Moloni Module"
|
||||
|
||||
local confirm="no"
|
||||
if [[ "$FORCE_INSTALL" == false ]]; then
|
||||
echo -e "${RED}WARNING: This will permanently delete all Desk-Moloni data!${NC}"
|
||||
echo -n "Type 'YES' to confirm uninstallation: "
|
||||
read -r confirm
|
||||
else
|
||||
confirm="YES"
|
||||
fi
|
||||
|
||||
if [[ "$confirm" != "YES" ]]; then
|
||||
log_info "Uninstallation cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create backup before uninstall
|
||||
BACKUP_BEFORE_INSTALL=true
|
||||
create_backup
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log_info "Would uninstall module and remove all data"
|
||||
return
|
||||
fi
|
||||
|
||||
# Remove cron jobs
|
||||
local cron_script="$MODULE_DIR/scripts/setup_cron.sh"
|
||||
if [[ -f "$cron_script" ]]; then
|
||||
"$cron_script" --uninstall --user "$WEB_USER" || true
|
||||
log_success "Cron jobs removed"
|
||||
fi
|
||||
|
||||
# Drop database tables
|
||||
if [[ "$SKIP_DATABASE" == false ]]; then
|
||||
local mysql_cmd="mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD $DB_NAME"
|
||||
local tables=("desk_moloni_sync_log" "desk_moloni_sync_queue" "desk_moloni_mapping" "desk_moloni_config")
|
||||
|
||||
for table in "${tables[@]}"; do
|
||||
echo "DROP TABLE IF EXISTS $table;" | $mysql_cmd
|
||||
log_success "Dropped table: $table"
|
||||
done
|
||||
fi
|
||||
|
||||
# Remove module files (but preserve backups)
|
||||
local preserve_dirs=("backups")
|
||||
for dir in "$MODULE_DIR"/*; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
local dirname=$(basename "$dir")
|
||||
if [[ ! " ${preserve_dirs[@]} " =~ " ${dirname} " ]]; then
|
||||
rm -rf "$dir"
|
||||
log_success "Removed directory: $dir"
|
||||
fi
|
||||
elif [[ -f "$dir" ]]; then
|
||||
rm -f "$dir"
|
||||
log_success "Removed file: $dir"
|
||||
fi
|
||||
done
|
||||
|
||||
log_success "Module uninstalled successfully"
|
||||
log_info "Backup preserved at: $BACKUP_DIR"
|
||||
}
|
||||
|
||||
# Restore from backup
|
||||
restore_from_backup() {
|
||||
log_step "Restoring from Backup"
|
||||
|
||||
if [[ ! -d "$RESTORE_BACKUP" ]]; then
|
||||
log_error "Backup directory not found: $RESTORE_BACKUP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local manifest_file="$RESTORE_BACKUP/manifest.txt"
|
||||
if [[ ! -f "$manifest_file" ]]; then
|
||||
log_error "Backup manifest not found: $manifest_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Backup details:"
|
||||
cat "$manifest_file"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log_info "Would restore from backup: $RESTORE_BACKUP"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -n "Proceed with restore? [y/N]: "
|
||||
read -r confirm
|
||||
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
||||
log_info "Restore cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Restore database tables
|
||||
local mysql_cmd="mysql -h$DB_HOST -u$DB_USER -p$DB_PASSWORD $DB_NAME"
|
||||
for sql_file in "$RESTORE_BACKUP"/*.sql; do
|
||||
if [[ -f "$sql_file" ]]; then
|
||||
local table_name=$(basename "$sql_file" .sql)
|
||||
log_info "Restoring table: $table_name"
|
||||
$mysql_cmd < "$sql_file"
|
||||
log_success "Table restored: $table_name"
|
||||
fi
|
||||
done
|
||||
|
||||
# Restore configuration files
|
||||
if [[ -d "$RESTORE_BACKUP/config" ]]; then
|
||||
cp -r "$RESTORE_BACKUP/config/"* "$MODULE_DIR/config/" 2>/dev/null || true
|
||||
log_success "Configuration files restored"
|
||||
fi
|
||||
|
||||
log_success "Restore completed successfully"
|
||||
}
|
||||
|
||||
# Main installation function
|
||||
main_install() {
|
||||
log_step "Starting Desk-Moloni v3.0 Installation"
|
||||
|
||||
# Installation steps
|
||||
check_requirements
|
||||
interactive_config
|
||||
test_database_connection
|
||||
create_backup
|
||||
install_database
|
||||
setup_permissions
|
||||
initialize_config
|
||||
setup_cron_jobs
|
||||
verify_installation
|
||||
|
||||
log_step "Installation Completed Successfully"
|
||||
|
||||
echo -e "\n${GREEN}🎉 Desk-Moloni v3.0 has been installed successfully!${NC}\n"
|
||||
|
||||
echo "Next steps:"
|
||||
echo "1. Configure OAuth credentials in the Perfex CRM admin panel"
|
||||
echo "2. Test the API connection: php $MODULE_DIR/cli/sync_commands.php test-connection"
|
||||
echo "3. Monitor the queue processor: tail -f $MODULE_DIR/logs/queue_processor.log"
|
||||
echo "4. Check system health: php $MODULE_DIR/cli/sync_commands.php health"
|
||||
echo ""
|
||||
echo "Documentation: See $MODULE_DIR/README.md"
|
||||
echo "Log files: $MODULE_DIR/logs/"
|
||||
echo "Configuration: $MODULE_DIR/config/"
|
||||
echo ""
|
||||
|
||||
if [[ "$ENVIRONMENT" == "development" ]]; then
|
||||
echo -e "${YELLOW}Development environment detected${NC}"
|
||||
echo "- Debug mode enabled"
|
||||
echo "- Extended API timeouts"
|
||||
echo "- Detailed logging"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
# Handle special operations
|
||||
if [[ "$UNINSTALL" == true ]]; then
|
||||
uninstall_module
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -n "$RESTORE_BACKUP" ]]; then
|
||||
restore_from_backup
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Normal installation
|
||||
main_install
|
||||
}
|
||||
|
||||
# Error handling
|
||||
trap 'log_error "Installation failed on line $LINENO. Check $INSTALL_LOG for details."' ERR
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user