Compare commits

..

8 Commits

28 changed files with 107 additions and 899 deletions

View File

@@ -1,13 +0,0 @@
# Django Settings
SECRET_KEY=your-secret-key-here
DEBUG=True
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
# Security
CSRF_TRUSTED_ORIGINS=https://yourdomain.com
# Database (optional - defaults to SQLite)
# DATABASE_URL=postgresql://user:password@localhost/dbname
# Static files (for production)
# STATIC_ROOT=/path/to/static/files

12
.gitignore vendored
View File

@@ -15,16 +15,4 @@ package-lock.json
package.json
# Diagram cache directory
media/diagram_cache/
# Environment files
.env
.env.local
.env.production
# Database
*.sqlite3
*.sqlite3-journal
# Static files
staticfiles/
/static/

View File

@@ -28,7 +28,10 @@ RUN rm -rf /app/Dockerfile* \
/app/k8s \
/app/data-loader \
/app/keys \
/app/requirements.txt
/app/requirements.txt \
/app/node_modules \
/app/*.json \
/app/test_*.py
RUN python3 manage.py collectstatic
CMD ["gunicorn","--bind","0.0.0.0:8000","--workers","3","VorgabenUI.wsgi:application"]

View File

@@ -24,7 +24,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ.get("SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = bool(os.environ.get("DEBUG", default="0"))
DEBUG = bool(os.environ.get("DEBUG", default=0)
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS","127.0.0.1").split(",")
@@ -41,12 +41,8 @@ INSTALLED_APPS = [
'dokumente',
'abschnitte',
'stichworte',
'referenzen',
'rollen',
'mptt',
'pages',
'nested_admin',
'revproxy.apps.RevProxyConfig',
]
MIDDLEWARE = [

View File

@@ -1,25 +1,40 @@
"""
Django settings for VorgabenUI project.
Generated by 'django-admin startproject' using Django 5.2.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""
import os
from pathlib import Path
# Use absolute path to avoid any issues
BASE_DIR = Path('/home/adebaumann/development/vgui-cicd')
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
SECRET_KEY = 'django-insecure-dev-key-change-in-production'
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '429ti9tugj9güLLO))(G&G94KF452R3Fieaek$&6s#zlao-ca!#)_@j6*u+8s&bvfil^qyo%&-sov$ysi'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'data/db.sqlite3',
}
}
ALLOWED_HOSTS = ["10.128.128.144","localhost","127.0.0.1","*"]
TEMPLATES = [
{"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
}
]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
@@ -28,19 +43,16 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'abschnitte',
'mptt',
'rollen',
'referenzen',
'stichworte',
'dokumente',
'abschnitte',
'stichworte',
'referenzen',
'rollen',
'mptt',
'pages',
'nested_admin',
'revproxy',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -51,6 +63,8 @@ MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
INTERNAL_IPS = [ "127.0.0.1","10.128.128.130"]
ROOT_URLCONF = 'VorgabenUI.urls'
TEMPLATES = [
@@ -60,7 +74,6 @@ TEMPLATES = [
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
@@ -71,6 +84,22 @@ TEMPLATES = [
WSGI_APPLICATION = 'VorgabenUI.wsgi.application'
CSRF_TRUSTED_ORIGINS=["https://vorgabenportal.knowyoursecurity.com"]
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'data/db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@@ -86,19 +115,50 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = 'de-ch'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [
BASE_DIR / "static",
]
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = '/static/'
#STATIC_ROOT="/home/adebaumann/VorgabenUI/staticfiles/"
STATIC_ROOT="/app/staticfiles/"
STATICFILES_DIRS= (
os.path.join(BASE_DIR,"static"),
)
# Media files (User-uploaded content)
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Diagram cache settings
DIAGRAM_CACHE_DIR = 'diagram_cache' # relative to MEDIA_ROOT
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
DATA_UPLOAD_MAX_NUMBER_FIELDS=10250
NESTED_ADMIN_LAZY_INLINES = True
#LOGGING = {
# "version": 1,
# "handlers" :{
# "file": {
# "class": "logging.FileHandler",
# "filename": "general.log",
# "level": "DEBUG",
# },
# },
#}

View File

@@ -1 +0,0 @@
# Settings package for VorgabenUI

View File

@@ -1,104 +0,0 @@
"""
Base Django settings for VorgabenUI project.
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'dokumente',
'abschnitte',
'stichworte',
'referenzen',
'rollen',
'mptt',
'pages',
'nested_admin',
'revproxy.apps.RevProxyConfig',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'VorgabenUI.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'VorgabenUI.wsgi.application'
# Password validation
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
LANGUAGE_CODE = 'de-ch'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
# Media files (User-uploaded content)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Diagram cache settings
DIAGRAM_CACHE_DIR = 'diagram_cache' # relative to MEDIA_ROOT
# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
DATA_UPLOAD_MAX_NUMBER_FIELDS = 10250
NESTED_ADMIN_LAZY_INLINES = True
# Security settings
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
# Admin site configuration
ADMIN_SITE_HEADER = "Autorenumgebung"

View File

@@ -1,62 +0,0 @@
"""
Development settings for VorgabenUI project.
"""
from .base import *
import os
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-dev-key-change-in-production')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = bool(os.environ.get('DEBUG', default='True').lower() == 'true')
ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
# Database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'data/db.sqlite3',
}
}
# Static files
STATIC_ROOT = BASE_DIR / 'staticfiles'
# CSRF settings
CSRF_TRUSTED_ORIGINS = os.environ.get('CSRF_TRUSTED_ORIGINS', '').split(',') if os.environ.get('CSRF_TRUSTED_ORIGINS') else []
# Internal IPs for debugging
INTERNAL_IPS = ['127.0.0.1']
# Logging
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
'file': {
'class': 'logging.FileHandler',
'filename': BASE_DIR / 'django.log',
'level': 'DEBUG',
},
},
'root': {
'handlers': ['console'],
'level': 'INFO',
},
'loggers': {
'django': {
'handlers': ['console', 'file'],
'level': 'INFO',
'propagate': False,
},
'dokumente': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
'propagate': False,
},
},
}

View File

@@ -1,84 +0,0 @@
"""
Production settings for VorgabenUI project.
"""
from .base import *
import os
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', '').split(',')
# Database - use PostgreSQL in production
DATABASES = {
'default': {
'ENGINE': os.environ.get('DB_ENGINE', 'django.db.backends.postgresql'),
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', '5432'),
'OPTIONS': {
'connect_timeout': 60,
},
}
}
# Static files
STATIC_ROOT = '/app/staticfiles/'
# Security settings
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# CSRF settings
CSRF_TRUSTED_ORIGINS = os.environ.get('CSRF_TRUSTED_ORIGINS', '').split(',')
# Logging
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/app/logs/django.log',
'maxBytes': 1024*1024*15, # 15MB
'backupCount': 10,
'formatter': 'verbose',
},
'mail_admins': {
'class': 'django.utils.log.AdminEmailHandler',
'level': 'ERROR',
},
},
'root': {
'handlers': ['file'],
'level': 'INFO',
},
'loggers': {
'django': {
'handlers': ['file', 'mail_admins'],
'level': 'INFO',
'propagate': False,
},
'dokumente': {
'handlers': ['file'],
'level': 'INFO',
'propagate': False,
},
},
}

View File

@@ -18,12 +18,11 @@ from django.contrib import admin
from django.urls import include, path, re_path
from django.conf import settings
from django.conf.urls.static import static
from diagramm_proxy.views import DiagrammProxyView
import dokumente.views
import pages.views
import referenzen.views
admin.site.site_header = getattr(settings, 'ADMIN_SITE_HEADER', "Autorenumgebung")
admin.site.site_header="Autorenumgebung"
urlpatterns = [
path('',pages.views.startseite),
@@ -33,7 +32,6 @@ urlpatterns = [
path('stichworte/', include("stichworte.urls")),
path('referenzen/', referenzen.views.tree, name="referenz_tree"),
path('referenzen/<str:refid>/', referenzen.views.detail, name="referenz_detail"),
re_path(r'^diagramm/(?P<path>.*)$', DiagrammProxyView.as_view()),
]
# Serve static files

View File

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

Binary file not shown.

View File

@@ -1 +0,0 @@
# Diagram proxy module

View File

@@ -1,4 +0,0 @@
from revproxy.views import ProxyView
class DiagrammProxyView(ProxyView):
upstream = "http://svckroki:8000/"

View File

@@ -1,12 +1,6 @@
from django.contrib import admin
#from nested_inline.admin import NestedStackedInline, NestedModelAdmin
try:
from nested_admin import NestedStackedInline, NestedModelAdmin, NestedTabularInline
except ImportError:
# Fallback to regular admin if nested_admin is not available
NestedStackedInline = admin.StackedInline
NestedModelAdmin = admin.ModelAdmin
NestedTabularInline = admin.TabularInline
from nested_admin import NestedStackedInline, NestedModelAdmin, NestedTabularInline
from django import forms
from mptt.forms import TreeNodeMultipleChoiceField
from mptt.admin import DraggableMPTTAdmin
@@ -186,18 +180,7 @@ class DokumentAdmin(SortableAdminBase, NestedModelAdmin):
@admin.register(VorgabenTable)
class VorgabenTableAdmin(admin.ModelAdmin):
list_display = ['order', 'nummer', 'dokument', 'thema', 'titel', 'gueltigkeit_von', 'gueltigkeit_bis', 'get_status_display']
def get_status_display(self, obj):
"""
Display status with emoji indicators for better visibility.
"""
if obj.dokument.aktiv:
return "✅ Aktiv"
else:
return "❌ Inaktiv"
get_status_display.short_description = 'Status'
list_display = ['order', 'nummer', 'dokument', 'thema', 'titel', 'gueltigkeit_von', 'gueltigkeit_bis']
list_display_links = ['dokument']
list_editable = ['order', 'nummer', 'thema', 'titel', 'gueltigkeit_von', 'gueltigkeit_bis']
list_filter = ['dokument', 'thema', 'gueltigkeit_von', 'gueltigkeit_bis']
@@ -205,8 +188,6 @@ class VorgabenTableAdmin(admin.ModelAdmin):
autocomplete_fields = ['dokument', 'thema', 'stichworte', 'referenzen', 'relevanz']
ordering = ['order']
list_per_page = 100
date_hierarchy = 'gueltigkeit_von'
date_hierarchy = 'gueltigkeit_von'
fieldsets = (
('Grunddaten', {
@@ -258,7 +239,6 @@ class VorgabeAdmin(NestedModelAdmin):
def vorgabe_nummer(self, obj):
return obj.Vorgabennummer()
vorgabe_nummer.short_description = 'Vorgabennummer'
admin.site.register(Checklistenfrage)

View File

@@ -1,75 +0,0 @@
# Generated by Django 4.2.25 on 2025-11-04 15:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dokumente', '0009_alter_vorgabe_options_vorgabe_order'),
]
operations = [
migrations.CreateModel(
name='VorgabenTable',
fields=[
],
options={
'verbose_name': 'Vorgabe (Tabellenansicht)',
'verbose_name_plural': 'Vorgaben (Tabellenansicht)',
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('dokumente.vorgabe',),
),
migrations.AlterField(
model_name='dokument',
name='aktiv',
field=models.BooleanField(),
),
migrations.AlterField(
model_name='dokument',
name='gueltigkeit_bis',
field=models.DateField(blank=True, db_index=True, null=True),
),
migrations.AlterField(
model_name='dokument',
name='gueltigkeit_von',
field=models.DateField(blank=True, db_index=True, null=True),
),
migrations.AlterField(
model_name='dokument',
name='name',
field=models.CharField(db_index=True, max_length=255),
),
migrations.AlterField(
model_name='vorgabe',
name='gueltigkeit_bis',
field=models.DateField(blank=True, db_index=True, null=True),
),
migrations.AlterField(
model_name='vorgabe',
name='gueltigkeit_von',
field=models.DateField(db_index=True),
),
migrations.AlterField(
model_name='vorgabe',
name='nummer',
field=models.IntegerField(db_index=True),
),
migrations.AlterField(
model_name='vorgabe',
name='order',
field=models.IntegerField(db_index=True),
),
migrations.AlterField(
model_name='vorgabe',
name='titel',
field=models.CharField(db_index=True, max_length=255),
),
migrations.AddConstraint(
model_name='vorgabe',
constraint=models.UniqueConstraint(fields=('dokument', 'thema', 'nummer', 'gueltigkeit_von'), name='unique_vorgabe_active_period'),
),
]

View File

@@ -40,14 +40,14 @@ class Thema(models.Model):
class Dokument(models.Model):
nummer = models.CharField(max_length=50, primary_key=True)
dokumententyp = models.ForeignKey(Dokumententyp, on_delete=models.PROTECT)
name = models.CharField(max_length=255, db_index=True)
name = models.CharField(max_length=255)
autoren = models.ManyToManyField(Person, related_name='verfasste_dokumente')
pruefende = models.ManyToManyField(Person, related_name='gepruefte_dokumente')
gueltigkeit_von = models.DateField(null=True, blank=True, db_index=True)
gueltigkeit_bis = models.DateField(null=True, blank=True, db_index=True)
gueltigkeit_von = models.DateField(null=True, blank=True)
gueltigkeit_bis = models.DateField(null=True, blank=True)
signatur_cso = models.CharField(max_length=255, blank=True)
anhaenge = models.TextField(blank=True)
aktiv = models.BooleanField()
aktiv = models.BooleanField(blank=True)
def __str__(self):
return f"{self.nummer} {self.name}"
@@ -57,14 +57,14 @@ class Dokument(models.Model):
verbose_name="Dokument"
class Vorgabe(models.Model):
order = models.IntegerField(db_index=True)
nummer = models.IntegerField(db_index=True)
order = models.IntegerField()
nummer = models.IntegerField()
dokument = models.ForeignKey(Dokument, on_delete=models.CASCADE, related_name='vorgaben')
thema = models.ForeignKey(Thema, on_delete=models.PROTECT, blank=False)
titel = models.CharField(max_length=255, db_index=True)
titel = models.CharField(max_length=255)
referenzen = models.ManyToManyField(Referenz, blank=True)
gueltigkeit_von = models.DateField(db_index=True)
gueltigkeit_bis = models.DateField(blank=True,null=True, db_index=True)
gueltigkeit_von = models.DateField()
gueltigkeit_bis = models.DateField(blank=True,null=True)
stichworte = models.ManyToManyField(Stichwort, blank=True)
relevanz = models.ManyToManyField(Rolle,blank=True)
@@ -206,12 +206,6 @@ class Vorgabe(models.Model):
class Meta:
verbose_name_plural="Vorgaben"
ordering = ['order']
constraints = [
models.UniqueConstraint(
fields=['dokument', 'thema', 'nummer', 'gueltigkeit_von'],
name='unique_vorgabe_active_period'
),
]
class VorgabeLangtext(Textabschnitt):
abschnitt=models.ForeignKey(Vorgabe,on_delete=models.CASCADE)

View File

@@ -13,7 +13,7 @@ calendar=parsedatetime.Calendar()
def standard_list(request):
dokumente = Dokument.objects.select_related('dokumententyp').prefetch_related('vorgaben__thema').all()
dokumente = Dokument.objects.all()
return render(request, 'standards/standard_list.html',
{'dokumente': dokumente}
)
@@ -29,11 +29,7 @@ def standard_detail(request, nummer,check_date=""):
check_date = date.today()
standard.history = False
standard.check_date=check_date
vorgaben = list(standard.vorgaben.order_by("thema","nummer")
.select_related("thema","dokument")
.prefetch_related("relevanz", "referenzen",
"vorgabekurztext_set__abschnitttyp",
"vorgabelangtext_set__abschnitttyp")) # convert queryset to list so we can attach attributes
vorgaben = list(standard.vorgaben.order_by("thema","nummer").select_related("thema","dokument")) # convert queryset to list so we can attach attributes
standard.geltungsbereich_html = render_textabschnitte(standard.geltungsbereich_set.order_by("order").select_related("abschnitttyp"))
standard.einleitung_html=render_textabschnitte(standard.einleitung_set.order_by("order"))

View File

@@ -31,6 +31,6 @@
<div class="flex-fill">{% block content %}Main Content{% endblock %}</div>
<div class="col-md-2">{% block sidebar_right %}{% endblock %}</div>
</div>
<div>VorgabenUI v0.942</div>
<div>VorgabenUI v0.945</div>
</body>
</html>

View File

@@ -1,95 +0,0 @@
#!/usr/bin/env python
"""Test Django settings with apps added incrementally"""
import os
import sys
from pathlib import Path
# Base settings template
base_settings = """
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'test-key'
DEBUG = True
ALLOWED_HOSTS = []
INSTALLED_APPS = [
'django.contrib.contenttypes',
'django.contrib.auth',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
{apps}
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'test.db.sqlite3',
}
}
"""
# Apps to test
apps_to_test = [
"'dokumente'",
"'abschnitte'",
"'stichworte'",
"'referenzen'",
"'rollen'",
"'mptt'",
"'pages'",
"'nested_admin'",
"'revproxy'",
]
# Test apps incrementally
current_apps = ""
for i, app in enumerate(apps_to_test):
print(f"\n=== Testing with apps {i+1}/{len(apps_to_test)}: {app} ===")
# Add the next app
if current_apps:
current_apps += ",\n " + app
else:
current_apps = app
# Write settings file
settings_content = base_settings.format(apps=current_apps)
with open('test_settings.py', 'w') as f:
f.write(settings_content)
# Test the settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test_settings')
try:
# Clear Django's internal cache
if 'django.conf' in sys.modules:
del sys.modules['django.conf']
if 'django.conf.settings' in sys.modules:
del sys.modules['django.conf.settings']
if 'test_settings' in sys.modules:
del sys.modules['test_settings']
import django
from django.conf import settings
# Reset Django
if hasattr(settings, '_wrapped'):
settings._wrapped = None
django.setup()
print(f"✓ SUCCESS: Apps up to {app} work fine")
except Exception as e:
print(f"✗ FAILED: Error with {app}: {e}")
break
# Clean up
import os
if os.path.exists('test_settings.py'):
os.remove('test_settings.py')
if os.path.exists('test.db.sqlite3'):
os.remove('test.db.sqlite3')

View File

@@ -1,33 +0,0 @@
#!/usr/bin/env python
"""Test current settings file directly"""
import os
import sys
from pathlib import Path
# Set up environment like Django would
BASE_DIR = Path('.').resolve()
# Read and execute the settings file with proper context
settings_globals = {
'__name__': 'VorgabenUI.settings',
'__file__': 'VorgabenUI/settings.py',
'__package__': 'VorgabenUI',
'os': os,
'Path': Path,
'BASE_DIR': BASE_DIR,
}
with open('VorgabenUI/settings.py', 'r') as f:
settings_code = f.read()
print('=== Executing current settings file ===')
try:
exec(settings_code, settings_globals)
print('Settings executed successfully')
print('DATABASES:', settings_globals.get('DATABASES', 'NOT FOUND'))
print('SECRET_KEY:', settings_globals.get('SECRET_KEY', 'NOT FOUND'))
print('DEBUG:', settings_globals.get('DEBUG', 'NOT FOUND'))
except Exception as e:
print('Error executing settings:', e)
import traceback
traceback.print_exc()

View File

@@ -1,32 +0,0 @@
#!/usr/bin/env python
import os
import sys
# Change to project directory
os.chdir('/home/adebaumann/development/vgui-cicd')
sys.path.insert(0, '.')
print("Testing direct import of settings module...")
try:
import VorgabenUI.settings as settings_module
print("✓ Import successful")
# Check if attributes exist
print("Has DATABASES:", hasattr(settings_module, 'DATABASES'))
print("Has BASE_DIR:", hasattr(settings_module, 'BASE_DIR'))
if hasattr(settings_module, 'DATABASES'):
print("DATABASES value:", settings_module.DATABASES)
else:
print("DATABASES not found")
if hasattr(settings_module, 'BASE_DIR'):
print("BASE_DIR value:", settings_module.BASE_DIR)
else:
print("BASE_DIR not found")
except Exception as e:
print("✗ Import failed:", e)
import traceback
traceback.print_exc()

View File

@@ -1,31 +0,0 @@
#!/usr/bin/env python
"""Test Django settings loading"""
import os
import sys
import django
from django.conf import settings
# Set the settings module
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'VorgabenUI.settings')
print("=== Before Django setup ===")
print(f"Settings module: {os.environ.get('DJANGO_SETTINGS_MODULE')}")
try:
print("Calling django.setup()...")
django.setup()
print("Django setup completed successfully")
print("=== After Django setup ===")
print(f"Settings configured: {settings.configured}")
print(f"Available attributes: {[attr for attr in dir(settings) if not attr.startswith('_')]}")
if hasattr(settings, 'DATABASES'):
print(f"DATABASES: {settings.DATABASES}")
else:
print("DATABASES not found in settings")
except Exception as e:
print(f"Error during Django setup: {e}")
import traceback
traceback.print_exc()

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env python
import os
import sys
import subprocess
# Change to project directory
os.chdir('/home/adebaumann/development/vgui-cicd')
# Clear Python cache
subprocess.run(['find', '.', '-name', '*.pyc', '-delete'], capture_output=True)
subprocess.run(['find', '.', '-name', '__pycache__', '-type', 'd', '-exec', 'rm', '-rf', '{}', '+'], capture_output=True)
# Set environment variable
os.environ['DJANGO_SETTINGS_MODULE'] = 'VorgabenUI.settings'
# Test Django import
import django
from django.conf import settings
try:
django.setup()
print('✓ Django setup successful')
print('DATABASES:', settings.DATABASES)
print('BASE_DIR:', getattr(settings, 'BASE_DIR', 'NOT SET'))
except Exception as e:
print('✗ Django setup failed:', e)
import traceback
traceback.print_exc()

View File

@@ -1,56 +0,0 @@
#!/usr/bin/env python
"""Test minimal Django settings"""
import os
import sys
from pathlib import Path
# Create a minimal settings file
minimal_settings = """
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'test-key'
DEBUG = True
ALLOWED_HOSTS = []
INSTALLED_APPS = [
'django.contrib.contenttypes',
'django.contrib.auth',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'test.db.sqlite3',
}
}
"""
# Write minimal settings to a file
with open('minimal_settings.py', 'w') as f:
f.write(minimal_settings)
# Test with minimal settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'minimal_settings')
import django
from django.conf import settings
print("=== Testing with minimal settings ===")
try:
django.setup()
print("Django setup completed successfully")
print(f"DATABASES: {settings.DATABASES}")
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()
# Clean up
import os
os.remove('minimal_settings.py')

View File

@@ -1,38 +0,0 @@
#!/usr/bin/env python
"""
Simple script to test Vorgaben sanity checking
"""
import os
import sys
import django
# Setup Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'VorgabenUI.settings')
django.setup()
from dokumente.utils import check_vorgabe_conflicts, format_conflict_report
def main():
print("Running Vorgaben sanity check...")
print("=" * 50)
# Check for conflicts
conflicts = check_vorgabe_conflicts()
# Generate and display report
report = format_conflict_report(conflicts, verbose=True)
print(report)
print("=" * 50)
if conflicts:
print(f"\n⚠️ Found {len(conflicts)} conflicts that need attention!")
sys.exit(1)
else:
print("✅ All Vorgaben are valid!")
sys.exit(0)
if __name__ == "__main__":
main()

View File

@@ -1 +0,0 @@
# Test package for VorgabenUI

View File

@@ -1,149 +0,0 @@
"""
Integration tests for VorgabenUI application.
"""
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth.models import User
from datetime import date, timedelta
from dokumente.models import Dokument, Dokumententyp, Vorgabe, Thema
class DokumentIntegrationTestCase(TestCase):
"""Test document functionality end-to-end."""
def setUp(self):
self.client = Client()
self.dokumententyp = Dokumententyp.objects.create(
name="Test Typ",
verantwortliche_ve="Test VE"
)
self.dokument = Dokument.objects.create(
nummer="TEST-001",
name="Test Dokument",
dokumententyp=self.dokumententyp,
gueltigkeit_von=date.today(),
aktiv=True
)
self.thema = Thema.objects.create(
name="Test Thema",
erklaerung="Test Erklärung"
)
self.vorgabe = Vorgabe.objects.create(
order=1,
nummer=1,
dokument=self.dokument,
thema=self.thema,
titel="Test Vorgabe",
gueltigkeit_von=date.today()
)
def test_standard_list_view(self):
"""Test that standard list view loads and displays documents."""
response = self.client.get(reverse('standard_list'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "TEST-001")
self.assertContains(response, "Test Dokument")
def test_standard_detail_view(self):
"""Test that standard detail view loads and displays document details."""
response = self.client.get(
reverse('standard_detail', kwargs={'nummer': 'TEST-001'})
)
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Test Dokument")
self.assertContains(response, "Test Vorgabe")
def test_standard_json_view(self):
"""Test that JSON endpoint returns valid data."""
response = self.client.get(
reverse('standard_json', kwargs={'nummer': 'TEST-001'})
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
def test_vorgabe_status_calculation(self):
"""Test vorgabe status calculation for different dates."""
# Test active vorgabe
self.assertEqual(self.vorgabe.get_status(), 'active')
# Test future vorgabe
future_date = date.today() + timedelta(days=30)
future_vorgabe = Vorgabe.objects.create(
order=2,
nummer=2,
dokument=self.dokument,
thema=self.thema,
titel="Future Vorgabe",
gueltigkeit_von=future_date
)
self.assertEqual(future_vorgabe.get_status(), 'future')
# Test expired vorgabe
past_date = date.today() - timedelta(days=30)
expired_vorgabe = Vorgabe.objects.create(
order=3,
nummer=3,
dokument=self.dokument,
thema=self.thema,
titel="Expired Vorgabe",
gueltigkeit_von=past_date,
gueltigkeit_bis=date.today() - timedelta(days=1)
)
self.assertEqual(expired_vorgabe.get_status(), 'expired')
class SearchIntegrationTestCase(TestCase):
"""Test search functionality."""
def setUp(self):
self.client = Client()
# Create test data for search testing
self.dokumententyp = Dokumententyp.objects.create(
name="Test Typ",
verantwortliche_ve="Test VE"
)
self.dokument = Dokument.objects.create(
nummer="SEARCH-001",
name="Searchable Document",
dokumententyp=self.dokumententyp,
gueltigkeit_von=date.today(),
aktiv=True
)
def test_search_view_loads(self):
"""Test that search view loads."""
response = self.client.get(reverse('search'))
self.assertEqual(response.status_code, 200)
def test_search_functionality(self):
"""Test search functionality with query parameters."""
response = self.client.get(reverse('search'), {'q': 'Searchable'})
self.assertEqual(response.status_code, 200)
class AdminIntegrationTestCase(TestCase):
"""Test admin interface functionality."""
def setUp(self):
self.user = User.objects.create_superuser(
username='admin',
email='admin@example.com',
password='testpass123'
)
self.client = Client()
self.client.login(username='admin', password='testpass123')
def test_admin_accessible(self):
"""Test that admin interface is accessible."""
response = self.client.get('/autorenumgebung/')
self.assertEqual(response.status_code, 200)
def test_dokument_admin_list(self):
"""Test document admin list view."""
response = self.client.get('/autorenumgebung/dokumente/dokument/')
self.assertEqual(response.status_code, 200)
def test_vorgabe_admin_list(self):
"""Test vorgabe admin list view."""
response = self.client.get('/autorenumgebung/dokumente/vorgabentable/')
self.assertEqual(response.status_code, 200)