🐛(backend) allow creating accesses when privileged by heritage
We took the opportunity of this bug to refactor serializers and permissions as advised one day by @qbey: no permission checks in serializers.
This commit is contained in:
committed by
Anthony LC
parent
d12c637dad
commit
433cead0ac
@@ -10,7 +10,7 @@ from django.utils.functional import lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
import magic
|
||||
from rest_framework import exceptions, serializers
|
||||
from rest_framework import serializers
|
||||
|
||||
from core import choices, enums, models, utils
|
||||
from core.services.ai_services import AI_ACTIONS
|
||||
@@ -38,78 +38,7 @@ class UserLightSerializer(UserSerializer):
|
||||
read_only_fields = ["full_name", "short_name"]
|
||||
|
||||
|
||||
class BaseAccessSerializer(serializers.ModelSerializer):
|
||||
"""Serialize template accesses."""
|
||||
|
||||
abilities = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
"""Make "user" field is readonly but only on update."""
|
||||
validated_data.pop("user", None)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def get_abilities(self, instance) -> dict:
|
||||
"""Return abilities of the logged-in user on the instance."""
|
||||
request = self.context.get("request")
|
||||
if request:
|
||||
return instance.get_abilities(request.user)
|
||||
return {}
|
||||
|
||||
def validate(self, attrs):
|
||||
"""
|
||||
Check access rights specific to writing (create/update)
|
||||
"""
|
||||
request = self.context.get("request")
|
||||
user = getattr(request, "user", None)
|
||||
role = attrs.get("role")
|
||||
|
||||
# Update
|
||||
if self.instance:
|
||||
can_set_role_to = self.instance.get_abilities(user)["set_role_to"]
|
||||
if role and role not in can_set_role_to:
|
||||
message = (
|
||||
f"You are only allowed to set role to {', '.join(can_set_role_to)}"
|
||||
if can_set_role_to
|
||||
else "You are not allowed to set this role for this template."
|
||||
)
|
||||
raise exceptions.PermissionDenied(message)
|
||||
|
||||
# Create
|
||||
else:
|
||||
try:
|
||||
resource_id = self.context["resource_id"]
|
||||
except KeyError as exc:
|
||||
raise exceptions.ValidationError(
|
||||
"You must set a resource ID in kwargs to create a new access."
|
||||
) from exc
|
||||
|
||||
if not self.Meta.model.objects.filter( # pylint: disable=no-member
|
||||
Q(user=user) | Q(team__in=user.teams),
|
||||
role__in=choices.PRIVILEGED_ROLES,
|
||||
**{self.Meta.resource_field_name: resource_id}, # pylint: disable=no-member
|
||||
).exists():
|
||||
raise exceptions.PermissionDenied(
|
||||
"You are not allowed to manage accesses for this resource."
|
||||
)
|
||||
|
||||
if (
|
||||
role == models.RoleChoices.OWNER
|
||||
and not self.Meta.model.objects.filter( # pylint: disable=no-member
|
||||
Q(user=user) | Q(team__in=user.teams),
|
||||
role=models.RoleChoices.OWNER,
|
||||
**{self.Meta.resource_field_name: resource_id}, # pylint: disable=no-member
|
||||
).exists()
|
||||
):
|
||||
raise exceptions.PermissionDenied(
|
||||
"Only owners of a resource can assign other users as owners."
|
||||
)
|
||||
|
||||
# pylint: disable=no-member
|
||||
attrs[f"{self.Meta.resource_field_name}_id"] = self.context["resource_id"]
|
||||
return attrs
|
||||
|
||||
|
||||
class DocumentAccessSerializer(BaseAccessSerializer):
|
||||
class DocumentAccessSerializer(serializers.ModelSerializer):
|
||||
"""Serialize document accesses."""
|
||||
|
||||
document_id = serializers.PrimaryKeyRelatedField(
|
||||
@@ -124,6 +53,7 @@ class DocumentAccessSerializer(BaseAccessSerializer):
|
||||
allow_null=True,
|
||||
)
|
||||
user = UserSerializer(read_only=True)
|
||||
abilities = serializers.SerializerMethodField(read_only=True)
|
||||
max_ancestors_role = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
@@ -141,10 +71,22 @@ class DocumentAccessSerializer(BaseAccessSerializer):
|
||||
]
|
||||
read_only_fields = ["id", "document_id", "abilities", "max_ancestors_role"]
|
||||
|
||||
def get_abilities(self, instance) -> dict:
|
||||
"""Return abilities of the logged-in user on the instance."""
|
||||
request = self.context.get("request")
|
||||
if request:
|
||||
return instance.get_abilities(request.user)
|
||||
return {}
|
||||
|
||||
def get_max_ancestors_role(self, instance):
|
||||
"""Return max_ancestors_role if annotated; else None."""
|
||||
return getattr(instance, "max_ancestors_role", None)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
"""Make "user" field is readonly but only on update."""
|
||||
validated_data.pop("user", None)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class DocumentAccessLightSerializer(DocumentAccessSerializer):
|
||||
"""Serialize document accesses with limited fields."""
|
||||
@@ -173,15 +115,29 @@ class DocumentAccessLightSerializer(DocumentAccessSerializer):
|
||||
]
|
||||
|
||||
|
||||
class TemplateAccessSerializer(BaseAccessSerializer):
|
||||
class TemplateAccessSerializer(serializers.ModelSerializer):
|
||||
"""Serialize template accesses."""
|
||||
|
||||
abilities = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = models.TemplateAccess
|
||||
resource_field_name = "template"
|
||||
fields = ["id", "user", "team", "role", "abilities"]
|
||||
read_only_fields = ["id", "abilities"]
|
||||
|
||||
def get_abilities(self, instance) -> dict:
|
||||
"""Return abilities of the logged-in user on the instance."""
|
||||
request = self.context.get("request")
|
||||
if request:
|
||||
return instance.get_abilities(request.user)
|
||||
return {}
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
"""Make "user" field is readonly but only on update."""
|
||||
validated_data.pop("user", None)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class ListDocumentSerializer(serializers.ModelSerializer):
|
||||
"""Serialize documents with limited fields for display in lists."""
|
||||
|
||||
Reference in New Issue
Block a user