Coverage for src/django_global_search/permissions.py: 100%
24 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-06 22:25 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-06 22:25 +0000
1"""Permission utilities for global search."""
3from __future__ import annotations
5from typing import TYPE_CHECKING
7from django.contrib.contenttypes.models import ContentType
9if TYPE_CHECKING:
10 from django.contrib.admin import ModelAdmin
11 from django.db.models import Model
12 from django.http import HttpRequest
15def has_search_permission(
16 request: HttpRequest,
17 model_admin: ModelAdmin,
18 model: Model,
19 excluded_models: set[str],
20) -> bool:
21 """Check if user has permission to search this model.
23 :param request: HTTP request object
24 :param model_admin: ModelAdmin instance
25 :param model: Django model class
26 :param excluded_models: Set of excluded model labels (format: "app_label.model_name")
27 :return: True if user can search this model, False otherwise
28 """
29 # Check if model has search_fields configured
30 if not getattr(model_admin, "search_fields", None):
31 return False
33 # Check module permission (app-level access)
34 if not model_admin.has_module_permission(request):
35 return False
37 # Check view permission (model-level access)
38 if not model_admin.has_view_permission(request):
39 return False
41 # Check if model is in excluded list
42 model_label = f"{model._meta.app_label}.{model._meta.model_name}"
43 return model_label not in excluded_models
46def filter_searchable_models(
47 request: HttpRequest,
48 admin_registry: dict,
49 excluded_models: set[str],
50 content_type_ids: list[int] | None = None,
51) -> list[ModelAdmin]:
52 """Filter admin registry to get searchable ModelAdmin instances.
54 :param request: HTTP request object
55 :param admin_registry: AdminSite._registry dictionary
56 :param excluded_models: Set of excluded model labels
57 :param content_type_ids: Optional list of content type IDs to filter
58 :return: List of searchable ModelAdmin instances
59 """
60 searchable_admins = []
61 selected_content_type_ids = set(content_type_ids) if content_type_ids else None
63 for model, model_admin in admin_registry.items():
64 # Check basic search permission
65 if not has_search_permission(request, model_admin, model, excluded_models):
66 continue
68 # Filter by content_type_ids if provided
69 if selected_content_type_ids:
70 content_type = ContentType.objects.get_for_model(model)
71 if content_type.id not in selected_content_type_ids:
72 continue
74 searchable_admins.append(model_admin)
76 return searchable_admins