mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-05-13 10:55:04 +00:00
- Implemented dashboard audit logging with InsertAuditLog, GetRecentAuditLogs, GetAuditLogsByIP, and CleanupOldAuditLogs methods. - Created dashboard configuration management with GetDashboardConfig and SetDashboardConfig methods. - Added new tables for dashboard_audit_log and dashboard_config in both MySQL and SQLite migrations. - Updated CMakeLists to include Crow and ASIO for dashboard server functionality. - Enhanced existing database classes to support new dashboard features, including character, play key, and property management. - Added new methods for retrieving and managing play keys, properties, and pet names. - Updated TestSQLDatabase to include stubs for new dashboard-related methods. - Modified shared and dashboard configuration files for new settings.
164 lines
6.5 KiB
HTML
164 lines
6.5 KiB
HTML
<div class="row">
|
|
<div class="col-12">
|
|
<h1 class="mb-4">
|
|
<i class="bi bi-person-badge"></i>
|
|
Character Management
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">All Characters</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<table id="characters-table" class="table table-striped table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Account</th>
|
|
<th>Name</th>
|
|
<th>Pending Name</th>
|
|
<th>Needs Rename</th>
|
|
<th>Last Login</th>
|
|
<th>Permission Map</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- Populated via DataTables Ajax -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Wait for jQuery + DataTables to be available
|
|
function showLibraryError(message) {
|
|
const el = document.getElementById('characters-table');
|
|
if (el) {
|
|
const wrapper = document.createElement('div');
|
|
wrapper.className = 'alert alert-danger';
|
|
wrapper.textContent = message;
|
|
el.replaceWith(wrapper);
|
|
} else {
|
|
alert(message);
|
|
}
|
|
}
|
|
|
|
function loadCharacters() {
|
|
API.get('/api/auth/status').then(status => {
|
|
if (!status || !status.authenticated || status.gm_level < 3) {
|
|
showLibraryError('You do not have permission to view characters. Please log in with sufficient GM level.');
|
|
return;
|
|
}
|
|
|
|
API.get('/api/characters').then(res => {
|
|
const data = Array.isArray(res.data) ? res.data : (res || []);
|
|
|
|
if ($.fn.DataTable.isDataTable('#characters-table')) {
|
|
const table = $('#characters-table').DataTable();
|
|
table.clear();
|
|
table.rows.add(data);
|
|
table.draw(false);
|
|
} else {
|
|
const table = $('#characters-table').DataTable({
|
|
data: data,
|
|
columns: [
|
|
{ data: 'id' },
|
|
{ data: 'account_name', render: function(d, t, row) {
|
|
return row.account_id ? `<a href="/accounts/view/${row.account_id}">${d || row.account_id}</a>` : (d || '-');
|
|
}},
|
|
{ data: 'name', render: function(d, t, row) {
|
|
return `<a href="/characters/view/${row.id}">${d}</a>`;
|
|
}},
|
|
{ data: 'pending_name', render: d => d || '-' },
|
|
{ data: 'needs_rename', render: d => d ? '<span class="badge bg-warning">Yes</span>' : '<span class="badge bg-success">No</span>' },
|
|
{ data: 'last_login', render: function(d) {
|
|
if (!d || d === 0) return 'Never';
|
|
return new Date(d * 1000).toLocaleString();
|
|
}},
|
|
{ data: 'permission_map', render: d => d || '-' },
|
|
{ data: null, orderable: false, render: function(data, type, row) {
|
|
return `
|
|
<div class="btn-group btn-group-sm" role="group">
|
|
<a href="/characters/view/${row.id}" class="btn btn-info" title="View"><i class="bi bi-eye"></i></a>
|
|
<button data-char-id="${row.id}" class="btn btn-warning js-rescue-char" title="Rescue Character"><i class="bi bi-life-preserver"></i></button>
|
|
<button data-char-id="${row.id}" class="btn btn-danger js-delete-char" title="Delete Character"><i class="bi bi-trash"></i></button>
|
|
</div>`;
|
|
}}
|
|
],
|
|
pageLength: 25,
|
|
order: [[0, 'desc']],
|
|
processing: true
|
|
});
|
|
|
|
// Delegated event handlers
|
|
$('#characters-table').on('click', '.js-rescue-char', function() {
|
|
const id = $(this).data('char-id');
|
|
rescueCharacter(id, table);
|
|
});
|
|
$('#characters-table').on('click', '.js-delete-char', function() {
|
|
const id = $(this).data('char-id');
|
|
deleteCharacter(id, table);
|
|
});
|
|
}
|
|
|
|
}).catch(err => {
|
|
const msg = err && err.message ? err.message : 'Failed to load characters';
|
|
showLibraryError(`Error loading characters: ${msg}`);
|
|
});
|
|
|
|
}).catch(err => {
|
|
showLibraryError(`Error checking authentication: ${err && err.message ? err.message : err}`);
|
|
});
|
|
}
|
|
|
|
// Initialize when jQuery/DataTables and API are ready
|
|
safeInit(function($) {
|
|
loadCharacters();
|
|
}, { requireApi: true, timeout: 8000 });
|
|
|
|
async function rescueCharacter(charId, table) {
|
|
if (!confirm('Are you sure you want to rescue this character? This will move them to a safe location.')) return;
|
|
try {
|
|
const result = await API.post(`/api/characters/${charId}/rescue`);
|
|
if (result.success) {
|
|
showAlert('success', 'Character rescued successfully');
|
|
if (table && table.ajax) table.ajax.reload();
|
|
} else {
|
|
showAlert('danger', result.error || 'Failed to rescue character');
|
|
}
|
|
} catch (error) {
|
|
showAlert('danger', error.message || error);
|
|
}
|
|
}
|
|
|
|
async function deleteCharacter(charId, table) {
|
|
const confirmMsg = 'Are you sure you want to DELETE this character? This action is irreversible!';
|
|
if (!confirm(confirmMsg)) return;
|
|
|
|
const doubleConfirm = prompt('Type "DELETE" to confirm:');
|
|
if (doubleConfirm !== 'DELETE') {
|
|
showAlert('info', 'Deletion cancelled');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const result = await API.post(`/api/characters/${charId}/delete`);
|
|
if (result.success) {
|
|
showAlert('success', 'Character deleted');
|
|
if (table && table.ajax) table.ajax.reload();
|
|
} else {
|
|
showAlert('danger', result.error || 'Failed to delete character');
|
|
}
|
|
} catch (error) {
|
|
showAlert('danger', error.message || error);
|
|
}
|
|
}
|
|
</script>
|