Initial commit: Diario Conversazioni Olimpic Nastri

- Django 5.2 + PostgreSQL + Gunicorn
- Conversazioni, Obiettivi, Documenti PDF, Persone
- Commenti e aggiornamenti con modifica/eliminazione
- Agenda, ricerca live, giorni rimanenti scadenze
- Bootstrap 5 + HTMX + toast notifications
- Deploy: Nginx + Gunicorn + SSL
This commit is contained in:
automationkriz
2026-04-05 14:48:22 +00:00
commit d296353dcb
48 changed files with 3538 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
{% extends "diario/base.html" %}
{% block title %}{{ conv.titolo }}{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="d-flex align-items-center mb-4 gap-3 fade-in">
<a href="{% url 'conversazioni_lista' %}" class="btn btn-icon btn-outline-secondary">
<i class="bi bi-arrow-left" style="font-size:.85rem;"></i>
</a>
<h5 class="mb-0 fw-bold flex-grow-1">{{ conv.titolo }}</h5>
{% if can_edit %}
<a href="{% url 'conversazione_modifica' conv.pk %}" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-pencil me-1"></i>Modifica
</a>
<a href="{% url 'conversazione_elimina' conv.pk %}" class="btn btn-sm btn-outline-danger">
<i class="bi bi-trash me-1"></i>Elimina
</a>
{% endif %}
</div>
<div class="card p-4 mb-4 fade-in">
<div class="d-flex align-items-center gap-3 mb-4">
<span class="avatar">{{ conv.registrato_da.username|slice:":2"|upper }}</span>
<div>
<div class="fw-semibold small">{{ conv.registrato_da.get_full_name|default:conv.registrato_da.username }}</div>
<small class="text-muted">{{ conv.data|date:"d/m/Y \a\l\l\e H:i" }}</small>
</div>
</div>
<div style="white-space:pre-wrap;line-height:1.8;font-size:.93rem;">{{ conv.contenuto }}</div>
{% if conv.partecipanti.all %}
<hr class="soft mt-4 mb-3">
<div>
<small class="text-muted fw-semibold d-block mb-2">Partecipanti</small>
<div class="d-flex flex-wrap gap-2">
{% for p in conv.partecipanti.all %}
<div class="d-flex align-items-center gap-1 px-2 py-1 rounded-pill" style="background:#f0f2f5; font-size:.8rem;">
<span class="avatar" style="width:20px;height:20px;font-size:.55rem;">{{ p.username|slice:":2"|upper }}</span>
{{ p.get_full_name|default:p.username }}
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
<!-- Documenti allegati -->
<div class="d-flex justify-content-between align-items-center mb-3 fade-in">
<p class="section-title mb-0"><i class="bi bi-paperclip me-1"></i>Allegati ({{ documenti|length }})</p>
<a href="{% url 'documento_nuovo' %}?conversazione={{ conv.pk }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-upload me-1"></i>Allega PDF
</a>
</div>
{% for doc in documenti %}
<div class="card mb-2 p-3 fade-in">
<div class="d-flex align-items-center gap-3">
<i class="bi bi-file-earmark-pdf" style="font-size:1.5rem;color:#dc3545;"></i>
<div class="flex-grow-1">
<a href="{% url 'documento_dettaglio' doc.pk %}" class="text-decoration-none text-dark fw-semibold small d-block">
{{ doc.titolo }}
</a>
<small class="text-muted">{{ doc.caricato_da.get_full_name|default:doc.caricato_da.username }} · {{ doc.data_caricamento|date:"d/m/Y" }}</small>
</div>
<a href="{{ doc.file.url }}" class="btn btn-sm btn-outline-secondary" hx-boost="false" target="_blank">
<i class="bi bi-download"></i>
</a>
</div>
</div>
{% empty %}
<p class="text-muted small text-center py-2 fade-in">Nessun documento allegato.</p>
{% endfor %}
<!-- Commenti -->
<p class="section-title mt-4 fade-in"><i class="bi bi-chat-dots me-1"></i>Commenti ({{ commenti|length }})</p>
<!-- Form nuovo commento -->
<div class="card p-3 mb-4 fade-in" style="border-left: 3px solid var(--accent) !important;">
<form method="post">
{% csrf_token %}
<label class="form-label fw-semibold small mb-2">Aggiungi un commento</label>
{{ comment_form.testo }}
<button type="submit" class="btn btn-primary btn-sm mt-2 px-3">
<i class="bi bi-send me-1"></i>Pubblica
</button>
</form>
</div>
{% for c in commenti %}
<div class="card mb-2 p-3 fade-in">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex align-items-center gap-2">
<span class="avatar" style="width:28px;height:28px;font-size:.65rem;">{{ c.autore.username|slice:":2"|upper }}</span>
<span class="fw-semibold small">{{ c.autore.get_full_name|default:c.autore.username }}</span>
</div>
<div class="d-flex align-items-center gap-2">
<small class="text-muted">{{ c.data|date:"d/m/Y H:i" }}</small>
{% if user == c.autore or user.is_superuser %}
<div class="dropdown">
<button class="btn btn-icon btn-outline-secondary" style="width:24px;height:24px;" data-bs-toggle="dropdown">
<i class="bi bi-three-dots" style="font-size:.7rem;"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow border-0" style="border-radius:10px; min-width:140px;">
<li><a class="dropdown-item small" href="{% url 'commento_modifica' c.pk %}"><i class="bi bi-pencil me-2 text-muted"></i>Modifica</a></li>
<li><a class="dropdown-item small text-danger" href="{% url 'commento_elimina' c.pk %}"><i class="bi bi-trash me-2"></i>Elimina</a></li>
</ul>
</div>
{% endif %}
</div>
</div>
<p class="mb-0 mt-2 small" style="white-space:pre-wrap;line-height:1.65;padding-left:40px;">{{ c.testo }}</p>
</div>
{% empty %}
<p class="text-muted small text-center py-3">Nessun commento ancora. Sii il primo!</p>
{% endfor %}
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,57 @@
{% extends "diario/base.html" %}
{% block title %}{{ titolo_pagina }}{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="d-flex align-items-center mb-4">
<a href="{% url 'conversazioni_lista' %}" class="btn btn-sm btn-outline-secondary me-3">
<i class="bi bi-arrow-left"></i>
</a>
<h4 class="mb-0">{{ titolo_pagina }}</h4>
</div>
<div class="card p-4">
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label class="form-label fw-semibold">{{ form.titolo.label }}</label>
{{ form.titolo }}
</div>
<div class="mb-3">
<label class="form-label fw-semibold">{{ form.data.label }}</label>
{{ form.data }}
<div class="form-text">Puoi inserire una data passata per conversazioni già avvenute.</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">{{ form.contenuto.label }}</label>
{{ form.contenuto }}
</div>
<div class="mb-4">
<label class="form-label fw-semibold">{{ form.partecipanti.label }}</label>
<div class="row row-cols-2 row-cols-sm-3 g-2 mt-1">
{% for checkbox in form.partecipanti %}
<div class="col">
<div class="form-check">
{{ checkbox.tag }}
<label class="form-check-label" for="{{ checkbox.id_for_label }}">
{{ checkbox.choice_label }}
</label>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Salva</button>
{% if conv %}
<a href="{% url 'conversazione_dettaglio' conv.pk %}" class="btn btn-outline-secondary">Annulla</a>
{% else %}
<a href="{% url 'conversazioni_lista' %}" class="btn btn-outline-secondary">Annulla</a>
{% endif %}
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,44 @@
{% extends "diario/base.html" %}
{% block title %}Conversazioni{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4 fade-in">
<p class="section-title mb-0">Cronologia conversazioni</p>
<a href="{% url 'conversazione_nuova' %}" class="btn btn-primary btn-sm px-3">
<i class="bi bi-plus-lg me-1"></i>Nuova conversazione
</a>
</div>
{% for conv in conversazioni %}
<div class="card mb-3 p-3 fade-in">
<div class="d-flex justify-content-between align-items-start gap-3">
<div class="flex-grow-1">
<a href="{% url 'conversazione_dettaglio' conv.pk %}" class="text-decoration-none text-dark fw-semibold d-block mb-1">
{{ conv.titolo }}
</a>
<div class="d-flex align-items-center gap-3 flex-wrap">
<small class="text-muted"><i class="bi bi-calendar3 me-1"></i>{{ conv.data|date:"d/m/Y H:i" }}</small>
<div class="d-flex align-items-center gap-1">
<span class="avatar" style="width:20px;height:20px;font-size:.58rem;">{{ conv.registrato_da.username|slice:":2"|upper }}</span>
<small class="text-muted">{{ conv.registrato_da.get_full_name|default:conv.registrato_da.username }}</small>
</div>
{% if conv.partecipanti.count > 0 %}
<small class="text-muted"><i class="bi bi-people me-1"></i>{{ conv.partecipanti.count }}</small>
{% endif %}
</div>
<p class="mb-0 text-muted small mt-2">{{ conv.contenuto|truncatewords:30 }}</p>
</div>
{% if user == conv.registrato_da or user.is_superuser %}
<a href="{% url 'conversazione_modifica' conv.pk %}" class="btn btn-icon btn-outline-secondary flex-shrink-0">
<i class="bi bi-pencil" style="font-size:.75rem;"></i>
</a>
{% endif %}
</div>
</div>
{% empty %}
<div class="empty-state">
<i class="bi bi-chat-square-dots"></i>
<p>Nessuna conversazione registrata.</p>
</div>
{% endfor %}
{% endblock %}