diff options
Diffstat (limited to 'ishtar_common/admin.py')
-rw-r--r-- | ishtar_common/admin.py | 205 |
1 files changed, 172 insertions, 33 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 5ca7ef105..7a621f601 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -836,6 +836,172 @@ class PermissionRequestAdmin(admin.ModelAdmin): form = PermissionRequestAdminForm +def get_content_types_with_sheet(with_empty=False): + choices = [] + for ct in ContentType.objects.all(): + klass = ct.model_class() + if not klass: + continue + if getattr(klass, "SHOW_URL", None): + choices.append((ct.pk, ct.name)) + lst = list( + sorted(choices, key=lambda x: x[1]) + ) + if with_empty: + lst = [("", "-" * 9)] + lst + return lst + + +class ContentTypeChoice: + def set_content_types_choices(self, field_name): + self.fields[field_name].choices = get_content_types_with_sheet() + + +class ContentTypeListFilter(admin.SimpleListFilter): + # Only display content types with sheet attached + title = _("content type") + parameter_name = 'content_type' + + def lookups(self, request, model_admin): + return get_content_types_with_sheet(with_empty=False) + + def queryset(self, request, queryset): + value = self.value() + if value: + query = {f"{self.parameter_name}_id": self.value()} + return queryset.filter(**query) + + +class BaseSheetFilterForm(forms.ModelForm, ContentTypeChoice): + content_type_field = "" + key = forms.CharField( + label=_("Key"), + initial="-", + help_text=_("Save first to choose a key"), + max_length=200, + ) + + def _get_content_type_model(self, instance): + raise NotImplementedError() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.set_content_types_choices(self.content_type_field) + instance = kwargs.get("instance") + if not instance: + return + if args: + query_dict = args[0] + query_dict._mutable = True + query_dict.setlist( + self.content_type_field, + [getattr(instance, self.content_type_field).pk] + ) + query_dict._mutable = False + self.fields[self.content_type_field].widget.attrs = {"disabled": "disabled"} + keys = instance.get_keys() + model = self._get_content_type_model(instance) + help_text = [] + for key in keys: + try: + field = model._meta.get_field(key) + except FieldDoesNotExist: + field = None + if field and getattr(field, "verbose_name", None): + key += f" ({field.verbose_name})" + help_text.append(key) + self.fields["key"].help_text = str(_("Available keys: ")) + " ; ".join( + help_text + ) + + +class SheetFilterForm(BaseSheetFilterForm): + class Meta: + model = models_common.SheetFilter + exclude = [] + + content_type_field = "content_type" + + def _get_content_type_model(self, instance): + return instance.content_type.model_class() + + +class ContentTypeSearchAdmin: + def search_results(self, queryset, search_term): + # search with real model name + # not efficient but searching only in ~10 models + search_terms = search_term.split(" ") + for ct in ContentType.objects.all(): + klass = ct.model_class() + if not klass: + continue + if getattr(klass, "SHOW_URL", None): + name = ct.name.lower() + for idx, k in enumerate(reversed(search_terms[:])): + if k in name: + queryset |= self.model.objects.filter( + content_type_id=ct.pk) + return queryset + + def get_search_results(self, request, queryset, search_term): + queryset, may_have_duplicates = super().get_search_results( + request, + queryset, + search_term, + ) + queryset = self.search_results(queryset, search_term) + return queryset, may_have_duplicates + + +@admin.register(models_common.SheetFilter, site=admin_site) +class SheetFilterAdmin(ContentTypeSearchAdmin, admin.ModelAdmin): + form = SheetFilterForm + model = models_common.SheetFilter + list_display = ("content_type", "exclude_or_include", "key") + list_filter = (ContentTypeListFilter,) + search_fields = ("key",) + + +class FilteredSheetForm(forms.ModelForm, ContentTypeChoice): + class Meta: + model = models_common.FilteredSheet + exclude = [] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.set_content_types_choices("content_type") + + def clean(self): + filters = self.cleaned_data.get("filters", []) + content_type = self.cleaned_data.get("content_type", None) + if not filters: + return self.cleaned_data + exc = None + for filtr in filters.all(): + if content_type != filtr.content_type: + raise forms.ValidationError( + _("Bad filter configuration. " + "Only use filters of the associacted content type.") + ) + if not exc: + exc = filtr.exclude_or_include + elif exc != filtr.exclude_or_include: + raise forms.ValidationError( + _("You cannot mix exclude and include filters.") + ) + return self.cleaned_data + + +@admin.register(models_common.FilteredSheet, site=admin_site) +class FilteredSheetAdmin(ContentTypeSearchAdmin, admin.ModelAdmin): + form = FilteredSheetForm + model = models_common.FilteredSheet + list_display = ("name", "content_type") + list_filter = (ContentTypeListFilter,) + autocomplete_fields = ("filters",) + search_fields = ("name",) + + MAIN_ITEM_READONLY_FIELDS = [ "history_creator", "history_modifier", @@ -1659,7 +1825,7 @@ admin_site.register(models.Area, AreaAdmin) class ProfileTypeAdmin(GeneralTypeAdmin): model = models.ProfileType filter_vertical = ("groups",) - autocomplete_fields = ("permission_requests",) + autocomplete_fields = ("permission_requests", "filtered_sheets") def save_related(self, request, form, formsets, change): super().save_related(request, form, formsets, change) @@ -2927,47 +3093,20 @@ class ApiKeyMatchAdmin(admin.ModelAdmin): admin_site.register(models_rest.ApiKeyMatch, ApiKeyMatchAdmin) -class ApiSheetFilterForm(forms.ModelForm): +class ApiSheetFilterForm(BaseSheetFilterForm): api_search_model = forms.ModelChoiceField( models_rest.ApiSearchModel.objects, label=_("API - Remote access - Search model"), ) - key = forms.CharField( - label=_("Key"), - initial="-", - help_text=_("Save first to choose a key"), - max_length=200, - ) class Meta: model = models_rest.ApiSheetFilter fields = ["api_search_model", "key"] - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - instance = kwargs.get("instance") - if not instance: - return - if args: - query_dict = args[0] - query_dict._mutable = True - query_dict.setlist("api_search_model", [instance.api_search_model.pk]) - query_dict._mutable = False - self.fields["api_search_model"].widget.attrs = {"disabled": "disabled"} - keys = instance.get_keys() - model = instance.api_search_model.content_type.model_class() - help_text = [] - for key in keys: - try: - field = model._meta.get_field(key) - except FieldDoesNotExist: - field = None - if field and getattr(field, "verbose_name", None): - key += f" ({field.verbose_name})" - help_text.append(key) - self.fields["key"].help_text = str(_("Available keys: ")) + " ; ".join( - help_text - ) + content_type_field = "api_search_model" + + def _get_content_type_model(self, instance): + return instance.api_search_model.content_type.model_class() class ApiSheetFilterAdmin(admin.ModelAdmin): |