from django.contrib import admin from django.urls import path from django.utils.html import format_html from .admin_forms import ( ClaimAdminForm, CounterArgumentInlineForm, EvidenceFileInlineForm, SourceInlineForm, ) from .admin_views import AssistantView, ReviewDraftView from .models import Category, Claim, ClaimDraft, CounterArgument, EvidenceFile, Source, Tag class FaktenAdminMixin: class Media: css = {'all': ['css/admin_custom.css']} js = ['js/admin_custom.js'] class EvidenceFileInline(FaktenAdminMixin, admin.StackedInline): model = EvidenceFile form = EvidenceFileInlineForm extra = 1 fields = ('preview', 'file', 'title', 'caption', 'order') readonly_fields = ('preview',) classes = ('collapse-open',) verbose_name = 'Nachweis' verbose_name_plural = 'Nachweise (Grafiken / PDFs)' @admin.display(description='Vorschau') def preview(self, obj): if not obj or not obj.pk or not obj.file: return format_html('Nach dem Speichern sichtbar') if obj.is_image: return format_html( '
' '{}
', obj.file.url, obj.file.url, obj.image_alt, ) if obj.is_pdf: return format_html( '
' '📄 PDF öffnen
', obj.file.url, ) return '—' class SourceInline(FaktenAdminMixin, admin.StackedInline): model = Source form = SourceInlineForm extra = 1 fields = ('title', 'organization', 'url', 'description') classes = ('collapse-open',) verbose_name = 'Quelle' verbose_name_plural = 'Quellen' class CounterArgumentInline(FaktenAdminMixin, admin.StackedInline): model = CounterArgument form = CounterArgumentInlineForm extra = 1 fields = ('argument', 'response') classes = ('collapse-open',) verbose_name = 'Gegenargument' verbose_name_plural = 'Gegenargumente' @admin.register(Tag) class TagAdmin(FaktenAdminMixin, admin.ModelAdmin): list_display = ('name', 'slug') prepopulated_fields = {'slug': ('name',)} search_fields = ('name',) @admin.register(Category) class CategoryAdmin(FaktenAdminMixin, admin.ModelAdmin): list_display = ('name', 'slug', 'claim_count', 'created_at') prepopulated_fields = {'slug': ('name',)} search_fields = ('name', 'description') fieldsets = ( (None, { 'fields': ('name', 'slug', 'icon'), }), ('Beschreibung', { 'fields': ('description',), 'classes': ('wide',), }), ) def formfield_for_dbfield(self, db_field, request, **kwargs): formfield = super().formfield_for_dbfield(db_field, request, **kwargs) if db_field.name == 'description': formfield.widget.attrs.update({'rows': 4, 'class': 'fk-admin-textarea'}) return formfield @admin.display(description='Anzahl Behauptungen') def claim_count(self, obj): return obj.claims.count() @admin.register(Claim) class ClaimAdmin(FaktenAdminMixin, admin.ModelAdmin): form = ClaimAdminForm change_form_template = 'admin/claims/claim/change_form.html' list_display = ('title', 'category', 'status', 'evidence_level', 'updated_at') list_display_links = ('title',) list_filter = ('category', 'status', 'evidence_level', 'tags') search_fields = ('title', 'short_answer', 'detailed_explanation') prepopulated_fields = {'slug': ('title',)} filter_horizontal = ('tags',) autocomplete_fields = ('category',) save_on_top = True date_hierarchy = 'updated_at' inlines = [EvidenceFileInline, SourceInline, CounterArgumentInline] readonly_fields = ('public_link', 'created_at', 'updated_at') fieldsets = ( ('Einordnung', { 'fields': ('category', 'status', 'evidence_level', 'tags'), }), ('Behauptung', { 'fields': ('title', 'slug', 'public_link'), }), ('Texte', { 'fields': ('short_answer', 'detailed_explanation'), 'classes': ('wide',), 'description': 'Kurzantwort: in ~20 Sekunden lesbar. Ausführliche Erklärung optional.', }), ('Zeitstempel', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',), }), ) @admin.display(description='Website') def public_link(self, obj): if not obj.pk: return '—' return format_html( 'Behauptung auf der Website öffnen', obj.get_absolute_url(), ) @admin.register(EvidenceFile) class EvidenceFileAdmin(FaktenAdminMixin, admin.ModelAdmin): list_display = ('preview_thumb', 'display_title', 'claim', 'order', 'created_at') list_filter = ('claim__category',) search_fields = ('title', 'caption', 'claim__title') readonly_fields = ('preview',) fields = ('claim', 'preview', 'file', 'title', 'caption', 'order') @admin.display(description='') def preview_thumb(self, obj): if obj.is_image and obj.file: return format_html( '', obj.file.url, ) return obj.file_extension.upper() @admin.display(description='Vorschau') def preview(self, obj): return EvidenceFileInline.preview(self, obj) @admin.register(Source) class SourceAdmin(FaktenAdminMixin, admin.ModelAdmin): form = SourceInlineForm list_display = ('title', 'organization', 'claim') list_filter = ('claim__category',) search_fields = ('title', 'organization', 'description') @admin.register(CounterArgument) class CounterArgumentAdmin(FaktenAdminMixin, admin.ModelAdmin): form = CounterArgumentInlineForm list_display = ('argument_preview', 'claim') list_filter = ('claim__category',) search_fields = ('argument', 'response') @admin.display(description='Gegenargument') def argument_preview(self, obj): return obj.argument[:80] @admin.register(ClaimDraft) class ClaimDraftAdmin(FaktenAdminMixin, admin.ModelAdmin): change_list_template = 'admin/claims/claimdraft/change_list.html' list_display = ('title', 'status', 'created_by', 'created_at', 'published_claim') list_filter = ('status', 'created_at') search_fields = ('title', 'user_notes', 'article_url') readonly_fields = ( 'created_by', 'status', 'article_url', 'user_notes', 'uploaded_file', 'article_text', 'conversation', 'ai_raw_response', 'error_message', 'published_claim', 'created_at', 'updated_at', ) def get_queryset(self, request): qs = super().get_queryset(request) if request.user.is_superuser: return qs return qs.filter(created_by=request.user) def has_change_permission(self, request, obj=None): if obj and not request.user.is_superuser and obj.created_by_id != request.user.id: return False return super().has_change_permission(request, obj) def has_delete_permission(self, request, obj=None): if obj and not request.user.is_superuser and obj.created_by_id != request.user.id: return False return super().has_delete_permission(request, obj) def get_urls(self): urls = super().get_urls() custom_urls = [ path( 'assistant/', self.admin_site.admin_view(AssistantView.as_view()), name='claims_claimdraft_assistant', ), path( '/review/', self.admin_site.admin_view(ReviewDraftView.as_view()), name='claims_claimdraft_review', ), ] return custom_urls + urls