116 lines
4.2 KiB
Python
116 lines
4.2 KiB
Python
from decimal import Decimal
|
|
|
|
from rest_framework import serializers
|
|
from core.serializers.base import BaseModelSerializer
|
|
from apps.projects.models import Project
|
|
from apps.workspaces.models import PriceUnit
|
|
|
|
|
|
def validate_thumbnail(value):
|
|
if value is None:
|
|
return value
|
|
max_bytes = 2 * 1024 * 1024
|
|
if getattr(value, "size", 0) > max_bytes:
|
|
raise serializers.ValidationError("Image size must be 2MB or less.")
|
|
content_type = (getattr(value, "content_type", "") or "").lower()
|
|
allowed_types = {"image/jpeg", "image/png", "image/webp"}
|
|
if content_type and content_type not in allowed_types:
|
|
raise serializers.ValidationError("Unsupported image type. Use JPG, PNG, or WebP.")
|
|
return value
|
|
|
|
|
|
class ProjectSerializer(BaseModelSerializer):
|
|
class Meta:
|
|
model = Project
|
|
fields = BaseModelSerializer.Meta.fields + (
|
|
"workspace",
|
|
"name",
|
|
"client",
|
|
"description",
|
|
"thumbnail",
|
|
"is_archived",
|
|
"color",
|
|
)
|
|
read_only_fields = fields
|
|
|
|
def to_representation(self, instance):
|
|
representation = super().to_representation(instance)
|
|
request = self.context.get("request")
|
|
if instance.thumbnail:
|
|
thumbnail_url = instance.thumbnail.url
|
|
representation["thumbnail"] = request.build_absolute_uri(thumbnail_url) if request else thumbnail_url
|
|
else:
|
|
representation["thumbnail"] = None
|
|
if instance.client:
|
|
representation['client'] = {
|
|
'id': instance.client.id,
|
|
'name': instance.client.name,
|
|
'thumbnail': (
|
|
request.build_absolute_uri(instance.client.thumbnail.url)
|
|
if request and instance.client.thumbnail
|
|
else instance.client.thumbnail.url
|
|
if instance.client.thumbnail
|
|
else None
|
|
),
|
|
}
|
|
return representation
|
|
|
|
|
|
class ProjectCreateSerializer(serializers.Serializer):
|
|
workspace = serializers.UUIDField()
|
|
name = serializers.CharField(max_length=255)
|
|
client = serializers.UUIDField(required=False, allow_null=True)
|
|
description = serializers.CharField(required=False, allow_blank=True, default="")
|
|
thumbnail = serializers.ImageField(required=False, allow_null=True)
|
|
color = serializers.CharField(max_length=7, required=False, allow_blank=True, default="")
|
|
|
|
def validate_thumbnail(self, value):
|
|
return validate_thumbnail(value)
|
|
|
|
|
|
class ProjectUpdateSerializer(serializers.Serializer):
|
|
name = serializers.CharField(max_length=255, required=False)
|
|
client = serializers.UUIDField(required=False, allow_null=True)
|
|
description = serializers.CharField(required=False, allow_blank=True)
|
|
thumbnail = serializers.ImageField(required=False, allow_null=True)
|
|
clear_thumbnail = serializers.BooleanField(required=False, default=False)
|
|
color = serializers.CharField(max_length=7, required=False, allow_blank=True)
|
|
is_archived = serializers.BooleanField(required=False)
|
|
|
|
def validate_thumbnail(self, value):
|
|
return validate_thumbnail(value)
|
|
|
|
|
|
class ProjectAccessQuerySerializer(serializers.Serializer):
|
|
workspace = serializers.UUIDField()
|
|
user = serializers.UUIDField()
|
|
|
|
|
|
class ProjectAccessMutationSerializer(serializers.Serializer):
|
|
workspace = serializers.UUIDField()
|
|
user = serializers.UUIDField()
|
|
project_ids = serializers.ListField(
|
|
child=serializers.UUIDField(),
|
|
allow_empty=False,
|
|
)
|
|
|
|
|
|
class ProjectAccessRateMutationSerializer(serializers.Serializer):
|
|
workspace = serializers.UUIDField()
|
|
user = serializers.UUIDField()
|
|
project = serializers.UUIDField()
|
|
hourly_rate = serializers.DecimalField(
|
|
max_digits=10,
|
|
decimal_places=2,
|
|
min_value=Decimal("0.01"),
|
|
required=False,
|
|
allow_null=True,
|
|
)
|
|
currency = serializers.CharField(max_length=3, required=False, default="USD")
|
|
|
|
def validate_currency(self, value):
|
|
code = value.upper()
|
|
if not PriceUnit.objects.filter(code=code, is_deleted=False).exists():
|
|
raise serializers.ValidationError("Selected price unit is invalid.")
|
|
return code
|