Compare commits
4 Commits
dynamic-si
...
fix-dashbo
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f9e8781e3 | |||
| 880f4fb615 | |||
| 42db5e6a63 | |||
| 7394e150f1 |
172
DASHBOARD_FIX.md
Normal file
172
DASHBOARD_FIX.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# Dashboard Routing Fix
|
||||||
|
|
||||||
|
Questo branch (`fix-dashboard-routing`) contiene le correzioni per risolvere i problemi di accesso alla dashboard nel branch `dynamic-site-enhancement`.
|
||||||
|
|
||||||
|
## Problemi Risolti
|
||||||
|
|
||||||
|
### 1. Template Mancante
|
||||||
|
- ✅ Aggiunto il template mancante `templates/dashboard/users.html`
|
||||||
|
- Il template è ora completo con paginazione e gestione degli errori
|
||||||
|
|
||||||
|
### 2. Gestione Errori Migliorata
|
||||||
|
- ✅ Aggiunta gestione degli errori in tutte le route della dashboard
|
||||||
|
- ✅ Messaggi di errore più dettagliati per il debugging
|
||||||
|
- ✅ Fallback sicuri quando il database non è accessibile
|
||||||
|
|
||||||
|
### 3. Route di Debug
|
||||||
|
- ✅ Aggiunta route `/dashboard/debug/auth` per controllare lo stato di autenticazione
|
||||||
|
- ✅ Aggiunta route `/dashboard/debug/access` per testare l'accesso alla dashboard
|
||||||
|
- ✅ Informazioni dettagliate su sessioni e privilegi utente
|
||||||
|
|
||||||
|
### 4. Script di Utilità
|
||||||
|
- ✅ Creato script `utils/create_admin.py` per creare utenti amministratore
|
||||||
|
- ✅ Supporto per creare, listare e promuovere utenti
|
||||||
|
|
||||||
|
## Come Risolvere i Problemi di Accesso
|
||||||
|
|
||||||
|
### Passo 1: Verifica la Configurazione
|
||||||
|
|
||||||
|
Assicurati che il file `config.py` abbia la `SECRET_KEY` configurata:
|
||||||
|
|
||||||
|
```python
|
||||||
|
SECRET_KEY = 'your-secret-key-here'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Passo 2: Inizializza il Database
|
||||||
|
|
||||||
|
Assicurati che il database sia inizializzato e accessibile:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Con Docker Compose
|
||||||
|
docker-compose up -d db
|
||||||
|
|
||||||
|
# Controlla i log per errori
|
||||||
|
docker-compose logs app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Passo 3: Crea un Utente Amministratore
|
||||||
|
|
||||||
|
Usa lo script di utilità per creare un utente admin:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Crea utente admin predefinito
|
||||||
|
python utils/create_admin.py create
|
||||||
|
|
||||||
|
# Oppure promuovi un utente esistente
|
||||||
|
python utils/create_admin.py promote username
|
||||||
|
|
||||||
|
# Lista tutti gli utenti
|
||||||
|
python utils/create_admin.py list
|
||||||
|
```
|
||||||
|
|
||||||
|
### Passo 4: Testa l'Accesso
|
||||||
|
|
||||||
|
1. **Controlla lo stato di autenticazione:**
|
||||||
|
```
|
||||||
|
GET /dashboard/debug/auth
|
||||||
|
```
|
||||||
|
Questo ti dirà se sei loggato e hai i privilegi corretti.
|
||||||
|
|
||||||
|
2. **Testa l'accesso alla dashboard:**
|
||||||
|
```
|
||||||
|
GET /dashboard/debug/access
|
||||||
|
```
|
||||||
|
Questo ti dirà se puoi accedere alla dashboard e perché.
|
||||||
|
|
||||||
|
3. **Effettua il login:**
|
||||||
|
- Vai a `/auth/login`
|
||||||
|
- Usa le credenziali dell'utente admin
|
||||||
|
- Dovresti essere reindirizzato automaticamente a `/dashboard/`
|
||||||
|
|
||||||
|
## Credenziali Admin Predefinite
|
||||||
|
|
||||||
|
Se usi lo script `create_admin.py create`, verranno create queste credenziali:
|
||||||
|
|
||||||
|
- **Username:** `admin`
|
||||||
|
- **Email:** `admin@hersel.it`
|
||||||
|
- **Password:** `admin123`
|
||||||
|
|
||||||
|
⚠️ **IMPORTANTE:** Cambia la password predefinita dopo il primo login!
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Problema: "401 Login required"
|
||||||
|
**Soluzione:** Non sei loggato. Vai a `/auth/login` e effettua il login.
|
||||||
|
|
||||||
|
### Problema: "403 Admin access required"
|
||||||
|
**Soluzione:** Il tuo utente non ha privilegi di amministratore. Usa:
|
||||||
|
```bash
|
||||||
|
python utils/create_admin.py promote il_tuo_username
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problema: "500 Internal Server Error"
|
||||||
|
**Possibili cause:**
|
||||||
|
1. Database non accessibile
|
||||||
|
2. Errore nei template
|
||||||
|
3. Configurazione mancante
|
||||||
|
|
||||||
|
**Debug:**
|
||||||
|
1. Controlla i log dell'applicazione
|
||||||
|
2. Usa le route di debug: `/dashboard/debug/auth` e `/dashboard/debug/access`
|
||||||
|
3. Verifica la configurazione del database
|
||||||
|
|
||||||
|
### Problema: Template non trovato
|
||||||
|
**Soluzione:** Assicurati che tutti i template esistano in `templates/dashboard/`:
|
||||||
|
- `index.html` ✅
|
||||||
|
- `projects.html` ✅
|
||||||
|
- `project_form.html` ✅
|
||||||
|
- `users.html` ✅ (aggiunto in questo fix)
|
||||||
|
- `base.html` ✅
|
||||||
|
|
||||||
|
## URL della Dashboard
|
||||||
|
|
||||||
|
Dopo aver risolto i problemi di autenticazione, puoi accedere a:
|
||||||
|
|
||||||
|
- **Dashboard principale:** `/dashboard/`
|
||||||
|
- **Gestione progetti:** `/dashboard/projects`
|
||||||
|
- **Nuovo progetto:** `/dashboard/projects/new`
|
||||||
|
- **Gestione utenti:** `/dashboard/users`
|
||||||
|
- **Debug autenticazione:** `/dashboard/debug/auth`
|
||||||
|
- **Test accesso:** `/dashboard/debug/access`
|
||||||
|
|
||||||
|
## Modifiche Apportate
|
||||||
|
|
||||||
|
1. **`templates/dashboard/users.html`** - Nuovo template per la gestione utenti
|
||||||
|
2. **`routes/dashboard.py`** - Migliorate gestione errori e aggiunte route di debug
|
||||||
|
3. **`utils/create_admin.py`** - Nuovo script per gestire utenti amministratore
|
||||||
|
4. **`DASHBOARD_FIX.md`** - Questa documentazione
|
||||||
|
|
||||||
|
## Come Applicare i Fix
|
||||||
|
|
||||||
|
1. **Merge di questo branch:**
|
||||||
|
```bash
|
||||||
|
git checkout dynamic-site-enhancement
|
||||||
|
git merge fix-dashboard-routing
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Oppure crea un PR:**
|
||||||
|
- Crea una pull request da `fix-dashboard-routing` a `dynamic-site-enhancement`
|
||||||
|
- Rivedi le modifiche e fai il merge
|
||||||
|
|
||||||
|
3. **Testa l'applicazione:**
|
||||||
|
```bash
|
||||||
|
# Restart dell'applicazione
|
||||||
|
docker-compose restart app
|
||||||
|
|
||||||
|
# Crea utente admin
|
||||||
|
docker-compose exec app python utils/create_admin.py create
|
||||||
|
|
||||||
|
# Testa l'accesso
|
||||||
|
curl http://localhost:5000/dashboard/debug/access
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supporto
|
||||||
|
|
||||||
|
Se hai ancora problemi dopo aver applicato questi fix:
|
||||||
|
|
||||||
|
1. Controlla i log dell'applicazione
|
||||||
|
2. Usa le route di debug per diagnosticare il problema
|
||||||
|
3. Verifica che il database sia accessibile
|
||||||
|
4. Assicurati di avere un utente con privilegi di amministratore
|
||||||
|
|
||||||
|
Tutti i fix sono backward-compatible e non dovrebbero causare problemi al codice esistente.
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
# Dashboard Routes (Admin)
|
# Dashboard Routes (Admin)
|
||||||
|
|
||||||
from quart import Blueprint, request, render_template, redirect, url_for, jsonify
|
from quart import Blueprint, request, render_template, redirect, url_for, jsonify, session
|
||||||
from models.user import User
|
from models.user import User
|
||||||
from models.project import Project
|
from models.project import Project
|
||||||
from models.category import Category
|
from models.category import Category
|
||||||
@@ -13,27 +13,115 @@ from utils.validators import validate_project_data
|
|||||||
|
|
||||||
dashboard_bp = Blueprint('dashboard', __name__, url_prefix='/dashboard')
|
dashboard_bp = Blueprint('dashboard', __name__, url_prefix='/dashboard')
|
||||||
|
|
||||||
|
# Debug route to check authentication status
|
||||||
|
@dashboard_bp.route('/debug/auth')
|
||||||
|
async def debug_auth():
|
||||||
|
"""Debug route to check authentication status"""
|
||||||
|
current_user = await get_current_user()
|
||||||
|
session_data = dict(session)
|
||||||
|
|
||||||
|
debug_info = {
|
||||||
|
'session_exists': 'user_id' in session,
|
||||||
|
'user_id_in_session': session.get('user_id'),
|
||||||
|
'username_in_session': session.get('username'),
|
||||||
|
'is_admin_in_session': session.get('is_admin'),
|
||||||
|
'current_user_found': current_user is not None,
|
||||||
|
'current_user_is_admin': current_user.is_admin if current_user else None,
|
||||||
|
'current_user_details': {
|
||||||
|
'id': current_user.id,
|
||||||
|
'username': current_user.username,
|
||||||
|
'email': current_user.email,
|
||||||
|
'role': current_user.role,
|
||||||
|
'is_admin': current_user.is_admin
|
||||||
|
} if current_user else None,
|
||||||
|
'session_data': session_data
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonify(debug_info)
|
||||||
|
|
||||||
|
# Public route to check dashboard access without admin_required decorator
|
||||||
|
@dashboard_bp.route('/debug/access')
|
||||||
|
async def debug_access():
|
||||||
|
"""Debug route to check dashboard access requirements"""
|
||||||
|
try:
|
||||||
|
current_user = await get_current_user()
|
||||||
|
|
||||||
|
if not current_user:
|
||||||
|
return jsonify({
|
||||||
|
'status': 'error',
|
||||||
|
'message': 'Nessun utente loggato',
|
||||||
|
'redirect': url_for('auth.login')
|
||||||
|
}), 401
|
||||||
|
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return jsonify({
|
||||||
|
'status': 'error',
|
||||||
|
'message': f'Utente {current_user.username} non ha privilegi di amministratore',
|
||||||
|
'user_role': current_user.role,
|
||||||
|
'is_admin': current_user.is_admin,
|
||||||
|
'redirect': url_for('home.index')
|
||||||
|
}), 403
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'status': 'success',
|
||||||
|
'message': f'Accesso consentito per {current_user.username}',
|
||||||
|
'user': {
|
||||||
|
'id': current_user.id,
|
||||||
|
'username': current_user.username,
|
||||||
|
'role': current_user.role,
|
||||||
|
'is_admin': current_user.is_admin
|
||||||
|
},
|
||||||
|
'dashboard_url': url_for('dashboard.index')
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({
|
||||||
|
'status': 'error',
|
||||||
|
'message': f'Errore durante il controllo accesso: {str(e)}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
@dashboard_bp.route('/')
|
@dashboard_bp.route('/')
|
||||||
@admin_required
|
@admin_required
|
||||||
async def index():
|
async def index():
|
||||||
"""Dashboard home"""
|
"""Dashboard home"""
|
||||||
current_user = await get_current_user()
|
try:
|
||||||
|
current_user = await get_current_user()
|
||||||
# Get statistics
|
|
||||||
stats = {
|
# Get statistics with error handling
|
||||||
'total_users': await User.count(),
|
stats = {
|
||||||
'total_projects': await Project.count(published_only=False),
|
'total_users': 0,
|
||||||
'published_projects': await Project.count(published_only=True),
|
'total_projects': 0,
|
||||||
'featured_projects': len(await Project.get_featured())
|
'published_projects': 0,
|
||||||
}
|
'featured_projects': 0
|
||||||
|
}
|
||||||
# Get recent projects
|
|
||||||
recent_projects = await Project.get_all(published_only=False, limit=5)
|
try:
|
||||||
|
stats['total_users'] = await User.count()
|
||||||
return await render_template('dashboard/index.html',
|
except Exception as e:
|
||||||
user=current_user,
|
print(f"Error getting user count: {e}")
|
||||||
stats=stats,
|
|
||||||
recent_projects=recent_projects)
|
try:
|
||||||
|
stats['total_projects'] = await Project.count(published_only=False)
|
||||||
|
stats['published_projects'] = await Project.count(published_only=True)
|
||||||
|
featured_projects = await Project.get_featured()
|
||||||
|
stats['featured_projects'] = len(featured_projects) if featured_projects else 0
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting project stats: {e}")
|
||||||
|
|
||||||
|
# Get recent projects with error handling
|
||||||
|
recent_projects = []
|
||||||
|
try:
|
||||||
|
recent_projects = await Project.get_all(published_only=False, limit=5)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting recent projects: {e}")
|
||||||
|
|
||||||
|
return await render_template('dashboard/index.html',
|
||||||
|
user=current_user,
|
||||||
|
stats=stats,
|
||||||
|
recent_projects=recent_projects)
|
||||||
|
except Exception as e:
|
||||||
|
flash_message(f'Errore nel caricamento della dashboard: {str(e)}', 'error')
|
||||||
|
return redirect(url_for('home.index'))
|
||||||
|
|
||||||
@dashboard_bp.route('/projects')
|
@dashboard_bp.route('/projects')
|
||||||
@admin_required
|
@admin_required
|
||||||
@@ -42,26 +130,34 @@ async def projects():
|
|||||||
page = int(request.args.get('page', 1))
|
page = int(request.args.get('page', 1))
|
||||||
per_page = 10
|
per_page = 10
|
||||||
|
|
||||||
# Get projects with pagination
|
try:
|
||||||
projects = await Project.get_all(published_only=False, limit=per_page, offset=(page-1)*per_page)
|
# Get projects with pagination
|
||||||
total_projects = await Project.count(published_only=False)
|
projects = await Project.get_all(published_only=False, limit=per_page, offset=(page-1)*per_page)
|
||||||
|
total_projects = await Project.count(published_only=False)
|
||||||
pagination = calculate_pagination(total_projects, page, per_page)
|
|
||||||
|
pagination = calculate_pagination(total_projects, page, per_page)
|
||||||
return await render_template('dashboard/projects.html',
|
|
||||||
projects=projects,
|
return await render_template('dashboard/projects.html',
|
||||||
pagination=pagination)
|
projects=projects,
|
||||||
|
pagination=pagination)
|
||||||
|
except Exception as e:
|
||||||
|
flash_message(f'Errore nel caricamento dei progetti: {str(e)}', 'error')
|
||||||
|
return redirect(url_for('dashboard.index'))
|
||||||
|
|
||||||
@dashboard_bp.route('/projects/new', methods=['GET', 'POST'])
|
@dashboard_bp.route('/projects/new', methods=['GET', 'POST'])
|
||||||
@admin_required
|
@admin_required
|
||||||
async def new_project():
|
async def new_project():
|
||||||
"""Create new project"""
|
"""Create new project"""
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
categories = await Category.get_all()
|
try:
|
||||||
return await render_template('dashboard/project_form.html',
|
categories = await Category.get_all()
|
||||||
project=None,
|
return await render_template('dashboard/project_form.html',
|
||||||
categories=categories,
|
project=None,
|
||||||
action='create')
|
categories=categories,
|
||||||
|
action='create')
|
||||||
|
except Exception as e:
|
||||||
|
flash_message(f'Errore nel caricamento delle categorie: {str(e)}', 'error')
|
||||||
|
return redirect(url_for('dashboard.projects'))
|
||||||
|
|
||||||
form_data = await request.form
|
form_data = await request.form
|
||||||
data = {
|
data = {
|
||||||
@@ -208,11 +304,15 @@ async def users():
|
|||||||
page = int(request.args.get('page', 1))
|
page = int(request.args.get('page', 1))
|
||||||
per_page = 10
|
per_page = 10
|
||||||
|
|
||||||
users = await User.get_all(limit=per_page, offset=(page-1)*per_page)
|
try:
|
||||||
total_users = await User.count()
|
users = await User.get_all(limit=per_page, offset=(page-1)*per_page)
|
||||||
|
total_users = await User.count()
|
||||||
pagination = calculate_pagination(total_users, page, per_page)
|
|
||||||
|
pagination = calculate_pagination(total_users, page, per_page)
|
||||||
return await render_template('dashboard/users.html',
|
|
||||||
users=users,
|
return await render_template('dashboard/users.html',
|
||||||
pagination=pagination)
|
users=users,
|
||||||
|
pagination=pagination)
|
||||||
|
except Exception as e:
|
||||||
|
flash_message(f'Errore nel caricamento degli utenti: {str(e)}', 'error')
|
||||||
|
return redirect(url_for('dashboard.index'))
|
||||||
157
templates/dashboard/users.html
Normal file
157
templates/dashboard/users.html
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
{% extends "dashboard/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Gestione Utenti - Dashboard{% endblock %}
|
||||||
|
|
||||||
|
{% block dashboard_content %}
|
||||||
|
<div class="dashboard-header">
|
||||||
|
<h1 class="dashboard-title">
|
||||||
|
<i class="fas fa-users"></i>
|
||||||
|
Gestione Utenti
|
||||||
|
</h1>
|
||||||
|
<div class="dashboard-actions">
|
||||||
|
<span class="badge badge-info">{{ pagination.total_items if pagination else 0 }} utenti totali</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dashboard-content">
|
||||||
|
{% if users %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Nome Completo</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Ruolo</th>
|
||||||
|
<th>Stato</th>
|
||||||
|
<th>Registrato</th>
|
||||||
|
<th>Ultimo Accesso</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for user in users %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ user.id }}</td>
|
||||||
|
<td>
|
||||||
|
<strong>{{ user.username }}</strong>
|
||||||
|
{% if user.is_admin %}
|
||||||
|
<span class="badge badge-danger ms-1">Admin</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ user.full_name or '-' }}</td>
|
||||||
|
<td>{{ user.email }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge {% if user.role == 'admin' %}badge-danger{% else %}badge-secondary{% endif %}">
|
||||||
|
{{ user.role.title() }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge {% if user.is_active %}badge-success{% else %}badge-warning{% endif %}">
|
||||||
|
{% if user.is_active %}Attivo{% else %}Inattivo{% endif %}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if user.created_at %}
|
||||||
|
<small>{{ user.created_at.strftime('%d/%m/%Y %H:%M') }}</small>
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if user.last_login %}
|
||||||
|
<small>{{ user.last_login.strftime('%d/%m/%Y %H:%M') }}</small>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">Mai</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
{% if pagination and pagination.total_pages > 1 %}
|
||||||
|
<nav aria-label="User pagination" class="mt-4">
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
{% if pagination.has_prev %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="{{ url_for('dashboard.users', page=pagination.prev_num) }}">
|
||||||
|
<i class="fas fa-chevron-left"></i> Precedente
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for page_num in pagination.iter_pages() %}
|
||||||
|
{% if page_num %}
|
||||||
|
{% if page_num != pagination.page %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="{{ url_for('dashboard.users', page=page_num) }}">{{ page_num }}</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item active">
|
||||||
|
<span class="page-link">{{ page_num }}</span>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<span class="page-link">…</span>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if pagination.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="{{ url_for('dashboard.users', page=pagination.next_num) }}">
|
||||||
|
Successivo <i class="fas fa-chevron-right"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info text-center">
|
||||||
|
<i class="fas fa-info-circle fa-2x mb-3"></i>
|
||||||
|
<h4>Nessun utente trovato</h4>
|
||||||
|
<p class="mb-0">Non ci sono utenti registrati nel sistema.</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.dashboard-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 2px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-title {
|
||||||
|
color: #495057;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-title i {
|
||||||
|
color: #6c757d;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th {
|
||||||
|
font-weight: 600;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert i {
|
||||||
|
color: #0dcaf0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
147
utils/create_admin.py
Normal file
147
utils/create_admin.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Utility script to create an admin user
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Add the parent directory to Python path to import our modules
|
||||||
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
from models.database import init_database
|
||||||
|
from models.user import User
|
||||||
|
|
||||||
|
async def create_admin_user():
|
||||||
|
"""Create an admin user for dashboard access"""
|
||||||
|
try:
|
||||||
|
# Initialize database
|
||||||
|
await init_database()
|
||||||
|
print("✅ Database connection established")
|
||||||
|
|
||||||
|
# Check if admin user already exists
|
||||||
|
existing_admin = await User.find_by_username('admin')
|
||||||
|
if existing_admin:
|
||||||
|
print("⚠️ Admin user already exists!")
|
||||||
|
print(f" Username: {existing_admin.username}")
|
||||||
|
print(f" Email: {existing_admin.email}")
|
||||||
|
print(f" Role: {existing_admin.role}")
|
||||||
|
print(f" Is Admin: {existing_admin.is_admin}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create admin user
|
||||||
|
admin_user = User(
|
||||||
|
username='admin',
|
||||||
|
email='admin@hersel.it',
|
||||||
|
first_name='Admin',
|
||||||
|
last_name='User',
|
||||||
|
role='admin'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set password (change this to a secure password)
|
||||||
|
admin_password = 'admin123' # CHANGE THIS IN PRODUCTION!
|
||||||
|
admin_user.set_password(admin_password)
|
||||||
|
|
||||||
|
# Save user
|
||||||
|
await admin_user.save()
|
||||||
|
|
||||||
|
print("🎉 Admin user created successfully!")
|
||||||
|
print("📝 Login credentials:")
|
||||||
|
print(f" Username: {admin_user.username}")
|
||||||
|
print(f" Email: {admin_user.email}")
|
||||||
|
print(f" Password: {admin_password}")
|
||||||
|
print(f" Role: {admin_user.role}")
|
||||||
|
print(f" Is Admin: {admin_user.is_admin}")
|
||||||
|
print("")
|
||||||
|
print("🔐 IMPORTANT: Change the default password after first login!")
|
||||||
|
print("📍 You can now access the dashboard at: /dashboard/")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error creating admin user: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
async def list_users():
|
||||||
|
"""List all users in the system"""
|
||||||
|
try:
|
||||||
|
await init_database()
|
||||||
|
users = await User.get_all()
|
||||||
|
|
||||||
|
if not users:
|
||||||
|
print("No users found in the system.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\n👥 Users in the system:")
|
||||||
|
print("-" * 80)
|
||||||
|
print(f"{'ID':<5} {'Username':<15} {'Email':<25} {'Role':<10} {'Admin':<7} {'Active':<8}")
|
||||||
|
print("-" * 80)
|
||||||
|
|
||||||
|
for user in users:
|
||||||
|
print(f"{user.id:<5} {user.username:<15} {user.email:<25} {user.role:<10} {user.is_admin:<7} {user.is_active:<8}")
|
||||||
|
|
||||||
|
print("-" * 80)
|
||||||
|
print(f"Total users: {len(users)}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error listing users: {e}")
|
||||||
|
|
||||||
|
async def promote_user_to_admin(username):
|
||||||
|
"""Promote an existing user to admin"""
|
||||||
|
try:
|
||||||
|
await init_database()
|
||||||
|
user = await User.find_by_username(username)
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
print(f"❌ User '{username}' not found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update user role
|
||||||
|
user.role = 'admin'
|
||||||
|
await user.save()
|
||||||
|
|
||||||
|
print(f"✅ User '{username}' promoted to admin successfully!")
|
||||||
|
print(f" Username: {user.username}")
|
||||||
|
print(f" Email: {user.email}")
|
||||||
|
print(f" Role: {user.role}")
|
||||||
|
print(f" Is Admin: {user.is_admin}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error promoting user: {e}")
|
||||||
|
|
||||||
|
def print_usage():
|
||||||
|
"""Print usage instructions"""
|
||||||
|
print("Usage:")
|
||||||
|
print(" python utils/create_admin.py create # Create default admin user")
|
||||||
|
print(" python utils/create_admin.py list # List all users")
|
||||||
|
print(" python utils/create_admin.py promote <username> # Promote user to admin")
|
||||||
|
print("")
|
||||||
|
print("Examples:")
|
||||||
|
print(" python utils/create_admin.py create")
|
||||||
|
print(" python utils/create_admin.py promote john_doe")
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
"""Main function"""
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print_usage()
|
||||||
|
return
|
||||||
|
|
||||||
|
command = sys.argv[1].lower()
|
||||||
|
|
||||||
|
if command == 'create':
|
||||||
|
await create_admin_user()
|
||||||
|
elif command == 'list':
|
||||||
|
await list_users()
|
||||||
|
elif command == 'promote':
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print("❌ Please provide a username to promote.")
|
||||||
|
print(" Usage: python utils/create_admin.py promote <username>")
|
||||||
|
return
|
||||||
|
username = sys.argv[2]
|
||||||
|
await promote_user_to_admin(username)
|
||||||
|
else:
|
||||||
|
print(f"❌ Unknown command: {command}")
|
||||||
|
print_usage()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
||||||
Reference in New Issue
Block a user