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