Files
2026-10-29 04:39:49 +08:00

59 lines
2.1 KiB
Python

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