From 78efaeb863d0ee69c018cc2ec50dffd440cc087b Mon Sep 17 00:00:00 2001
From: Konrad Mohrfeldt <konrad.mohrfeldt@farbdev.org>
Date: Sun, 9 Apr 2023 18:18:50 +0200
Subject: [PATCH] =?UTF-8?q?fix:=20don=E2=80=99t=20output=20invalid=20PPOI?=
 =?UTF-8?q?=20format?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The serializer would return an invalid format for the image.ppoi field
causing errors on save through the API even if the API consumer didn’t
modify the ppoi field value.

Apart from that the current implementation caused an internal server
error instead of rejecting invalid formats on save.
---
 program/serializers.py | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/program/serializers.py b/program/serializers.py
index 1cef8814..1837a54c 100644
--- a/program/serializers.py
+++ b/program/serializers.py
@@ -18,6 +18,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
+import re
 from typing import List, TypedDict
 
 from rest_framework import serializers
@@ -197,6 +198,22 @@ class HostLinkSerializer(serializers.ModelSerializer):
         fields = ("type", "url")
 
 
+class PPOIField(serializers.CharField):
+    def validate_format(self, value: str):
+        if not re.match(r"\d(?:\.\d+)?x\d(?:\.\d+)?", value):
+            raise serializers.ValidationError("PPOI must match format: ${float}x${float}")
+
+    def __init__(self, **kwargs):
+        kwargs["max_length"] = 20
+        kwargs.setdefault("validators", [])
+        kwargs["validators"].append(self.validate_format)
+        super().__init__(**kwargs)
+
+    def to_representation(self, value: tuple[float, float]):
+        [left, top] = value
+        return f"{left}x{top}"
+
+
 class Thumbnail(TypedDict):
     width: float
     height: float
@@ -204,7 +221,7 @@ class Thumbnail(TypedDict):
 
 
 class ImageSerializer(serializers.ModelSerializer):
-    ppoi = serializers.CharField(max_length=20)  # PPOIField max_length
+    ppoi = PPOIField()
     thumbnails = serializers.SerializerMethodField()
 
     @staticmethod
-- 
GitLab