Migrate from Quart to Flask and add MariaDB dynamic database
Major Changes: - Migrated web framework from Quart (async) to Flask (sync) - Added MariaDB database integration with SQLAlchemy ORM - Implemented dynamic content management for portfolio New Features: - Database models for Profile, Skills, Projects, ProjectTags, and SocialLinks - RESTful API endpoints for CRUD operations on all entities - Database initialization script (init_db.py) with sample data - Docker Compose configuration with MariaDB service Modified Files: - app.py: Replaced Quart with Flask, added database initialization - config.py: Added database configuration with environment variables - routes/home.py: Converted async to sync, added database queries - requirements.txt: Replaced Quart/Hypercorn with Flask/Gunicorn, added Flask-SQLAlchemy and PyMySQL - docker-compose.yml: Added MariaDB service with health checks - templates/: Updated all templates to use dynamic data from database with Jinja2 - .env.example: Added database configuration variables - README.md: Complete rewrite with new setup instructions and API documentation New Files: - models.py: SQLAlchemy models for all database entities - init_db.py: Database initialization script - routes/api.py: REST API endpoints for content management Benefits: - Simplified architecture (sync vs async) - Better ecosystem compatibility - Dynamic content management via database - Easy content updates through REST API - Improved deployment with standard WSGI server (Gunicorn)
This commit is contained in:
@@ -3,52 +3,77 @@
|
||||
<h2 class="text-center section-title animate__animated animate__fadeIn">Chi Sono</h2>
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 animate__animated animate__fadeInLeft">
|
||||
{% if profile %}
|
||||
<h3 class="mb-4">{{ profile.title }}</h3>
|
||||
<p class="lead">{{ profile.lead_text }}</p>
|
||||
{% if profile.description_1 %}
|
||||
<p>{{ profile.description_1 }}</p>
|
||||
{% endif %}
|
||||
{% if profile.description_2 %}
|
||||
<p>{{ profile.description_2 }}</p>
|
||||
{% endif %}
|
||||
<div class="mt-4">
|
||||
{% if profile.cv_url %}
|
||||
<a href="{{ profile.cv_url }}" class="btn btn-primary me-2">Scarica CV</a>
|
||||
{% endif %}
|
||||
<a href="#links" class="btn btn-outline-secondary">I Miei Profili</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<h3 class="mb-4">Il ponte tra sistemi e sviluppo web</h3>
|
||||
<p class="lead">Con oltre 7 Anni di esperienza nello sviluppo di applicazioni web con Python Flask, offro soluzioni complete end-to-end.</p>
|
||||
<p>La mia doppia specializzazione mi permette di comprendere a fondo l'intero ciclo di vita delle applicazioni, dall'architettura del server fino all'implementazione e al deployment.</p>
|
||||
<p>Mi piace risolvere problemi complessi e creare soluzioni che siano robuste, scalabili e facili da mantenere.</p>
|
||||
<div class="mt-4">
|
||||
<!--<a href="#" class="btn btn-primary me-2">Scarica CV</a>-->
|
||||
<a href="#links" class="btn btn-outline-secondary">I Miei Profili</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-lg-6 animate__animated animate__fadeInRight">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body p-4">
|
||||
<h4 class="mb-4 text-primary">Tecnologie che utilizzo</h4>
|
||||
<div class="d-flex flex-wrap justify-content-center">
|
||||
<div class="text-center m-3">
|
||||
<i class="fab fa-linux tech-icon"></i>
|
||||
<p>Linux</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fab fa-windows tech-icon"></i>
|
||||
<p>Windows</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fab fa-python tech-icon"></i>
|
||||
<p>Python</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fas fa-flask tech-icon"></i>
|
||||
<p>Flask</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fas fa-database tech-icon"></i>
|
||||
<p>Database</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fab fa-docker tech-icon"></i>
|
||||
<p>Docker</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fas fa-server tech-icon"></i>
|
||||
<p>Server</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fas fa-network-wired tech-icon"></i>
|
||||
<p>Networking</p>
|
||||
</div>
|
||||
{% if skills %}
|
||||
{% for skill in skills %}
|
||||
<div class="text-center m-3">
|
||||
<i class="{{ skill.icon_class }} tech-icon"></i>
|
||||
<p>{{ skill.name }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="text-center m-3">
|
||||
<i class="fab fa-linux tech-icon"></i>
|
||||
<p>Linux</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fab fa-windows tech-icon"></i>
|
||||
<p>Windows</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fab fa-python tech-icon"></i>
|
||||
<p>Python</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fas fa-flask tech-icon"></i>
|
||||
<p>Flask</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fas fa-database tech-icon"></i>
|
||||
<p>Database</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fab fa-docker tech-icon"></i>
|
||||
<p>Docker</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fas fa-server tech-icon"></i>
|
||||
<p>Server</p>
|
||||
</div>
|
||||
<div class="text-center m-3">
|
||||
<i class="fas fa-network-wired tech-icon"></i>
|
||||
<p>Networking</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,42 +6,53 @@
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body p-5">
|
||||
<div class="d-flex flex-wrap justify-content-center mb-4">
|
||||
<a href="https://linkedin.com/in/hersel" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.1s">
|
||||
<div class="text-center">
|
||||
<i class="fab fa-linkedin social-icon"></i>
|
||||
<p class="mt-2 fs-5">LinkedIn</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://github.com/blulupo" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.2s">
|
||||
<div class="text-center">
|
||||
<i class="fab fa-github social-icon"></i>
|
||||
<p class="mt-2 fs-5">GitHub</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://stackoverflow.com/users/11765177/hersel-giannella" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.3s">
|
||||
<div class="text-center">
|
||||
<i class="fab fa-stack-overflow social-icon"></i>
|
||||
<p class="mt-2 fs-5">Stack Overflow</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://www.codewars.com/users/BluLupo" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.4s">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-code social-icon"></i>
|
||||
<p class="mt-2 fs-5">CodeWars</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://blog.hersel.it" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.5s">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-blog social-icon"></i>
|
||||
<p class="mt-2 fs-5">Blog</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="mailto:info@hersel.it" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.6s">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-envelope social-icon"></i>
|
||||
<p class="mt-2 fs-5">Email</p>
|
||||
</div>
|
||||
</a>
|
||||
{% if social_links %}
|
||||
{% for link in social_links %}
|
||||
<a href="{{ link.url }}" class="m-3 text-decoration-none animate__animated animate__bounceIn" {% if link.animation_delay != '0s' %}style="animation-delay: {{ link.animation_delay }}"{% endif %}>
|
||||
<div class="text-center">
|
||||
<i class="{{ link.icon_class }} social-icon"></i>
|
||||
<p class="mt-2 fs-5">{{ link.platform_name }}</p>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<a href="https://linkedin.com/in/hersel" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.1s">
|
||||
<div class="text-center">
|
||||
<i class="fab fa-linkedin social-icon"></i>
|
||||
<p class="mt-2 fs-5">LinkedIn</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://github.com/blulupo" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.2s">
|
||||
<div class="text-center">
|
||||
<i class="fab fa-github social-icon"></i>
|
||||
<p class="mt-2 fs-5">GitHub</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://stackoverflow.com/users/11765177/hersel-giannella" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.3s">
|
||||
<div class="text-center">
|
||||
<i class="fab fa-stack-overflow social-icon"></i>
|
||||
<p class="mt-2 fs-5">Stack Overflow</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://www.codewars.com/users/BluLupo" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.4s">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-code social-icon"></i>
|
||||
<p class="mt-2 fs-5">CodeWars</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://blog.hersel.it" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.5s">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-blog social-icon"></i>
|
||||
<p class="mt-2 fs-5">Blog</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="mailto:info@hersel.it" class="m-3 text-decoration-none animate__animated animate__bounceIn" style="animation-delay: 0.6s">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-envelope social-icon"></i>
|
||||
<p class="mt-2 fs-5">Email</p>
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="lead mt-4">Scopri di più sul mio lavoro e segui i miei progetti attraverso questi canali</p>
|
||||
</div>
|
||||
|
||||
@@ -2,68 +2,95 @@
|
||||
<div class="container">
|
||||
<h2 class="text-center section-title animate__animated animate__fadeIn">I Miei Progetti</h2>
|
||||
<div class="row">
|
||||
<!-- Progetto 1 -->
|
||||
<div class="col-lg-4 col-md-6 mb-4 animate__animated animate__fadeInUp">
|
||||
<div class="card project-card shadow-sm">
|
||||
<img src="{{ url_for('static', filename='img/bash.webp')}}" class="card-img-top" alt="Progetto 1">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Script di Backup Database (MariaDB/MySQL)</h5>
|
||||
<p class="card-text">Script in Bash per sistemi Linux che permette l'automazione dei backup database</p>
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<div>
|
||||
<span class="badge bg-primary me-1">Bash</span>
|
||||
<span class="badge bg-info me-1">Linux</span>
|
||||
{% if projects %}
|
||||
{% for project in projects %}
|
||||
<!-- {{ project.title }} -->
|
||||
<div class="col-lg-4 col-md-6 mb-4 animate__animated animate__fadeInUp" {% if project.animation_delay != '0s' %}style="animation-delay: {{ project.animation_delay }}"{% endif %}>
|
||||
<div class="card project-card shadow-sm">
|
||||
{% if project.image_url %}
|
||||
<img src="{{ url_for('static', filename=project.image_url) }}" class="card-img-top" alt="{{ project.title }}">
|
||||
{% endif %}
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ project.title }}</h5>
|
||||
<p class="card-text">{{ project.description }}</p>
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<div>
|
||||
{% for tag in project.tags|sort(attribute='display_order') %}
|
||||
<span class="badge {{ tag.color_class }} me-1">{{ tag.name }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if project.github_url or project.demo_url %}
|
||||
<a href="{{ project.demo_url if project.demo_url else project.github_url }}" class="btn btn-sm btn-outline-primary">Dettagli</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<!-- Progetto 1 -->
|
||||
<div class="col-lg-4 col-md-6 mb-4 animate__animated animate__fadeInUp">
|
||||
<div class="card project-card shadow-sm">
|
||||
<img src="{{ url_for('static', filename='img/bash.webp')}}" class="card-img-top" alt="Progetto 1">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Script di Backup Database (MariaDB/MySQL)</h5>
|
||||
<p class="card-text">Script in Bash per sistemi Linux che permette l'automazione dei backup database</p>
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<div>
|
||||
<span class="badge bg-primary me-1">Bash</span>
|
||||
<span class="badge bg-info me-1">Linux</span>
|
||||
</div>
|
||||
<a href="https://github.com/BluLupo/server-script/tree/main/db_bash_backup-main" class="btn btn-sm btn-outline-primary">Dettagli</a>
|
||||
</div>
|
||||
<a href="https://github.com/BluLupo/server-script/tree/main/db_bash_backup-main" class="btn btn-sm btn-outline-primary">Dettagli</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progetto 2 -->
|
||||
<div class="col-lg-4 col-md-6 mb-4 animate__animated animate__fadeInUp" style="animation-delay: 0.2s">
|
||||
<div class="card project-card shadow-sm">
|
||||
<img src="{{ url_for('static', filename='img/byte.webp')}}" class="card-img-top" alt="Progetto 2">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Personal ByteStash</h5>
|
||||
<p class="card-text">Ho realizzato un repository personale di snippet sfruttando Bytestash, ottimizzando la gestione del codice riutilizzabile e migliorando la produttività nello sviluppo di progetti software.</p>
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<div>
|
||||
<span class="badge bg-warning text-dark me-1">LXC</span>
|
||||
<span class="badge bg-dark me-1">Proxmox</span>
|
||||
<span class="badge bg-info me-1">Nginx</span>
|
||||
<span class="badge bg-secondary me-1">Reverse Proxy</span>
|
||||
<span class="badge bg-primary me-1">Linux</span>
|
||||
<span class="badge bg-primary me-1">Self-hosted</span>
|
||||
<!-- Progetto 2 -->
|
||||
<div class="col-lg-4 col-md-6 mb-4 animate__animated animate__fadeInUp" style="animation-delay: 0.2s">
|
||||
<div class="card project-card shadow-sm">
|
||||
<img src="{{ url_for('static', filename='img/byte.webp')}}" class="card-img-top" alt="Progetto 2">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Personal ByteStash</h5>
|
||||
<p class="card-text">Ho realizzato un repository personale di snippet sfruttando Bytestash, ottimizzando la gestione del codice riutilizzabile e migliorando la produttività nello sviluppo di progetti software.</p>
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<div>
|
||||
<span class="badge bg-warning text-dark me-1">LXC</span>
|
||||
<span class="badge bg-dark me-1">Proxmox</span>
|
||||
<span class="badge bg-info me-1">Nginx</span>
|
||||
<span class="badge bg-secondary me-1">Reverse Proxy</span>
|
||||
<span class="badge bg-primary me-1">Linux</span>
|
||||
<span class="badge bg-primary me-1">Self-hosted</span>
|
||||
</div>
|
||||
<a href="https://bytestash.gwserver.it/public/snippets" class="btn btn-sm btn-outline-primary">Dettagli</a>
|
||||
</div>
|
||||
<a href="https://bytestash.gwserver.it/public/snippets" class="btn btn-sm btn-outline-primary">Dettagli</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progetto 3 -->
|
||||
<div class="col-lg-4 col-md-6 mb-4 animate__animated animate__fadeInUp" style="animation-delay: 0.4s">
|
||||
<div class="card project-card shadow-sm">
|
||||
<img src="{{ url_for('static', filename='img/next.webp')}}" class="card-img-top" alt="Nextcloud Personale">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Nextcloud Personale</h5>
|
||||
<p class="card-text">Installazione di Nextcloud su container LXC con database PostgreSQL e caching Redis, integrato in una rete privata con gestione IP tramite server DHCP.</p>
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<div>
|
||||
<span class="badge bg-primary me-1">Nextcloud</span>
|
||||
<span class="badge bg-secondary me-1">PostgreSQL</span>
|
||||
<span class="badge bg-info me-1">Redis</span>
|
||||
<span class="badge bg-warning text-dark me-1">LXC</span>
|
||||
<span class="badge bg-dark me-1">Proxmox</span>
|
||||
<span class="badge bg-success me-1">Rete Privata</span>
|
||||
<span class="badge bg-secondary me-1">DHCP Server</span>
|
||||
<!-- Progetto 3 -->
|
||||
<div class="col-lg-4 col-md-6 mb-4 animate__animated animate__fadeInUp" style="animation-delay: 0.4s">
|
||||
<div class="card project-card shadow-sm">
|
||||
<img src="{{ url_for('static', filename='img/next.webp')}}" class="card-img-top" alt="Nextcloud Personale">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Nextcloud Personale</h5>
|
||||
<p class="card-text">Installazione di Nextcloud su container LXC con database PostgreSQL e caching Redis, integrato in una rete privata con gestione IP tramite server DHCP.</p>
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<div>
|
||||
<span class="badge bg-primary me-1">Nextcloud</span>
|
||||
<span class="badge bg-secondary me-1">PostgreSQL</span>
|
||||
<span class="badge bg-info me-1">Redis</span>
|
||||
<span class="badge bg-warning text-dark me-1">LXC</span>
|
||||
<span class="badge bg-dark me-1">Proxmox</span>
|
||||
<span class="badge bg-success me-1">Rete Privata</span>
|
||||
<span class="badge bg-secondary me-1">DHCP Server</span>
|
||||
</div>
|
||||
<a href="https://cloud.gwserver.it" class="btn btn-sm btn-outline-primary">Dettagli</a>
|
||||
</div>
|
||||
<a href="https://cloud.gwserver.it" class="btn btn-sm btn-outline-primary">Dettagli</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!--
|
||||
|
||||
|
||||
Reference in New Issue
Block a user