update module
This commit is contained in:
parent
aac1cdb118
commit
236e9e6438
3 changed files with 5 additions and 252 deletions
|
|
@ -2,6 +2,7 @@ from pathlib import Path
|
||||||
import os
|
import os
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
DATA_DIR = Path(os.environ.get("FRAGDENRAT_DATA_DIR", str(BASE_DIR)))
|
||||||
|
|
||||||
SECRET_KEY = os.environ.get("SECRET_KEY", "dev-secret-key-change-me")
|
SECRET_KEY = os.environ.get("SECRET_KEY", "dev-secret-key-change-me")
|
||||||
DEBUG = os.environ.get("DEBUG", "1").lower() in ("1", "true", "yes", "on")
|
DEBUG = os.environ.get("DEBUG", "1").lower() in ("1", "true", "yes", "on")
|
||||||
|
|
@ -50,7 +51,7 @@ WSGI_APPLICATION = "fragdenrat.wsgi.application"
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
"default": {
|
"default": {
|
||||||
"ENGINE": "django.db.backends.sqlite3",
|
"ENGINE": "django.db.backends.sqlite3",
|
||||||
"NAME": str(BASE_DIR / "db.sqlite3"),
|
"NAME": str(DATA_DIR / "db.sqlite3"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,5 +62,5 @@ USE_TZ = True
|
||||||
|
|
||||||
STATIC_URL = "/static/"
|
STATIC_URL = "/static/"
|
||||||
STATICFILES_DIRS = [BASE_DIR / "assets"]
|
STATICFILES_DIRS = [BASE_DIR / "assets"]
|
||||||
STATIC_ROOT = BASE_DIR / "staticfiles"
|
STATIC_ROOT = DATA_DIR / "staticfiles"
|
||||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
250
fragify.py
250
fragify.py
|
|
@ -1,250 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Fragify - A web application to generate prefilled FragDenStaat.de request links
|
|
||||||
"""
|
|
||||||
|
|
||||||
import falcon
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
from urllib.parse import urlencode
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from jinja2 import Environment, FileSystemLoader
|
|
||||||
|
|
||||||
SITE_BASE_URL = os.environ.get('FRAGIFY_BASE_URL', 'http://localhost:8000')
|
|
||||||
|
|
||||||
class BaseTemplateResource:
|
|
||||||
"""Base class for resources that need template rendering"""
|
|
||||||
|
|
||||||
def _get_template_dir(self):
|
|
||||||
"""Get the template directory path, handling both development and installed environments"""
|
|
||||||
# Allow overriding via environment variable (for packaged deployments)
|
|
||||||
env_dir = os.environ.get('FRAGIFY_TEMPLATES_DIR')
|
|
||||||
if env_dir and os.path.exists(env_dir):
|
|
||||||
return env_dir
|
|
||||||
|
|
||||||
# Get the directory where this script is located
|
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
|
|
||||||
# Try development templates first
|
|
||||||
dev_template_dir = os.path.join(script_dir, 'templates')
|
|
||||||
if os.path.exists(dev_template_dir):
|
|
||||||
return dev_template_dir
|
|
||||||
|
|
||||||
# Try to find templates relative to the executable
|
|
||||||
try:
|
|
||||||
# If we're running from a Nix store, look for templates in share/fragify
|
|
||||||
if '/nix/store/' in script_dir:
|
|
||||||
# Go up from bin to share/fragify/templates
|
|
||||||
share_dir = os.path.join(script_dir, '..', 'share', 'fragify', 'templates')
|
|
||||||
if os.path.exists(share_dir):
|
|
||||||
return share_dir
|
|
||||||
|
|
||||||
# Alternative: look for templates in the same store path
|
|
||||||
store_root = script_dir.split('/nix/store/')[1].split('/')[0]
|
|
||||||
store_path = f"/nix/store/{store_root}"
|
|
||||||
alt_share_dir = os.path.join(store_path, 'share', 'fragify', 'templates')
|
|
||||||
if os.path.exists(alt_share_dir):
|
|
||||||
return alt_share_dir
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Last resort: try to find any templates directory
|
|
||||||
for root, dirs, files in os.walk('/nix/store'):
|
|
||||||
if 'templates' in dirs and 'index.html' in os.listdir(os.path.join(root, 'templates')):
|
|
||||||
return os.path.join(root, 'templates')
|
|
||||||
|
|
||||||
# Fallback to current directory
|
|
||||||
return dev_template_dir
|
|
||||||
|
|
||||||
class FragifyApp(BaseTemplateResource):
|
|
||||||
def __init__(self):
|
|
||||||
self.fragdenstaat_api = "https://fragdenstaat.de/api/v1"
|
|
||||||
# Setup Jinja2 template environment
|
|
||||||
template_dir = self._get_template_dir()
|
|
||||||
print(f"Using template directory: {template_dir}")
|
|
||||||
self.jinja_env = Environment(loader=FileSystemLoader(template_dir))
|
|
||||||
|
|
||||||
def on_get(self, req, resp):
|
|
||||||
"""Serve the main page"""
|
|
||||||
template = self.jinja_env.get_template('index.html')
|
|
||||||
resp.content_type = 'text/html; charset=utf-8'
|
|
||||||
resp.text = template.render(
|
|
||||||
meta_title='Fragify – Anfragelinks für FragDenStaat',
|
|
||||||
meta_description='Erstelle vorausgefüllte Anfragelinks für FragDenStaat.de, suche Behörden, füge Betreff und Text hinzu und teile den Link.',
|
|
||||||
canonical_url=f"{SITE_BASE_URL}/"
|
|
||||||
)
|
|
||||||
|
|
||||||
def on_post(self, req, resp):
|
|
||||||
"""Handle form submission and generate link"""
|
|
||||||
try:
|
|
||||||
# Parse form data - use get_param for form fields
|
|
||||||
publicbody_id = req.get_param('publicbody_id', default='')
|
|
||||||
subject = req.get_param('subject', default='')
|
|
||||||
body = req.get_param('body', default='')
|
|
||||||
|
|
||||||
# Generate FragDenStaat.de link
|
|
||||||
base_url = "https://fragdenstaat.de/anfrage-stellen/"
|
|
||||||
if publicbody_id:
|
|
||||||
base_url += f"an/{publicbody_id}/"
|
|
||||||
|
|
||||||
params = {}
|
|
||||||
if subject:
|
|
||||||
params['subject'] = subject
|
|
||||||
if body:
|
|
||||||
params['body'] = body
|
|
||||||
|
|
||||||
if params:
|
|
||||||
base_url += "?" + urlencode(params)
|
|
||||||
|
|
||||||
resp.content_type = 'application/json'
|
|
||||||
resp.text = json.dumps({
|
|
||||||
'success': True,
|
|
||||||
'link': base_url
|
|
||||||
})
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
resp.status = falcon.HTTP_500
|
|
||||||
resp.content_type = 'application/json'
|
|
||||||
resp.text = json.dumps({
|
|
||||||
'success': False,
|
|
||||||
'error': str(e)
|
|
||||||
})
|
|
||||||
|
|
||||||
class ImpressumResource(BaseTemplateResource):
|
|
||||||
def __init__(self):
|
|
||||||
template_dir = self._get_template_dir()
|
|
||||||
self.jinja_env = Environment(loader=FileSystemLoader(template_dir))
|
|
||||||
|
|
||||||
def on_get(self, req, resp):
|
|
||||||
"""Serve the Impressum page"""
|
|
||||||
template = self.jinja_env.get_template('impressum.html')
|
|
||||||
resp.content_type = 'text/html; charset=utf-8'
|
|
||||||
resp.text = template.render(
|
|
||||||
meta_title='Impressum – Fragify',
|
|
||||||
meta_description='Impressum für Fragify.',
|
|
||||||
canonical_url=f"{SITE_BASE_URL}/impressum",
|
|
||||||
noindex=True
|
|
||||||
)
|
|
||||||
|
|
||||||
class DatenschutzResource(BaseTemplateResource):
|
|
||||||
def __init__(self):
|
|
||||||
template_dir = self._get_template_dir()
|
|
||||||
self.jinja_env = Environment(loader=FileSystemLoader(template_dir))
|
|
||||||
|
|
||||||
def on_get(self, req, resp):
|
|
||||||
"""Serve the Datenschutz page"""
|
|
||||||
template = self.jinja_env.get_template('datenschutz.html')
|
|
||||||
resp.content_type = 'text/html; charset=utf-8'
|
|
||||||
resp.text = template.render(
|
|
||||||
meta_title='Datenschutz – Fragify',
|
|
||||||
meta_description='Datenschutzerklärung für Fragify. Keine Cookies, es werden nur Anfragen an die FragDenStaat-API gestellt.',
|
|
||||||
canonical_url=f"{SITE_BASE_URL}/datenschutz",
|
|
||||||
noindex=True
|
|
||||||
)
|
|
||||||
|
|
||||||
class PublicBodiesResource:
|
|
||||||
def __init__(self):
|
|
||||||
self.fragdenstaat_api = "https://fragdenstaat.de/api/v1"
|
|
||||||
|
|
||||||
def on_get(self, req, resp):
|
|
||||||
"""API endpoint to search public bodies"""
|
|
||||||
try:
|
|
||||||
search = req.get_param('search', default='')
|
|
||||||
page = req.get_param('page', default=1)
|
|
||||||
|
|
||||||
# Build API URL
|
|
||||||
url = f"{self.fragdenstaat_api}/publicbody/"
|
|
||||||
params = {
|
|
||||||
'limit': 20,
|
|
||||||
'offset': (int(page) - 1) * 20
|
|
||||||
}
|
|
||||||
|
|
||||||
if search:
|
|
||||||
params['q'] = search
|
|
||||||
|
|
||||||
# Make request to FragDenStaat API
|
|
||||||
response = requests.get(url, params=params, timeout=10)
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
resp.content_type = 'application/json'
|
|
||||||
resp.text = json.dumps(data)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
resp.status = falcon.HTTP_500
|
|
||||||
resp.content_type = 'application/json'
|
|
||||||
resp.text = json.dumps({
|
|
||||||
'error': str(e),
|
|
||||||
'results': [],
|
|
||||||
'next': None
|
|
||||||
})
|
|
||||||
|
|
||||||
class RobotsResource:
|
|
||||||
def on_get(self, req, resp):
|
|
||||||
resp.content_type = 'text/plain; charset=utf-8'
|
|
||||||
resp.text = f"""User-agent: *
|
|
||||||
Allow: /
|
|
||||||
Sitemap: {SITE_BASE_URL}/sitemap.xml
|
|
||||||
"""
|
|
||||||
|
|
||||||
class SitemapResource:
|
|
||||||
def on_get(self, req, resp):
|
|
||||||
resp.content_type = 'application/xml; charset=utf-8'
|
|
||||||
resp.text = f"""<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
||||||
<url><loc>{SITE_BASE_URL}/</loc></url>
|
|
||||||
<url><loc>{SITE_BASE_URL}/impressum</loc></url>
|
|
||||||
<url><loc>{SITE_BASE_URL}/datenschutz</loc></url>
|
|
||||||
</urlset>
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Create Falcon application
|
|
||||||
app = falcon.App()
|
|
||||||
|
|
||||||
# Discover static assets directory
|
|
||||||
STATIC_DIR = os.environ.get('FRAGIFY_STATIC_DIR')
|
|
||||||
if not STATIC_DIR:
|
|
||||||
# Prefer local assets folder in development (relative to this file)
|
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
candidate = os.path.join(script_dir, 'assets')
|
|
||||||
if os.path.isdir(candidate):
|
|
||||||
STATIC_DIR = candidate
|
|
||||||
else:
|
|
||||||
# Try current working directory (useful when running packaged binary from project root)
|
|
||||||
cwd_candidate = os.path.join(os.getcwd(), 'assets')
|
|
||||||
if os.path.isdir(cwd_candidate):
|
|
||||||
STATIC_DIR = cwd_candidate
|
|
||||||
else:
|
|
||||||
# Fallback to packaged location under share
|
|
||||||
STATIC_DIR = os.path.join(script_dir, '..', 'share', 'fragify', 'assets')
|
|
||||||
|
|
||||||
# Add routes
|
|
||||||
fragify = FragifyApp()
|
|
||||||
impressum = ImpressumResource()
|
|
||||||
datenschutz = DatenschutzResource()
|
|
||||||
publicbodies = PublicBodiesResource()
|
|
||||||
robots = RobotsResource()
|
|
||||||
sitemap = SitemapResource()
|
|
||||||
|
|
||||||
app.add_route('/', fragify)
|
|
||||||
app.add_route('/impressum', impressum)
|
|
||||||
app.add_route('/datenschutz', datenschutz)
|
|
||||||
app.add_route('/api/publicbodies', publicbodies)
|
|
||||||
app.add_route('/robots.txt', robots)
|
|
||||||
app.add_route('/sitemap.xml', sitemap)
|
|
||||||
|
|
||||||
# Static file route
|
|
||||||
if STATIC_DIR and os.path.isdir(STATIC_DIR):
|
|
||||||
app.add_static_route('/static', STATIC_DIR)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import wsgiref.simple_server
|
|
||||||
|
|
||||||
print("Starting Fragify web application...")
|
|
||||||
print("Open your browser and navigate to: http://localhost:8000")
|
|
||||||
print(f"Serving static assets from: {STATIC_DIR}")
|
|
||||||
|
|
||||||
httpd = wsgiref.simple_server.make_server('localhost', 8000, app)
|
|
||||||
httpd.serve_forever()
|
|
||||||
|
|
@ -54,6 +54,8 @@ in
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
"static-map" = "/static=${pkgs.fragdenrat}/share/fragdenrat/assets";
|
"static-map" = "/static=${pkgs.fragdenrat}/share/fragdenrat/assets";
|
||||||
|
# Ensure Python can import the project package
|
||||||
|
pythonpath = "${pkgs.fragdenrat}/share/fragdenrat";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue