""" ============================================== MODELS COMPLETS - EDUCONNECT AFRICA API ============================================== """ # ============================================ # apps/core/models.py - Mixins & Base Classes # ============================================ from django.db import models from django.utils import timezone class TimestampMixin(models.Model): """Mixin pour timestamps automatiques""" created_at = models.DateTimeField(auto_now_add=True, db_index=True) updated_at = models.DateTimeField(auto_now=True) class Meta: abstract = True class SoftDeleteMixin(models.Model): """Mixin pour soft delete""" deleted_at = models.DateTimeField(null=True, blank=True, db_index=True) is_active = models.BooleanField(default=True, db_index=True) class Meta: abstract = True def delete(self, hard=False, **kwargs): if hard: super().delete(**kwargs) else: self.deleted_at = timezone.now() self.is_active = False self.save() def restore(self): self.deleted_at = None self.is_active = True self.save() class VersionedFieldMixin(models.Model): """Mixin pour champs versionnés""" is_current = models.BooleanField(default=True, db_index=True) class Meta: abstract = True # Continuer dans le prochain message avec Gamification, Messaging, etc... class ImpactStat(TimestampMixin): """Statistiques d'impact affichées sur la page d'accueil""" title = models.CharField(max_length=100, help_text="Ex: Étudiants formés") value = models.CharField(max_length=50, help_text="Ex: 5000+") icon = models.CharField(max_length=50, help_text="Nom de l'icône Lucide (ex: Users, GraduationCap)") description = models.TextField(blank=True, help_text="Description courte") order = models.IntegerField(default=0, help_text="Ordre d'affichage") is_visible = models.BooleanField(default=True) class Meta: db_table = 'impact_stats' ordering = ['order'] verbose_name = "Statistique d'impact" verbose_name_plural = "Statistiques d'impact" def __str__(self): return f"{self.title} ({self.value})" class LearningTool(TimestampMixin): """Outils d'apprentissage pratiques (calculatrice, labo, etc.)""" CATEGORY_CHOICES = [ ('Sciences', 'Sciences'), ('Créativité', 'Créativité'), ('Langues', 'Langues'), ('Informatique', 'Informatique'), ] LEVEL_CHOICES = [ ('Primaire', 'Primaire'), ('Collège', 'Collège'), ('Lycée', 'Lycée'), ('Tous niveaux', 'Tous niveaux'), ] STATUS_CHOICES = [ ('available', 'Disponible'), ('dev', 'En développement'), ] tool_id = models.CharField(max_length=50, unique=True, help_text="Identifiant unique (ex: calc, chem)") title = models.CharField(max_length=100) description = models.TextField() icon = models.CharField(max_length=50, help_text="Nom de l'icône Lucide") category = models.CharField(max_length=50, choices=CATEGORY_CHOICES) level = models.CharField(max_length=50, choices=LEVEL_CHOICES) # Styling color = models.CharField(max_length=100, help_text="Classes Tailwind pour le fond de l'icône (ex: bg-blue-100)") text_color = models.CharField(max_length=100, help_text="Classes Tailwind pour la couleur de l'icône (ex: text-blue-600)") bg_gradient = models.CharField(max_length=100, help_text="Classes Tailwind pour le dégradé (ex: from-blue-500 to-cyan-400)") status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='available') link = models.CharField(max_length=200, blank=True, help_text="Lien interne (ex: /tools/calculator) ou externe") order = models.IntegerField(default=0) is_visible = models.BooleanField(default=True) class Meta: db_table = 'learning_tools' ordering = ['order'] verbose_name = "Outil d'apprentissage" verbose_name_plural = "Outils d'apprentissage" def __str__(self): return self.title class Testimonial(TimestampMixin): """Témoignages affichés sur la page d'accueil (L'impact EduLab)""" name = models.CharField(max_length=100) role = models.CharField(max_length=100, help_text="Ex: Étudiante en Chimie") country = models.CharField(max_length=100, help_text="Ex: Sénégal") text = models.TextField(help_text="Le témoignage") avatar = models.ImageField(upload_to='testimonials/', blank=True, null=True) order = models.IntegerField(default=0) is_visible = models.BooleanField(default=True) class Meta: db_table = 'testimonials' ordering = ['order'] verbose_name = "Témoignage" verbose_name_plural = "Témoignages" def __str__(self): return f"{self.name} - {self.country}" class SocialLink(TimestampMixin): """Liens vers les réseaux sociaux""" PLATFORM_CHOICES = [ ('facebook', 'Facebook'), ('twitter', 'Twitter (X)'), ('linkedin', 'LinkedIn'), ('instagram', 'Instagram'), ('youtube', 'YouTube'), ('email', 'Email'), ('website', 'Site Web'), ('other', 'Autre'), ] platform = models.CharField(max_length=50, choices=PLATFORM_CHOICES) name = models.CharField(max_length=100, help_text="Nom affiché (ex: LinkedIn)") url = models.URLField(help_text="Lien complet (ex: https://linkedin.com/in/...)") icon = models.CharField(max_length=50, help_text="Nom de l'icône Lucide (ex: Linkedin, Twitter, Mail)") order = models.IntegerField(default=0) is_visible = models.BooleanField(default=True) class Meta: db_table = 'social_links' ordering = ['order'] verbose_name = "Lien social" verbose_name_plural = "Liens sociaux" def __str__(self): return f"{self.name} ({self.platform})"