2020-05-14 11:51:05 +00:00
|
|
|
"""policy API Views"""
|
2020-05-23 22:57:25 +00:00
|
|
|
from rest_framework.serializers import ModelSerializer, SerializerMethodField
|
2020-09-08 15:38:41 +00:00
|
|
|
from rest_framework.utils.model_meta import get_field_info
|
2020-05-23 22:57:25 +00:00
|
|
|
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
2020-05-14 11:51:05 +00:00
|
|
|
|
2020-09-08 15:38:41 +00:00
|
|
|
from passbook.lib.api import InheritancePrimaryKeyRelatedField
|
2020-05-23 22:57:25 +00:00
|
|
|
from passbook.policies.forms import GENERAL_FIELDS
|
2020-09-08 15:38:41 +00:00
|
|
|
from passbook.policies.models import Policy, PolicyBinding, PolicyBindingModel
|
2020-05-14 11:51:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
class PolicyBindingSerializer(ModelSerializer):
|
|
|
|
"""PolicyBinding Serializer"""
|
|
|
|
|
2020-09-08 15:38:41 +00:00
|
|
|
# Because we're not interested in the PolicyBindingModel's PK but rather the subclasses PK,
|
|
|
|
# we have to manually declare this field
|
|
|
|
target = InheritancePrimaryKeyRelatedField(
|
|
|
|
queryset=PolicyBindingModel.objects.all().select_subclasses(),
|
|
|
|
source="target.pk",
|
|
|
|
required=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def update(self, instance, validated_data):
|
|
|
|
info = get_field_info(instance)
|
|
|
|
|
|
|
|
# Simply set each attribute on the instance, and then save it.
|
|
|
|
# Note that unlike `.create()` we don't need to treat many-to-many
|
|
|
|
# relationships as being a special case. During updates we already
|
|
|
|
# have an instance pk for the relationships to be associated with.
|
|
|
|
m2m_fields = []
|
|
|
|
for attr, value in validated_data.items():
|
|
|
|
if attr in info.relations and info.relations[attr].to_many:
|
|
|
|
m2m_fields.append((attr, value))
|
|
|
|
else:
|
|
|
|
if attr == "target":
|
|
|
|
instance.target_pk = value["pk"].pbm_uuid
|
|
|
|
else:
|
|
|
|
setattr(instance, attr, value)
|
|
|
|
|
|
|
|
instance.save()
|
|
|
|
|
|
|
|
# Note that many-to-many fields are set after updating instance.
|
|
|
|
# Setting m2m fields triggers signals which could potentially change
|
|
|
|
# updated instance and we do not want it to collide with .update()
|
|
|
|
for attr, value in m2m_fields:
|
|
|
|
field = getattr(instance, attr)
|
|
|
|
field.set(value)
|
|
|
|
|
|
|
|
return instance
|
|
|
|
|
2020-05-14 11:51:05 +00:00
|
|
|
class Meta:
|
|
|
|
|
|
|
|
model = PolicyBinding
|
2020-09-07 09:25:59 +00:00
|
|
|
fields = ["pk", "policy", "target", "enabled", "order", "timeout"]
|
2020-05-14 11:51:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
class PolicyBindingViewSet(ModelViewSet):
|
|
|
|
"""PolicyBinding Viewset"""
|
|
|
|
|
|
|
|
queryset = PolicyBinding.objects.all()
|
|
|
|
serializer_class = PolicyBindingSerializer
|
2020-05-23 22:57:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
class PolicySerializer(ModelSerializer):
|
|
|
|
"""Policy Serializer"""
|
|
|
|
|
|
|
|
__type__ = SerializerMethodField(method_name="get_type")
|
|
|
|
|
|
|
|
def get_type(self, obj):
|
|
|
|
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
|
|
|
return obj._meta.object_name.lower().replace("policy", "")
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
|
|
|
model = Policy
|
|
|
|
fields = ["pk"] + GENERAL_FIELDS + ["__type__"]
|
|
|
|
|
|
|
|
|
|
|
|
class PolicyViewSet(ReadOnlyModelViewSet):
|
|
|
|
"""Policy Viewset"""
|
|
|
|
|
|
|
|
queryset = Policy.objects.all()
|
|
|
|
serializer_class = PolicySerializer
|
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
return Policy.objects.select_subclasses()
|