togethere.cloud/private_html/administration/users/setting/index.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';
?>