Coverage for api/serializers/fields.py: 94%
30 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 06:14 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 06:14 +0000
1import re
3from django.conf import settings
4from rest_framework import serializers
6from api.utils.help_text import make_comma_separated_help_text
9class SchemableHyperlinkedIdentityField(serializers.HyperlinkedIdentityField):
10 """
11 This field returns the link but allows the option to replace the URL scheme.
13 This is useful when the API runs on ``http`` behind a proxy that serves ``https``.
14 In these cases, the scheme in hyperlinks must be forced to ``https``.
15 """
17 def __init__(self, scheme=settings.API_LINK_SCHEME, *args, **kwargs):
18 super().__init__(*args, **kwargs)
20 self.scheme = scheme
22 def get_url(self, *args, **kwargs):
23 url = super().get_url(*args, **kwargs)
25 # Only rewrite URLs if a fixed scheme is provided
26 if self.scheme is not None: 26 ↛ 27line 26 didn't jump to line 27 because the condition on line 26 was never true
27 url = re.sub(r"^\w+://", f"{self.scheme}://", url, 1)
29 return url
32class EnumCharField(serializers.CharField):
33 """This field extends the ``CharField`` to add enum validation."""
35 default_error_messages = serializers.CharField.default_error_messages | {
36 "outside_enum": "Invalid value: {given}. Allowed values: {allowed}"
37 }
39 def __init__(self, plural: str, enum_class: set[str], **kwargs):
40 kwargs["help_text"] = make_comma_separated_help_text(enum_class, plural)
41 super().__init__(**kwargs)
43 self.enum_class = enum_class
45 def _validate_enum(self, given_value: str):
46 """
47 Validate whether the given values are all members of the given enum.
49 :param given_value: the comma separated list received in the input
50 :return: the lower cased form of the input, if the input is valid
51 :raise: ``ValidationError``, if the input is invalid
52 """
54 lower = given_value.lower()
55 input_values = lower.split(",")
56 for value in input_values:
57 if value not in self.enum_class:
58 self.fail("outside_enum", given=value, allowed=self.enum_class)
59 return lower
61 def to_internal_value(self, data):
62 data = super().to_internal_value(data)
63 self._validate_enum(data)
64 return data