96 lines
3.7 KiB
Python

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}'
@property
def average_score(self) -> int:
return getattr(self, "average_score", None)
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}'