289 lines
9.6 KiB
PHP
289 lines
9.6 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../../includes/auth.php';
|
|
require_once __DIR__ . '/../../includes/config.php';
|
|
require_once __DIR__ . '/../../includes/header.php';
|
|
require_once __DIR__ . '/../../includes/sidebar.php';
|
|
|
|
try {
|
|
$pdo->exec(
|
|
"CREATE TABLE IF NOT EXISTS blocked_usernames (
|
|
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
name VARCHAR(20) NOT NULL,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by INT NULL,
|
|
UNIQUE KEY unique_blocked_username (name),
|
|
KEY idx_blocked_created_by (created_by)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
|
|
);
|
|
} catch (Throwable $e) {
|
|
}
|
|
|
|
$blockedRows = [];
|
|
try {
|
|
$stmt = $pdo->prepare(
|
|
"SELECT b.id, b.name, b.created_at, b.created_by, u.username AS created_by_username
|
|
FROM blocked_usernames b
|
|
LEFT JOIN users u ON u.id = b.created_by
|
|
ORDER BY b.created_at DESC, b.id DESC
|
|
LIMIT 100"
|
|
);
|
|
$stmt->execute();
|
|
$blockedRows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
|
} catch (Throwable $e) {
|
|
$blockedRows = [];
|
|
}
|
|
?>
|
|
|
|
<div class="admin-content">
|
|
<style>
|
|
.admin-page-title {
|
|
font-size: 24px;
|
|
font-weight: 600;
|
|
color: #23282d;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid #0073aa;
|
|
}
|
|
|
|
.admin-content-box {
|
|
background: #fff;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 20px;
|
|
margin-top: 20px;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.blocked-form {
|
|
display: grid;
|
|
grid-template-columns: 1fr auto;
|
|
gap: 10px;
|
|
margin-bottom: 14px;
|
|
align-items: end;
|
|
}
|
|
|
|
.blocked-form label {
|
|
display: block;
|
|
margin-bottom: 6px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: #444;
|
|
}
|
|
|
|
.blocked-form input[type="text"] {
|
|
width: 100%;
|
|
min-height: 38px;
|
|
border: 1px solid #d0d7de;
|
|
border-radius: 6px;
|
|
padding: 8px 12px;
|
|
font-size: 14px;
|
|
outline: none;
|
|
}
|
|
|
|
.blocked-form input[type="text"]:focus {
|
|
border-color: #0073aa;
|
|
box-shadow: 0 0 0 3px rgba(0,115,170,0.12);
|
|
}
|
|
|
|
.blocked-btn {
|
|
min-height: 38px;
|
|
border: 0;
|
|
border-radius: 6px;
|
|
padding: 9px 14px;
|
|
background: #0073aa;
|
|
color: #fff;
|
|
font-size: 13px;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.blocked-btn:hover {
|
|
background: #005f8d;
|
|
}
|
|
|
|
.blocked-status {
|
|
min-height: 20px;
|
|
font-size: 13px;
|
|
margin-bottom: 12px;
|
|
color: #666;
|
|
}
|
|
|
|
.blocked-status.success {
|
|
color: #1e7e34;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.blocked-status.error {
|
|
color: #b32d2e;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.blocked-help {
|
|
font-size: 12px;
|
|
color: #666;
|
|
margin-bottom: 14px;
|
|
line-height: 1.45;
|
|
}
|
|
|
|
.blocked-table-wrap {
|
|
overflow-x: auto;
|
|
border: 1px solid #e6e6e6;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.blocked-table {
|
|
width: 100%;
|
|
min-width: 560px;
|
|
border-collapse: collapse;
|
|
background: #fff;
|
|
}
|
|
|
|
.blocked-table th,
|
|
.blocked-table td {
|
|
padding: 10px 12px;
|
|
border-bottom: 1px solid #eee;
|
|
text-align: left;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.blocked-table th {
|
|
background: #f8f9fa;
|
|
color: #23282d;
|
|
font-weight: 700;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.blocked-table tbody tr:hover {
|
|
background: #fafcff;
|
|
}
|
|
|
|
.blocked-empty {
|
|
padding: 16px;
|
|
text-align: center;
|
|
font-size: 13px;
|
|
color: #666;
|
|
}
|
|
|
|
@media (max-width: 720px) {
|
|
.blocked-form {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<h1 class="admin-page-title">⚙️ Użytkownicy - Ustawienia</h1>
|
|
|
|
<div class="admin-content-box">
|
|
<h3 style="margin:0 0 12px 0; color:#23282d;">Blokowane nazwy użytkowników</h3>
|
|
|
|
<div class="blocked-help">
|
|
Endpoint: <strong>/admin/user/settings/blocked-names</strong> • metoda: <strong>POST</strong> • format nazwy: <strong>[A-Za-z0-9_&!]{1,20}</strong>
|
|
</div>
|
|
|
|
<form id="blockedNameForm" class="blocked-form">
|
|
<div>
|
|
<label for="blockedNameInput">Nazwa użytkownika do zablokowania</label>
|
|
<input type="text" id="blockedNameInput" maxlength="20" placeholder="np. admin" required>
|
|
</div>
|
|
<button class="blocked-btn" type="submit">Zablokuj nazwę</button>
|
|
</form>
|
|
|
|
<div id="blockedStatus" class="blocked-status"></div>
|
|
|
|
<div class="blocked-table-wrap">
|
|
<table class="blocked-table" aria-label="Zablokowane nazwy użytkowników">
|
|
<thead>
|
|
<tr>
|
|
<th style="width:70px;">ID</th>
|
|
<th>Nazwa</th>
|
|
<th style="width:190px;">Data dodania</th>
|
|
<th style="width:220px;">Dodane przez</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($blockedRows)): ?>
|
|
<tr>
|
|
<td colspan="4" class="blocked-empty">Brak zablokowanych nazw</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($blockedRows as $row): ?>
|
|
<tr>
|
|
<td><?php echo (int)($row['id'] ?? 0); ?></td>
|
|
<td><strong><?php echo htmlspecialchars((string)($row['name'] ?? ''), ENT_QUOTES, 'UTF-8'); ?></strong></td>
|
|
<td><?php echo htmlspecialchars((string)($row['created_at'] ?? ''), ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td>
|
|
<?php
|
|
$createdByUsername = (string)($row['created_by_username'] ?? '');
|
|
$createdById = (int)($row['created_by'] ?? 0);
|
|
if ($createdByUsername !== '') {
|
|
echo htmlspecialchars($createdByUsername, ENT_QUOTES, 'UTF-8') . ' (#' . $createdById . ')';
|
|
} elseif ($createdById > 0) {
|
|
echo '#' . $createdById;
|
|
} else {
|
|
echo '-';
|
|
}
|
|
?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
const form = document.getElementById('blockedNameForm');
|
|
const input = document.getElementById('blockedNameInput');
|
|
const statusEl = document.getElementById('blockedStatus');
|
|
const endpoint = '/admin/user/settings/blocked-names';
|
|
|
|
function setStatus(message, type) {
|
|
statusEl.textContent = message || '';
|
|
statusEl.classList.remove('success', 'error');
|
|
if (type) statusEl.classList.add(type);
|
|
}
|
|
|
|
form.addEventListener('submit', async function (e) {
|
|
e.preventDefault();
|
|
const value = (input.value || '').trim();
|
|
if (value === '') {
|
|
setStatus('Nazwa użytkownika nie może być pusta.', 'error');
|
|
return;
|
|
}
|
|
|
|
setStatus('Zapisywanie...', null);
|
|
|
|
try {
|
|
const response = await fetch(endpoint, {
|
|
method: 'POST',
|
|
credentials: 'same-origin',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ name: value })
|
|
});
|
|
|
|
const json = await response.json();
|
|
if (!response.ok) {
|
|
throw new Error((json && json.message) ? json.message : 'Nie udało się zablokować nazwy.');
|
|
}
|
|
|
|
setStatus(json.message || 'Nazwa użytkownika została zablokowana pomyślnie.', 'success');
|
|
input.value = '';
|
|
setTimeout(function () {
|
|
window.location.reload();
|
|
}, 500);
|
|
} catch (error) {
|
|
setStatus(error && error.message ? error.message : 'Błąd podczas zapisu.', 'error');
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</div>
|
|
|
|
<?php
|
|
require_once __DIR__ . '/../../includes/footer.php';
|
|
?>
|