This commit is contained in:
nvrl committed 2026-02-19 18:32:24 +01:00
commit 9705979001
6 files changed
+65 -24

No files matched your search

+12 -12
View File
@@ -1,4 +1,7 @@
# --- Application Security ---
# --- Essential Site Configuration ---
# Your primary domain (e.g., holy.narl.io). Used to derive ALLOWED_HOSTS, CORS, and CSRF settings.
DOMAIN="localhost"
# Set to a long, random string in production (e.g. 50+ chars)
SECRET_KEY="django-insecure-replace-this-in-production"
@@ -8,15 +11,12 @@ DEBUG=true
# Custom URL for the Django Admin interface (e.g., my-secret-admin/)
ADMIN_URL="admin"
# --- Hosting & Networking ---
# The primary domain where your app is hosted (e.g., holy.narl.io)
ALLOWED_HOSTS=localhost,127.0.0.1,backend,holy.narl.io
# CSRF protection: Comma-separated list of trusted origins (MUST start with https:// in production)
CSRF_TRUSTED_ORIGINS=https://holy.narl.io
# CORS protection: Comma-separated list of allowed origins
CORS_ALLOWED_ORIGINS=https://holy.narl.io
# --- Advanced Networking (Optional, derived from DOMAIN if unset) ---
# ALLOWED_HOSTS=holy.narl.io,another-domain.com
# CSRF_TRUSTED_ORIGINS=https://holy.narl.io
# CORS_ALLOWED_ORIGINS=https://holy.narl.io
# FRONTEND_URL=https://holy.narl.io
# VITE_API_URL=https://holy.narl.io/api/
# --- SMTP Configuration (Required for Email Verification) ---
# For development, if EMAIL_HOST is empty, emails are printed to the console.
@@ -32,8 +32,8 @@ EMAIL_HOST_PASSWORD="your-password"
EMAIL_SKIP_CERT_VERIFICATION=false
# --- Frontend Configuration ---
# The base URL of the backend API (MUST end with /api/)
VITE_API_URL=https://holy.narl.io/api/
# Optional: defaults to ${DOMAIN}/api/ if not set
# VITE_API_URL=https://holy.narl.io/api/
VITE_ALLOWED_HOSTS=localhost,holy.narl.io
# --- Impressum / Contact Details (Required for German Law § 5 TMG) ---
@@ -0,0 +1,18 @@
# Generated by Django 6.0.2 on 2026-02-19 17:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0028_job_systemconfig'),
]
operations = [
migrations.AlterField(
model_name='job',
name='name',
field=models.CharField(choices=[('sync_flavors', 'Sync Holy Flavors'), ('cleanup_duplicates', 'Cleanup Duplicate Flavors'), ('backup_db', 'Database Backup'), ('seed_legacy', 'Seed Legacy Data')], max_length=100),
),
]
+1 -1
View File
@@ -241,7 +241,7 @@ class SystemConfig(models.Model):
class Job(models.Model):
"""Tracks background jobs, their status and scheduling."""
JOB_TYPES = [
('sync_flavors', 'Sync Shopify Flavors'),
('sync_flavors', 'Sync Holy Flavors'),
('cleanup_duplicates', 'Cleanup Duplicate Flavors'),
('backup_db', 'Database Backup'),
('seed_legacy', 'Seed Legacy Data'),
+8 -1
View File
@@ -919,7 +919,14 @@ class AdminViewSet(viewsets.ViewSet):
if next_run is not None:
from django.utils.dateparse import parse_datetime
job.next_run = parse_datetime(next_run)
from django.utils import timezone
parsed_dt = parse_datetime(next_run)
if parsed_dt:
# If it's naive (has no timezone info), assume it's local time
if timezone.is_naive(parsed_dt):
job.next_run = timezone.make_aware(parsed_dt, timezone.get_current_timezone())
else:
job.next_run = parsed_dt
elif interval is not None and job.interval_hours > 0 and not job.next_run:
from django.utils import timezone
job.next_run = timezone.now()
+14 -7
View File
@@ -26,8 +26,17 @@ SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-zos99ue2a89!4jrv4g@_b
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ.get('DEBUG', 'false').lower() == 'true'
ALLOWED_HOSTS_STRING = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1,backend,holy.narl.io')
ALLOWED_HOSTS = [host.strip() for host in ALLOWED_HOSTS_STRING.split(',')]
# Simplification: Use a single DOMAIN variable to derive multiple settings
DOMAIN = os.environ.get('DOMAIN', 'holy.narl.io')
# Helper to build lists from env or defaults
def get_env_list(var_name, default_list):
val = os.environ.get(var_name)
if val:
return [item.strip() for item in val.split(',')]
return default_list
ALLOWED_HOSTS = get_env_list('ALLOWED_HOSTS', ['localhost', '127.0.0.1', 'backend', 'worker', DOMAIN])
# Application definition
@@ -166,8 +175,7 @@ if not DEBUG:
SECURE_HSTS_PRELOAD = True
# Read CSRF trusted origins from environment variable
CSRF_TRUSTED_ORIGINS_STRING = os.environ.get('CSRF_TRUSTED_ORIGINS', 'https://holy.narl.io,http://localhost:5173')
CSRF_TRUSTED_ORIGINS = [origin.strip() for origin in CSRF_TRUSTED_ORIGINS_STRING.split(',')]
CSRF_TRUSTED_ORIGINS = get_env_list('CSRF_TRUSTED_ORIGINS', [f'https://{DOMAIN}', 'http://localhost:5173'])
# Custom User Model
AUTH_USER_MODEL = 'api.User'
@@ -188,10 +196,9 @@ REST_FRAMEWORK = {
}
# CORS
CORS_ALLOWED_ORIGINS_STRING = os.environ.get('CORS_ALLOWED_ORIGINS', 'https://holy.narl.io,http://localhost:5173,http://127.0.0.1:5173')
CORS_ALLOWED_ORIGINS = [origin.strip() for origin in CORS_ALLOWED_ORIGINS_STRING.split(',')]
CORS_ALLOWED_ORIGINS = get_env_list('CORS_ALLOWED_ORIGINS', [f'https://{DOMAIN}', 'http://localhost:5173', 'http://127.0.0.1:5173'])
FRONTEND_URL = os.environ.get('FRONTEND_URL', 'https://holy.narl.io').rstrip('/')
FRONTEND_URL = os.environ.get('FRONTEND_URL', f'https://{DOMAIN}').rstrip('/')
import os
# ... (near top of file)
+12 -3
View File
@@ -17,11 +17,15 @@ services:
- ./legacy:/app/legacy
environment:
- PYTHONUNBUFFERED=1
- DOMAIN=${DOMAIN:-holy.narl.io}
dns:
- 8.8.8.8
- 1.1.1.1
labels:
- "traefik.enable=true"
- "traefik.docker.network=narl"
- "traefik.http.routers.holy-energy-backend.priority=100"
- "traefik.http.routers.holy-energy-backend.rule=Host(`holy.narl.io`) && (PathPrefix(`/api`) || PathPrefix(`/admin/`) || PathPrefix(`/static`) || PathPrefix(`/media`))"
- "traefik.http.routers.holy-energy-backend.rule=Host(`${DOMAIN:-holy.narl.io}`) && (PathPrefix(`/api`) || PathPrefix(`/admin/`) || PathPrefix(`/static`) || PathPrefix(`/media`))"
- "traefik.http.routers.holy-energy-backend.entrypoints=websecure"
- "traefik.http.routers.holy-energy-backend.tls.certresolver=https_resolver"
- "traefik.http.services.holy-energy-backend.loadbalancer.server.port=8000"
@@ -40,8 +44,13 @@ services:
restart: unless-stopped
networks:
- internal
dns:
- 8.8.8.8
- 1.1.1.1
env_file:
- .env
environment:
- DOMAIN=${DOMAIN:-holy.narl.io}
volumes:
- ./backend:/app
- ./legacy:/app/legacy
@@ -53,7 +62,7 @@ services:
build:
context: ./frontend
args:
- VITE_API_URL=https://holy.narl.io/api/
- VITE_API_URL=https://${DOMAIN:-holy.narl.io}/api/
- VITE_IMPRESSUM_NAME=${VITE_IMPRESSUM_NAME}
- VITE_IMPRESSUM_STREET=${VITE_IMPRESSUM_STREET}
- VITE_IMPRESSUM_CITY=${VITE_IMPRESSUM_CITY}
@@ -74,7 +83,7 @@ services:
- "traefik.enable=true"
- "traefik.docker.network=narl"
- "traefik.http.routers.holy-energy-frontend.priority=10"
- "traefik.http.routers.holy-energy-frontend.rule=Host(`holy.narl.io`)"
- "traefik.http.routers.holy-energy-frontend.rule=Host(`${DOMAIN:-holy.narl.io}`)"
- "traefik.http.routers.holy-energy-frontend.entrypoints=websecure"
- "traefik.http.routers.holy-energy-frontend.tls.certresolver=https_resolver"
- "traefik.http.services.holy-energy-frontend.loadbalancer.server.port=80"