Files
Faktenkompass/claims/services/draft_publisher.py
T
Pirmin Hinderling (fedora) db3558872e 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>
2026-07-07 15:33:58 +02:00

104 lines
3.3 KiB
Python

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)