db3558872e
Modernisiert die öffentliche Oberfläche mit Inter, Dark Mode und Live-Suche, ergänzt KI-gestützte Entwürfe im Admin mit Nachweis-Uploads und dokumentiert Daphne/Nginx für den Serverbetrieb. Co-authored-by: Cursor <cursoragent@cursor.com>
136 lines
5.5 KiB
Python
136 lines
5.5 KiB
Python
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)
|