Files
diario_coversazioni/diario/models.py
automationkriz 09f51b1227 Tag progetto, @menzioni, appuntamenti da conversazioni
- Modello Tag con nome e colore, M2M su Conversazione
- Modello Appuntamento con luogo, note, partecipanti, link a Conversazione
- @menzioni nei commenti e aggiornamenti: @username → link al profilo
- Autocomplete JS per @menzioni nelle textarea
- Auto-data conversazioni (default=now)
- CRUD completo appuntamenti con permessi autore
- Appuntamenti in agenda, dashboard, dettaglio conversazione
- Crea riunione direttamente da una conversazione (pre-compila titolo e partecipanti)
- Admin: Tag, Appuntamento registrati
2026-04-07 14:28:47 +00:00

181 lines
6.0 KiB
Python

from django.db import models
from django.contrib.auth.models import User
from django.core.validators import FileExtensionValidator
from django.utils import timezone
def validate_file_size(value):
limit = 10 * 1024 * 1024 # 10 MB
if value.size > limit:
from django.core.exceptions import ValidationError
raise ValidationError('Il file non può superare i 10 MB.')
class Tag(models.Model):
nome = models.CharField(max_length=50, unique=True)
colore = models.CharField(max_length=7, default='#4361ee') # colore hex
class Meta:
ordering = ['nome']
verbose_name = 'Tag'
verbose_name_plural = 'Tag'
def __str__(self):
return self.nome
class Conversazione(models.Model):
titolo = models.CharField(max_length=200)
data = models.DateTimeField(default=timezone.now)
partecipanti = models.ManyToManyField(User, related_name='conversazioni_partecipate', blank=True)
contenuto = models.TextField()
registrato_da = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, related_name='conversazioni_registrate'
)
tags = models.ManyToManyField(Tag, blank=True, related_name='conversazioni')
class Meta:
ordering = ['-data']
verbose_name = 'Conversazione'
verbose_name_plural = 'Conversazioni'
def __str__(self):
return f"{self.titolo} ({self.data.strftime('%d/%m/%Y')})"
class Obiettivo(models.Model):
TIPO_CHOICES = [
('collettivo', 'Collettivo'),
('individuale', 'Individuale'),
]
STATO_CHOICES = [
('aperto', 'Aperto'),
('in_corso', 'In corso'),
('completato', 'Completato'),
('sospeso', 'Sospeso'),
]
titolo = models.CharField(max_length=200)
descrizione = models.TextField(blank=True)
avanzamento = models.PositiveSmallIntegerField(default=0) # 0-100
tipo = models.CharField(max_length=20, choices=TIPO_CHOICES, default='collettivo')
assegnato_a = models.ManyToManyField(
User, blank=True,
related_name='obiettivi_assegnati'
)
stato = models.CharField(max_length=20, choices=STATO_CHOICES, default='aperto')
data_scadenza = models.DateField(null=True, blank=True)
creato_da = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, related_name='obiettivi_creati'
)
data_creazione = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-data_creazione']
verbose_name = 'Obiettivo'
verbose_name_plural = 'Obiettivi'
def __str__(self):
return self.titolo
@property
def giorni_rimanenti(self):
"""Restituisce i giorni rimanenti alla scadenza (None se non impostata)."""
if not self.data_scadenza:
return None
delta = self.data_scadenza - timezone.now().date()
return delta.days
class AggiornamentoObiettivo(models.Model):
obiettivo = models.ForeignKey(Obiettivo, on_delete=models.CASCADE, related_name='aggiornamenti')
testo = models.TextField()
autore = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='aggiornamenti')
data = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-data']
verbose_name = 'Aggiornamento'
verbose_name_plural = 'Aggiornamenti'
def __str__(self):
return f"Aggiornamento su '{self.obiettivo}' del {self.data.strftime('%d/%m/%Y')}"
class CommentoConversazione(models.Model):
conversazione = models.ForeignKey(Conversazione, on_delete=models.CASCADE, related_name='commenti')
testo = models.TextField()
autore = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='commenti_conversazione')
data = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-data']
verbose_name = 'Commento'
verbose_name_plural = 'Commenti'
def __str__(self):
return f"Commento su '{self.conversazione}' del {self.data.strftime('%d/%m/%Y')}"
class Documento(models.Model):
file = models.FileField(
upload_to='documenti/%Y/%m/',
validators=[
FileExtensionValidator(allowed_extensions=['pdf']),
validate_file_size,
],
)
titolo = models.CharField(max_length=200)
descrizione = models.TextField(blank=True)
caricato_da = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, related_name='documenti_caricati'
)
data_caricamento = models.DateTimeField(auto_now_add=True)
conversazione = models.ForeignKey(
'Conversazione', on_delete=models.SET_NULL, null=True, blank=True, related_name='documenti'
)
obiettivo = models.ForeignKey(
'Obiettivo', on_delete=models.SET_NULL, null=True, blank=True, related_name='documenti'
)
class Meta:
ordering = ['-data_caricamento']
verbose_name = 'Documento'
verbose_name_plural = 'Documenti'
def __str__(self):
return self.titolo
@property
def filename(self):
import os
return os.path.basename(self.file.name)
class Appuntamento(models.Model):
titolo = models.CharField(max_length=200)
data_ora = models.DateTimeField()
luogo = models.CharField(max_length=200, blank=True)
note = models.TextField(blank=True)
conversazione = models.ForeignKey(
Conversazione, on_delete=models.SET_NULL, null=True, blank=True, related_name='appuntamenti'
)
partecipanti = models.ManyToManyField(User, blank=True, related_name='appuntamenti')
creato_da = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, related_name='appuntamenti_creati'
)
data_creazione = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['data_ora']
verbose_name = 'Appuntamento'
verbose_name_plural = 'Appuntamenti'
def __str__(self):
return f"{self.titolo} ({self.data_ora.strftime('%d/%m/%Y %H:%M')})"
@property
def is_passato(self):
return self.data_ora < timezone.now()