Faktenkompass: UI-Rebrand, Admin-Assistent und Produktions-Setup.
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>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from django.db import transaction
|
||||
from django.utils.text import slugify
|
||||
|
||||
from claims.models import Category, Claim, CounterArgument, EvidenceFile, Source, Tag
|
||||
|
||||
|
||||
class DraftPublishError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _resolve_category(draft):
|
||||
if draft.category_slug:
|
||||
category = Category.objects.filter(slug=draft.category_slug).first()
|
||||
if category:
|
||||
return category
|
||||
|
||||
if draft.new_category_name:
|
||||
category, _ = Category.objects.get_or_create(
|
||||
slug=slugify(draft.new_category_name),
|
||||
defaults={
|
||||
'name': draft.new_category_name,
|
||||
'description': draft.new_category_description or draft.new_category_name,
|
||||
'icon': draft.new_category_icon or 'bi-book',
|
||||
},
|
||||
)
|
||||
return category
|
||||
|
||||
raise DraftPublishError('Bitte eine Kategorie auswählen oder eine neue angeben.')
|
||||
|
||||
|
||||
def _get_or_create_tags(tag_names):
|
||||
tags = []
|
||||
for name in tag_names or []:
|
||||
clean = str(name).strip()
|
||||
if not clean:
|
||||
continue
|
||||
tag, _ = Tag.objects.get_or_create(name=clean, defaults={'slug': slugify(clean)})
|
||||
tags.append(tag)
|
||||
return tags
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def publish_draft(draft):
|
||||
if draft.status == draft.DraftStatus.PUBLISHED and draft.published_claim_id:
|
||||
return draft.published_claim
|
||||
|
||||
if not draft.title or not draft.short_answer:
|
||||
raise DraftPublishError('Titel und Kurzantwort sind erforderlich.')
|
||||
|
||||
category = _resolve_category(draft)
|
||||
claim = Claim.objects.create(
|
||||
category=category,
|
||||
title=draft.title,
|
||||
status=draft.claim_status or Claim.Status.UNBELEGT,
|
||||
short_answer=draft.short_answer,
|
||||
detailed_explanation=draft.detailed_explanation,
|
||||
evidence_level=draft.evidence_level or Claim.EvidenceLevel.MITTEL,
|
||||
)
|
||||
claim.tags.set(_get_or_create_tags(draft.tags))
|
||||
|
||||
for source in draft.sources or []:
|
||||
url = (source.get('url') or '').strip()
|
||||
if not url:
|
||||
continue
|
||||
Source.objects.create(
|
||||
claim=claim,
|
||||
title=source.get('title') or url,
|
||||
organization=source.get('organization') or 'Unbekannt',
|
||||
url=url,
|
||||
description=source.get('description', ''),
|
||||
)
|
||||
|
||||
for counter in draft.counter_arguments or []:
|
||||
argument = (counter.get('argument') or '').strip()
|
||||
response = (counter.get('response') or '').strip()
|
||||
if argument and response:
|
||||
CounterArgument.objects.create(claim=claim, argument=argument, response=response)
|
||||
|
||||
if draft.uploaded_file:
|
||||
_attach_uploaded_file(draft, claim)
|
||||
|
||||
draft.published_claim = claim
|
||||
draft.status = draft.DraftStatus.PUBLISHED
|
||||
draft.save(update_fields=['published_claim', 'status', 'updated_at'])
|
||||
return claim
|
||||
|
||||
|
||||
def _attach_uploaded_file(draft, claim):
|
||||
if not draft.uploaded_file:
|
||||
return
|
||||
|
||||
original_name = os.path.basename(draft.uploaded_file.name)
|
||||
ext = original_name.rsplit('.', 1)[-1].lower() if '.' in original_name else ''
|
||||
if ext not in {'jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'pdf'}:
|
||||
return
|
||||
|
||||
evidence = EvidenceFile(claim=claim, title='')
|
||||
short_name = f'{uuid.uuid4().hex[:12]}.{ext}'
|
||||
with draft.uploaded_file.open('rb') as source_file:
|
||||
evidence.file.save(short_name, source_file, save=True)
|
||||
Reference in New Issue
Block a user