|
|
|
|
|
|
|
|
|
|
|
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin |
|
|
from django.db import models |
|
|
from apps.core.models import TimestampMixin, SoftDeleteMixin, VersionedFieldMixin |
|
|
|
|
|
class UserManager(BaseUserManager): |
|
|
def create_user(self, email, password=None, **extra_fields): |
|
|
if not email: |
|
|
raise ValueError('L\'adresse email est obligatoire') |
|
|
email = self.normalize_email(email) |
|
|
user = self.model(email=email, **extra_fields) |
|
|
user.set_password(password) |
|
|
user.save(using=self._db) |
|
|
return user |
|
|
|
|
|
def create_superuser(self, email, password=None, **extra_fields): |
|
|
extra_fields.setdefault('is_staff', True) |
|
|
extra_fields.setdefault('is_superuser', True) |
|
|
extra_fields.setdefault('role', 'ADMIN') |
|
|
return self.create_user(email, password, **extra_fields) |
|
|
|
|
|
class User(AbstractBaseUser, PermissionsMixin, TimestampMixin, SoftDeleteMixin): |
|
|
"""Modèle utilisateur personnalisé""" |
|
|
ROLE_CHOICES = [ |
|
|
('STUDENT', 'Étudiant'), |
|
|
('MENTOR', 'Mentor'), |
|
|
('ADMIN', 'Administrateur'), |
|
|
] |
|
|
|
|
|
email = models.EmailField(unique=True, db_index=True) |
|
|
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='STUDENT', db_index=True) |
|
|
points = models.IntegerField(default=0, db_index=True) |
|
|
is_staff = models.BooleanField(default=False) |
|
|
email_verified = models.BooleanField(default=False) |
|
|
last_login_ip = models.GenericIPAddressField(null=True, blank=True) |
|
|
|
|
|
objects = UserManager() |
|
|
USERNAME_FIELD = 'email' |
|
|
REQUIRED_FIELDS = [] |
|
|
|
|
|
class Meta: |
|
|
db_table = 'users' |
|
|
verbose_name = 'Utilisateur' |
|
|
verbose_name_plural = 'Utilisateurs' |
|
|
indexes = [ |
|
|
models.Index(fields=['email', 'is_active']), |
|
|
models.Index(fields=['role', 'is_active']), |
|
|
models.Index(fields=['points'], name='idx_user_points'), |
|
|
] |
|
|
|
|
|
def __str__(self): |
|
|
return self.email |
|
|
|
|
|
def add_points(self, points, reason=''): |
|
|
"""Ajouter des points avec traçabilité""" |
|
|
from apps.gamification.models import UserPointsHistory |
|
|
|
|
|
previous_total = self.points |
|
|
self.points += points |
|
|
self.save() |
|
|
|
|
|
UserPointsHistory.objects.create( |
|
|
user=self, |
|
|
points_change=points, |
|
|
previous_total=previous_total, |
|
|
new_total=self.points, |
|
|
reason=reason |
|
|
) |
|
|
|
|
|
return self.points |
|
|
|
|
|
class UserProfile(TimestampMixin, VersionedFieldMixin): |
|
|
"""Profil utilisateur versionné""" |
|
|
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='profiles') |
|
|
name = models.CharField(max_length=255) |
|
|
public_key = models.TextField(null=True, blank=True) |
|
|
encrypted_private_key = models.TextField(null=True, blank=True) |
|
|
|
|
|
class Meta: |
|
|
db_table = 'user_profiles' |
|
|
verbose_name = 'Profil Utilisateur' |
|
|
verbose_name_plural = 'Profils Utilisateurs' |
|
|
indexes = [ |
|
|
models.Index(fields=['user', 'is_current']), |
|
|
] |
|
|
|
|
|
def __str__(self): |
|
|
return f"{self.name} ({self.user.email})" |
|
|
|
|
|
def save(self, *args, **kwargs): |
|
|
if self.is_current: |
|
|
UserProfile.objects.filter(user=self.user, is_current=True).update(is_current=False) |
|
|
super().save(*args, **kwargs) |
|
|
|
|
|
class UserAvatar(TimestampMixin, VersionedFieldMixin): |
|
|
profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='avatars') |
|
|
avatar_url = models.URLField(max_length=500) |
|
|
|
|
|
class Meta: |
|
|
db_table = 'user_avatars' |
|
|
|
|
|
class UserCountry(TimestampMixin, VersionedFieldMixin): |
|
|
profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='countries') |
|
|
country = models.CharField(max_length=100) |
|
|
|
|
|
class Meta: |
|
|
db_table = 'user_countries' |
|
|
|
|
|
class UserUniversity(TimestampMixin, VersionedFieldMixin): |
|
|
profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='universities') |
|
|
university = models.CharField(max_length=255) |
|
|
|
|
|
class Meta: |
|
|
db_table = 'user_universities' |
|
|
|
|
|
|