528 lines
21 KiB
HTML
528 lines
21 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Server Settings - {{ guild_name }}</title>
|
||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||
<style>
|
||
body {
|
||
background: linear-gradient(135deg, #0c1426 0%, #1a1f2e 25%, #2d3748 75%, #0c1426 100%);
|
||
min-height: 100vh;
|
||
color: #e2e8f0;
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
}
|
||
|
||
.main-container {
|
||
background: rgba(26, 31, 46, 0.8);
|
||
backdrop-filter: blur(15px);
|
||
border: 1px solid rgba(102, 126, 234, 0.2);
|
||
border-radius: 20px;
|
||
margin: 2rem auto;
|
||
max-width: 1000px;
|
||
padding: 2rem;
|
||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
.header-section {
|
||
text-align: center;
|
||
margin-bottom: 2rem;
|
||
padding-bottom: 1.5rem;
|
||
border-bottom: 1px solid rgba(102, 126, 234, 0.2);
|
||
}
|
||
|
||
.header-title {
|
||
color: #e2e8f0;
|
||
font-size: 2.2rem;
|
||
font-weight: 700;
|
||
margin-bottom: 0.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.header-icon {
|
||
color: #667eea;
|
||
font-size: 2.2rem;
|
||
}
|
||
|
||
.server-name {
|
||
color: #a0aec0;
|
||
font-size: 1.1rem;
|
||
}
|
||
|
||
.settings-section {
|
||
background: rgba(45, 55, 72, 0.6);
|
||
border: 1px solid rgba(102, 126, 234, 0.2);
|
||
border-radius: 15px;
|
||
padding: 2rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.section-title {
|
||
color: #e2e8f0;
|
||
font-size: 1.5rem;
|
||
font-weight: 600;
|
||
margin-bottom: 1.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.section-icon {
|
||
color: #667eea;
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.form-group label {
|
||
color: #e2e8f0;
|
||
font-weight: 600;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.form-control {
|
||
background: rgba(45, 55, 72, 0.8);
|
||
border: 1px solid rgba(102, 126, 234, 0.3);
|
||
border-radius: 8px;
|
||
color: #e2e8f0;
|
||
padding: 0.75rem;
|
||
}
|
||
|
||
.form-control:focus {
|
||
background: rgba(45, 55, 72, 0.9);
|
||
border-color: #667eea;
|
||
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
|
||
color: #e2e8f0;
|
||
}
|
||
|
||
.form-control::placeholder {
|
||
color: #a0aec0;
|
||
}
|
||
|
||
.form-check {
|
||
margin: 1rem 0;
|
||
padding: 1rem;
|
||
background: rgba(45, 55, 72, 0.4);
|
||
border-radius: 8px;
|
||
border: 1px solid rgba(102, 126, 234, 0.2);
|
||
}
|
||
|
||
.form-check-input {
|
||
margin-top: 0.3rem;
|
||
}
|
||
|
||
.form-check-label {
|
||
color: #e2e8f0;
|
||
font-weight: 500;
|
||
margin-left: 0.5rem;
|
||
}
|
||
|
||
.help-text {
|
||
color: #a0aec0;
|
||
font-size: 0.875rem;
|
||
margin-top: 0.25rem;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
border: none;
|
||
color: white;
|
||
padding: 0.75rem 2rem;
|
||
border-radius: 10px;
|
||
font-weight: 600;
|
||
transition: all 0.3s ease;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: rgba(45, 55, 72, 0.6);
|
||
border: 1px solid rgba(102, 126, 234, 0.2);
|
||
color: #e2e8f0;
|
||
padding: 0.75rem 1.5rem;
|
||
border-radius: 10px;
|
||
font-weight: 600;
|
||
transition: all 0.3s ease;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.1);
|
||
color: #e2e8f0;
|
||
text-decoration: none;
|
||
border-color: rgba(102, 126, 234, 0.4);
|
||
}
|
||
|
||
.alert {
|
||
border-radius: 10px;
|
||
border: none;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.alert-success {
|
||
background: rgba(72, 187, 120, 0.1);
|
||
color: #48bb78;
|
||
border: 1px solid rgba(72, 187, 120, 0.3);
|
||
}
|
||
|
||
.alert-danger {
|
||
background: rgba(245, 101, 101, 0.1);
|
||
color: #f56565;
|
||
border: 1px solid rgba(245, 101, 101, 0.3);
|
||
}
|
||
|
||
.info-card {
|
||
background: rgba(56, 178, 172, 0.1);
|
||
border: 1px solid rgba(56, 178, 172, 0.2);
|
||
border-radius: 10px;
|
||
padding: 1rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.info-card-title {
|
||
color: #38b2ac;
|
||
font-weight: 600;
|
||
margin-bottom: 0.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.info-card-text {
|
||
color: #a0aec0;
|
||
margin: 0;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.main-container {
|
||
margin: 1rem;
|
||
padding: 1.5rem;
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 1.8rem;
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.settings-section {
|
||
padding: 1.5rem;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
{% include 'navigation.html' %}
|
||
|
||
<div class="main-container">
|
||
<div class="header-section">
|
||
<h1 class="header-title">
|
||
<i class="fas fa-cogs header-icon"></i>
|
||
Server Settings
|
||
</h1>
|
||
<p class="server-name">{{ guild_name }}</p>
|
||
</div>
|
||
|
||
<!-- Flash Messages -->
|
||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||
{% if messages %}
|
||
{% for category, message in messages %}
|
||
<div class="alert alert-{{ 'success' if category == 'success' else 'danger' }}">
|
||
<i class="fas fa-{{ 'check-circle' if category == 'success' else 'exclamation-triangle' }}"></i>
|
||
{{ message }}
|
||
</div>
|
||
{% endfor %}
|
||
{% endif %}
|
||
{% endwith %}
|
||
|
||
<form method="POST">
|
||
<!-- Mute Settings -->
|
||
<div class="settings-section">
|
||
<h3 class="section-title">
|
||
<i class="fas fa-volume-mute section-icon"></i>
|
||
Mute Settings
|
||
</h3>
|
||
|
||
<div class="info-card">
|
||
<div class="info-card-title">
|
||
<i class="fas fa-info-circle"></i>
|
||
Role ID Information
|
||
</div>
|
||
<p class="info-card-text">
|
||
To find a role ID: Right-click on the role → "Copy ID" (Developer mode must be enabled)
|
||
</p>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="form-group">
|
||
<label for="mute_role_id">Mute Role ID</label>
|
||
<input type="text" class="form-control" id="mute_role_id" name="mute_role_id"
|
||
value="{{ settings.mute_role_id or '' }}" placeholder="e.g. 123456789012345678">
|
||
<small class="help-text">Leave empty for automatic search by name</small>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="form-group">
|
||
<label for="mute_role_name">Mute Role Name</label>
|
||
<input type="text" class="form-control" id="mute_role_name" name="mute_role_name"
|
||
value="{{ settings.mute_role_name }}" placeholder="Muted" required>
|
||
<small class="help-text">Name for automatically created mute roles</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="checkbox" id="auto_create_mute_role"
|
||
name="auto_create_mute_role" {% if settings.auto_create_mute_role %}checked{% endif %}>
|
||
<label class="form-check-label" for="auto_create_mute_role">
|
||
Auto-create mute role
|
||
</label>
|
||
<small class="help-text d-block">Automatically creates a mute role if none is found</small>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Warning Settings -->
|
||
<div class="settings-section">
|
||
<h3 class="section-title">
|
||
<i class="fas fa-exclamation-triangle section-icon"></i>
|
||
Warning Settings
|
||
</h3>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="form-group">
|
||
<label for="max_warn_threshold">Maximum Warnings</label>
|
||
<input type="number" class="form-control" id="max_warn_threshold" name="max_warn_threshold"
|
||
value="{{ settings.max_warn_threshold }}" min="1" max="10" required>
|
||
<small class="help-text">Number of warnings before automatic actions</small>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="form-group">
|
||
<label for="auto_mute_duration">Auto-Mute Duration</label>
|
||
<input type="text" class="form-control" id="auto_mute_duration" name="auto_mute_duration"
|
||
value="{{ settings.auto_mute_duration }}" placeholder="1h" required>
|
||
<small class="help-text">Format: 10m, 1h, 2d (minutes, hours, days)</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="checkbox" id="auto_mute_on_warns"
|
||
name="auto_mute_on_warns" {% if settings.auto_mute_on_warns %}checked{% endif %}>
|
||
<label class="form-check-label" for="auto_mute_on_warns">
|
||
Automatic mute on too many warnings
|
||
</label>
|
||
<small class="help-text d-block">Automatically mutes users when they reach the warning limit</small>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Log Settings -->
|
||
<div class="settings-section">
|
||
<h3 class="section-title">
|
||
<i class="fas fa-clipboard-list section-icon"></i>
|
||
Log Settings
|
||
</h3>
|
||
|
||
<div class="form-group">
|
||
<label for="log_channel_id">Log Channel ID</label>
|
||
<input type="text" class="form-control" id="log_channel_id" name="log_channel_id"
|
||
value="{{ settings.log_channel_id or '' }}" placeholder="e.g. 123456789012345678">
|
||
<small class="help-text">Channel for moderation logs (leave empty to disable)</small>
|
||
</div>
|
||
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="checkbox" id="mod_log_enabled"
|
||
name="mod_log_enabled" {% if settings.mod_log_enabled %}checked{% endif %}>
|
||
<label class="form-check-label" for="mod_log_enabled">
|
||
Moderation logs enabled
|
||
</label>
|
||
<small class="help-text d-block">Logs all moderation actions</small>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Honeypot Settings -->
|
||
<div class="settings-section">
|
||
<h3 class="section-title">
|
||
<i class="fas fa-spider section-icon"></i>
|
||
Honeypot System
|
||
</h3>
|
||
|
||
<div class="info-card">
|
||
<div class="info-card-title">
|
||
<i class="fas fa-info-circle"></i>
|
||
What is a Honeypot?
|
||
</div>
|
||
<p class="info-card-text">
|
||
A honeypot channel is a hidden channel that attracts bots and spam accounts.
|
||
Any user who writes there will be automatically banned — or if old account protection
|
||
is enabled, muted for 1 year.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="checkbox" id="honeypot_enabled"
|
||
name="honeypot_enabled" {% if settings.honeypot_enabled %}checked{% endif %}>
|
||
<label class="form-check-label" for="honeypot_enabled">
|
||
Enable Honeypot System
|
||
</label>
|
||
<small class="help-text d-block">Enables automatic detection in the honeypot channel</small>
|
||
</div>
|
||
|
||
<div class="row mt-3">
|
||
<div class="col-md-6">
|
||
<div class="form-group">
|
||
<label for="honeypot_channel_id">Honeypot Channel ID</label>
|
||
<input type="text" class="form-control" id="honeypot_channel_id"
|
||
name="honeypot_channel_id"
|
||
value="{{ settings.honeypot_channel_id or '' }}"
|
||
placeholder="e.g. 123456789012345678">
|
||
<small class="help-text">Channel where messages trigger a ban</small>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="form-group">
|
||
<label for="honeypot_log_channel_id">Honeypot Log Channel ID</label>
|
||
<input type="text" class="form-control" id="honeypot_log_channel_id"
|
||
name="honeypot_log_channel_id"
|
||
value="{{ settings.honeypot_log_channel_id or '' }}"
|
||
placeholder="e.g. 123456789012345678">
|
||
<small class="help-text">Channel for honeypot logs (empty = disabled)</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="checkbox" id="honeypot_preserve_old_accounts"
|
||
name="honeypot_preserve_old_accounts"
|
||
{% if settings.honeypot_preserve_old_accounts %}checked{% endif %}>
|
||
<label class="form-check-label" for="honeypot_preserve_old_accounts">
|
||
Enable Old Account Protection
|
||
</label>
|
||
<small class="help-text d-block">
|
||
Users who have been on the server longer than the minimum age will not be banned,
|
||
but only muted for 1 year (for possibly hacked accounts)
|
||
</small>
|
||
</div>
|
||
|
||
<div class="row mt-3">
|
||
<div class="col-md-6">
|
||
<div class="form-group">
|
||
<label for="honeypot_acc_age_min">Minimum Server Age (Days)</label>
|
||
<input type="number" class="form-control" id="honeypot_acc_age_min"
|
||
name="honeypot_acc_age_min"
|
||
value="{{ settings.honeypot_acc_age_min or 30 }}" min="1">
|
||
<small class="help-text">
|
||
Users must be on the server for at least this many days
|
||
to be considered an "old account"
|
||
</small>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="form-group">
|
||
<label for="honeypot_get_role">Mute Role ID (Old Accounts)</label>
|
||
<input type="text" class="form-control" id="honeypot_get_role"
|
||
name="honeypot_get_role"
|
||
value="{{ settings.honeypot_get_role or '' }}"
|
||
placeholder="e.g. 123456789012345678">
|
||
<small class="help-text">
|
||
Role for muted old accounts. Empty = use normal mute role
|
||
</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="honeypot_ignore_roles">Ignored Roles (Mod Roles, etc.)</label>
|
||
<input type="text" class="form-control" id="honeypot_ignore_roles"
|
||
name="honeypot_ignore_roles"
|
||
value="{{ settings.honeypot_ignore_roles | from_json_ids if settings.honeypot_ignore_roles else '' }}"
|
||
placeholder="e.g. 111222333444 555666777888">
|
||
<small class="help-text">
|
||
Space- or comma-separated role IDs that are exempt from honeypot
|
||
(e.g., mod roles)
|
||
</small>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Action Buttons -->
|
||
<div class="text-center">
|
||
<button type="submit" class="btn btn-primary mr-3">
|
||
<i class="fas fa-save"></i> Save Settings
|
||
</button>
|
||
<a href="{{ url_for('server_admin_dashboard', guild_id=guild_id) }}" class="btn btn-secondary">
|
||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||
</a>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.2/dist/js/bootstrap.bundle.min.js"></script>
|
||
|
||
<script>
|
||
// Form validation
|
||
document.querySelector('form').addEventListener('submit', function(e) {
|
||
const muteRoleId = document.getElementById('mute_role_id').value;
|
||
const logChannelId = document.getElementById('log_channel_id').value;
|
||
const muteDuration = document.getElementById('auto_mute_duration').value;
|
||
const honeypotChannelId = document.getElementById('honeypot_channel_id').value;
|
||
const honeypotLogChannelId = document.getElementById('honeypot_log_channel_id').value;
|
||
const honeypotGetRole = document.getElementById('honeypot_get_role').value;
|
||
const honeypotAccAgeMin = document.getElementById('honeypot_acc_age_min').value;
|
||
|
||
// Validate role ID format (if provided)
|
||
if (muteRoleId && !/^\d{17,19}$/.test(muteRoleId)) {
|
||
alert('Mute Role ID must be a 17-19 digit number');
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
|
||
// Validate log channel ID format (if provided)
|
||
if (logChannelId && !/^\d{17,19}$/.test(logChannelId)) {
|
||
alert('Log Channel ID must be a 17-19 digit number');
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
|
||
// Validate time format
|
||
if (muteDuration && !/^\d+[mhd]$/.test(muteDuration)) {
|
||
alert('Auto-Mute Duration must be in format "10m", "1h" or "2d"');
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
// Honeypot validations
|
||
if (honeypotChannelId && !/^\d{17,19}$/.test(honeypotChannelId)) {
|
||
alert('Honeypot channel ID must be a 17–19 digit number');
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
if (honeypotLogChannelId && !/^\d{17,19}$/.test(honeypotLogChannelId)) {
|
||
alert('Honeypot log channel ID must be a 17–19 digit number');
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
if (honeypotGetRole && !/^\d{17,19}$/.test(honeypotGetRole)) {
|
||
alert('Mute role ID must be a 17–19 digit number');
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
if (honeypotAccAgeMin && (isNaN(honeypotAccAgeMin) || parseInt(honeypotAccAgeMin) < 1)) {
|
||
alert('Minimum account age must be at least 1 day');
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|