use enums for validation

This commit is contained in:
Simon
2025-02-17 18:43:54 +07:00
parent cfcb4e6f9e
commit 0ea4c87b9e
5 changed files with 56 additions and 84 deletions

View File

@@ -4,6 +4,7 @@
from common.serializers import PaginationSerializer, ValidateUnknownFieldsMixin from common.serializers import PaginationSerializer, ValidateUnknownFieldsMixin
from rest_framework import serializers from rest_framework import serializers
from video.src.constants import VideoTypeEnum
class DownloadItemSerializer(serializers.Serializer): class DownloadItemSerializer(serializers.Serializer):
@@ -19,9 +20,7 @@ class DownloadItemSerializer(serializers.Serializer):
timestamp = serializers.IntegerField() timestamp = serializers.IntegerField()
title = serializers.CharField() title = serializers.CharField()
vid_thumb_url = serializers.CharField() vid_thumb_url = serializers.CharField()
vid_type = serializers.ChoiceField( vid_type = serializers.ChoiceField(choices=VideoTypeEnum.values())
choices=["videos", "streams", "shorts", "unknown"]
)
youtube_id = serializers.CharField() youtube_id = serializers.CharField()
_index = serializers.CharField(required=False) _index = serializers.CharField(required=False)
_score = serializers.IntegerField(required=False) _score = serializers.IntegerField(required=False)

View File

@@ -2,8 +2,10 @@
# pylint: disable=abstract-method # pylint: disable=abstract-method
from common.src.helper import get_stylesheets
from rest_framework import serializers from rest_framework import serializers
from user.models import Account from user.models import Account
from video.src.constants import OrderEnum, SortEnum
class AccountSerializer(serializers.ModelSerializer): class AccountSerializer(serializers.ModelSerializer):
@@ -25,24 +27,15 @@ class AccountSerializer(serializers.ModelSerializer):
class UserMeConfigSerializer(serializers.Serializer): class UserMeConfigSerializer(serializers.Serializer):
"""serialize user me config""" """serialize user me config"""
stylesheet = serializers.CharField() stylesheet = serializers.ChoiceField(choices=get_stylesheets())
page_size = serializers.IntegerField() page_size = serializers.IntegerField()
sort_by = serializers.ChoiceField( sort_by = serializers.ChoiceField(choices=SortEnum.names())
choices=[ sort_order = serializers.ChoiceField(choices=OrderEnum.values())
"published",
"downloaded",
"views",
"likes",
"duration",
"filesize",
]
)
sort_order = serializers.ChoiceField(choices=["asc", "desc"])
view_style_home = serializers.ChoiceField(choices=["grid", "list"]) view_style_home = serializers.ChoiceField(choices=["grid", "list"])
view_style_channel = serializers.ChoiceField(choices=["grid", "list"]) view_style_channel = serializers.ChoiceField(choices=["grid", "list"])
view_style_downloads = serializers.ChoiceField(choices=["grid", "list"]) view_style_downloads = serializers.ChoiceField(choices=["grid", "list"])
view_style_playlist = serializers.ChoiceField(choices=["grid", "list"]) view_style_playlist = serializers.ChoiceField(choices=["grid", "list"])
grid_items = serializers.IntegerField() grid_items = serializers.IntegerField(max_value=7, min_value=3)
hide_watched = serializers.BooleanField() hide_watched = serializers.BooleanField()
show_ignored_only = serializers.BooleanField() show_ignored_only = serializers.BooleanField()
show_subed_only = serializers.BooleanField() show_subed_only = serializers.BooleanField()

View File

@@ -7,7 +7,6 @@ Functionality:
from typing import TypedDict from typing import TypedDict
from common.src.es_connect import ElasticWrap from common.src.es_connect import ElasticWrap
from common.src.helper import get_stylesheets
class UserConfigType(TypedDict, total=False): class UserConfigType(TypedDict, total=False):
@@ -29,7 +28,10 @@ class UserConfigType(TypedDict, total=False):
class UserConfig: class UserConfig:
"""Handle settings for an individual user""" """
Handle settings for an individual user
items are expected to be validated in the serializer
"""
_DEFAULT_USER_SETTINGS = UserConfigType( _DEFAULT_USER_SETTINGS = UserConfigType(
stylesheet="dark.css", stylesheet="dark.css",
@@ -47,19 +49,6 @@ class UserConfig:
show_help_text=True, show_help_text=True,
) )
VALID_STYLESHEETS = get_stylesheets()
VALID_VIEW_STYLE = ["grid", "list"]
VALID_SORT_ORDER = ["asc", "desc"]
VALID_SORT_BY = [
"published",
"downloaded",
"views",
"likes",
"duration",
"filesize",
]
VALID_GRID_ITEMS = range(3, 8)
def __init__(self, user_id: str): def __init__(self, user_id: str):
self._user_id: str = user_id self._user_id: str = user_id
self._config: UserConfigType = self.get_config() self._config: UserConfigType = self.get_config()
@@ -84,7 +73,6 @@ class UserConfig:
def set_value(self, key: str, value: str | bool | int): def set_value(self, key: str, value: str | bool | int):
"""Set or replace a configuration value for the user""" """Set or replace a configuration value for the user"""
self._validate(key, value)
data = {"doc": {"config": {key: value}}} data = {"doc": {"config": {key: value}}}
response, status = ElasticWrap(self.es_update_url).post(data) response, status = ElasticWrap(self.es_update_url).post(data)
if status < 200 or status > 299: if status < 200 or status > 299:
@@ -92,43 +80,6 @@ class UserConfig:
print(f"User {self._user_id} value '{key}' change: to {value}") print(f"User {self._user_id} value '{key}' change: to {value}")
def _validate(self, key, value):
"""validate key and value"""
if not self._user_id:
raise ValueError("Unable to persist config for null user_id")
if key not in self._DEFAULT_USER_SETTINGS:
raise KeyError(
f"Unable to persist config for an unknown key '{key}'"
)
valid_values = {
"stylesheet": self.VALID_STYLESHEETS,
"sort_by": self.VALID_SORT_BY,
"sort_order": self.VALID_SORT_ORDER,
"view_style_home": self.VALID_VIEW_STYLE,
"view_style_channel": self.VALID_VIEW_STYLE,
"view_style_download": self.VALID_VIEW_STYLE,
"view_style_playlist": self.VALID_VIEW_STYLE,
"grid_items": self.VALID_GRID_ITEMS,
"page_size": int,
"hide_watched": bool,
"show_ignored_only": bool,
"show_subed_only": bool,
"show_help_text": bool,
}
validation_value = valid_values.get(key)
if isinstance(validation_value, (list, range)):
if value not in validation_value:
raise ValueError(f"Invalid value for {key}: {value}")
elif validation_value == int:
if not isinstance(value, int):
raise ValueError(f"Invalid value for {key}: {value}")
elif validation_value == bool:
if not isinstance(value, bool):
raise ValueError(f"Invalid value for {key}: {value}")
def get_config(self) -> UserConfigType: def get_config(self) -> UserConfigType:
"""get config from ES or load from the application defaults""" """get config from ES or load from the application defaults"""
if not self._user_id: if not self._user_id:

View File

@@ -5,6 +5,7 @@
from channel.serializers import ChannelSerializer from channel.serializers import ChannelSerializer
from common.serializers import PaginationSerializer from common.serializers import PaginationSerializer
from rest_framework import serializers from rest_framework import serializers
from video.src.constants import OrderEnum, SortEnum, VideoTypeEnum, WatchedEnum
class PlayerSerializer(serializers.Serializer): class PlayerSerializer(serializers.Serializer):
@@ -91,7 +92,7 @@ class VideoSerializer(serializers.Serializer):
title = serializers.CharField() title = serializers.CharField()
vid_last_refresh = serializers.CharField() vid_last_refresh = serializers.CharField()
vid_thumb_url = serializers.CharField() vid_thumb_url = serializers.CharField()
vid_type = serializers.ChoiceField(choices=["video", "stream", "short"]) vid_type = serializers.ChoiceField(choices=VideoTypeEnum.values_known())
youtube_id = serializers.CharField() youtube_id = serializers.CharField()
_index = serializers.CharField(required=False) _index = serializers.CharField(required=False)
_score = serializers.FloatField(required=False) _score = serializers.FloatField(required=False)
@@ -110,22 +111,12 @@ class VideoListQuerySerializer(serializers.Serializer):
playlist = serializers.CharField(required=False) playlist = serializers.CharField(required=False)
channel = serializers.CharField(required=False) channel = serializers.CharField(required=False)
watch = serializers.ChoiceField( watch = serializers.ChoiceField(
choices=["watched", "unwatched", "continue"], required=False choices=WatchedEnum.values(), required=False
) )
sort = serializers.ChoiceField( sort = serializers.ChoiceField(choices=SortEnum.names(), required=False)
choices=[ order = serializers.ChoiceField(choices=OrderEnum.values(), required=False)
"published",
"downloaded",
"views",
"likes",
"duration",
"filesize",
],
required=False,
)
order = serializers.ChoiceField(choices=["asc", "desc"], required=False)
type = serializers.ChoiceField( type = serializers.ChoiceField(
choices=["videos", "streams", "shorts"], required=False choices=VideoTypeEnum.values_known(), required=False
) )

View File

@@ -11,6 +11,16 @@ class VideoTypeEnum(enum.Enum):
SHORTS = "shorts" SHORTS = "shorts"
UNKNOWN = "unknown" UNKNOWN = "unknown"
@classmethod
def values(cls) -> list[str]:
"""value list"""
return [i.value for i in cls]
@classmethod
def values_known(cls) -> list[str]:
"""values known"""
return [i.value for i in cls if i.value != "unknown"]
class SortEnum(enum.Enum): class SortEnum(enum.Enum):
"""all sort by options""" """all sort by options"""
@@ -22,9 +32,37 @@ class SortEnum(enum.Enum):
DURATION = "player.duration" DURATION = "player.duration"
MEDIASIZE = "media_size" MEDIASIZE = "media_size"
@classmethod
def values(cls) -> list[str]:
"""value list"""
return [i.value for i in cls]
@classmethod
def names(cls) -> list[str]:
"""name list"""
return [i.name.lower() for i in cls]
class OrderEnum(enum.Enum): class OrderEnum(enum.Enum):
"""all order by options""" """all order by options"""
ASC = "asc" ASC = "asc"
DESC = "desc" DESC = "desc"
@classmethod
def values(cls) -> list[str]:
"""value list"""
return [i.value for i in cls]
class WatchedEnum(enum.Enum):
"""watched state enum"""
WATCHED = "watched"
UNWATCHED = "unwatched"
CONTINUE = "continue"
@classmethod
def values(cls) -> list[str]:
"""value list"""
return [i.value for i in cls]