537 lines
31 KiB
PHP
537 lines
31 KiB
PHP
<?php
|
|
/**
|
|
* Settings Page - Admin Only
|
|
*
|
|
* Contains: Integrations, Audit Log, Advanced, Whitelabel, Developer tabs
|
|
*/
|
|
|
|
// Include config
|
|
$configFile = __DIR__ . '/config.php';
|
|
if (file_exists($configFile)) {
|
|
require_once $configFile;
|
|
}
|
|
|
|
// Fallback CSRF
|
|
if (!function_exists('generateCSRFToken')) {
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
function generateCSRFToken() {
|
|
if (empty($_SESSION['csrf_token'])) {
|
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
}
|
|
return $_SESSION['csrf_token'];
|
|
}
|
|
}
|
|
|
|
// Require authentication
|
|
if (function_exists('requireAuth')) {
|
|
requireAuth();
|
|
}
|
|
|
|
// Include auth helper
|
|
require_once __DIR__ . '/includes/auth.php';
|
|
|
|
// Require admin role
|
|
if (!isAdmin()) {
|
|
header('Location: index.php?error=unauthorized');
|
|
exit;
|
|
}
|
|
|
|
// Set page variables for header
|
|
$pageTitle = 'Settings - ISP IP Manager';
|
|
$currentPage = 'settings';
|
|
$showSettingsLink = false;
|
|
|
|
// Get current tab from URL
|
|
$currentTab = $_GET['tab'] ?? 'integrations';
|
|
$validTabs = ['integrations', 'audit', 'advanced', 'whitelabel', 'developer'];
|
|
if (!in_array($currentTab, $validTabs)) {
|
|
$currentTab = 'integrations';
|
|
}
|
|
|
|
// Include header
|
|
require_once __DIR__ . '/includes/header.php';
|
|
?>
|
|
|
|
<h1 class="settings-page-title">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="3"/>
|
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
|
</svg>
|
|
Settings
|
|
</h1>
|
|
|
|
<!-- Settings Navigation -->
|
|
<div class="settings-nav">
|
|
<a href="?tab=integrations" class="settings-nav-item <?php echo $currentTab === 'integrations' ? 'active' : ''; ?>">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
|
|
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
|
|
</svg>
|
|
Integrations
|
|
</a>
|
|
<a href="?tab=audit" class="settings-nav-item <?php echo $currentTab === 'audit' ? 'active' : ''; ?>">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
|
<polyline points="14 2 14 8 20 8"/>
|
|
<line x1="16" y1="13" x2="8" y2="13"/>
|
|
<line x1="16" y1="17" x2="8" y2="17"/>
|
|
</svg>
|
|
Audit Log
|
|
</a>
|
|
<a href="?tab=advanced" class="settings-nav-item <?php echo $currentTab === 'advanced' ? 'active' : ''; ?>">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="3"/>
|
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
|
</svg>
|
|
Advanced
|
|
</a>
|
|
<a href="?tab=whitelabel" class="settings-nav-item <?php echo $currentTab === 'whitelabel' ? 'active' : ''; ?>">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
|
|
<circle cx="8.5" cy="8.5" r="1.5"/>
|
|
<polyline points="21 15 16 10 5 21"/>
|
|
</svg>
|
|
Whitelabel
|
|
</a>
|
|
<a href="?tab=developer" class="settings-nav-item <?php echo $currentTab === 'developer' ? 'active' : ''; ?>">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="16 18 22 12 16 6"/>
|
|
<polyline points="8 6 2 12 8 18"/>
|
|
</svg>
|
|
Developer
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Integrations Section -->
|
|
<div class="settings-section <?php echo $currentTab === 'integrations' ? 'active' : ''; ?>" id="section-integrations">
|
|
<!-- AWS Route53 Settings -->
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
|
|
<polyline points="3.27 6.96 12 12.01 20.73 6.96"/>
|
|
<line x1="12" y1="22.08" x2="12" y2="12"/>
|
|
</svg>
|
|
AWS Route53 Settings
|
|
</h2>
|
|
<p class="advanced-section-desc">Configure AWS credentials and hosted zones for PTR record management.</p>
|
|
|
|
<div class="form-grid" style="margin-top: 16px;">
|
|
<div class="form-group">
|
|
<label class="form-label">AWS Access Key ID</label>
|
|
<input type="text" class="form-input" id="awsAccessKeyId" placeholder="AKIAIOSFODNN7EXAMPLE">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">AWS Secret Access Key</label>
|
|
<input type="password" class="form-input" id="awsSecretAccessKey" placeholder="••••••••••••••••">
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">AWS Region</label>
|
|
<select class="form-select" id="awsRegion">
|
|
<option value="us-east-1">US East (N. Virginia)</option>
|
|
<option value="us-east-2">US East (Ohio)</option>
|
|
<option value="us-west-1">US West (N. California)</option>
|
|
<option value="us-west-2">US West (Oregon)</option>
|
|
<option value="eu-west-1">EU (Ireland)</option>
|
|
<option value="eu-west-2">EU (London)</option>
|
|
<option value="eu-central-1">EU (Frankfurt)</option>
|
|
<option value="ap-southeast-1">Asia Pacific (Singapore)</option>
|
|
<option value="ap-southeast-2">Asia Pacific (Sydney)</option>
|
|
<option value="ap-northeast-1">Asia Pacific (Tokyo)</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Route53 Hosted Zone IDs (comma separated)</label>
|
|
<input type="text" class="form-input" id="awsHostedZones" placeholder="Z1234567890ABC, Z0987654321DEF">
|
|
<small style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">Enter the hosted zone IDs for your forward DNS zones (A records)</small>
|
|
</div>
|
|
|
|
<div style="display: flex; gap: 12px; flex-wrap: wrap; margin-top: 16px;">
|
|
<button class="btn btn-primary" onclick="saveAwsSettings()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
|
<polyline points="17 21 17 13 7 13 7 21"/>
|
|
<polyline points="7 3 7 8 15 8"/>
|
|
</svg>
|
|
Save AWS Settings
|
|
</button>
|
|
<button class="btn btn-secondary" onclick="testAwsConnection()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
|
|
</svg>
|
|
Test Connection
|
|
</button>
|
|
</div>
|
|
|
|
<div id="awsTestResult" style="margin-top: 16px; display: none;"></div>
|
|
</div>
|
|
|
|
<!-- IP Registry Settings -->
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"/>
|
|
<line x1="2" y1="12" x2="22" y2="12"/>
|
|
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
|
|
</svg>
|
|
IP Registry Integration
|
|
</h2>
|
|
<p class="advanced-section-desc">Enrich IP entries with ISP, organization, and security flag data from <a href="https://ipregistry.co" target="_blank" rel="noopener" style="color: var(--purple-primary);">ipregistry.co</a>.</p>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">
|
|
<input type="checkbox" id="ipRegistryEnabled" style="margin-right: 8px; vertical-align: middle;">
|
|
Enable IP Registry Auto-Enrichment
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">API Key</label>
|
|
<input type="password" class="form-input" id="ipRegistryApiKey" placeholder="Enter your ipregistry.co API key">
|
|
<div class="form-hint">Get your API key from <a href="https://ipregistry.co" target="_blank" rel="noopener" style="color: var(--purple-primary);">ipregistry.co</a>.</div>
|
|
</div>
|
|
|
|
<div style="display: flex; gap: 12px; flex-wrap: wrap;">
|
|
<button class="btn btn-primary" onclick="saveIpRegistrySettings()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
|
<polyline points="17 21 17 13 7 13 7 21"/>
|
|
<polyline points="7 3 7 8 15 8"/>
|
|
</svg>
|
|
Save Settings
|
|
</button>
|
|
<button class="btn btn-secondary" onclick="enrichAllIps(this)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"/>
|
|
<line x1="2" y1="12" x2="22" y2="12"/>
|
|
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
|
|
</svg>
|
|
Enrich All Un-enriched IPs
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- n8n Webhook Settings -->
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
|
|
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
|
|
</svg>
|
|
n8n Webhook Integration
|
|
</h2>
|
|
<p class="advanced-section-desc">Configure webhooks to notify n8n when geofeed data changes.</p>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">
|
|
<input type="checkbox" id="webhookEnabled" style="margin-right: 8px; vertical-align: middle;">
|
|
Enable Webhook Notifications
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Webhook URL</label>
|
|
<input type="url" class="form-input" id="webhookUrl" placeholder="https://your-n8n-instance.com/webhook/xxx">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Debounce Delay (minutes)</label>
|
|
<input type="number" class="form-input" id="webhookDelay" min="1" max="60" value="3" style="max-width: 120px;">
|
|
</div>
|
|
|
|
<div style="display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 20px;">
|
|
<button class="btn btn-primary" onclick="saveWebhookSettings()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
|
<polyline points="17 21 17 13 7 13 7 21"/>
|
|
<polyline points="7 3 7 8 15 8"/>
|
|
</svg>
|
|
Save Settings
|
|
</button>
|
|
<button class="btn btn-secondary" onclick="testWebhook()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polygon points="5 3 19 12 5 21 5 3"/>
|
|
</svg>
|
|
Test Connection
|
|
</button>
|
|
<button class="btn btn-secondary" onclick="triggerWebhookNow()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
|
|
</svg>
|
|
Trigger Now
|
|
</button>
|
|
</div>
|
|
|
|
<div class="table-container" style="margin-top: 16px;">
|
|
<div class="table-header">
|
|
<h3 class="table-title">Webhook Queue</h3>
|
|
<button class="btn btn-ghost btn-sm" onclick="loadWebhookQueueStatus()">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="23 4 23 10 17 10"/>
|
|
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/>
|
|
</svg>
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
<div id="webhookQueueContainer" style="padding: 20px;">
|
|
<div class="loading"><div class="spinner"></div></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Audit Log Section -->
|
|
<div class="settings-section <?php echo $currentTab === 'audit' ? 'active' : ''; ?>" id="section-audit">
|
|
<div class="advanced-section">
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
|
<p class="advanced-section-desc" style="margin: 0;">View all changes made to geofeed entries including creates, updates, and deletes.</p>
|
|
<button class="btn btn-secondary btn-sm" onclick="exportAuditLog()">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
|
<polyline points="7 10 12 15 17 10"/>
|
|
<line x1="12" y1="15" x2="12" y2="3"/>
|
|
</svg>
|
|
Export CSV
|
|
</button>
|
|
</div>
|
|
|
|
<div class="table-container">
|
|
<div class="audit-log-container" id="auditLogContainer">
|
|
<div class="loading"><div class="spinner"></div></div>
|
|
</div>
|
|
<div class="pagination" id="auditPagination" style="display: none;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Advanced Section -->
|
|
<div class="settings-section <?php echo $currentTab === 'advanced' ? 'active' : ''; ?>" id="section-advanced">
|
|
<!-- Client Shortnames -->
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
|
|
<circle cx="9" cy="7" r="4"/>
|
|
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
|
|
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
|
</svg>
|
|
Client Shortnames
|
|
</h2>
|
|
<p class="advanced-section-desc">Manage client shortnames for organizing geofeed entries.</p>
|
|
|
|
<div id="shortnamesContainer" style="margin-top: 16px;">
|
|
<div class="loading"><div class="spinner"></div></div>
|
|
</div>
|
|
|
|
<div style="display: flex; gap: 12px; margin-top: 16px;">
|
|
<input type="text" class="form-input" id="newShortname" placeholder="New shortname" style="max-width: 200px;">
|
|
<button class="btn btn-primary" onclick="addShortname()">Add Shortname</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Company Logos -->
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
|
|
<circle cx="8.5" cy="8.5" r="1.5"/>
|
|
<polyline points="21 15 16 10 5 21"/>
|
|
</svg>
|
|
Company Logos
|
|
</h2>
|
|
<p class="advanced-section-desc">Upload logos for client shortnames to display in the table.</p>
|
|
|
|
<div id="logosContainer" style="margin-top: 16px;">
|
|
<div class="loading"><div class="spinner"></div></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Whitelabel Section -->
|
|
<div class="settings-section <?php echo $currentTab === 'whitelabel' ? 'active' : ''; ?>" id="section-whitelabel">
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
|
|
<circle cx="8.5" cy="8.5" r="1.5"/>
|
|
<polyline points="21 15 16 10 5 21"/>
|
|
</svg>
|
|
Branding
|
|
</h2>
|
|
<p class="advanced-section-desc">Customize the appearance of the application with your company branding.</p>
|
|
|
|
<div class="form-grid" style="margin-top: 16px;">
|
|
<div class="form-group">
|
|
<label class="form-label">App Name</label>
|
|
<input type="text" class="form-input" id="whitelabelAppName" placeholder="ISP IP Manager">
|
|
<div class="form-hint">Displayed in the header and browser tab title</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Company Name</label>
|
|
<input type="text" class="form-input" id="whitelabelCompanyName" placeholder="Your Company">
|
|
<div class="form-hint">Displayed as subtitle in the header</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Webapp Icon URL</label>
|
|
<input type="text" class="form-input" id="whitelabelIconUrl" placeholder="https://example.com/logo.svg">
|
|
<div class="form-hint">URL to an SVG or PNG logo for the header</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Favicon URL</label>
|
|
<input type="text" class="form-input" id="whitelabelFaviconUrl" placeholder="https://example.com/favicon.ico">
|
|
<div class="form-hint">URL to a favicon (.ico, .png, or .svg)</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Default Geofeed Import URL</label>
|
|
<input type="text" class="form-input" id="whitelabelDefaultImportUrl" placeholder="https://example.com/geofeed.csv">
|
|
<div class="form-hint">Pre-populated URL when importing from URL</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="display: flex; gap: 12px; margin-top: 16px;">
|
|
<button class="btn btn-primary" onclick="saveWhitelabelSettings()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
|
<polyline points="17 21 17 13 7 13 7 21"/>
|
|
<polyline points="7 3 7 8 15 8"/>
|
|
</svg>
|
|
Save Settings
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Preview -->
|
|
<div style="margin-top: 24px; padding: 16px; background: var(--bg-tertiary); border-radius: var(--radius-md);">
|
|
<h3 style="font-size: 14px; font-weight: 600; color: var(--text-secondary); margin-bottom: 12px;">Preview</h3>
|
|
<div style="display: flex; align-items: center; gap: 12px; padding: 12px; background: var(--bg-secondary); border-radius: var(--radius-md);">
|
|
<div id="whitelabelPreviewIcon" style="width: 40px; height: 40px; background: var(--purple-primary); border-radius: 8px; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
|
<svg viewBox="0 0 258 258" fill="none" width="24" height="24">
|
|
<path fill="white" d="M241.13 56.2A26.53 26.53 0 11188.07 56.2a26.53 26.53 0 0153.06 0zm-5.34-.05a21.19 21.19 0 10-42.38 0 21.19 21.19 0 0042.38 0z" transform="translate(-30,-5) scale(0.75)"/>
|
|
<path fill="white" d="M21.42 37.38h55.28a.32.32 0 01.32.32v12.21a.46.46 0 00.8.3c13.2-14.73 32.09-17.47 50.68-12.7 35.19 9.03 47.69 43.89 45.07 77C170.91 148.16 150.93 173.81 115.1 175.14q-22.52.84-37.38-15.22a.65.65 0 00-1.13.47c.06 1.2.49 2.44.49 4.15q-.04 23.9.01 56.37a.42.41 0 01-.42.41H21.66a.88.88 0 01-.88-.88V38.01a.64.63 0 01.64-.63zM77.02 104.64c0 12.43 5.67 26.28 20.24 26.28s20.25-13.85 20.25-26.28-5.67-26.28-20.25-26.28-20.24 13.85-20.24 26.28z" transform="translate(30,30) scale(0.75)"/>
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<span id="whitelabelPreviewAppName" style="font-weight: 600; color: var(--text-primary);">ISP IP Manager</span>
|
|
<div id="whitelabelPreviewCompanyName" style="font-size: 11px; color: var(--text-tertiary);"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Developer Section -->
|
|
<div class="settings-section <?php echo $currentTab === 'developer' ? 'active' : ''; ?>" id="section-developer">
|
|
<!-- Import Section -->
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">Import Geofeed Data</h2>
|
|
<p class="advanced-section-desc">Import geofeed entries from a CSV file or a remote URL.</p>
|
|
|
|
<div class="import-options" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; margin-top: 16px;">
|
|
<!-- File Upload -->
|
|
<div class="import-card" style="padding: 20px; background: var(--bg-tertiary); border-radius: var(--radius-md); border: 2px dashed var(--border-strong);">
|
|
<h3 style="font-size: 14px; font-weight: 600; margin-bottom: 12px;">Upload CSV File</h3>
|
|
<input type="file" id="csvFileInput" accept=".csv,.txt" style="display: none;" onchange="handleFileUpload(this)">
|
|
<button class="btn btn-secondary" onclick="document.getElementById('csvFileInput').click()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
|
<polyline points="17 8 12 3 7 8"/>
|
|
<line x1="12" y1="3" x2="12" y2="15"/>
|
|
</svg>
|
|
Choose File
|
|
</button>
|
|
<div id="fileUploadStatus" style="margin-top: 8px; font-size: 12px; color: var(--text-secondary);"></div>
|
|
</div>
|
|
|
|
<!-- URL Import -->
|
|
<div class="import-card" style="padding: 20px; background: var(--bg-tertiary); border-radius: var(--radius-md); border: 2px dashed var(--border-strong);">
|
|
<h3 style="font-size: 14px; font-weight: 600; margin-bottom: 12px;">Import from URL</h3>
|
|
<div style="display: flex; gap: 8px;">
|
|
<input type="url" class="form-input" id="importUrl" placeholder="https://example.com/geofeed.csv" style="flex: 1;">
|
|
<button class="btn btn-primary" onclick="importFromUrl()">Import</button>
|
|
</div>
|
|
<div id="urlImportStatus" style="margin-top: 8px; font-size: 12px; color: var(--text-secondary);"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- System Info -->
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">System Information</h2>
|
|
<div id="systemInfoContainer" style="margin-top: 16px;">
|
|
<div class="loading"><div class="spinner"></div></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Error Logs -->
|
|
<div class="advanced-section">
|
|
<h2 class="advanced-section-title">Error Logs</h2>
|
|
<div style="display: flex; justify-content: flex-end; margin-bottom: 12px;">
|
|
<button class="btn btn-secondary btn-sm" onclick="clearErrorLogs()">Clear Logs</button>
|
|
</div>
|
|
<div id="errorLogsContainer" style="margin-top: 16px; max-height: 400px; overflow-y: auto; background: var(--bg-tertiary); border-radius: var(--radius-md); padding: 16px; font-family: monospace; font-size: 12px;">
|
|
<div class="loading"><div class="spinner"></div></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Danger Zone -->
|
|
<div class="advanced-section" style="border: 2px solid var(--error); background: var(--error-bg);">
|
|
<h2 class="advanced-section-title" style="color: var(--error);">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
|
|
<line x1="12" y1="9" x2="12" y2="13"/>
|
|
<line x1="12" y1="17" x2="12.01" y2="17"/>
|
|
</svg>
|
|
Danger Zone
|
|
</h2>
|
|
<p class="advanced-section-desc">Irreversible actions. Proceed with caution.</p>
|
|
|
|
<div style="display: flex; gap: 12px; flex-wrap: wrap; margin-top: 16px;">
|
|
<button class="btn btn-danger" onclick="confirmClearAll()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="3 6 5 6 21 6"/>
|
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
|
</svg>
|
|
Clear All Entries
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Initialize settings page
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const currentTab = '<?php echo $currentTab; ?>';
|
|
|
|
// Load data for the current tab
|
|
switch(currentTab) {
|
|
case 'integrations':
|
|
loadAwsSettings();
|
|
loadIpRegistrySettings();
|
|
loadWebhookSettings();
|
|
loadWebhookQueueStatus();
|
|
break;
|
|
case 'audit':
|
|
loadAuditLog();
|
|
break;
|
|
case 'advanced':
|
|
loadShortnames();
|
|
loadLogosGrid();
|
|
break;
|
|
case 'whitelabel':
|
|
loadWhitelabelSettings();
|
|
break;
|
|
case 'developer':
|
|
loadSystemInfo();
|
|
loadErrorLogs();
|
|
break;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<?php
|
|
// Include footer
|
|
require_once __DIR__ . '/includes/footer.php';
|
|
?>
|