mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
The NexusDashboard-parity dashboard (dDashboardServer) and everything built on it on the experimental branch: accounts, characters, properties and moderation tools, permissions shared with in-game slash commands, economy reports, World 3D and property 3D views with client scenery, scheduled events (features, vanity changes, live events, announcements, restarts), vanity files and events, the CDClient browser, the message inspector with saved captures, chat filter tools, community challenges, live ops, the AI moderator helper, and the server-side changes they need. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
109 lines
5.1 KiB
Django/Jinja
109 lines
5.1 KiB
Django/Jinja
{% extends "base.jinja2" %}
|
|
|
|
{% block title %}Maintenance - DarkflameServer{% endblock %}
|
|
|
|
{% block content %}
|
|
<h2 class="mb-1">Maintenance</h2>
|
|
<p class="text-body-secondary mb-4">Data repairs. Every action is recorded in the audit log. Scans read every character, so they can pause the dashboard for a moment on large servers.</p>
|
|
|
|
<div class="row g-4">
|
|
<div class="col-lg-6">
|
|
<div class="card h-100">
|
|
<div class="card-header"><h5 class="mb-0">Pet names</h5></div>
|
|
<div class="card-body">
|
|
<p class="small">Pending names that were already approved for another pet are approved automatically every hour. Run it now:</p>
|
|
<button class="btn btn-sm btn-outline-primary mb-3" data-action="petApprove">Approve previously approved names</button>
|
|
<p class="small">Find pet names whose pet no longer exists on any character (e.g. the pet was released).</p>
|
|
<button class="btn btn-sm btn-outline-primary" data-action="petScan">Scan</button>
|
|
<button class="btn btn-sm btn-outline-danger d-none" data-action="petDelete" id="petDeleteBtn">Delete orphaned names</button>
|
|
<pre class="small mt-2 mb-0 d-none" id="petResult"></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="card h-100">
|
|
<div class="card-header"><h5 class="mb-0">Buffs</h5></div>
|
|
<div class="card-body">
|
|
<p class="small">Remove every buff from every character, e.g. after a buff got stuck. Only possible while nobody is online.</p>
|
|
<button class="btn btn-sm btn-outline-primary" data-action="buffScan">Count characters with buffs</button>
|
|
<button class="btn btn-sm btn-outline-danger" data-action="buffRemove">Remove all buffs</button>
|
|
<pre class="small mt-2 mb-0 d-none" id="buffResult"></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="card h-100">
|
|
<div class="card-header"><h5 class="mb-0">Property clone IDs</h5></div>
|
|
<div class="card-body">
|
|
<p class="small">Repair properties whose clone ID doesn't match their owner's (left behind by an old bug), which stops them loading.</p>
|
|
<button class="btn btn-sm btn-outline-primary" data-action="fixClones">Fix clone IDs</button>
|
|
<pre class="small mt-2 mb-0 d-none" id="cloneResult"></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="card h-100">
|
|
<div class="card-header"><h5 class="mb-0">Game data check</h5></div>
|
|
<div class="card-body">
|
|
<p class="small">Mission reward items that have no commendation vendor price in the game data.</p>
|
|
<button class="btn btn-sm btn-outline-primary" data-action="commendation">Find items</button>
|
|
<div class="small mt-2" id="commendationResult"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
function show(id, text) {
|
|
var el = document.getElementById(id);
|
|
el.textContent = text;
|
|
el.classList.remove('d-none');
|
|
}
|
|
|
|
var actions = {
|
|
petApprove: function () { return api.action('/api/maintenance/pet_names/auto_approve', {}).then(function (d) { toast(d.message, 'success'); }); },
|
|
petScan: function () {
|
|
show('petResult', 'Scanning every character...');
|
|
return api.job('/api/maintenance/pet_names/orphans', {}).then(function (d) {
|
|
show('petResult', d.characters + ' characters scanned, ' + d.petsFound + ' pets found, ' + d.petNames + ' pet names stored.\n' +
|
|
d.orphaned + ' orphaned' + (d.sample.length ? ', e.g.: ' + d.sample.map(function (p) { return p.name; }).join(', ') : ''));
|
|
document.getElementById('petDeleteBtn').classList.toggle('d-none', !d.orphaned);
|
|
});
|
|
},
|
|
petDelete: function () {
|
|
if (!confirm('Delete the orphaned pet names?')) return Promise.resolve();
|
|
return api.job('/api/maintenance/pet_names/orphans', { delete: true }).then(function (d) {
|
|
show('petResult', 'Deleted ' + d.deleted + ' orphaned pet name(s).');
|
|
document.getElementById('petDeleteBtn').classList.add('d-none');
|
|
});
|
|
},
|
|
buffScan: function () {
|
|
show('buffResult', 'Scanning every character...');
|
|
return api.job('/api/maintenance/remove_buffs', { dry_run: true }).then(function (d) { show('buffResult', d.characters + ' character(s) have buffs'); });
|
|
},
|
|
buffRemove: function () {
|
|
if (!confirm('Remove all buffs from every character?')) return Promise.resolve();
|
|
return api.job('/api/maintenance/remove_buffs', { dry_run: false }).then(function (d) { show('buffResult', 'Removed buffs from ' + d.characters + ' character(s)'); });
|
|
},
|
|
fixClones: function () { return api.action('/api/maintenance/fix_clone_ids', {}).then(function (d) { show('cloneResult', d.message); }); },
|
|
commendation: function () {
|
|
return api.get('/api/maintenance/missing_commendation_items').then(function (d) {
|
|
var el = document.getElementById('commendationResult');
|
|
el.innerHTML = d.items.length
|
|
? '<ul class="mb-0">' + d.items.map(function (i) { return '<li>' + esc(i.name) + ' <span class="text-body-secondary">(' + esc(i.lot) + ')</span></li>'; }).join('') + '</ul>'
|
|
: 'Every mission reward item has a commendation price.';
|
|
});
|
|
}
|
|
};
|
|
|
|
document.addEventListener('click', function (e) {
|
|
var btn = e.target.closest('[data-action]');
|
|
if (!btn) return;
|
|
btn.disabled = true;
|
|
actions[btn.getAttribute('data-action')]().catch(function () {}).finally(function () { btn.disabled = false; });
|
|
});
|
|
</script>
|
|
{% endblock %}
|