XML export added
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Failing after 1m5s
Build containers when image tags change / build-if-image-changed (data-loader, loader, initContainers, init-container, git.baumann.gr/adebaumann/vui-data-loader) (push) Successful in 4s
Build containers when image tags change / build-if-image-changed (., web, containers, main container, git.baumann.gr/adebaumann/vui) (push) Failing after 8s

This commit is contained in:
2026-01-07 14:43:59 +01:00
parent d3d0298ad1
commit b7f50ce30f
6 changed files with 683 additions and 17 deletions

View File

@@ -25,7 +25,7 @@ spec:
mountPath: /data mountPath: /data
containers: containers:
- name: web - name: web
image: git.baumann.gr/adebaumann/vui:0.973 image: git.baumann.gr/adebaumann/vui:0.974
imagePullPolicy: Always imagePullPolicy: Always
ports: ports:
- containerPort: 8000 - containerPort: 8000

View File

@@ -0,0 +1,144 @@
from django.core.management.base import BaseCommand
import xml.etree.ElementTree as ET
from datetime import datetime
from dokumente.models import Dokument, Vorgabe, VorgabeKurztext, VorgabeLangtext, Checklistenfrage
class Command(BaseCommand):
help = 'Export all dokumente as XML'
def add_arguments(self, parser):
parser.add_argument(
'--output',
type=str,
help='Output file path (default: stdout)',
)
def handle(self, *args, **options):
dokumente = Dokument.objects.filter(aktiv=True).prefetch_related(
'autoren', 'pruefende', 'vorgaben__thema',
'vorgaben__referenzen', 'vorgaben__stichworte',
'vorgaben__checklistenfragen', 'vorgaben__vorgabekurztext_set',
'vorgaben__vorgabelangtext_set', 'geltungsbereich_set',
'einleitung_set', 'changelog__autoren'
).order_by('nummer')
root = ET.Element('Vorgabendokumente')
for dokument in dokumente:
doc_element = ET.SubElement(root, 'Vorgabendokument')
ET.SubElement(doc_element, 'Typ').text = dokument.dokumententyp.name if dokument.dokumententyp else ""
ET.SubElement(doc_element, 'Nummer').text = dokument.nummer
ET.SubElement(doc_element, 'Name').text = dokument.name
autoren_element = ET.SubElement(doc_element, 'Autoren')
for autor in dokument.autoren.all():
ET.SubElement(autoren_element, 'Autor').text = autor.name
pruefende_element = ET.SubElement(doc_element, 'Pruefende')
for pruefender in dokument.pruefende.all():
ET.SubElement(pruefende_element, 'Pruefender').text = pruefender.name
gueltigkeit_element = ET.SubElement(doc_element, 'Gueltigkeit')
ET.SubElement(gueltigkeit_element, 'Von').text = dokument.gueltigkeit_von.strftime("%Y-%m-%d") if dokument.gueltigkeit_von else ""
ET.SubElement(gueltigkeit_element, 'Bis').text = dokument.gueltigkeit_bis.strftime("%Y-%m-%d") if dokument.gueltigkeit_bis else None
ET.SubElement(doc_element, 'SignaturCSO').text = dokument.signatur_cso
geltungsbereich_sections = dokument.geltungsbereich_set.all().order_by('order')
if geltungsbereich_sections:
geltungsbereich_element = ET.SubElement(doc_element, 'Geltungsbereich')
abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt')
for gb in geltungsbereich_sections:
section = ET.SubElement(abschnitt_element, 'Teil')
section.set('typ', gb.abschnitttyp.abschnitttyp if gb.abschnitttyp else "text")
section.text = gb.inhalt
einleitung_sections = dokument.einleitung_set.all().order_by('order')
if einleitung_sections:
einleitung_element = ET.SubElement(doc_element, 'Einleitung')
abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt')
for ei in einleitung_sections:
section = ET.SubElement(abschnitt_element, 'Teil')
section.set('typ', ei.abschnitttyp.abschnitttyp if ei.abschnitttyp else "text")
section.text = ei.inhalt
ET.SubElement(doc_element, 'Ziel').text = ""
ET.SubElement(doc_element, 'Grundlagen').text = ""
changelog_element = ET.SubElement(doc_element, 'Changelog')
for cl in dokument.changelog.all().order_by('-datum'):
entry = ET.SubElement(changelog_element, 'Eintrag')
ET.SubElement(entry, 'Datum').text = cl.datum.strftime("%Y-%m-%d")
autoren = ET.SubElement(entry, 'Autoren')
for autor in cl.autoren.all():
ET.SubElement(autoren, 'Autor').text = autor.name
ET.SubElement(entry, 'Aenderung').text = cl.aenderung
anhaenge_element = ET.SubElement(doc_element, 'Anhaenge')
ET.SubElement(anhaenge_element, 'Anhang').text = dokument.anhaenge
ET.SubElement(doc_element, 'Verantwortlich').text = "Information Security Management BIT"
ET.SubElement(doc_element, 'Klassifizierung').text = ""
glossar_element = ET.SubElement(doc_element, 'Glossar')
vorgaben_element = ET.SubElement(doc_element, 'Vorgaben')
for vorgabe in dokument.vorgaben.all().order_by('order'):
vorgabe_el = ET.SubElement(vorgaben_element, 'Vorgabe')
ET.SubElement(vorgabe_el, 'Nummer').text = str(vorgabe.nummer)
ET.SubElement(vorgabe_el, 'Titel').text = vorgabe.titel
ET.SubElement(vorgabe_el, 'Thema').text = vorgabe.thema.name if vorgabe.thema else ""
kurztext_sections = vorgabe.vorgabekurztext_set.all().order_by('order')
if kurztext_sections:
kurztext_element = ET.SubElement(vorgabe_el, 'Kurztext')
abschnitt = ET.SubElement(kurztext_element, 'Abschnitt')
for kt in kurztext_sections:
teil = ET.SubElement(abschnitt, 'Teil')
teil.set('typ', kt.abschnitttyp.abschnitttyp if kt.abschnitttyp else "text")
teil.text = kt.inhalt
langtext_sections = vorgabe.vorgabelangtext_set.all().order_by('order')
if langtext_sections:
langtext_element = ET.SubElement(vorgabe_el, 'Langtext')
abschnitt = ET.SubElement(langtext_element, 'Abschnitt')
for lt in langtext_sections:
teil = ET.SubElement(abschnitt, 'Teil')
teil.set('typ', lt.abschnitttyp.abschnitttyp if lt.abschnitttyp else "text")
teil.text = lt.inhalt
referenz_element = ET.SubElement(vorgabe_el, 'Referenzen')
for ref in vorgabe.referenzen.all():
ref_text = f"{ref.name_nummer}: {ref.name_text}" if ref.name_text else ref.name_nummer
ET.SubElement(referenz_element, 'Referenz').text = ref_text
vorgabe_gueltigkeit = ET.SubElement(vorgabe_el, 'Gueltigkeit')
ET.SubElement(vorgabe_gueltigkeit, 'Von').text = vorgabe.gueltigkeit_von.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_von else ""
ET.SubElement(vorgabe_gueltigkeit, 'Bis').text = vorgabe.gueltigkeit_bis.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_bis else None
checklistenfragen_element = ET.SubElement(vorgabe_el, 'Checklistenfragen')
for cf in vorgabe.checklistenfragen.all():
ET.SubElement(checklistenfragen_element, 'Frage').text = cf.frage
stichworte_element = ET.SubElement(vorgabe_el, 'Stichworte')
for stw in vorgabe.stichworte.all():
ET.SubElement(stichworte_element, 'Stichwort').text = stw.stichwort
xml_str = ET.tostring(root, encoding='unicode', method='xml')
xml_output = self._prettify_xml(xml_str)
if options['output']:
with open(options['output'], 'w', encoding='utf-8') as f:
f.write(xml_output)
self.stdout.write(self.style.SUCCESS(f'XML exported to {options["output"]}'))
else:
self.stdout.write(xml_output)
def _prettify_xml(self, xml_string):
import xml.dom.minidom
dom = xml.dom.minidom.parseString(xml_string)
return dom.toprettyxml(indent=" ", encoding="UTF-8").decode('utf-8')

View File

@@ -209,6 +209,11 @@
download="{{ standard.nummer }}.json"> download="{{ standard.nummer }}.json">
JSON herunterladen JSON herunterladen
</a> </a>
<a href="{% url 'standard_xml' standard.nummer %}"
class="btn btn-secondary icon icon--before icon--download"
download="{{ standard.nummer }}.xml">
XML herunterladen
</a>
</p> </p>
</div> </div>
</div> </div>

View File

@@ -1483,6 +1483,200 @@ class JSONExportManagementCommandTest(TestCase):
self.assertIn('"Test Standard"', output) self.assertIn('"Test Standard"', output)
class ExportXMLCommandTest(TestCase):
"""Test cases for export_xml management command"""
def setUp(self):
"""Set up test data for XML export"""
# Create test data
self.dokumententyp = Dokumententyp.objects.create(
name="Standard IT-Sicherheit",
verantwortliche_ve="SR-SUR-SEC"
)
self.autor1 = Person.objects.create(
name="Max Mustermann",
funktion="Security Analyst"
)
self.autor2 = Person.objects.create(
name="Erika Mustermann",
funktion="Security Manager"
)
self.thema = Thema.objects.create(
name="Access Control",
erklaerung="Zugangskontrolle"
)
self.dokument = Dokument.objects.create(
nummer="TEST-001",
dokumententyp=self.dokumententyp,
name="Test Standard",
gueltigkeit_von=date(2023, 1, 1),
gueltigkeit_bis=date(2025, 12, 31),
signatur_cso="CSO-123",
anhaenge="Anhang1.pdf, Anhang2.pdf",
aktiv=True
)
self.dokument.autoren.add(self.autor1, self.autor2)
self.vorgabe = Vorgabe.objects.create(
order=1,
nummer=1,
dokument=self.dokument,
thema=self.thema,
titel="Test Vorgabe",
gueltigkeit_von=date(2023, 1, 1),
gueltigkeit_bis=date(2025, 12, 31)
)
# Create text sections
self.abschnitttyp_text = AbschnittTyp.objects.create(abschnitttyp="text")
self.abschnitttyp_table = AbschnittTyp.objects.create(abschnitttyp="table")
self.geltungsbereich = Geltungsbereich.objects.create(
geltungsbereich=self.dokument,
abschnitttyp=self.abschnitttyp_text,
inhalt="Dies ist der Geltungsbereich",
order=1
)
self.einleitung = Einleitung.objects.create(
einleitung=self.dokument,
abschnitttyp=self.abschnitttyp_text,
inhalt="Dies ist die Einleitung",
order=1
)
self.kurztext = VorgabeKurztext.objects.create(
abschnitt=self.vorgabe,
abschnitttyp=self.abschnitttyp_text,
inhalt="Dies ist der Kurztext",
order=1
)
self.langtext = VorgabeLangtext.objects.create(
abschnitt=self.vorgabe,
abschnitttyp=self.abschnitttyp_table,
inhalt="Spalte1|Spalte2\nWert1|Wert2",
order=1
)
self.checklistenfrage = Checklistenfrage.objects.create(
vorgabe=self.vorgabe,
frage="Ist die Zugriffskontrolle implementiert?"
)
self.changelog = Changelog.objects.create(
dokument=self.dokument,
datum=date(2023, 6, 1),
aenderung="Erste Version erstellt"
)
self.changelog.autoren.add(self.autor1)
def test_export_xml_command_stdout(self):
"""Test export_xml command output to stdout"""
out = StringIO()
call_command('export_xml', stdout=out)
output = out.getvalue()
# Check that output contains expected XML structure
self.assertIn('<Vorgabendokumente>', output)
self.assertIn('<Vorgabendokument>', output)
self.assertIn('<Typ>Standard IT-Sicherheit</Typ>', output)
self.assertIn('<Nummer>TEST-001</Nummer>', output)
self.assertIn('<Name>Test Standard</Name>', output)
self.assertIn('<Autor>Max Mustermann</Autor>', output)
self.assertIn('<Autor>Erika Mustermann</Autor>', output)
self.assertIn('<Von>2023-01-01</Von>', output)
self.assertIn('<Bis>2025-12-31</Bis>', output)
self.assertIn('<SignaturCSO>CSO-123</SignaturCSO>', output)
self.assertIn('Dies ist der Geltungsbereich', output)
self.assertIn('Dies ist die Einleitung', output)
self.assertIn('Dies ist der Kurztext', output)
self.assertIn('<Frage>Ist die Zugriffskontrolle implementiert?</Frage>', output)
self.assertIn('Erste Version erstellt', output)
def test_export_xml_command_to_file(self):
"""Test export_xml command output to file"""
import tempfile
import os
import xml.etree.ElementTree as ET
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.xml') as tmp_file:
tmp_filename = tmp_file.name
try:
call_command('export_xml', output=tmp_filename)
# Read file content
with open(tmp_filename, 'r', encoding='utf-8') as f:
content = f.read()
# Parse XML to ensure it's valid
root = ET.fromstring(content)
# Verify structure
self.assertEqual(root.tag, 'Vorgabendokumente')
docs = root.findall('Vorgabendokument')
self.assertEqual(len(docs), 1)
doc = docs[0]
self.assertEqual(doc.find('Nummer').text, 'TEST-001')
self.assertEqual(doc.find('Name').text, 'Test Standard')
self.assertEqual(doc.find('Typ').text, 'Standard IT-Sicherheit')
autoren = doc.find('Autoren').findall('Autor')
self.assertEqual(len(autoren), 2)
autor_names = [autor.text for autor in autoren]
self.assertIn('Max Mustermann', autor_names)
self.assertIn('Erika Mustermann', autor_names)
finally:
# Clean up temporary file
if os.path.exists(tmp_filename):
os.unlink(tmp_filename)
def test_export_xml_command_empty_database(self):
"""Test export_xml command with no documents"""
# Delete all documents
Dokument.objects.all().delete()
out = StringIO()
call_command('export_xml', stdout=out)
output = out.getvalue()
# Should output empty XML structure (accepts both formats)
self.assertIn('Vorgabendokumente', output)
self.assertNotIn('<Vorgabendokument>', output)
def test_export_xml_command_inactive_documents(self):
"""Test export_xml command filters inactive documents"""
# Create inactive document
inactive_doc = Dokument.objects.create(
nummer="INACTIVE-001",
dokumententyp=self.dokumententyp,
name="Inactive Document",
aktiv=False
)
out = StringIO()
call_command('export_xml', stdout=out)
output = out.getvalue()
# Should not contain inactive document
self.assertNotIn('INACTIVE-001', output)
self.assertNotIn('Inactive Document', output)
# Should still contain active document
self.assertIn('TEST-001', output)
self.assertIn('Test Standard', output)
class StandardJSONViewTest(TestCase): class StandardJSONViewTest(TestCase):
"""Test cases for standard_json view""" """Test cases for standard_json view"""
@@ -1668,6 +1862,195 @@ class StandardJSONViewTest(TestCase):
self.assertIn(' ', response.content.decode()) # Check for indentation self.assertIn(' ', response.content.decode()) # Check for indentation
class StandardXMLViewTest(TestCase):
"""Test cases for standard_xml view"""
def setUp(self):
"""Set up test data for XML view"""
self.client = Client()
# Create test data
self.dokumententyp = Dokumententyp.objects.create(
name="Standard IT-Sicherheit",
verantwortliche_ve="SR-SUR-SEC"
)
self.autor = Person.objects.create(
name="Test Autor",
funktion="Security Analyst"
)
self.pruefender = Person.objects.create(
name="Test Pruefender",
funktion="Security Manager"
)
self.thema = Thema.objects.create(
name="Access Control",
erklaerung="Zugangskontrolle"
)
self.dokument = Dokument.objects.create(
nummer="XML-001",
dokumententyp=self.dokumententyp,
name="XML Test Standard",
gueltigkeit_von=date(2023, 1, 1),
gueltigkeit_bis=date(2025, 12, 31),
signatur_cso="CSO-456",
anhaenge="test.pdf",
aktiv=True
)
self.dokument.autoren.add(self.autor)
self.dokument.pruefende.add(self.pruefender)
self.vorgabe = Vorgabe.objects.create(
order=1,
nummer=1,
dokument=self.dokument,
thema=self.thema,
titel="XML Test Vorgabe",
gueltigkeit_von=date(2023, 1, 1),
gueltigkeit_bis=date(2025, 12, 31)
)
# Create text sections
self.abschnitttyp_text = AbschnittTyp.objects.create(abschnitttyp="text")
self.geltungsbereich = Geltungsbereich.objects.create(
geltungsbereich=self.dokument,
abschnitttyp=self.abschnitttyp_text,
inhalt="XML Geltungsbereich",
order=1
)
self.kurztext = VorgabeKurztext.objects.create(
abschnitt=self.vorgabe,
abschnitttyp=self.abschnitttyp_text,
inhalt="XML Kurztext",
order=1
)
self.langtext = VorgabeLangtext.objects.create(
abschnitt=self.vorgabe,
abschnitttyp=self.abschnitttyp_text,
inhalt="XML Langtext",
order=1
)
self.checklistenfrage = Checklistenfrage.objects.create(
vorgabe=self.vorgabe,
frage="XML Checklistenfrage?"
)
self.changelog = Changelog.objects.create(
dokument=self.dokument,
datum=date(2023, 6, 1),
aenderung="XML Changelog Eintrag"
)
self.changelog.autoren.add(self.autor)
def test_standard_xml_view_success(self):
"""Test standard_xml view returns correct XML"""
url = reverse('standard_xml', kwargs={'nummer': 'XML-001'})
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/xml; charset=utf-8')
self.assertIn('attachment', response['Content-Disposition'])
self.assertIn('XML-001.xml', response['Content-Disposition'])
# Parse XML response
import xml.etree.ElementTree as ET
root = ET.fromstring(response.content)
# Verify document structure
self.assertEqual(root.tag, 'Vorgabendokument')
self.assertEqual(root.find('Nummer').text, 'XML-001')
self.assertEqual(root.find('Name').text, 'XML Test Standard')
self.assertEqual(root.find('Typ').text, 'Standard IT-Sicherheit')
self.assertEqual(root.find('Autoren').find('Autor').text, 'Test Autor')
self.assertEqual(root.find('Pruefende').find('Pruefender').text, 'Test Pruefender')
self.assertEqual(root.find('Gueltigkeit').find('Von').text, '2023-01-01')
self.assertEqual(root.find('Gueltigkeit').find('Bis').text, '2025-12-31')
self.assertEqual(root.find('SignaturCSO').text, 'CSO-456')
self.assertEqual(root.find('Anhaenge').find('Anhang').text, 'test.pdf')
self.assertEqual(root.find('Verantwortlich').text, 'Information Security Management BIT')
self.assertIn(root.find('Klassifizierung').text, ['', None]) # Empty string or None
def test_standard_xml_view_not_found(self):
"""Test standard_xml view returns 404 for non-existent document"""
url = reverse('standard_xml', kwargs={'nummer': 'NONEXISTENT'})
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_standard_xml_view_empty_sections(self):
"""Test standard_xml view handles empty sections correctly"""
# Create document without sections
empty_doc = Dokument.objects.create(
nummer="EMPTY-XML-001",
dokumententyp=self.dokumententyp,
name="Empty Document",
aktiv=True
)
url = reverse('standard_xml', kwargs={'nummer': 'EMPTY-XML-001'})
response = self.client.get(url)
# Parse XML response
import xml.etree.ElementTree as ET
root = ET.fromstring(response.content)
# Verify empty sections are handled correctly
self.assertIsNone(root.find('Geltungsbereich'))
self.assertIsNone(root.find('Einleitung'))
self.assertEqual(len(root.find('Vorgaben')), 0)
self.assertEqual(len(root.find('Changelog')), 0)
def test_standard_xml_view_null_dates(self):
"""Test standard_xml view handles null dates correctly"""
# Create document with null dates
null_doc = Dokument.objects.create(
nummer="NULL-XML-001",
dokumententyp=self.dokumententyp,
name="Null Dates Document",
gueltigkeit_von=None,
gueltigkeit_bis=None,
aktiv=True
)
url = reverse('standard_xml', kwargs={'nummer': 'NULL-XML-001'})
response = self.client.get(url)
# Parse XML response
import xml.etree.ElementTree as ET
root = ET.fromstring(response.content)
# Verify null dates are handled correctly
self.assertIn(root.find('Gueltigkeit').find('Von').text, ['', None])
self.assertIsNone(root.find('Gueltigkeit').find('Bis').text)
def test_standard_xml_view_xml_formatting(self):
"""Test standard_xml view returns properly formatted XML"""
url = reverse('standard_xml', kwargs={'nummer': 'XML-001'})
response = self.client.get(url)
# Check that response is valid XML
import xml.etree.ElementTree as ET
try:
ET.fromstring(response.content)
xml_valid = True
except ET.ParseError:
xml_valid = False
self.assertTrue(xml_valid)
# Check that XML is properly indented (should be formatted)
self.assertIn('<?xml version', response.content.decode())
self.assertIn('\n', response.content.decode())
self.assertIn(' ', response.content.decode()) # Check for indentation
class VorgabeCommentModelTest(TestCase): class VorgabeCommentModelTest(TestCase):
"""Test cases for VorgabeComment model""" """Test cases for VorgabeComment model"""

View File

@@ -11,6 +11,7 @@ urlpatterns = [
path('<str:nummer>/history/', views.standard_detail, {"check_date":"today"}, name='standard_history'), path('<str:nummer>/history/', views.standard_detail, {"check_date":"today"}, name='standard_history'),
path('<str:nummer>/checkliste/', views.standard_checkliste, name='standard_checkliste'), path('<str:nummer>/checkliste/', views.standard_checkliste, name='standard_checkliste'),
path('<str:nummer>/json/', views.standard_json, name='standard_json'), path('<str:nummer>/json/', views.standard_json, name='standard_json'),
path('<str:nummer>/xml/', views.standard_xml, name='standard_xml'),
path('comments/<int:vorgabe_id>/', views.get_vorgabe_comments, name='get_vorgabe_comments'), path('comments/<int:vorgabe_id>/', views.get_vorgabe_comments, name='get_vorgabe_comments'),
path('comments/<int:vorgabe_id>/add/', views.add_vorgabe_comment, name='add_vorgabe_comment'), path('comments/<int:vorgabe_id>/add/', views.add_vorgabe_comment, name='add_vorgabe_comment'),
path('comments/delete/<int:comment_id>/', views.delete_vorgabe_comment, name='delete_vorgabe_comment'), path('comments/delete/<int:comment_id>/', views.delete_vorgabe_comment, name='delete_vorgabe_comment'),

View File

@@ -1,12 +1,13 @@
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.decorators import login_required, user_passes_test
from django.http import JsonResponse from django.http import JsonResponse, HttpResponse
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.utils.html import escape, mark_safe from django.utils.html import escape, mark_safe
from django.utils.safestring import SafeString from django.utils.safestring import SafeString
import json import json
import xml.etree.ElementTree as ET
from .models import Dokument, Vorgabe, VorgabeKurztext, VorgabeLangtext, Checklistenfrage, VorgabeComment from .models import Dokument, Vorgabe, VorgabeKurztext, VorgabeLangtext, Checklistenfrage, VorgabeComment
from abschnitte.utils import render_textabschnitte from abschnitte.utils import render_textabschnitte
@@ -254,6 +255,138 @@ def standard_json(request, nummer):
return JsonResponse(doc_data, json_dumps_params={'indent': 2, 'ensure_ascii': False}, encoder=DjangoJSONEncoder) return JsonResponse(doc_data, json_dumps_params={'indent': 2, 'ensure_ascii': False}, encoder=DjangoJSONEncoder)
def standard_xml(request, nummer):
"""
Export a single Dokument as XML
"""
# Get the document with all related data
dokument = get_object_or_404(
Dokument.objects.prefetch_related(
'autoren', 'pruefende', 'vorgaben__thema',
'vorgaben__referenzen', 'vorgaben__stichworte',
'vorgaben__checklistenfragen', 'vorgaben__vorgabekurztext_set',
'vorgaben__vorgabelangtext_set', 'geltungsbereich_set',
'einleitung_set', 'changelog__autoren'
),
nummer=nummer
)
root = ET.Element('Vorgabendokument')
ET.SubElement(root, 'Typ').text = dokument.dokumententyp.name if dokument.dokumententyp else ""
ET.SubElement(root, 'Nummer').text = dokument.nummer
ET.SubElement(root, 'Name').text = dokument.name
autoren_element = ET.SubElement(root, 'Autoren')
for autor in dokument.autoren.all():
ET.SubElement(autoren_element, 'Autor').text = autor.name
pruefende_element = ET.SubElement(root, 'Pruefende')
for pruefender in dokument.pruefende.all():
ET.SubElement(pruefende_element, 'Pruefender').text = pruefender.name
gueltigkeit_element = ET.SubElement(root, 'Gueltigkeit')
ET.SubElement(gueltigkeit_element, 'Von').text = dokument.gueltigkeit_von.strftime("%Y-%m-%d") if dokument.gueltigkeit_von else ""
ET.SubElement(gueltigkeit_element, 'Bis').text = dokument.gueltigkeit_bis.strftime("%Y-%m-%d") if dokument.gueltigkeit_bis else None
ET.SubElement(root, 'SignaturCSO').text = dokument.signatur_cso
geltungsbereich_sections = dokument.geltungsbereich_set.all().order_by('order')
if geltungsbereich_sections:
geltungsbereich_element = ET.SubElement(root, 'Geltungsbereich')
abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt')
for gb in geltungsbereich_sections:
section = ET.SubElement(abschnitt_element, 'Teil')
section.set('typ', gb.abschnitttyp.abschnitttyp if gb.abschnitttyp else "text")
section.text = gb.inhalt
einleitung_sections = dokument.einleitung_set.all().order_by('order')
if einleitung_sections:
einleitung_element = ET.SubElement(root, 'Einleitung')
abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt')
for ei in einleitung_sections:
section = ET.SubElement(abschnitt_element, 'Teil')
section.set('typ', ei.abschnitttyp.abschnitttyp if ei.abschnitttyp else "text")
section.text = ei.inhalt
ET.SubElement(root, 'Ziel').text = ""
ET.SubElement(root, 'Grundlagen').text = ""
changelog_element = ET.SubElement(root, 'Changelog')
for cl in dokument.changelog.all().order_by('-datum'):
entry = ET.SubElement(changelog_element, 'Eintrag')
ET.SubElement(entry, 'Datum').text = cl.datum.strftime("%Y-%m-%d")
autoren = ET.SubElement(entry, 'Autoren')
for autor in cl.autoren.all():
ET.SubElement(autoren, 'Autor').text = autor.name
ET.SubElement(entry, 'Aenderung').text = cl.aenderung
anhaenge_element = ET.SubElement(root, 'Anhaenge')
ET.SubElement(anhaenge_element, 'Anhang').text = dokument.anhaenge
ET.SubElement(root, 'Verantwortlich').text = "Information Security Management BIT"
ET.SubElement(root, 'Klassifizierung').text = ""
glossar_element = ET.SubElement(root, 'Glossar')
vorgaben_element = ET.SubElement(root, 'Vorgaben')
for vorgabe in dokument.vorgaben.all().order_by('order'):
vorgabe_el = ET.SubElement(vorgaben_element, 'Vorgabe')
ET.SubElement(vorgabe_el, 'Nummer').text = str(vorgabe.nummer)
ET.SubElement(vorgabe_el, 'Titel').text = vorgabe.titel
ET.SubElement(vorgabe_el, 'Thema').text = vorgabe.thema.name if vorgabe.thema else ""
kurztext_sections = vorgabe.vorgabekurztext_set.all().order_by('order')
if kurztext_sections:
kurztext_element = ET.SubElement(vorgabe_el, 'Kurztext')
abschnitt = ET.SubElement(kurztext_element, 'Abschnitt')
for kt in kurztext_sections:
teil = ET.SubElement(abschnitt, 'Teil')
teil.set('typ', kt.abschnitttyp.abschnitttyp if kt.abschnitttyp else "text")
teil.text = kt.inhalt
langtext_sections = vorgabe.vorgabelangtext_set.all().order_by('order')
if langtext_sections:
langtext_element = ET.SubElement(vorgabe_el, 'Langtext')
abschnitt = ET.SubElement(langtext_element, 'Abschnitt')
for lt in langtext_sections:
teil = ET.SubElement(abschnitt, 'Teil')
teil.set('typ', lt.abschnitttyp.abschnitttyp if lt.abschnitttyp else "text")
teil.text = lt.inhalt
referenz_element = ET.SubElement(vorgabe_el, 'Referenzen')
for ref in vorgabe.referenzen.all():
ref_text = f"{ref.name_nummer}: {ref.name_text}" if ref.name_text else ref.name_nummer
ET.SubElement(referenz_element, 'Referenz').text = ref_text
vorgabe_gueltigkeit = ET.SubElement(vorgabe_el, 'Gueltigkeit')
ET.SubElement(vorgabe_gueltigkeit, 'Von').text = vorgabe.gueltigkeit_von.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_von else ""
ET.SubElement(vorgabe_gueltigkeit, 'Bis').text = vorgabe.gueltigkeit_bis.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_bis else None
checklistenfragen_element = ET.SubElement(vorgabe_el, 'Checklistenfragen')
for cf in vorgabe.checklistenfragen.all():
ET.SubElement(checklistenfragen_element, 'Frage').text = cf.frage
stichworte_element = ET.SubElement(vorgabe_el, 'Stichworte')
for stw in vorgabe.stichworte.all():
ET.SubElement(stichworte_element, 'Stichwort').text = stw.stichwort
xml_str = ET.tostring(root, encoding='unicode', method='xml')
xml_output = _prettify_xml(xml_str)
response = HttpResponse(xml_output, content_type='application/xml; charset=utf-8')
response['Content-Disposition'] = f'attachment; filename="{dokument.nummer}.xml"'
return response
def _prettify_xml(xml_string):
import xml.dom.minidom
dom = xml.dom.minidom.parseString(xml_string)
return dom.toprettyxml(indent=" ", encoding="UTF-8").decode('utf-8')
@login_required @login_required
def get_vorgabe_comments(request, vorgabe_id): def get_vorgabe_comments(request, vorgabe_id):
"""Get comments for a specific Vorgabe""" """Get comments for a specific Vorgabe"""