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
183 lines
10 KiB
HTML
183 lines
10 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ player.username }}{% endblock %}
|
|
{% block page_title %}<i class="bi bi-person-fill me-2"></i>{{ player.username }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- Spieler-Info Karte -->
|
|
<div class="row g-3 mb-4">
|
|
<div class="col-12 col-md-4">
|
|
<div class="card h-100">
|
|
<div class="card-body text-center py-4">
|
|
<img src="https://minotar.net/avatar/{{ player.username }}/80"
|
|
class="rounded mb-3" alt="{{ player.username }}" onerror="this.src='/static/img/default.png'">
|
|
<h5 class="fw-bold mb-1">{{ player.username }}</h5>
|
|
{% if player.is_op %}
|
|
<span class="badge bg-warning text-dark mb-2"><i class="bi bi-shield-fill"></i> OP</span>
|
|
{% endif %}
|
|
<table class="table table-sm mt-2 text-start">
|
|
<tr><th>UUID</th><td class="small text-break">{{ player.uuid }}</td></tr>
|
|
<tr><th>IP</th><td class="small">{{ player.ip_address or '—' }}</td></tr>
|
|
<tr><th>Locale</th><td class="small">{{ player.locale or '—' }}</td></tr>
|
|
<tr><th>Playtime</th><td>{{ player.total_playtime_sec | fmt_duration }}</td></tr>
|
|
<tr><th>Since</th><td class="small">{{ player.first_seen | fmt_dt }}</td></tr>
|
|
<tr><th>Last Seen</th><td class="small">{{ player.last_seen | fmt_dt }}</td></tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-8">
|
|
<!-- Tabs -->
|
|
<ul class="nav nav-tabs mb-3" id="playerTabs">
|
|
<li class="nav-item"><a class="nav-link active" data-bs-toggle="tab" href="#tab-sessions">Sessions ({{ sessions|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-chat">Chat ({{ chat|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-cmds">Commands ({{ commands|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-deaths">Deaths ({{ deaths|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-tp">Teleports ({{ teleports|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-stats">Stats ({{ stats|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-proxy">Proxy ({{ proxy_events|length }})</a></li>
|
|
</ul>
|
|
|
|
<div class="tab-content">
|
|
<!-- Sessions -->
|
|
<div class="tab-pane fade show active" id="tab-sessions">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Login</th><th>Logout</th><th>Duration</th><th>Server</th><th>IP</th></tr></thead>
|
|
<tbody>
|
|
{% for s in sessions %}
|
|
<tr>
|
|
<td class="small text-nowrap">{{ s.login_time | fmt_dt }}</td>
|
|
<td class="small text-nowrap">{{ s.logout_time | fmt_dt }}</td>
|
|
<td class="small">{{ s.duration_sec | fmt_duration }}</td>
|
|
<td><span class="badge bg-secondary">{{ s.server_name or '—' }}</span></td>
|
|
<td class="small text-muted">{{ s.ip_address or '—' }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="5" class="text-center text-muted">No sessions</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Chat -->
|
|
<div class="tab-pane fade" id="tab-chat">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Server</th><th>Message</th></tr></thead>
|
|
<tbody>
|
|
{% for c in chat %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ c.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-secondary">{{ c.server_name or '—' }}</span></td>
|
|
<td class="small">{{ c.message }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="3" class="text-center text-muted">No chat messages</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Commands -->
|
|
<div class="tab-pane fade" id="tab-cmds">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Server</th><th>Command</th><th>Position</th></tr></thead>
|
|
<tbody>
|
|
{% for c in commands %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ c.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-secondary">{{ c.server_name or '—' }}</span></td>
|
|
<td class="small font-monospace">{{ c.command }}</td>
|
|
<td class="small text-muted">{{ c.world or '' }} {% if c.x %}({{ c.x|round(1) }}, {{ c.y|round(1) }}, {{ c.z|round(1) }}){% endif %}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="4" class="text-center text-muted">No commands</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tode -->
|
|
<div class="tab-pane fade" id="tab-deaths">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Cause</th><th>Killer</th><th>Level</th><th>World</th></tr></thead>
|
|
<tbody>
|
|
{% for d in deaths %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ d.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-danger">{{ d.cause or '—' }}</span></td>
|
|
<td class="small">{{ d.killer_name or '—' }}</td>
|
|
<td class="small">{{ d.exp_level }}</td>
|
|
<td class="small text-muted">{{ d.world }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="5" class="text-center text-muted">No deaths</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Teleports -->
|
|
<div class="tab-pane fade" id="tab-tp">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>From</th><th>To</th><th>Cause</th></tr></thead>
|
|
<tbody>
|
|
{% for t in teleports %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ t.timestamp | fmt_dt }}</td>
|
|
<td class="small">{{ t.from_world }} ({{ t.from_x|round(0)|int }}, {{ t.from_y|round(0)|int }}, {{ t.from_z|round(0)|int }})</td>
|
|
<td class="small">{{ t.to_world }} ({{ t.to_x|round(0)|int }}, {{ t.to_y|round(0)|int }}, {{ t.to_z|round(0)|int }})</td>
|
|
<td><span class="badge bg-info text-dark">{{ t.cause or '—' }}</span></td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="4" class="text-center text-muted">No teleports</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats -->
|
|
<div class="tab-pane fade" id="tab-stats">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Type</th><th>Old</th><th>New</th></tr></thead>
|
|
<tbody>
|
|
{% for s in stats %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ s.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-secondary">{{ s.event_type }}</span></td>
|
|
<td class="small">{{ s.old_value or '—' }}</td>
|
|
<td class="small">{{ s.new_value or '—' }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="4" class="text-center text-muted">No stats</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Proxy-Events -->
|
|
<div class="tab-pane fade" id="tab-proxy">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Type</th><th>From</th><th>To</th></tr></thead>
|
|
<tbody>
|
|
{% for e in proxy_events %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ e.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-primary">{{ e.event_type }}</span></td>
|
|
<td class="small">{{ e.from_server or '—' }}</td>
|
|
<td class="small">{{ e.to_server or '—' }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="4" class="text-center text-muted">No proxy events</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div><!-- /tab-content -->
|
|
</div>
|
|
</div>
|
|
|
|
<a href="{{ url_for('players') }}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-left me-1"></i>Back to Overview
|
|
</a>
|
|
{% endblock %}
|