funkwhale/api/funkwhale_api/common/serializers.py

85 wiersze
3.0 KiB
Python
Czysty Zwykły widok Historia

2018-05-23 17:52:47 +00:00
from rest_framework import serializers
class ActionSerializer(serializers.Serializer):
"""
A special serializer that can operate on a list of objects
and apply actions on it.
"""
action = serializers.CharField(required=True)
objects = serializers.JSONField(required=True)
filters = serializers.DictField(required=False)
actions = None
filterset_class = None
# those are actions identifier where we don't want to allow the "all"
# selector because it's to dangerous. Like object deletion.
dangerous_actions = []
2018-05-23 17:52:47 +00:00
def __init__(self, *args, **kwargs):
2018-06-09 13:36:16 +00:00
self.queryset = kwargs.pop("queryset")
2018-05-23 17:52:47 +00:00
if self.actions is None:
raise ValueError(
2018-06-09 13:36:16 +00:00
"You must declare a list of actions on " "the serializer class"
)
2018-05-23 17:52:47 +00:00
for action in self.actions:
2018-06-09 13:36:16 +00:00
handler_name = "handle_{}".format(action)
assert hasattr(self, handler_name), "{} miss a {} method".format(
self.__class__.__name__, handler_name
2018-05-23 17:52:47 +00:00
)
super().__init__(self, *args, **kwargs)
def validate_action(self, value):
if value not in self.actions:
raise serializers.ValidationError(
2018-06-09 13:36:16 +00:00
"{} is not a valid action. Pick one of {}.".format(
value, ", ".join(self.actions)
2018-05-23 17:52:47 +00:00
)
)
return value
def validate_objects(self, value):
qs = None
2018-06-09 13:36:16 +00:00
if value == "all":
return self.queryset.all().order_by("id")
2018-05-23 17:52:47 +00:00
if type(value) in [list, tuple]:
2018-06-09 13:36:16 +00:00
return self.queryset.filter(pk__in=value).order_by("id")
2018-05-23 17:52:47 +00:00
raise serializers.ValidationError(
2018-06-09 13:36:16 +00:00
"{} is not a valid value for objects. You must provide either a "
'list of identifiers or the string "all".'.format(value)
)
2018-05-23 17:52:47 +00:00
def validate(self, data):
2018-06-09 13:36:16 +00:00
dangerous = data["action"] in self.dangerous_actions
if dangerous and self.initial_data["objects"] == "all":
raise serializers.ValidationError(
2018-06-09 13:36:16 +00:00
"This action is to dangerous to be applied to all objects"
)
if self.filterset_class and "filters" in data:
qs_filterset = self.filterset_class(
2018-06-09 13:36:16 +00:00
data["filters"], queryset=data["objects"]
)
try:
assert qs_filterset.form.is_valid()
except (AssertionError, TypeError):
2018-06-09 13:36:16 +00:00
raise serializers.ValidationError("Invalid filters")
data["objects"] = qs_filterset.qs
2018-05-23 17:52:47 +00:00
2018-06-09 13:36:16 +00:00
data["count"] = data["objects"].count()
if data["count"] < 1:
raise serializers.ValidationError("No object matching your request")
2018-05-23 17:52:47 +00:00
return data
def save(self):
2018-06-09 13:36:16 +00:00
handler_name = "handle_{}".format(self.validated_data["action"])
2018-05-23 17:52:47 +00:00
handler = getattr(self, handler_name)
2018-06-09 13:36:16 +00:00
result = handler(self.validated_data["objects"])
2018-05-23 17:52:47 +00:00
payload = {
2018-06-09 13:36:16 +00:00
"updated": self.validated_data["count"],
"action": self.validated_data["action"],
"result": result,
2018-05-23 17:52:47 +00:00
}
return payload