import os import uuid from django.db import models from django.core.validators import FileExtensionValidator from django.core.exceptions import ValidationError from users.models import User from .utils import validate_image_size, validate_video_size, validate_score from .managers import PublicationManager ALLOWED_IMAGE_EXTS = ['jpg', 'jpeg', 'png', 'webp', 'gif'] ALLOWED_VIDEO_EXTS = ['mp4', 'webm', 'mov'] def user_directory_path(instance, filename): ext = os.path.splitext(filename)[1] return f'publications/user_{instance.user.id}/{uuid.uuid4()}{ext}' class Category(models.Model): name = models.CharField(max_length=50) def __str__(self): return self.name # Create your models here. class Publication(models.Model): class StatusVarioations(models.TextChoices): PUBLIC = 'public', 'Public' PENDING = 'pending', 'Pending' class ContentVariations(models.TextChoices): IMAGE = 'image', 'Image' VIDEO = 'video', 'Video' image = models.ImageField(upload_to=user_directory_path, blank=True, null=True, validators=[FileExtensionValidator(ALLOWED_IMAGE_EXTS), validate_image_size]) video = models.FileField(upload_to=user_directory_path, blank=True, null=True, validators=[FileExtensionValidator(ALLOWED_VIDEO_EXTS), validate_video_size]) content_type = models.CharField(max_length=20, choices=ContentVariations.choices) status = models.CharField(max_length=50, choices=StatusVarioations.choices, default=StatusVarioations.PENDING) description = models.CharField(max_length=255) is_pinned = models.BooleanField(default=False) user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, blank=False) category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True) time_created = models.DateTimeField(auto_now_add=True) time_updated = models.DateTimeField(auto_now=True) objects: PublicationManager["Publication"] = PublicationManager() def __str__(self): return f'Content #{self.pk}' def clean(self): errors = [] if self.content_type == 'image' and not self.image: errors.append('Required image file') if self.content_type == 'video' and not self.video: errors.append('Required video file') if self.image and self.video: errors.append('You must upload either a video or an image, not both') if errors: raise ValidationError(errors) class Rating(models.Model): score = models.IntegerField(validators=[validate_score], null=False) user = models.ForeignKey(User, on_delete=models.CASCADE) publication = models.ForeignKey(Publication, on_delete=models.CASCADE, related_name="ratings") time_created = models.DateTimeField(auto_now_add=True) time_updated = models.DateTimeField(auto_now=True) @staticmethod def rate_publication(user: User, publication: Publication, score: int): exists_rate = Rating.objects.filter(user=user, publication=publication).first() if exists_rate: exists_rate.score = score exists_rate.save() else: Rating.objects.create( user=user, publication=publication, score=score ) class Meta: constraints = [ models.UniqueConstraint(fields=['user', 'publication'], name='unique_user_publication') ] def __str__(self): return f'Score {self.score} by {self.user} for {self.publication}'