DB/model Add Conversion model + ConversionStatus enum (pending, processing, ready, failed) Alembic migrations: create conversions table, indexes, unique (source_event_media_id, target_format, file_hash), and NOT NULL on file_hash API Enqueue on upload (ppt|pptx|odp) in routes/eventmedia.py: compute sha256, upsert Conversion, enqueue job New routes: POST /api/conversions/<media_id>/pdf — ensure/enqueue conversion GET /api/conversions/<media_id>/status — latest status/details GET /api/files/converted/<path> — serve converted PDFs Register conversions blueprint in wsgi Worker server/worker.py: convert_event_media_to_pdf Calls Gotenberg /forms/libreoffice/convert, writes to server/media/converted/ Updates Conversion status, timestamps, error messages Fix media root resolution to /server/media Prefer function enqueue over string path; expose server.worker in package init for RQ string compatibility Queue/infra server/task_queue.py: RQ queue helper (REDIS_URL, default redis://redis:6379/0) docker-compose: Add redis and gotenberg services Add worker service (rq worker conversions) Pass REDIS_URL and GOTENBERG_URL to server/worker Mount shared media volume in prod for API/worker parity docker-compose.override: Add dev redis/gotenberg/worker services Ensure PYTHONPATH + working_dir allow importing server.worker Use rq CLI instead of python -m rq for worker Dashboard dev: run as appropriate user/root and pre-create/chown caches to avoid EACCES Dashboard dev UX Vite: set cacheDir .vite to avoid EACCES in node_modules Disable Node inspector by default to avoid port conflicts Docs Update copilot-instructions.md with conversion system: flow, services, env vars, endpoints, storage paths, and data model
54 lines
1.6 KiB
Python
54 lines
1.6 KiB
Python
# server/wsgi.py
|
||
from server.routes.eventmedia import eventmedia_bp
|
||
from server.routes.files import files_bp
|
||
from server.routes.events import events_bp
|
||
from server.routes.conversions import conversions_bp
|
||
from server.routes.holidays import holidays_bp
|
||
from server.routes.academic_periods import academic_periods_bp
|
||
from server.routes.groups import groups_bp
|
||
from server.routes.clients import clients_bp
|
||
from server.database import Session, engine
|
||
from flask import Flask, jsonify, send_from_directory, request
|
||
import glob
|
||
import os
|
||
import sys
|
||
sys.path.append('/workspace')
|
||
|
||
app = Flask(__name__)
|
||
|
||
# Blueprints importieren und registrieren
|
||
|
||
app.register_blueprint(clients_bp)
|
||
app.register_blueprint(groups_bp)
|
||
app.register_blueprint(events_bp)
|
||
app.register_blueprint(eventmedia_bp)
|
||
app.register_blueprint(files_bp)
|
||
app.register_blueprint(holidays_bp)
|
||
app.register_blueprint(academic_periods_bp)
|
||
app.register_blueprint(conversions_bp)
|
||
|
||
|
||
@app.route("/health")
|
||
def health():
|
||
return jsonify(status="ok")
|
||
|
||
|
||
@app.route("/")
|
||
def index():
|
||
return "Hello from Infoscreen‐API!"
|
||
|
||
|
||
@app.route("/screenshots/<uuid>")
|
||
def get_screenshot(uuid):
|
||
pattern = os.path.join("screenshots", f"{uuid}*.jpg")
|
||
files = glob.glob(pattern)
|
||
if not files:
|
||
# Dummy-Bild als Redirect oder direkt als Response
|
||
return jsonify({"error": "Screenshot not found", "dummy": "https://placehold.co/400x300?text=No+Screenshot"}), 404
|
||
filename = os.path.basename(files[0])
|
||
return send_from_directory("screenshots", filename)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
app.run(host="0.0.0.0", port=8000, debug=True)
|