FileServer/templates/admin.html

266 lines
8.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% 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 %}