mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
feat(dashboard): chat filter page shows phrases and the block list's state
Blocked entries marked Phrase, no Allow for a phrase, phrase matches named in the message test, and the Word files section says when blocklist.dcf is in the old format and how to rebuild it from blocklist.txt. issue 215 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,9 @@
|
|||||||
var page = document.getElementById('chatFilterPage');
|
var page = document.getElementById('chatFilterPage');
|
||||||
var canChat = !!page.dataset.canChat;
|
var canChat = !!page.dataset.canChat;
|
||||||
var PAGE = 50;
|
var PAGE = 50;
|
||||||
|
function isPhrase(word) { return String(word).indexOf(' ') !== -1; }
|
||||||
|
function phraseBadge(word) { return isPhrase(word) ? ' ' + fmt.badge('Phrase', 'secondary') : ''; }
|
||||||
|
|
||||||
var REASONS = {
|
var REASONS = {
|
||||||
blocked_here: 'Blocked on the staff list',
|
blocked_here: 'Blocked on the staff list',
|
||||||
allowed_here: 'Allowed on the staff list',
|
allowed_here: 'Allowed on the staff list',
|
||||||
@@ -26,7 +29,8 @@
|
|||||||
|
|
||||||
function wordAction(w) {
|
function wordAction(w) {
|
||||||
if (!w.word) return '';
|
if (!w.word) return '';
|
||||||
if (w.reason === 'blocked_here' || w.reason === 'allowed_here') return '<button type="button" class="btn btn-sm btn-outline-secondary" data-remove="' + esc(w.word) + '">Remove…</button>';
|
if (w.reason === 'blocked_here' || w.reason === 'allowed_here') return '<button type="button" class="btn btn-sm btn-outline-secondary" data-remove="' + esc(w.phrase || w.word) + '">Remove…</button>';
|
||||||
|
if (w.phrase) return '';
|
||||||
if (w.reason === 'not_allowed') return '<button type="button" class="btn btn-sm btn-outline-success" data-add="allowed" data-word="' + esc(w.word) + '">Allow…</button>';
|
if (w.reason === 'not_allowed') return '<button type="button" class="btn btn-sm btn-outline-success" data-add="allowed" data-word="' + esc(w.word) + '">Allow…</button>';
|
||||||
return '<button type="button" class="btn btn-sm btn-outline-danger" data-add="blocked" data-word="' + esc(w.word) + '">Block…</button>';
|
return '<button type="button" class="btn btn-sm btn-outline-danger" data-add="blocked" data-word="' + esc(w.word) + '">Block…</button>';
|
||||||
}
|
}
|
||||||
@@ -48,7 +52,7 @@
|
|||||||
}).join('');
|
}).join('');
|
||||||
document.getElementById('testRows').innerHTML = d.words.map(function (w) {
|
document.getElementById('testRows').innerHTML = d.words.map(function (w) {
|
||||||
return '<tr><td>' + esc(w.word || '(empty: two spaces in a row)') + '</td><td>' + (w.stopped ? fmt.badge('Stopped', 'danger') : fmt.badge('OK', 'success')) + '</td>' +
|
return '<tr><td>' + esc(w.word || '(empty: two spaces in a row)') + '</td><td>' + (w.stopped ? fmt.badge('Stopped', 'danger') : fmt.badge('OK', 'success')) + '</td>' +
|
||||||
'<td class="small">' + esc(REASONS[w.reason] || w.reason) + '</td><td class="text-end">' + wordAction(w) + '</td></tr>';
|
'<td class="small">' + esc(REASONS[w.reason] || w.reason) + (w.phrase ? ' (the phrase <strong>' + esc(w.phrase) + '</strong>)' : '') + '</td><td class="text-end">' + wordAction(w) + '</td></tr>';
|
||||||
}).join('');
|
}).join('');
|
||||||
document.getElementById('testResult').classList.remove('d-none');
|
document.getElementById('testResult').classList.remove('d-none');
|
||||||
}).catch(function () {});
|
}).catch(function () {});
|
||||||
@@ -83,10 +87,10 @@
|
|||||||
var shown = rows.slice(listStart, listStart + PAGE);
|
var shown = rows.slice(listStart, listStart + PAGE);
|
||||||
document.getElementById('listRows').innerHTML = shown.map(function (w) {
|
document.getElementById('listRows').innerHTML = shown.map(function (w) {
|
||||||
var other = w.allowed ? 'blocked' : 'allowed';
|
var other = w.allowed ? 'blocked' : 'allowed';
|
||||||
return '<tr><td>' + esc(w.word) + '</td><td>' + (w.allowed ? fmt.badge('Allowed', 'success') : fmt.badge('Blocked', 'danger')) + '</td>' +
|
return '<tr><td>' + esc(w.word) + phraseBadge(w.word) + '</td><td>' + (w.allowed ? fmt.badge('Allowed', 'success') : fmt.badge('Blocked', 'danger')) + '</td>' +
|
||||||
'<td class="small">' + esc(w.added_by) + '</td><td class="small text-nowrap">' + esc(fmt.unix(w.added_at)) + '</td>' +
|
'<td class="small">' + esc(w.added_by) + '</td><td class="small text-nowrap">' + esc(fmt.unix(w.added_at)) + '</td>' +
|
||||||
'<td class="text-end text-nowrap"><button type="button" class="btn btn-sm btn-outline-secondary" data-test="' + esc(w.word) + '">Test</button> ' +
|
'<td class="text-end text-nowrap"><button type="button" class="btn btn-sm btn-outline-secondary" data-test="' + esc(w.word) + '">Test</button> ' +
|
||||||
'<button type="button" class="btn btn-sm btn-outline-' + (w.allowed ? 'danger' : 'success') + '" data-add="' + other + '" data-word="' + esc(w.word) + '">' + (w.allowed ? 'Block…' : 'Allow…') + '</button> ' +
|
(isPhrase(w.word) && !w.allowed ? '' : '<button type="button" class="btn btn-sm btn-outline-' + (w.allowed ? 'danger' : 'success') + '" data-add="' + other + '" data-word="' + esc(w.word) + '">' + (w.allowed ? 'Block…' : 'Allow…') + '</button> ') +
|
||||||
'<button type="button" class="btn btn-sm btn-outline-secondary" data-remove="' + esc(w.word) + '">Remove…</button></td></tr>';
|
'<button type="button" class="btn btn-sm btn-outline-secondary" data-remove="' + esc(w.word) + '">Remove…</button></td></tr>';
|
||||||
}).join('') || '<tr><td colspan="5" class="text-body-secondary">' + (words.length ? 'No words match.' : 'No words added yet.') + '</td></tr>';
|
}).join('') || '<tr><td colspan="5" class="text-body-secondary">' + (words.length ? 'No words match.' : 'No words added yet.') + '</td></tr>';
|
||||||
document.getElementById('listRange').textContent = rows.length ? (listStart + 1) + '–' + (listStart + shown.length) + ' of ' + rows.length : '';
|
document.getElementById('listRange').textContent = rows.length ? (listStart + 1) + '–' + (listStart + shown.length) + ' of ' + rows.length : '';
|
||||||
@@ -114,8 +118,9 @@
|
|||||||
addForm.addEventListener('click', function (e) { var b = e.target.closest('button[data-list]'); if (b) addList = b.dataset.list; });
|
addForm.addEventListener('click', function (e) { var b = e.target.closest('button[data-list]'); if (b) addList = b.dataset.list; });
|
||||||
addForm.addEventListener('submit', function (e) {
|
addForm.addEventListener('submit', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var word = addWord.value.trim();
|
var word = addWord.value.trim().replace(/\s+/g, ' ');
|
||||||
if (!word) return;
|
if (!word) return;
|
||||||
|
if (addList === 'allowed' && isPhrase(word)) { toast('Phrases can only be blocked: normal chat checks each word on its own, so allow the words instead', 'warning'); return; }
|
||||||
confirmAdd(word, addList === 'allowed').then(function (done) { if (done) addWord.value = ''; });
|
confirmAdd(word, addList === 'allowed').then(function (done) { if (done) addWord.value = ''; });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -129,7 +134,7 @@
|
|||||||
var parts = [d.inAllowFile ? 'in chatplus_en_us.txt' : 'not in chatplus_en_us.txt'];
|
var parts = [d.inAllowFile ? 'in chatplus_en_us.txt' : 'not in chatplus_en_us.txt'];
|
||||||
if (d.inBlockFile) parts.push('in blocklist.dcf');
|
if (d.inBlockFile) parts.push('in blocklist.dcf');
|
||||||
parts.push(d.dashboard ? (d.dashboard === 'blocked' ? 'on the Blocked list' : 'on the Allowed list') : 'on neither staff list');
|
parts.push(d.dashboard ? (d.dashboard === 'blocked' ? 'on the Blocked list' : 'on the Allowed list') : 'on neither staff list');
|
||||||
return '<strong>' + esc(d.word) + '</strong> now: ' + esc(parts.join(', ')) + '.';
|
return '<strong>' + esc(d.word) + '</strong>' + phraseBadge(d.word) + ' now: ' + esc(parts.join(', ')) + '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
function openConfirm(options) {
|
function openConfirm(options) {
|
||||||
@@ -186,7 +191,8 @@
|
|||||||
function confirmAdd(word, allowed) {
|
function confirmAdd(word, allowed) {
|
||||||
var p = openConfirm({
|
var p = openConfirm({
|
||||||
title: (allowed ? 'Allow "' : 'Block "') + word + '"?',
|
title: (allowed ? 'Allow "' : 'Block "') + word + '"?',
|
||||||
text: allowed ? 'Players may use it in normal chat. Running worlds apply it at once.' : 'It is stopped in all chat, even where a word file allows it. Running worlds apply it at once.',
|
text: allowed ? 'Players may use it in normal chat. Running worlds apply it at once.'
|
||||||
|
: (isPhrase(word) ? 'The phrase is stopped in all chat when its words come in a row. Running worlds apply it at once.' : 'It is stopped in all chat, even where a word file allows it. Running worlds apply it at once.'),
|
||||||
tone: allowed ? 'success' : 'danger',
|
tone: allowed ? 'success' : 'danger',
|
||||||
button: allowed ? 'Allow' : 'Block',
|
button: allowed ? 'Allow' : 'Block',
|
||||||
run: function () { return api.action('/api/chat_filter/words', { word: word, allowed: allowed }).then(function (d) { toast(d.message, 'success'); }); }
|
run: function () { return api.action('/api/chat_filter/words', { word: word, allowed: allowed }).then(function (d) { toast(d.message, 'success'); }); }
|
||||||
@@ -228,8 +234,11 @@
|
|||||||
? esc(d.allowTotal) + ' words normal chat may use (from the client); ' + esc(d.onDashboard) + ' are on a staff list too, which wins.'
|
? esc(d.allowTotal) + ' words normal chat may use (from the client); ' + esc(d.onDashboard) + ' are on a staff list too, which wins.'
|
||||||
: 'could not be read. Set <code>client_location</code>.') + '</li>' +
|
: 'could not be read. Set <code>client_location</code>.') + '</li>' +
|
||||||
'<li><code>' + esc(d.blockFile) + '</code>: ' + (d.blockFileFound
|
'<li><code>' + esc(d.blockFile) + '</code>: ' + (d.blockFileFound
|
||||||
? esc(d.blockTotal) + ' words best friends\' free chat may not use. Stored as hashes, so they can\'t be listed; test a word to see if it is one.'
|
? esc(d.blockTotal) + ' words' + (d.blockMaxWords > 1 ? ' and phrases (up to ' + esc(d.blockMaxWords) + ' words)' : '') + ' best friends\' free chat may not use. Stored as hashes, so they can\'t be listed; test a word or phrase to see if it is one.'
|
||||||
: 'not found next to the servers, so best friends\' free chat stops everything.') + '</li>';
|
: d.blockFileOld
|
||||||
|
? 'in the old format (its hashes depended on the platform), so the servers can\'t read it and best friends\' free chat stops everything.'
|
||||||
|
: 'not found next to the servers (' + esc(d.blockFileStatus) + '), so best friends\' free chat stops everything.') +
|
||||||
|
' To change it, put the words in <code>' + esc(d.blockText) + '</code> next to the servers (one word or phrase per line) and start the servers again; they build <code>' + esc(d.blockFile) + '</code> from it.</li>';
|
||||||
document.getElementById('fileWords').innerHTML = d.words.map(function (w) {
|
document.getElementById('fileWords').innerHTML = d.words.map(function (w) {
|
||||||
var cls = w.dashboard === 'blocked' ? 'text-bg-danger' : w.dashboard === 'allowed' ? 'text-bg-success' : 'text-bg-secondary';
|
var cls = w.dashboard === 'blocked' ? 'text-bg-danger' : w.dashboard === 'allowed' ? 'text-bg-success' : 'text-bg-secondary';
|
||||||
return '<button type="button" class="badge border-0 ' + cls + '" data-test="' + esc(w.word) + '">' + esc(w.word) + '</button>';
|
return '<button type="button" class="badge border-0 ' + cls + '" data-test="' + esc(w.word) + '">' + esc(w.word) + '</button>';
|
||||||
|
|||||||
@@ -54,12 +54,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<dl class="small cf-explain mb-3 row">
|
<dl class="small cf-explain mb-3 row">
|
||||||
<dt class="col-sm-2 text-danger">Blocked</dt><dd class="col-sm-10">Stopped in all chat, even if a word file allows it.</dd>
|
<dt class="col-sm-2 text-danger">Blocked</dt><dd class="col-sm-10">Stopped in all chat, even if a word file allows it. A phrase (several words) is stopped when its words come in a row, whatever the spaces and punctuation between them.</dd>
|
||||||
<dt class="col-sm-2 text-success">Allowed</dt><dd class="col-sm-10">Usable in normal chat, like the words in <code>chatplus_en_us.txt</code>.</dd>
|
<dt class="col-sm-2 text-success">Allowed</dt><dd class="col-sm-10">Usable in normal chat, like the words in <code>chatplus_en_us.txt</code>. Single words only: normal chat checks each word on its own, as the client does.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<form class="row g-2 align-items-end mb-3" id="addForm">
|
<form class="row g-2 align-items-end mb-3" id="addForm">
|
||||||
<div class="col-md-6"><label class="form-label small mb-1" for="addWord">Add a word</label>
|
<div class="col-md-6"><label class="form-label small mb-1" for="addWord">Add a word or phrase</label>
|
||||||
<input class="form-control form-control-sm" id="addWord" maxlength="64" required autocomplete="off" placeholder="One word, no spaces"></div>
|
<input class="form-control form-control-sm" id="addWord" maxlength="64" required autocomplete="off" placeholder="A word, or a phrase to block"></div>
|
||||||
<div class="col-md-6 d-flex gap-2">
|
<div class="col-md-6 d-flex gap-2">
|
||||||
<button type="submit" class="btn btn-sm btn-danger" data-list="blocked">Block…</button>
|
<button type="submit" class="btn btn-sm btn-danger" data-list="blocked">Block…</button>
|
||||||
<button type="submit" class="btn btn-sm btn-success" data-list="allowed">Allow…</button>
|
<button type="submit" class="btn btn-sm btn-success" data-list="allowed">Allow…</button>
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
<input type="search" class="form-control form-control-sm w-auto ms-auto" id="listSearch" placeholder="Search the lists" aria-label="Search the lists">
|
<input type="search" class="form-control form-control-sm w-auto ms-auto" id="listSearch" placeholder="Search the lists" aria-label="Search the lists">
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-sm table-hover align-middle w-100 table-stack mb-2" id="cfWordTable">
|
<table class="table table-sm table-hover align-middle w-100 table-stack mb-2" id="cfWordTable">
|
||||||
<thead><tr><th>Word</th><th>List</th><th>Added by</th><th>Added</th><th></th></tr></thead>
|
<thead><tr><th>Word or phrase</th><th>List</th><th>Added by</th><th>Added</th><th></th></tr></thead>
|
||||||
<tbody id="listRows"></tbody>
|
<tbody id="listRows"></tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="d-flex justify-content-between align-items-center small">
|
<div class="d-flex justify-content-between align-items-center small">
|
||||||
|
|||||||
Reference in New Issue
Block a user