Files
Discord-ai-chatbot/templates/server_settings.html
SimolZimol d0a3954f0a modified: app.py
modified:   bot.py
	modified:   templates/server_settings.html
2026-06-15 21:10:09 +02:00

528 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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 1719 digit number');
e.preventDefault();
return;
}
if (honeypotLogChannelId && !/^\d{17,19}$/.test(honeypotLogChannelId)) {
alert('Honeypot log channel ID must be a 1719 digit number');
e.preventDefault();
return;
}
if (honeypotGetRole && !/^\d{17,19}$/.test(honeypotGetRole)) {
alert('Mute role ID must be a 1719 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>