266 lines
8.9 KiB
HTML
266 lines
8.9 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Admin Panel - Das File Storage{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="nav-tabs">
|
||
<a href="/dashboard" class="nav-tab">📂 My Files</a>
|
||
<a href="/settings" class="nav-tab">⚙️ Settings</a>
|
||
<a href="/admin" class="nav-tab active">👑 Admin Panel</a>
|
||
</div>
|
||
|
||
{% if message %}
|
||
<div class="alert alert-success">
|
||
{{ message }}
|
||
</div>
|
||
{% endif %}
|
||
|
||
{% if error %}
|
||
<div class="alert alert-error">
|
||
{{ error }}
|
||
</div>
|
||
{% endif %}
|
||
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||
<h2>User Management</h2>
|
||
<button onclick="openCreateUserModal()" class="btn btn-primary">
|
||
➕ Create New User
|
||
</button>
|
||
</div>
|
||
|
||
<div style="background: #f9fafb; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
|
||
<h3 style="margin-bottom: 15px; color: #374151;">📊 Statistics</h3>
|
||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px;">
|
||
<div style="background: white; padding: 15px; border-radius: 6px; border-left: 4px solid #667eea;">
|
||
<div style="color: #6b7280; font-size: 12px;">Total Users</div>
|
||
<div style="font-size: 24px; font-weight: bold; color: #374151;">{{ stats.total_users }}</div>
|
||
</div>
|
||
<div style="background: white; padding: 15px; border-radius: 6px; border-left: 4px solid #10b981;">
|
||
<div style="color: #6b7280; font-size: 12px;">Active Users</div>
|
||
<div style="font-size: 24px; font-weight: bold; color: #374151;">{{ stats.active_users }}</div>
|
||
</div>
|
||
<div style="background: white; padding: 15px; border-radius: 6px; border-left: 4px solid #ef4444;">
|
||
<div style="color: #6b7280; font-size: 12px;">Blocked Users</div>
|
||
<div style="font-size: 24px; font-weight: bold; color: #374151;">{{ stats.blocked_users }}</div>
|
||
</div>
|
||
<div style="background: white; padding: 15px; border-radius: 6px; border-left: 4px solid #f59e0b;">
|
||
<div style="color: #6b7280; font-size: 12px;">Total Files</div>
|
||
<div style="font-size: 24px; font-weight: bold; color: #374151;">{{ stats.total_files }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Username</th>
|
||
<th>Role</th>
|
||
<th>Files</th>
|
||
<th>Created</th>
|
||
<th>Status</th>
|
||
<th>Actions</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for user in users %}
|
||
<tr>
|
||
<td>
|
||
<strong>{{ user.username }}</strong>
|
||
</td>
|
||
<td>
|
||
{% if user.is_admin %}
|
||
<span class="admin-badge">Admin</span>
|
||
{% else %}
|
||
User
|
||
{% endif %}
|
||
</td>
|
||
<td class="file-size">{{ user.file_count }} files</td>
|
||
<td class="file-size">{{ user.created_at.strftime('%Y-%m-%d') }}</td>
|
||
<td>
|
||
{% if user.is_blocked %}
|
||
<span style="color: #ef4444; font-weight: bold;">🚫 Blocked</span>
|
||
{% else %}
|
||
<span style="color: #10b981; font-weight: bold;">✅ Active</span>
|
||
{% endif %}
|
||
</td>
|
||
<td>
|
||
{% if user.username != username %}
|
||
{% if user.is_blocked %}
|
||
<button onclick="unblockUser({{ user.id }}, '{{ user.username }}')" class="btn btn-success btn-small">
|
||
✅ Unblock
|
||
</button>
|
||
{% else %}
|
||
<button onclick="blockUser({{ user.id }}, '{{ user.username }}')" class="btn btn-secondary btn-small">
|
||
🚫 Block
|
||
</button>
|
||
{% endif %}
|
||
<button onclick="deleteUser({{ user.id }}, '{{ user.username }}')" class="btn btn-danger btn-small">
|
||
🗑️ Delete
|
||
</button>
|
||
{% else %}
|
||
<span style="color: #6b7280; font-size: 12px;">Current User</span>
|
||
{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
|
||
<!-- Create User Modal -->
|
||
<div id="createUserModal" class="modal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">Create New User</div>
|
||
<form id="createUserForm">
|
||
<div class="form-group">
|
||
<label for="new_username">Username</label>
|
||
<input type="text" id="new_username" name="username" required minlength="3" maxlength="50">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="new_password">Password</label>
|
||
<input type="password" id="new_password" name="password" required minlength="8">
|
||
<small style="color: #6b7280;">Minimum 8 characters</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="confirm_new_password">Confirm Password</label>
|
||
<input type="password" id="confirm_new_password" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<div class="checkbox-group">
|
||
<input type="checkbox" id="is_admin" name="is_admin">
|
||
<label for="is_admin" style="margin: 0;">Administrator privileges</label>
|
||
</div>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button type="button" onclick="closeCreateUserModal()" class="btn btn-secondary">Cancel</button>
|
||
<button type="submit" class="btn btn-primary">Create User</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
{% endblock %}
|
||
|
||
{% block extra_scripts %}
|
||
<script>
|
||
function openCreateUserModal() {
|
||
document.getElementById('createUserModal').classList.add('active');
|
||
}
|
||
|
||
function closeCreateUserModal() {
|
||
document.getElementById('createUserModal').classList.remove('active');
|
||
document.getElementById('createUserForm').reset();
|
||
}
|
||
|
||
document.getElementById('createUserForm').addEventListener('submit', async (e) => {
|
||
e.preventDefault();
|
||
|
||
const password = document.getElementById('new_password').value;
|
||
const confirmPassword = document.getElementById('confirm_new_password').value;
|
||
|
||
if (password !== confirmPassword) {
|
||
alert('Passwords do not match!');
|
||
return;
|
||
}
|
||
|
||
const formData = {
|
||
username: document.getElementById('new_username').value,
|
||
password: password,
|
||
is_admin: document.getElementById('is_admin').checked
|
||
};
|
||
|
||
try {
|
||
const response = await fetch('/api/users', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(formData)
|
||
});
|
||
|
||
if (response.ok) {
|
||
window.location.reload();
|
||
} else {
|
||
const error = await response.json();
|
||
alert('Failed to create user: ' + (error.detail || 'Unknown error'));
|
||
}
|
||
} catch (error) {
|
||
alert('Failed to create user: ' + error.message);
|
||
}
|
||
});
|
||
|
||
async function blockUser(userId, username) {
|
||
if (!confirm(`Are you sure you want to block user "${username}"?`)) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`/api/users/${userId}/block?block=true`, {
|
||
method: 'PATCH'
|
||
});
|
||
|
||
if (response.ok) {
|
||
window.location.reload();
|
||
} else {
|
||
alert('Failed to block user');
|
||
}
|
||
} catch (error) {
|
||
alert('Failed to block user: ' + error.message);
|
||
}
|
||
}
|
||
|
||
async function unblockUser(userId, username) {
|
||
if (!confirm(`Are you sure you want to unblock user "${username}"?`)) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`/api/users/${userId}/block?block=false`, {
|
||
method: 'PATCH'
|
||
});
|
||
|
||
if (response.ok) {
|
||
window.location.reload();
|
||
} else {
|
||
alert('Failed to unblock user');
|
||
}
|
||
} catch (error) {
|
||
alert('Failed to unblock user: ' + error.message);
|
||
}
|
||
}
|
||
|
||
async function deleteUser(userId, username) {
|
||
if (!confirm(`Are you sure you want to DELETE user "${username}"?\n\nThis will also delete all their files. This action cannot be undone!`)) {
|
||
return;
|
||
}
|
||
|
||
const confirmation = prompt(`Type "${username}" to confirm deletion:`);
|
||
if (confirmation !== username) {
|
||
alert('Deletion cancelled - username did not match');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`/api/users/${userId}`, {
|
||
method: 'DELETE'
|
||
});
|
||
|
||
if (response.ok) {
|
||
window.location.reload();
|
||
} else {
|
||
alert('Failed to delete user');
|
||
}
|
||
} catch (error) {
|
||
alert('Failed to delete user: ' + error.message);
|
||
}
|
||
}
|
||
|
||
// Close modals when clicking outside
|
||
document.querySelectorAll('.modal').forEach(modal => {
|
||
modal.addEventListener('click', (e) => {
|
||
if (e.target === modal) {
|
||
modal.classList.remove('active');
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
{% endblock %} |