schon/core/permissions.py
Egor fureunoir Gorbunov 04656ea223 Features: 1) Add "list" and "retrieve" to USER_SCOPED_ACTIONS; 2) Include new image asset evibes-big-simple.png;
Fixes: None;

Extra: 1) Simplify queryset filtering logic for "list" and "retrieve" actions;
2025-05-29 22:56:19 +03:00

138 lines
5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.users 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.
- If an instance or queryset has a "user" attribute, ensure that the request.user is the same,
unless the user is an admin with the required django permission.
"""
ACTION_PERM_MAP = {
"retrieve": "view",
"list": "view",
"create": "add",
"update": "change",
"partial_update": "change",
"destroy": "delete",
}
USER_SCOPED_ACTIONS = {
"list",
"retrieve",
"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_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
if hasattr(obj, "user"):
if obj.user == request.user:
return True
# Allow admins who hold the required model permission
app_label = obj._meta.app_label
model_name = obj._meta.model_name
action = getattr(view, "action", None)
perm_prefix = self.ACTION_PERM_MAP.get(action)
return bool(perm_prefix and request.user.has_perm(f"{app_label}.{perm_prefix}_{model_name}"))
model = view.queryset.model
app_label = model._meta.app_label
model_name = model._meta.model_name
action = getattr(view, "action", None)
perm_prefix = self.ACTION_PERM_MAP.get(action)
return bool(perm_prefix and request.user.has_perm(f"{app_label}.{perm_prefix}_{model_name}"))
def has_queryset_permission(self, request, view, queryset):
"""
Filter the base queryset according to the action and user.
For models with a "user" field, restrict access to records belonging to the request user
unless the admin holds the needed permissions.
"""
model = view.queryset.model
app_label = model._meta.app_label
model_name = model._meta.model_name
if hasattr(model, "user"):
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}"):
return queryset
return queryset.none()
base = queryset.filter(is_active=True, user=request.user)
if request.user.is_staff and request.user.has_perm(
f"{app_label}.{self.ACTION_PERM_MAP.get(view.action)}_{model_name}"
):
return queryset.filter(is_active=True)
return base
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)
match view.action:
case "update" | "partial_update":
if request.user.has_perm(f"{app_label}.change_{model_name}"):
return base
case "destroy":
if request.user.has_perm(f"{app_label}.delete_{model_name}"):
return base
return queryset.none()