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)