from django.contrib import admin, messages from django.contrib.admin.views.decorators import staff_member_required from django.core.exceptions import SuspiciousFileOperation from django.shortcuts import get_object_or_404, redirect, render from django.urls import path, reverse from django.utils.decorators import method_decorator from django.views import View from claims.forms import AssistantInputForm, RefineDraftForm, ReviewDraftForm from claims.models import ClaimDraft from claims.services.ai_assistant import AIAssistantError from claims.services.article_fetcher import ArticleFetchError from claims.services.draft_processor import process_claim_draft from claims.services.draft_publisher import DraftPublishError, publish_draft def _get_user_draft(request, draft_id): if request.user.is_superuser: return get_object_or_404(ClaimDraft, pk=draft_id) return get_object_or_404(ClaimDraft, pk=draft_id, created_by=request.user) @method_decorator(staff_member_required, name='dispatch') class AssistantView(View): template_name = 'admin/claims/assistant.html' def get(self, request): form = AssistantInputForm() drafts = ClaimDraft.objects.filter(created_by=request.user).order_by('-created_at')[:10] return render(request, self.template_name, { **admin.site.each_context(request), 'form': form, 'recent_drafts': drafts, 'title': 'Fakten-Assistent', 'opts': ClaimDraft._meta, }) def post(self, request): form = AssistantInputForm(request.POST, request.FILES) if not form.is_valid(): return render(request, self.template_name, { **admin.site.each_context(request), 'form': form, 'recent_drafts': ClaimDraft.objects.filter(created_by=request.user)[:10], 'title': 'Fakten-Assistent', 'opts': ClaimDraft._meta, }) draft = ClaimDraft.objects.create( created_by=request.user, article_url=form.cleaned_data.get('article_url') or '', user_notes=form.cleaned_data.get('user_notes') or '', uploaded_file=form.cleaned_data.get('uploaded_file'), ) try: process_claim_draft(draft) except (ArticleFetchError, AIAssistantError): return redirect('admin:claims_claimdraft_review', draft.pk) messages.success(request, 'Entwurf wurde erstellt. Bitte vor der Veröffentlichung prüfen.') return redirect('admin:claims_claimdraft_review', draft.pk) @method_decorator(staff_member_required, name='dispatch') class ReviewDraftView(View): template_name = 'admin/claims/review_draft.html' def get(self, request, draft_id): draft = _get_user_draft(request, draft_id) return render(request, self.template_name, { **admin.site.each_context(request), 'draft': draft, 'form': ReviewDraftForm(instance=draft), 'refine_form': RefineDraftForm(), 'title': f'Entwurf prüfen: {draft.title or draft.pk}', 'opts': ClaimDraft._meta, }) def post(self, request, draft_id): draft = _get_user_draft(request, draft_id) action = request.POST.get('action') if action == 'refine': refine_form = RefineDraftForm(request.POST) if refine_form.is_valid(): try: process_claim_draft(draft, refinement=refine_form.cleaned_data['refinement']) messages.success(request, 'Entwurf wurde überarbeitet.') except (ArticleFetchError, AIAssistantError) as exc: messages.error(request, str(exc)) return redirect('admin:claims_claimdraft_review', draft.pk) if action == 'reject': draft.status = ClaimDraft.DraftStatus.REJECTED draft.save(update_fields=['status', 'updated_at']) messages.info(request, 'Entwurf wurde verworfen.') return redirect('admin:claims_claimdraft_assistant') form = ReviewDraftForm(request.POST, instance=draft) if not form.is_valid(): return render(request, self.template_name, { **admin.site.each_context(request), 'draft': draft, 'form': form, 'refine_form': RefineDraftForm(), 'title': f'Entwurf prüfen: {draft.title or draft.pk}', 'opts': ClaimDraft._meta, }) draft = form.save() if action == 'save': draft.status = ClaimDraft.DraftStatus.REVIEW draft.save(update_fields=['status', 'updated_at']) messages.success(request, 'Änderungen gespeichert.') return redirect('admin:claims_claimdraft_review', draft.pk) if action == 'publish': try: claim = publish_draft(draft) except DraftPublishError as exc: messages.error(request, str(exc)) return redirect('admin:claims_claimdraft_review', draft.pk) except SuspiciousFileOperation as exc: messages.error(request, f'Datei konnte nicht gespeichert werden: {exc}') return redirect('admin:claims_claimdraft_review', draft.pk) messages.success( request, f'Behauptung „{claim.title}" wurde veröffentlicht.', ) return redirect(reverse('admin:claims_claim_change', args=[claim.pk])) return redirect('admin:claims_claimdraft_review', draft.pk)