99 lines
3.3 KiB
Python
Raw Permalink 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.

# backend\api\v1\permissions.py
from __future__ import annotations
from typing import Iterable, Tuple
from rest_framework.permissions import BasePermission
from rest_framework.request import Request
class IsSelfOrStaff(BasePermission):
"""Доступ для staff/superuser или владельца объекта.
ВАЖНО:
• SAFE-методы НЕ дают автоматического допуска.
• Добавлена поддержка кейса "объект = сам пользователь" (self-update).
"""
DEFAULT_OWNER_ID_ATTRS: Tuple[str, ...] = (
"employee_id",
"author_id",
"user_id",
"owner_id",
)
DEFAULT_OWNER_OBJ_ATTRS: Tuple[str, ...] = (
"employee",
"author",
"user",
"owner",
)
def has_permission(self, request: Request, view) -> bool:
"""Пускаем только аутентифицированных.
Args:
request (Request): DRF-запрос.
view: DRF ViewSet.
Returns:
bool: True если пользователь аутентифицирован.
"""
user = getattr(request, "user", None)
return bool(user and user.is_authenticated)
def has_object_permission(self, request: Request, view, obj) -> bool:
"""Разрешает доступ staff/superuser или владельцу объекта.
Логика владельца:
1) Совпадение *_id полей (employee_id/user_id/…)
2) Совпадение связанных owner-объектов (employee/user/…)
3) Фоллбек "self-object": obj.__class__ == user.__class__
и obj.pk == user.pk
Args:
request (Request): DRF-запрос.
view: DRF ViewSet.
obj: Проверяемый объект.
Returns:
bool: True если доступ разрешён.
Raises:
Ничего не выбрасывает.
"""
user = getattr(request, "user", None)
if not user or not user.is_authenticated:
return False
# Админский доступ
if getattr(user, "is_staff", False) or getattr(user, "is_superuser", False):
return True
# 1) *_id поля владельца
owner_id_attrs: Iterable[str] = getattr(
view, "owner_id_attrs", self.DEFAULT_OWNER_ID_ATTRS
)
for attr in owner_id_attrs:
if getattr(obj, attr, None) == user.id:
return True
# 2) связанные owner-объекты
owner_obj_attrs: Iterable[str] = getattr(
view, "owner_obj_attrs", self.DEFAULT_OWNER_OBJ_ATTRS
)
for attr in owner_obj_attrs:
owner = getattr(obj, attr, None)
if owner is not None and getattr(owner, "id", None) == user.id:
return True
# 3) self-object: редактирование собственной учётки (Employee ↔
# Employee)
if obj.__class__ is user.__class__ and getattr(obj, "pk", None) == getattr(
user,
"pk",
None,
):
return True
return False