Fixes: 1) Ensure 'user' is set to authenticated user in AddressSerializer.create method. Extra: 1) Refactor EvibesPermission for clarity and comprehensive action handling; 2) Add detailed class-level docstring for EvibesPermission; 3) Simplify queryset filtering logic with USER_SCOPED_ACTIONS and explicit permission checks.
90 lines
3.1 KiB
Python
90 lines
3.1 KiB
Python
from rest_framework import permissions
|
||
|
||
|
||
class IsOwner(permissions.BasePermission):
|
||
def has_object_permission(self, request, view, obj):
|
||
return obj.user == request.user
|
||
|
||
|
||
class IsOwnerOrReadOnly(permissions.BasePermission):
|
||
def has_object_permission(self, request, view, obj):
|
||
if request.method in permissions.SAFE_METHODS:
|
||
return True
|
||
return obj.user == request.user
|
||
|
||
|
||
class EvibesPermission(permissions.BasePermission):
|
||
"""
|
||
Custom permission class for EvibesViewSet endpoints.
|
||
|
||
- 'create' may be explicitly allowed via view.additional['create'] == 'ALLOW'.
|
||
- Certain actions are scoped to the request.user’s own objects.
|
||
- Standard model perms ('add', 'view', 'change', 'delete') are enforced for all other actions,
|
||
including for staff users.
|
||
- Publicly visible models allow anonymous list/retrieve.
|
||
"""
|
||
|
||
ACTION_PERM_MAP = {
|
||
'retrieve': 'view',
|
||
'list': 'view',
|
||
'create': 'add',
|
||
'update': 'change',
|
||
'partial_update': 'change',
|
||
'destroy': 'delete',
|
||
}
|
||
|
||
USER_SCOPED_ACTIONS = {
|
||
'buy', 'buy_unregistered', 'current',
|
||
'add_order_product', 'remove_order_product',
|
||
'add_wishlist_product', 'remove_wishlist_product',
|
||
'bulk_add_wishlist_products', 'bulk_remove_wishlist_products',
|
||
'autocomplete',
|
||
}
|
||
|
||
def has_permission(self, request, view):
|
||
action = getattr(view, 'action', None)
|
||
model = view.queryset.model
|
||
app_label = model._meta.app_label
|
||
model_name = model._meta.model_name
|
||
|
||
if action == 'create' and view.additional.get('create') == 'ALLOW':
|
||
return True
|
||
|
||
if action in self.USER_SCOPED_ACTIONS:
|
||
return True
|
||
|
||
perm_prefix = self.ACTION_PERM_MAP.get(action)
|
||
if perm_prefix:
|
||
codename = f"{perm_prefix}_{model_name}"
|
||
if request.user.has_perm(f"{app_label}.{codename}"):
|
||
return True
|
||
|
||
return bool(action in ('list', 'retrieve') and getattr(model, 'is_publicly_visible', False))
|
||
|
||
def has_queryset_permission(self, request, view, queryset):
|
||
"""
|
||
Filter the base queryset according to the action and user.
|
||
Staff users still require view permissions to see records.
|
||
"""
|
||
model = view.queryset.model
|
||
app_label = model._meta.app_label
|
||
model_name = model._meta.model_name
|
||
|
||
if view.action in self.USER_SCOPED_ACTIONS:
|
||
return queryset.filter(user=request.user)
|
||
|
||
if view.action in ('list', 'retrieve'):
|
||
if request.user.has_perm(f"{app_label}.view_{model_name}"):
|
||
if request.user.is_staff:
|
||
return queryset
|
||
return queryset.filter(is_active=True)
|
||
return queryset.none()
|
||
|
||
base = queryset.filter(is_active=True)
|
||
if view.action in ('update', 'partial_update'):
|
||
if request.user.has_perm(f"{app_label}.change_{model_name}"):
|
||
return base
|
||
if view.action == 'destroy':
|
||
if request.user.has_perm(f"{app_label}.delete_{model_name}"):
|
||
return base
|
||
return queryset.none()
|