feat: scope project access to Django Admin
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
from django.db.models import Q
|
||||
|
||||
from .models import MainProduct, ProjectAccess, ProjectAccessPolicy, SubProduct
|
||||
|
||||
|
||||
def _mode(user):
|
||||
try:
|
||||
return user.project_access_policy.mode
|
||||
except ProjectAccessPolicy.DoesNotExist:
|
||||
return ProjectAccessPolicy.OWN
|
||||
|
||||
|
||||
def accessible_projects(user, model, *, edit=False):
|
||||
"""Return projects visible/editable by a user; explicit overrides win."""
|
||||
if model not in (MainProduct, SubProduct):
|
||||
raise ValueError("Expected a main project or sub-project model")
|
||||
if not user.is_authenticated or not user.is_active:
|
||||
return model.objects.none()
|
||||
if user.is_superuser:
|
||||
return model.objects.all()
|
||||
|
||||
field = "main_product" if model is MainProduct else "sub_product"
|
||||
overrides = ProjectAccess.objects.filter(user=user, **{f"{field}__isnull": False})
|
||||
allowed_levels = (ProjectAccess.EDIT,) if edit else (ProjectAccess.VIEW, ProjectAccess.EDIT)
|
||||
permitted = overrides.filter(level__in=allowed_levels)
|
||||
excluded = overrides.exclude(level__in=allowed_levels)
|
||||
|
||||
mode = _mode(user)
|
||||
base = Q(created_by=user) if mode != ProjectAccessPolicy.NONE else Q(pk__in=[])
|
||||
if mode == ProjectAccessPolicy.ALL_EDIT or (mode == ProjectAccessPolicy.ALL_VIEW and not edit):
|
||||
base = Q(pk__isnull=False)
|
||||
return model.objects.filter(base | Q(pk__in=permitted.values_list(f"{field}_id", flat=True))).exclude(
|
||||
pk__in=excluded.values_list(f"{field}_id", flat=True)
|
||||
).distinct()
|
||||
|
||||
|
||||
def can_access_project(user, project, *, edit=False):
|
||||
if project is None:
|
||||
return False
|
||||
return accessible_projects(user, type(project), edit=edit).filter(pk=project.pk).exists()
|
||||
|
||||
|
||||
def can_create_project(user):
|
||||
return user.is_authenticated and user.is_active and (
|
||||
user.is_superuser or _mode(user) != ProjectAccessPolicy.NONE
|
||||
)
|
||||
|
||||
|
||||
def project_for_related(obj):
|
||||
if isinstance(obj, (MainProduct, SubProduct)):
|
||||
return obj
|
||||
if getattr(obj, "sub_product_id", None):
|
||||
return obj.sub_product
|
||||
if getattr(obj, "main_product_id", None):
|
||||
return obj.main_product
|
||||
if getattr(obj, "article_id", None):
|
||||
return project_for_related(obj.article)
|
||||
return None
|
||||
Reference in New Issue
Block a user