new file: .gitignore

new file:   README.md
	new file:   database/schema.sql
	new file:   paper-plugin/pom.xml
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/PaperLoggerPlugin.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/commands/MCLoggerCommand.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/database/DatabaseManager.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/BlockListener.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/EntityListener.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/InventoryListener.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/LuckPermsListener.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerChatCommandListener.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerDeathListener.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerMiscListener.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerSessionListener.java
	new file:   paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/WorldListener.java
	new file:   paper-plugin/src/main/resources/config.yml
	new file:   paper-plugin/src/main/resources/plugin.yml
	new file:   paper-plugin/target/classes/config.yml
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/PaperLoggerPlugin.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/commands/MCLoggerCommand$RsConsumer.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/commands/MCLoggerCommand.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/database/DatabaseManager$ThrowingRunnable.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/database/DatabaseManager.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/BlockListener.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/EntityListener.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/InventoryListener.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/LuckPermsListener.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerChatCommandListener.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerDeathListener.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerMiscListener.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerSessionListener.class
	new file:   paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/WorldListener.class
	new file:   paper-plugin/target/classes/plugin.yml
	new file:   paper-plugin/target/maven-archiver/pom.properties
	new file:   paper-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
	new file:   paper-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
	new file:   paper-plugin/target/mclogger-paper-1.0.0.jar
	new file:   paper-plugin/target/original-mclogger-paper-1.0.0.jar
	new file:   velocity-plugin/pom.xml
	new file:   velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/VelocityLoggerPlugin.java
	new file:   velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager.java
	new file:   velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/listeners/VelocityEventListener.java
	new file:   velocity-plugin/src/main/resources/velocity-config.yml
	new file:   velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/VelocityLoggerPlugin.class
	new file:   velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager$ThrowingRunnable.class
	new file:   velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager.class
	new file:   velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/listeners/VelocityEventListener.class
	new file:   velocity-plugin/target/classes/velocity-config.yml
	new file:   velocity-plugin/target/classes/velocity-plugin.json
	new file:   velocity-plugin/target/maven-archiver/pom.properties
	new file:   velocity-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
	new file:   velocity-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
	new file:   velocity-plugin/target/mclogger-velocity-1.0.0.jar
	new file:   velocity-plugin/target/original-mclogger-velocity-1.0.0.jar
	new file:   web/Dockerfile
	new file:   web/app.py
	new file:   web/blueprints/__init__.py
	new file:   web/blueprints/auth.py
	new file:   web/blueprints/group_admin.py
	new file:   web/blueprints/panel.py
	new file:   web/blueprints/site_admin.py
	new file:   web/config.py
	new file:   web/crypto.py
	new file:   web/docker-compose.yml
	new file:   web/panel_db.py
	new file:   web/requirements.txt
	new file:   web/static/css/style.css
	new file:   web/static/js/main.js
	new file:   web/templates/_pagination.html
	new file:   web/templates/admin/base.html
	new file:   web/templates/admin/dashboard.html
	new file:   web/templates/admin/group_edit.html
	new file:   web/templates/admin/group_members.html
	new file:   web/templates/admin/groups.html
	new file:   web/templates/admin/user_edit.html
	new file:   web/templates/admin/users.html
	new file:   web/templates/auth/admin_login.html
	new file:   web/templates/auth/login.html
	new file:   web/templates/base.html
	new file:   web/templates/blocks.html
	new file:   web/templates/chat.html
	new file:   web/templates/commands.html
	new file:   web/templates/dashboard.html
	new file:   web/templates/deaths.html
	new file:   web/templates/group_admin/base.html
	new file:   web/templates/group_admin/dashboard.html
	new file:   web/templates/group_admin/database.html
	new file:   web/templates/group_admin/member_edit.html
	new file:   web/templates/group_admin/members.html
	new file:   web/templates/login.html
	new file:   web/templates/panel/blocks.html
	new file:   web/templates/panel/chat.html
	new file:   web/templates/panel/commands.html
	new file:   web/templates/panel/dashboard.html
	new file:   web/templates/panel/deaths.html
	new file:   web/templates/panel/no_db.html
	new file:   web/templates/panel/perms.html
	new file:   web/templates/panel/player_detail.html
	new file:   web/templates/panel/players.html
	new file:   web/templates/panel/proxy.html
	new file:   web/templates/panel/server_events.html
	new file:   web/templates/panel/sessions.html
	new file:   web/templates/perms.html
	new file:   web/templates/player_detail.html
	new file:   web/templates/players.html
	new file:   web/templates/proxy.html
	new file:   web/templates/server_events.html
	new file:   web/templates/sessions.html
This commit is contained in:
SimolZimol
2026-04-01 01:36:01 +02:00
commit b918dadb0c
109 changed files with 9196 additions and 0 deletions

View File

@@ -0,0 +1,194 @@
{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block page_title %}<i class="bi bi-speedometer2 me-2"></i>Dashboard{% endblock %}
{% block content %}
<!-- ── Statistik-Karten ────────────────────────────────── -->
<div class="row g-3 mb-4">
{% set cards = [
('Total Players', stats.players_total, 'bi-people-fill', 'success'),
('Sessions Today', stats.sessions_today, 'bi-clock-history', 'info'),
('Chats Today', stats.chat_today, 'bi-chat-dots-fill', 'primary'),
('Commands Today', stats.commands_today, 'bi-terminal-fill', 'warning'),
('Blocks Today', stats.blocks_today, 'bi-bricks', 'secondary'),
('Deaths Today', stats.deaths_today, 'bi-heartbreak-fill', 'danger'),
('Entity Events', stats.entity_events_today, 'bi-bug-fill', 'light'),
('Proxy Events', stats.proxy_events_today, 'bi-diagram-3-fill', 'dark'),
] %}
{% for label, value, icon, color in cards %}
<div class="col-6 col-md-3 col-xl-3">
<div class="card stat-card h-100">
<div class="card-body d-flex align-items-center gap-3">
<div class="stat-icon bg-{{ color }} bg-opacity-25">
<i class="bi {{ icon }} text-{{ color }}"></i>
</div>
<div>
<div class="stat-value">{{ value | int }}</div>
<div class="stat-label">{{ label }}</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<!-- ── Zeile 2: Online-Spieler + Letzte Aktivität ────── -->
<div class="row g-3 mb-4">
<div class="col-12 col-lg-4">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<span><i class="bi bi-circle-fill text-success me-2 blink" style="font-size:.5rem"></i>Online Players</span>
<button class="btn btn-sm btn-outline-secondary" onclick="refreshOnline()">
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
<div class="card-body p-0">
<div id="online-table">
{% if online %}
<table class="table table-sm table-hover mb-0">
<thead class="table-dark">
<tr><th>Player</th><th>Server</th><th>Since</th></tr>
</thead>
<tbody>
{% for s in online %}
<tr>
<td><a href="{{ url_for('panel.player_detail', uuid=s.get('player_uuid','')) }}">{{ s.player_name }}</a></td>
<td><span class="badge bg-secondary">{{ s.server_name }}</span></td>
<td class="small text-muted">{{ s.login_time | fmt_dt }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="text-center text-muted py-4">
<i class="bi bi-moon-stars-fill fs-3"></i><br>No players online
</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-8">
<div class="card h-100">
<div class="card-header">
<i class="bi bi-activity me-2"></i>Last 24h Activity
</div>
<div class="card-body p-0" style="overflow-y:auto; max-height:320px;">
<table class="table table-sm table-hover mb-0">
<thead class="table-dark sticky-top">
<tr><th>Time</th><th>Type</th><th>Player</th><th>Server</th><th>Detail</th></tr>
</thead>
<tbody>
{% for r in recent %}
<tr>
<td class="small text-muted text-nowrap">{{ r.timestamp | fmt_dt }}</td>
<td>
{% set badge = {'chat':'primary','command':'warning','block':'secondary','death':'danger'} %}
<span class="badge bg-{{ badge.get(r.source,'light') }}">{{ r.source }}</span>
</td>
<td class="small">{{ r.player_name or '—' }}</td>
<td class="small">{{ r.server_name or '—' }}</td>
<td class="small text-truncate" style="max-width:200px;" title="{{ r.detail }}">{{ r.detail }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- ── Zeile 3: Charts ────────────────────────────────── -->
<div class="row g-3 mb-4">
<div class="col-12 col-md-6">
<div class="card">
<div class="card-header"><i class="bi bi-bricks me-2"></i>Block Events (last 7 days)</div>
<div class="card-body">
<canvas id="blockChart" height="200"></canvas>
</div>
</div>
</div>
<div class="col-12 col-md-3">
<div class="card">
<div class="card-header"><i class="bi bi-heartbreak-fill me-2"></i>Death Causes (7d)</div>
<div class="card-body">
<canvas id="deathChart" height="200"></canvas>
</div>
</div>
</div>
<div class="col-12 col-md-3">
<div class="card">
<div class="card-header"><i class="bi bi-trophy-fill me-2"></i>Top Playtime</div>
<div class="card-body p-0" style="overflow-y:auto;max-height:240px;">
<table class="table table-sm mb-0">
<tbody>
{% for p in top_players %}
<tr>
<td>{{ loop.index }}. {{ p.username }}</td>
<td class="text-end text-muted small">{{ p.total_playtime_sec | fmt_duration }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- ── Zeile 4: Server-Events ─────────────────────────── -->
<div class="row g-3">
<div class="col-12">
<div class="card">
<div class="card-header"><i class="bi bi-server me-2"></i>Server Events (last 24h)</div>
<div class="card-body p-0">
<table class="table table-sm table-hover mb-0">
<thead class="table-dark"><tr><th>Time</th><th>Type</th><th>Server</th><th>Message</th></tr></thead>
<tbody>
{% for e in server_events %}
<tr>
<td class="small text-muted text-nowrap">{{ e.timestamp | fmt_dt }}</td>
<td><span class="badge bg-info text-dark">{{ e.event_type }}</span></td>
<td class="small">{{ e.server_name }}</td>
<td class="small">{{ e.message }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
const blockCtx = document.getElementById('blockChart');
new Chart(blockCtx, {
type: 'bar',
data: {
labels: {{ block_chart | map(attribute='day') | list | tojson }},
datasets: [{ label: 'Block-Events', data: {{ block_chart | map(attribute='cnt') | list | tojson }},
backgroundColor: 'rgba(25,135,84,0.7)', borderColor: 'rgba(25,135,84,1)', borderWidth: 1 }]
},
options: { plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true } } }
});
const deathCtx = document.getElementById('deathChart');
new Chart(deathCtx, {
type: 'doughnut',
data: {
labels: {{ death_causes | map(attribute='cause') | list | tojson }},
datasets: [{ data: {{ death_causes | map(attribute='cnt') | list | tojson }},
backgroundColor: ['#dc3545','#fd7e14','#ffc107','#198754','#0dcaf0','#6f42c1','#d63384','#6c757d'] }]
},
options: { plugins: { legend: { position: 'bottom', labels: { font: { size:10 } } } } }
});
function refreshOnline() {
fetch('/api/online').then(r => r.json()).then(data => {
document.getElementById('online-count').textContent = data.length;
});
}
setInterval(refreshOnline, 30000);
refreshOnline();
</script>
{% endblock %}