File size: 2,909 Bytes
4f01198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
"""
Custom RBAC Permission Classes

Admin   → full access to everything
Caregiver → read own profile, manage own bookings
User    → manage own pets/bookings, read caregivers
"""

from rest_framework.permissions import BasePermission, SAFE_METHODS
from api.models import Role


class IsAdmin(BasePermission):
    """Only platform admins (role=admin OR is_staff)."""
    message = 'Admin access required.'

    def has_permission(self, request, view):
        return (
            request.user
            and request.user.is_authenticated
            and (request.user.role == Role.ADMIN or request.user.is_staff)
        )


class IsCaregiver(BasePermission):
    """Only caregivers."""
    message = 'Caregiver account required.'

    def has_permission(self, request, view):
        return (
            request.user
            and request.user.is_authenticated
            and request.user.role == Role.CAREGIVER
        )


class IsAdminOrReadOnly(BasePermission):
    """
    GET/HEAD/OPTIONS → any authenticated user.
    Mutations (POST/PUT/PATCH/DELETE) → admin only.
    Used on /caregivers/ endpoint.
    """
    message = 'Write access requires admin privileges.'

    def has_permission(self, request, view):
        if not request.user or not request.user.is_authenticated:
            return False
        if request.method in SAFE_METHODS:
            return True
        return request.user.role == Role.ADMIN or request.user.is_staff


class IsOwnerOrAdmin(BasePermission):
    """
    Object-level: owner or admin can access.
    Works for Pet, Booking, Conversation objects.
    """
    message = 'You do not have permission to access this resource.'

    def has_object_permission(self, request, view, obj):
        if request.user.role == Role.ADMIN or request.user.is_staff:
            return True
        # Support objects with either .user or .owner attribute
        owner = getattr(obj, 'user', None) or getattr(obj, 'owner', None)
        return owner == request.user


class IsParticipantOrAdmin(BasePermission):
    """For Conversation / Message objects."""
    message = 'You are not a participant in this conversation.'

    def has_object_permission(self, request, view, obj):
        if request.user.role == Role.ADMIN or request.user.is_staff:
            return True
        # obj is a Conversation
        conversation = getattr(obj, 'conversation', obj)
        return request.user in conversation.participants.all()


class IsCaregiverOwnerOrAdmin(BasePermission):
    """Caregiver can update their own profile; admin can update any."""
    message = 'You can only manage your own caregiver profile.'

    def has_object_permission(self, request, view, obj):
        if request.user.role == Role.ADMIN or request.user.is_staff:
            return True
        if request.method in SAFE_METHODS:
            return True
        return obj.user == request.user