♻️(contacts) switch API to get_abilities

Use the common way to define permissions on the API.

Note: we keep here the notion of "public" contacts,
even if the API does not really allows that. The use
case is not clear for that, but we allow contact w/o
owner to be displayed.
This commit is contained in:
Quentin BEY
2024-12-06 11:38:22 +01:00
committed by BEY Quentin
parent 019ce99a86
commit 7154a491f4
3 changed files with 29 additions and 6 deletions

View File

@@ -136,7 +136,7 @@ class ContactViewSet(
):
"""Contact ViewSet"""
permission_classes = [permissions.IsOwnedOrPublic]
permission_classes = [permissions.AccessPermission]
queryset = models.Contact.objects.all()
serializer_class = serializers.ContactSerializer
throttle_classes = [BurstRateThrottle, SustainedRateThrottle]
@@ -150,8 +150,10 @@ class ContactViewSet(
# List only contacts that:
queryset = queryset.filter(
# - is public (owner is None)
Q(owner__isnull=True)
# - are owned by the user
Q(owner=user)
| Q(owner=user)
# - are profile contacts for a user from the same organization
| Q(user__organization_id=user.organization_id),
# - are not overriden by another contact

View File

@@ -187,6 +187,27 @@ class Contact(BaseModel):
error_message = f"Validation error in '{field_path:s}': {e.message}"
raise exceptions.ValidationError({"data": [error_message]}) from e
def get_abilities(self, user):
"""
Compute and return abilities for a given user on the contact.
Beware that the model allows owner to be None, we are still not
sure about the use case for this and the API does not allow this.
For now, we still consider here, a contact without owner is "public"
so we allow access to it.
"""
is_owner = user == self.owner
is_profile_member_or_same_organization = bool(self.user) and (
self.user.organization_id == user.organization_id
)
return {
"get": is_owner or is_profile_member_or_same_organization or not self.owner,
"patch": is_owner,
"put": is_owner,
"delete": is_owner and not self.user, # Can't delete a profile contact
}
class ServiceProvider(BaseModel):
"""

View File

@@ -86,10 +86,10 @@ def test_api_contacts_delete_authenticated_owner():
def test_api_contacts_delete_authenticated_profile():
"""
Authenticated users should be allowed to delete their profile contact.
Authenticated users should not be allowed to delete their profile contact.
"""
user = factories.UserFactory()
contact = factories.ContactFactory(owner=user, user=user)
contact = factories.ProfileContactFactory(user=user)
client = APIClient()
client.force_login(user)
@@ -98,8 +98,8 @@ def test_api_contacts_delete_authenticated_profile():
f"/api/v1.0/contacts/{contact.id!s}/",
)
assert response.status_code == 204
assert models.Contact.objects.exists() is False
assert response.status_code == 403
assert models.Contact.objects.exists() is True
def test_api_contacts_delete_authenticated_other():