feat(media): add client and project thumbnails

This commit is contained in:
2026-05-26 12:15:09 +03:30
parent f99e883f12
commit e42e0612aa
10 changed files with 199 additions and 57 deletions

View File

@@ -3,32 +3,65 @@ from apps.clients.models import Client
from core.serializers.base import BaseModelSerializer
class ClientSerializer(BaseModelSerializer):
class ClientSerializer(BaseModelSerializer):
"""
Serializer for retrieving and representing client details.
"""
class Meta:
model = Client
fields = BaseModelSerializer.Meta.fields + (
"workspace",
"name",
"notes",
)
read_only_fields = fields
fields = BaseModelSerializer.Meta.fields + (
"workspace",
"name",
"notes",
"thumbnail",
)
read_only_fields = fields
def to_representation(self, instance):
data = super().to_representation(instance)
request = self.context.get("request")
if instance.thumbnail:
thumbnail_url = instance.thumbnail.url
data["thumbnail"] = request.build_absolute_uri(thumbnail_url) if request else thumbnail_url
else:
data["thumbnail"] = None
return data
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 ClientCreateSerializer(serializers.Serializer):
"""
Serializer for handling input data during client creation.
"""
workspace_id = serializers.UUIDField()
name = serializers.CharField(max_length=255)
notes = serializers.CharField(allow_blank=True, required=False, default="")
workspace_id = serializers.UUIDField()
name = serializers.CharField(max_length=255)
notes = serializers.CharField(allow_blank=True, required=False, default="")
thumbnail = serializers.ImageField(required=False, allow_null=True)
def validate_thumbnail(self, value):
return validate_thumbnail(value)
class ClientUpdateSerializer(serializers.Serializer):
"""
Serializer for handling input data during client updates.
"""
name = serializers.CharField(max_length=255, required=False)
notes = serializers.CharField(allow_blank=True, required=False)
name = serializers.CharField(max_length=255, required=False)
notes = serializers.CharField(allow_blank=True, required=False)
thumbnail = serializers.ImageField(required=False, allow_null=True)
clear_thumbnail = serializers.BooleanField(required=False, default=False)
def validate_thumbnail(self, value):
return validate_thumbnail(value)

View File

@@ -61,12 +61,13 @@ class ClientViewSet(ModelViewSet):
client = create_client(
user=request.user,
workspace_id=serializer.validated_data["workspace_id"],
name=serializer.validated_data["name"],
notes=serializer.validated_data.get("notes", "")
)
output_serializer = ClientSerializer(client)
workspace_id=serializer.validated_data["workspace_id"],
name=serializer.validated_data["name"],
notes=serializer.validated_data.get("notes", ""),
thumbnail=serializer.validated_data.get("thumbnail"),
)
output_serializer = ClientSerializer(client, context={"request": request})
return Response(output_serializer.data, status=status.HTTP_201_CREATED)
def update(self, request, *args, **kwargs):
@@ -80,12 +81,14 @@ class ClientViewSet(ModelViewSet):
serializer.is_valid(raise_exception=True)
updated_client = update_client(
client=client,
name=serializer.validated_data.get("name"),
notes=serializer.validated_data.get("notes")
)
output_serializer = ClientSerializer(updated_client)
client=client,
name=serializer.validated_data.get("name"),
notes=serializer.validated_data.get("notes"),
thumbnail=serializer.validated_data.get("thumbnail"),
clear_thumbnail=serializer.validated_data.get("clear_thumbnail", False),
)
output_serializer = ClientSerializer(updated_client, context={"request": request})
return Response(output_serializer.data, status=status.HTTP_200_OK)
def destroy(self, request, *args, **kwargs):