Files
hersel.it/templates/admin/project_form.html
Claude aa2c704bfb Add authentication system and admin dashboard
Security Features:
- Added User model with bcrypt password hashing
- Implemented Flask-Login for session management
- Protected all API write operations with @login_required decorator
- Added authentication routes (login/logout)

Admin Dashboard:
- Created comprehensive admin dashboard with statistics
- Profile management interface
- Skills management (add/edit/delete)
- Projects management with full CRUD operations
- Social links management
- Modern responsive UI with Bootstrap 5

New Files:
- models.py: Added User model with bcrypt
- routes/auth.py: Login/logout functionality
- routes/admin.py: Complete admin dashboard with CRUD operations
- templates/auth/login.html: Login page
- templates/admin/base.html: Admin base template
- templates/admin/dashboard.html: Main dashboard
- templates/admin/profile.html: Profile editor
- templates/admin/skills.html: Skills manager
- templates/admin/projects.html: Projects list
- templates/admin/project_form.html: Project editor
- templates/admin/social_links.html: Social links manager

Modified Files:
- app.py: Integrated Flask-Login and bcrypt, registered new blueprints
- requirements.txt: Added Flask-Login, Flask-Bcrypt, bcrypt
- init_db.py: Creates default admin user (admin/admin123)
- routes/api.py: Protected all write operations with authentication

Default Credentials:
- Username: admin
- Password: admin123
- ⚠️ MUST be changed after first login!

Benefits:
- Secure API access with session-based authentication
- User-friendly admin interface for content management
- No need to edit code or database directly
- Bcrypt password hashing for security
- Protected against unauthorized access
2025-11-13 13:49:36 +00:00

84 lines
4.1 KiB
HTML

{% extends "admin/base.html" %}
{% block title %}{{ 'Modifica' if project else 'Nuovo' }} Progetto{% endblock %}
{% block page_title %}{{ 'Modifica' if project else 'Nuovo' }} Progetto{% endblock %}
{% block content %}
<div class="card">
<div class="card-body">
<form method="POST">
<div class="mb-3">
<label for="title" class="form-label">Titolo *</label>
<input type="text" class="form-control" id="title" name="title"
value="{{ project.title if project else '' }}" required>
</div>
<div class="mb-3">
<label for="description" class="form-label">Descrizione *</label>
<textarea class="form-control" id="description" name="description" rows="4" required>{{ project.description if project else '' }}</textarea>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="image_url" class="form-label">URL Immagine</label>
<input type="text" class="form-control" id="image_url" name="image_url"
value="{{ project.image_url if project else '' }}" placeholder="img/project.webp">
<small class="text-muted">Percorso relativo alla cartella static/</small>
</div>
<div class="col-md-6 mb-3">
<label for="github_url" class="form-label">URL GitHub</label>
<input type="url" class="form-control" id="github_url" name="github_url"
value="{{ project.github_url if project else '' }}">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="demo_url" class="form-label">URL Demo</label>
<input type="url" class="form-control" id="demo_url" name="demo_url"
value="{{ project.demo_url if project else '' }}">
</div>
<div class="col-md-3 mb-3">
<label for="display_order" class="form-label">Ordine Visualizzazione</label>
<input type="number" class="form-control" id="display_order" name="display_order"
value="{{ project.display_order if project else 0 }}">
</div>
<div class="col-md-3 mb-3">
<label for="animation_delay" class="form-label">Delay Animazione</label>
<input type="text" class="form-control" id="animation_delay" name="animation_delay"
value="{{ project.animation_delay if project else '0s' }}" placeholder="0.2s">
</div>
</div>
<div class="mb-3">
<label for="tags" class="form-label">Tags (separati da virgola)</label>
<input type="text" class="form-control" id="tags" name="tags"
value="{% if project %}{% for tag in project.tags|sort(attribute='display_order') %}{{ tag.name }}:{{ tag.color_class }}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}"
placeholder="Python:bg-primary, Flask:bg-info, Docker:bg-success">
<small class="text-muted">Formato: Nome:colore, Nome:colore (es: Python:bg-primary, Flask:bg-info)</small>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="is_published" name="is_published"
{% if not project or project.is_published %}checked{% endif %}>
<label class="form-check-label" for="is_published">
Pubblica il progetto
</label>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-gradient">
<i class="fas fa-save me-2"></i>Salva
</button>
<a href="{{ url_for('admin.projects_manage') }}" class="btn btn-outline-secondary">
<i class="fas fa-times me-2"></i>Annulla
</a>
</div>
</form>
</div>
</div>
{% endblock %}