Upgraded to 1.1.0
1.1.0 (2025-10-09) - **User Notifications System** - In-app notification center with 7 notification types, filtering, pagination - **Advanced Session Management** - Database-backed sessions with geolocation (country, city, ISP) - **Remote Session Control** - Terminate any device instantly with immediate logout validation - **Enhanced Profile Page** - Sidebar navigation with 4 tabs, hash-based routing (#profile, #security, #sessions) - **MVC Architecture Refactoring** - 3 new Helpers (Layout, Domain, Session), ~265 lines cleaned from views - **Geolocation Tracking** - IP-based location detection using ip-api.com, country flags with flag-icons - **Device Detection** - Browser & device type parsing (Chrome/Firefox/Safari, Desktop/Mobile/Tablet) - **Auto-Detected Cron Paths** - Settings show actual installation paths (thanks @jadeops) - **Welcome Notifications** - Sent to new users on registration or fresh install - **Upgrade Notifications** - Admins notified on system updates with version & migration count - **Web-Based Installer** - Replaces CLI, auto-generates encryption key, one-time password display - **Web-Based Updater** - `/install/update` for running new migrations with smart detection - **User Registration** - Full signup flow with email verification, password reset, resend verification - **User Management** - CRUD for users with filtering, sorting, pagination (admin-only) - **Remember Me** - 30-day secure tokens linked to sessions, cascade deletion on logout - **Session Validator** - Middleware validates sessions on every request for instant remote logout - **Consistent UI/UX** - Unified filtering, sorting, pagination across Domains, Users, Notifications, TLD Registry - **Smart Migrations** - Consolidated schema for fresh installs, incremental for upgrades - **XSS Protection** - htmlspecialchars() applied across all user-facing data (thanks @jadeops)
This commit is contained in:
@@ -1,155 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
|
||||
// Load environment variables
|
||||
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
|
||||
$dotenv->load();
|
||||
|
||||
try {
|
||||
// Check if encryption key is set, if not generate and save it
|
||||
if (empty($_ENV['APP_ENCRYPTION_KEY'])) {
|
||||
echo "🔑 Generating encryption key...\n";
|
||||
|
||||
// Generate a secure 32-byte (256-bit) key
|
||||
$encryptionKey = base64_encode(random_bytes(32));
|
||||
|
||||
// Path to .env file
|
||||
$envFile = __DIR__ . '/../.env';
|
||||
|
||||
if (!file_exists($envFile)) {
|
||||
echo "✗ Error: .env file not found. Please create it first.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Read current .env content
|
||||
$envContent = file_get_contents($envFile);
|
||||
|
||||
// Check if APP_ENCRYPTION_KEY line exists
|
||||
if (strpos($envContent, 'APP_ENCRYPTION_KEY=') !== false) {
|
||||
// Replace empty value with generated key
|
||||
$envContent = preg_replace(
|
||||
'/APP_ENCRYPTION_KEY=.*$/m',
|
||||
"APP_ENCRYPTION_KEY=$encryptionKey",
|
||||
$envContent
|
||||
);
|
||||
} else {
|
||||
// Append the key to the file
|
||||
$envContent .= "\nAPP_ENCRYPTION_KEY=$encryptionKey\n";
|
||||
}
|
||||
|
||||
// Write updated content back to .env
|
||||
if (!file_put_contents($envFile, $envContent)) {
|
||||
echo "✗ Error: Could not write to .env file.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Reload environment variables
|
||||
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
|
||||
$dotenv->load();
|
||||
|
||||
echo "✓ Encryption key generated and saved to .env\n";
|
||||
echo " Key: $encryptionKey\n";
|
||||
echo " ⚠️ Keep this key secret and backup securely!\n\n";
|
||||
}
|
||||
|
||||
$host = $_ENV['DB_HOST'];
|
||||
$port = $_ENV['DB_PORT'];
|
||||
$database = $_ENV['DB_DATABASE'];
|
||||
$username = $_ENV['DB_USERNAME'];
|
||||
$password = $_ENV['DB_PASSWORD'];
|
||||
|
||||
// Connect to database
|
||||
$dsn = "mysql:host=$host;port=$port;dbname=$database;charset=utf8mb4";
|
||||
$pdo = new PDO($dsn, $username, $password, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
]);
|
||||
|
||||
echo "Connected to database successfully!\n\n";
|
||||
|
||||
// Generate random admin password
|
||||
$adminPassword = bin2hex(random_bytes(8)); // 16 character random password
|
||||
$adminPasswordHash = password_hash($adminPassword, PASSWORD_BCRYPT);
|
||||
|
||||
// Get all migration files
|
||||
$migrationFiles = [
|
||||
__DIR__ . '/migrations/001_create_tables.sql',
|
||||
__DIR__ . '/migrations/002_create_users_table.sql',
|
||||
__DIR__ . '/migrations/003_add_whois_fields.sql',
|
||||
__DIR__ . '/migrations/004_create_tld_registry_table.sql',
|
||||
__DIR__ . '/migrations/005_update_tld_import_logs.sql',
|
||||
__DIR__ . '/migrations/006_add_complete_workflow_import_type.sql',
|
||||
__DIR__ . '/migrations/007_add_app_and_email_settings.sql',
|
||||
__DIR__ . '/migrations/008_add_notes_to_domains.sql',
|
||||
];
|
||||
|
||||
foreach ($migrationFiles as $migrationFile) {
|
||||
if (!file_exists($migrationFile)) {
|
||||
echo "⚠ Migration file not found: " . basename($migrationFile) . "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
echo "Running migration: " . basename($migrationFile) . "\n";
|
||||
|
||||
$sql = file_get_contents($migrationFile);
|
||||
|
||||
// Replace password placeholder in users migration
|
||||
if (basename($migrationFile) === '002_create_users_table.sql') {
|
||||
$sql = str_replace('{{ADMIN_PASSWORD_HASH}}', $adminPasswordHash, $sql);
|
||||
}
|
||||
|
||||
// Split by semicolon and execute each statement
|
||||
$statements = array_filter(array_map('trim', explode(';', $sql)));
|
||||
|
||||
foreach ($statements as $statement) {
|
||||
if (!empty($statement)) {
|
||||
try {
|
||||
$pdo->exec($statement);
|
||||
} catch (PDOException $e) {
|
||||
// Check if it's a "column already exists" error for migrations 003, 005, and 008
|
||||
if (strpos($e->getMessage(), 'Duplicate column name') !== false &&
|
||||
(basename($migrationFile) === '003_add_whois_fields.sql' ||
|
||||
basename($migrationFile) === '005_update_tld_import_logs.sql' ||
|
||||
basename($migrationFile) === '008_add_notes_to_domains.sql')) {
|
||||
echo " ⚠ Column already exists, skipping: " . $e->getMessage() . "\n";
|
||||
continue;
|
||||
}
|
||||
// Check if it's an enum modification error for migrations 005 and 006
|
||||
if (strpos($e->getMessage(), 'Duplicate entry') !== false &&
|
||||
(basename($migrationFile) === '005_update_tld_import_logs.sql' ||
|
||||
basename($migrationFile) === '006_add_complete_workflow_import_type.sql')) {
|
||||
echo " ⚠ Enum already updated, skipping: " . $e->getMessage() . "\n";
|
||||
continue;
|
||||
}
|
||||
// Re-throw other errors
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "✓ " . basename($migrationFile) . " completed\n";
|
||||
}
|
||||
|
||||
echo "\n✓ All migrations completed successfully!\n";
|
||||
echo "✓ All tables created.\n";
|
||||
echo "\n🔑 Admin credentials (SAVE THESE!):\n";
|
||||
echo " ═══════════════════════════════════════\n";
|
||||
echo " Username: admin\n";
|
||||
echo " Password: $adminPassword\n";
|
||||
echo " ═══════════════════════════════════════\n";
|
||||
echo " ⚠️ This password will not be shown again!\n";
|
||||
echo " 💾 Save it to a secure password manager.\n\n";
|
||||
echo "🌐 TLD Registry System:\n";
|
||||
echo " • Import RDAP data: php cron/import_tld_registry.php --rdap-only\n";
|
||||
echo " • Import WHOIS data: php cron/import_tld_registry.php --whois-only\n";
|
||||
echo " • Check for updates: php cron/import_tld_registry.php --check-updates\n";
|
||||
echo " • Full import: php cron/import_tld_registry.php\n\n";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
echo "✗ Migration failed: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
270
database/migrations/000_initial_schema_v1.1.0.sql
Normal file
270
database/migrations/000_initial_schema_v1.1.0.sql
Normal file
@@ -0,0 +1,270 @@
|
||||
-- Domain Monitor v1.1.0 - Complete Initial Schema
|
||||
-- This consolidated migration includes all features for fresh installations
|
||||
|
||||
-- =====================================================
|
||||
-- CORE TABLES
|
||||
-- =====================================================
|
||||
|
||||
-- Domains table
|
||||
CREATE TABLE IF NOT EXISTS domains (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
domain_name VARCHAR(255) NOT NULL UNIQUE,
|
||||
notification_group_id INT NULL,
|
||||
registrar VARCHAR(255),
|
||||
registrar_url VARCHAR(255),
|
||||
expiration_date DATE,
|
||||
updated_date DATE,
|
||||
abuse_email VARCHAR(255),
|
||||
last_checked TIMESTAMP NULL,
|
||||
status ENUM('active', 'expiring_soon', 'expired', 'error', 'available') DEFAULT 'active',
|
||||
whois_data JSON,
|
||||
notes TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (notification_group_id) REFERENCES notification_groups(id) ON DELETE SET NULL,
|
||||
INDEX idx_notification_group_id (notification_group_id),
|
||||
INDEX idx_domain_name (domain_name),
|
||||
INDEX idx_expiration_date (expiration_date),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_is_active (is_active)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Notification groups table
|
||||
CREATE TABLE IF NOT EXISTS notification_groups (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
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;
|
||||
|
||||
-- Notification channels table
|
||||
CREATE TABLE IF NOT EXISTS notification_channels (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
notification_group_id INT NOT NULL,
|
||||
channel_type ENUM('email', 'telegram', 'discord', 'slack') NOT NULL,
|
||||
channel_config JSON NOT NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (notification_group_id) REFERENCES notification_groups(id) ON DELETE CASCADE,
|
||||
INDEX idx_group_id (notification_group_id),
|
||||
INDEX idx_channel_type (channel_type)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Notification logs table
|
||||
CREATE TABLE IF NOT EXISTS notification_logs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
domain_id INT NOT NULL,
|
||||
notification_type VARCHAR(50) NOT NULL,
|
||||
channel_type VARCHAR(50) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
status ENUM('sent', 'failed') DEFAULT 'sent',
|
||||
error_message TEXT,
|
||||
FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE,
|
||||
INDEX idx_domain_id (domain_id),
|
||||
INDEX idx_sent_at (sent_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- =====================================================
|
||||
-- USER MANAGEMENT & AUTHENTICATION
|
||||
-- =====================================================
|
||||
|
||||
-- Users table
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(100) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255),
|
||||
email_verified BOOLEAN DEFAULT FALSE,
|
||||
email_verification_token VARCHAR(255) NULL,
|
||||
email_verification_sent_at TIMESTAMP NULL,
|
||||
full_name VARCHAR(255),
|
||||
role VARCHAR(50) DEFAULT 'user',
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
last_login TIMESTAMP NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_username (username),
|
||||
INDEX idx_email (email),
|
||||
INDEX idx_role (role)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Insert default admin user (password will be set during installation)
|
||||
INSERT INTO users (username, password, email, full_name, is_active, role, email_verified) VALUES
|
||||
('admin', '{{ADMIN_PASSWORD_HASH}}', 'admin@domainmonitor.local', 'Administrator', 1, 'admin', 1)
|
||||
ON DUPLICATE KEY UPDATE username=username;
|
||||
|
||||
-- Password reset tokens table
|
||||
CREATE TABLE IF NOT EXISTS password_reset_tokens (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
token VARCHAR(255) NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
used BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
INDEX idx_token (token),
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_expires_at (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Sessions table (database-backed sessions)
|
||||
CREATE TABLE IF NOT EXISTS sessions (
|
||||
id VARCHAR(128) NOT NULL PRIMARY KEY,
|
||||
user_id INT DEFAULT NULL,
|
||||
ip_address VARCHAR(45) NOT NULL,
|
||||
user_agent TEXT,
|
||||
country VARCHAR(100) DEFAULT NULL,
|
||||
country_code VARCHAR(2) DEFAULT NULL,
|
||||
region VARCHAR(100) DEFAULT NULL,
|
||||
city VARCHAR(100) DEFAULT NULL,
|
||||
isp VARCHAR(255) DEFAULT NULL,
|
||||
timezone VARCHAR(50) DEFAULT NULL,
|
||||
payload MEDIUMTEXT NOT NULL,
|
||||
last_activity INT UNSIGNED NOT NULL,
|
||||
created_at INT UNSIGNED NOT NULL,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_last_activity (last_activity),
|
||||
INDEX idx_created_at (created_at),
|
||||
CONSTRAINT fk_sessions_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Remember me tokens table
|
||||
CREATE TABLE IF NOT EXISTS remember_tokens (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
session_id VARCHAR(128) DEFAULT NULL,
|
||||
token VARCHAR(255) NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE,
|
||||
INDEX idx_token (token),
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_session_id (session_id),
|
||||
INDEX idx_expires_at (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- User notifications table (in-app notifications)
|
||||
CREATE TABLE IF NOT EXISTS user_notifications (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
domain_id INT NULL,
|
||||
is_read BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
read_at TIMESTAMP NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE SET NULL,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_is_read (is_read),
|
||||
INDEX idx_created_at (created_at),
|
||||
INDEX idx_type (type)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- =====================================================
|
||||
-- TLD REGISTRY SYSTEM
|
||||
-- =====================================================
|
||||
|
||||
-- TLD registry table
|
||||
CREATE TABLE IF NOT EXISTS tld_registry (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
tld VARCHAR(63) NOT NULL UNIQUE,
|
||||
rdap_servers JSON,
|
||||
whois_server VARCHAR(255),
|
||||
registry_url VARCHAR(500),
|
||||
iana_publication_date TIMESTAMP NULL,
|
||||
iana_last_updated TIMESTAMP NULL,
|
||||
record_last_updated TIMESTAMP NULL,
|
||||
registration_date DATE NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_tld (tld),
|
||||
INDEX idx_is_active (is_active),
|
||||
INDEX idx_iana_publication_date (iana_publication_date)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- TLD import logs table
|
||||
CREATE TABLE IF NOT EXISTS tld_import_logs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
import_type ENUM('tld_list', 'rdap', 'whois', 'manual', 'complete_workflow', 'check_updates') NOT NULL,
|
||||
total_tlds INT DEFAULT 0,
|
||||
new_tlds INT DEFAULT 0,
|
||||
updated_tlds INT DEFAULT 0,
|
||||
failed_tlds INT DEFAULT 0,
|
||||
iana_publication_date TIMESTAMP NULL,
|
||||
version VARCHAR(50) NULL,
|
||||
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
completed_at TIMESTAMP NULL,
|
||||
status ENUM('running', 'completed', 'failed') DEFAULT 'running',
|
||||
error_message TEXT,
|
||||
details JSON,
|
||||
INDEX idx_started_at (started_at),
|
||||
INDEX idx_status (status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- =====================================================
|
||||
-- SYSTEM SETTINGS
|
||||
-- =====================================================
|
||||
|
||||
-- Settings table
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
setting_key VARCHAR(255) NOT NULL UNIQUE,
|
||||
setting_value TEXT,
|
||||
`type` VARCHAR(50) DEFAULT 'string',
|
||||
`description` TEXT,
|
||||
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;
|
||||
|
||||
-- Insert default settings
|
||||
INSERT INTO settings (setting_key, setting_value, `type`, `description`) VALUES
|
||||
-- Application settings
|
||||
('app_name', 'Domain Monitor', 'string', 'Application name'),
|
||||
('app_url', 'http://localhost:8000', 'string', 'Application URL'),
|
||||
('app_timezone', 'UTC', 'string', 'Application timezone'),
|
||||
('app_version', '1.1.0', 'string', 'Application version number'),
|
||||
|
||||
-- Email settings
|
||||
('mail_host', 'smtp.mailtrap.io', 'string', 'SMTP server host'),
|
||||
('mail_port', '2525', 'string', 'SMTP server port'),
|
||||
('mail_username', '', 'string', 'SMTP username'),
|
||||
('mail_password', '', 'encrypted', 'SMTP password (encrypted)'),
|
||||
('mail_encryption', 'tls', 'string', 'SMTP encryption (tls/ssl)'),
|
||||
('mail_from_address', 'noreply@domainmonitor.com', 'string', 'From email address'),
|
||||
('mail_from_name', 'Domain Monitor', 'string', 'From name'),
|
||||
|
||||
-- Monitoring settings
|
||||
('notification_days_before', '60,30,21,14,7,5,3,2,1', 'string', 'Notification days before expiration'),
|
||||
('check_interval_hours', '24', 'string', 'Domain check interval in hours'),
|
||||
('last_check_run', NULL, 'datetime', 'Last time cron job ran'),
|
||||
|
||||
-- Authentication settings
|
||||
('registration_enabled', '0', 'boolean', 'Enable user registration'),
|
||||
('require_email_verification', '1', 'boolean', 'Require email verification for new users')
|
||||
|
||||
ON DUPLICATE KEY UPDATE setting_key=setting_key;
|
||||
|
||||
-- =====================================================
|
||||
-- MIGRATION TRACKING
|
||||
-- =====================================================
|
||||
|
||||
-- Migrations tracking table
|
||||
CREATE TABLE IF NOT EXISTS migrations (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
migration VARCHAR(255) NOT NULL UNIQUE,
|
||||
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_migration (migration)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Mark this consolidated migration as executed
|
||||
INSERT INTO migrations (migration) VALUES ('000_initial_schema_v1.1.0.sql')
|
||||
ON DUPLICATE KEY UPDATE migration=migration;
|
||||
|
||||
@@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Insert default admin user
|
||||
-- Password is randomly generated during migration and displayed in output
|
||||
-- Hash placeholder will be replaced by migrate.php
|
||||
-- Password is randomly generated during installation and displayed in output
|
||||
-- Hash placeholder will be replaced by web installer
|
||||
INSERT INTO users (username, password, email, full_name, is_active) VALUES
|
||||
('admin', '{{ADMIN_PASSWORD_HASH}}', 'admin@domainmonitor.local', 'Administrator', 1)
|
||||
ON DUPLICATE KEY UPDATE username=username;
|
||||
|
||||
49
database/migrations/009_add_authentication_features.sql
Normal file
49
database/migrations/009_add_authentication_features.sql
Normal file
@@ -0,0 +1,49 @@
|
||||
-- Add authentication features
|
||||
-- Email verification and password reset tokens
|
||||
|
||||
-- Add email verification fields to users table
|
||||
ALTER TABLE users
|
||||
ADD COLUMN email_verified BOOLEAN DEFAULT FALSE AFTER email,
|
||||
ADD COLUMN email_verification_token VARCHAR(255) NULL AFTER email_verified,
|
||||
ADD COLUMN email_verification_sent_at TIMESTAMP NULL AFTER email_verification_token;
|
||||
|
||||
-- Create password reset tokens table
|
||||
CREATE TABLE IF NOT EXISTS password_reset_tokens (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
token VARCHAR(255) NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
used BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
INDEX idx_token (token),
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_expires_at (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Create remember me tokens table
|
||||
CREATE TABLE IF NOT EXISTS remember_tokens (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
token VARCHAR(255) NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
INDEX idx_token (token),
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_expires_at (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Add role field to users for future multi-user support
|
||||
ALTER TABLE users
|
||||
ADD COLUMN role VARCHAR(50) DEFAULT 'user' AFTER full_name;
|
||||
|
||||
-- Update existing admin user to have admin role
|
||||
UPDATE users SET role = 'admin' WHERE username = 'admin';
|
||||
|
||||
-- Add settings for registration
|
||||
INSERT INTO settings (setting_key, setting_value) VALUES
|
||||
('registration_enabled', '0'),
|
||||
('require_email_verification', '1')
|
||||
ON DUPLICATE KEY UPDATE setting_key=setting_key;
|
||||
|
||||
5
database/migrations/010_add_app_version_setting.sql
Normal file
5
database/migrations/010_add_app_version_setting.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- Add application version to settings
|
||||
INSERT INTO settings (setting_key, setting_value) VALUES
|
||||
('app_version', '1.1.0')
|
||||
ON DUPLICATE KEY UPDATE setting_key=setting_key;
|
||||
|
||||
21
database/migrations/011_create_sessions_table.sql
Normal file
21
database/migrations/011_create_sessions_table.sql
Normal file
@@ -0,0 +1,21 @@
|
||||
-- Create new sessions table compatible with PHP session handler
|
||||
CREATE TABLE `sessions` (
|
||||
`id` VARCHAR(128) NOT NULL PRIMARY KEY,
|
||||
`user_id` INT DEFAULT NULL,
|
||||
`ip_address` VARCHAR(45) NOT NULL,
|
||||
`user_agent` TEXT,
|
||||
`country` VARCHAR(100) DEFAULT NULL,
|
||||
`country_code` VARCHAR(2) DEFAULT NULL,
|
||||
`region` VARCHAR(100) DEFAULT NULL,
|
||||
`city` VARCHAR(100) DEFAULT NULL,
|
||||
`isp` VARCHAR(255) DEFAULT NULL,
|
||||
`timezone` VARCHAR(50) DEFAULT NULL,
|
||||
`payload` MEDIUMTEXT NOT NULL,
|
||||
`last_activity` INT UNSIGNED NOT NULL,
|
||||
`created_at` INT UNSIGNED NOT NULL,
|
||||
INDEX `idx_user_id` (`user_id`),
|
||||
INDEX `idx_last_activity` (`last_activity`),
|
||||
INDEX `idx_created_at` (`created_at`),
|
||||
CONSTRAINT `fk_sessions_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-- Link remember tokens to sessions
|
||||
-- This ensures deleting a session also invalidates the remember token
|
||||
|
||||
-- Add session_id column to remember_tokens
|
||||
ALTER TABLE `remember_tokens`
|
||||
ADD COLUMN `session_id` VARCHAR(128) DEFAULT NULL AFTER `user_id`,
|
||||
ADD INDEX `idx_session_id` (`session_id`);
|
||||
19
database/migrations/013_create_user_notifications_table.sql
Normal file
19
database/migrations/013_create_user_notifications_table.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- Create user_notifications table for in-app notifications
|
||||
CREATE TABLE IF NOT EXISTS `user_notifications` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`user_id` INT NOT NULL,
|
||||
`type` VARCHAR(50) NOT NULL,
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`domain_id` INT NULL,
|
||||
`is_read` BOOLEAN DEFAULT FALSE,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`read_at` TIMESTAMP NULL,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`domain_id`) REFERENCES `domains`(`id`) ON DELETE SET NULL,
|
||||
INDEX `idx_user_id` (`user_id`),
|
||||
INDEX `idx_is_read` (`is_read`),
|
||||
INDEX `idx_created_at` (`created_at`),
|
||||
INDEX `idx_type` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
36
database/migrations/README.md
Normal file
36
database/migrations/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Database Migrations
|
||||
|
||||
## Fresh Installation (v1.1.0+)
|
||||
|
||||
For new installations, use the consolidated schema:
|
||||
|
||||
- **`000_initial_schema_v1.1.0.sql`** - Complete database schema for v1.1.0
|
||||
|
||||
**Install via:** Web installer at `/install`
|
||||
|
||||
## Incremental Migrations (v1.0.0 → v1.1.0)
|
||||
|
||||
If upgrading from v1.0.0, these incremental migrations will be applied:
|
||||
|
||||
- `001_create_tables.sql` - Core tables (domains, groups, channels, logs)
|
||||
- `002_create_users_table.sql` - Users table
|
||||
- `003_add_whois_fields.sql` - WHOIS data fields
|
||||
- `004_create_tld_registry_table.sql` - TLD registry
|
||||
- `005_update_tld_import_logs.sql` - Import logs updates
|
||||
- `006_add_complete_workflow_import_type.sql` - Workflow import type
|
||||
- `007_add_app_and_email_settings.sql` - Application settings
|
||||
- `008_add_notes_to_domains.sql` - Domain notes field
|
||||
- `009_add_authentication_features.sql` - Authentication system
|
||||
- `010_add_app_version_setting.sql` - Version setting
|
||||
|
||||
**Upgrade via:** Web updater at `/install/update`
|
||||
|
||||
## Migration System
|
||||
|
||||
The installer automatically:
|
||||
- Detects if this is a fresh install or upgrade
|
||||
- Uses consolidated schema for fresh installs
|
||||
- Uses incremental migrations for upgrades
|
||||
- Tracks executed migrations in `migrations` table
|
||||
- Prevents re-running completed migrations
|
||||
|
||||
Reference in New Issue
Block a user