From 713bc5fdf89aafa60a775d9898fb0f7b085e8402 Mon Sep 17 00:00:00 2001 From: Blackwhitebear8 Date: Tue, 12 Aug 2025 17:37:24 +0200 Subject: [PATCH] Upload files to "/" --- app.py | 301 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 app.py diff --git a/app.py b/app.py new file mode 100644 index 0000000..e6b5e64 --- /dev/null +++ b/app.py @@ -0,0 +1,301 @@ +# -*- coding: utf-8 -*- +""" +Een Flask-applicatie die elke Discord-webhook op een dynamisch pad kan ontvangen, +weergeeft als HTML, en doorstuurt naar een dynamisch gegenereerde URL +op basis van een .env configuratie. + +Vereisten: +pip install Flask python-dotenv requests Markdown waitress jinja2 + +Hoe te gebruiken: +1. Maak een `.env` bestand aan in dezelfde map. +2. Definieer 'OUTGOING_WEBHOOK_BASE_URL' en optioneel 'OUTGOING_WEBHOOK_PARAMS'. +3. Sla dit bestand op als `app.py`. +4. Voer het uit vanuit je terminal: `python app.py` +5. Stuur een POST-verzoek naar een willekeurig endpoint, + bijv. http://127.0.0.1:5001/webhook/any-string-you-want +""" +import os +import datetime +import markdown +import requests +import json +from flask import Flask, request, render_template, jsonify, abort, url_for +from dotenv import load_dotenv +from jinja2 import DictLoader + +# Laad de omgevingsvariabelen uit het .env-bestand +load_dotenv() + +# Initialiseer de Flask-applicatie +app = Flask(__name__) + +# Lees de configuratie uit de omgevingsvariabelen. +OUTGOING_WEBHOOK_BASE_URL = os.getenv('OUTGOING_WEBHOOK_BASE_URL') +OUTGOING_WEBHOOK_PARAMS = os.getenv('OUTGOING_WEBHOOK_PARAMS', '') # Standaard lege string + +if not OUTGOING_WEBHOOK_BASE_URL: + print("WAARSCHUWING: OUTGOING_WEBHOOK_BASE_URL niet gevonden in .env. Doorsturen van webhooks is uitgeschakeld.") + +# In-memory opslag voor de laatst ontvangen webhook-data per ID. +# Deze wordt dynamisch gevuld als er nieuwe webhooks binnenkomen. +webhook_data_store = {} + +# --- HTML TEMPLATES (ongewijzigd) --- +BASE_TEMPLATE = """ + + + + + + Discord Webhook Weergave + + + + + +
{% block content %}{% endblock %}
+ +""" +HOME_TEMPLATE = """ +{% extends "base.html" %} +{% block content %} +

Ontvangen Webhooks

+
+

Hieronder staat een lijst van alle webhooks die ten minste één keer een bericht hebben ontvangen. Klik op een webhook om de laatste data te zien.

+

Inkomende URL's hebben de vorm /webhook/<naam>.

+

Uitgaande URL: {{ base_url or 'Niet geconfigureerd' }}<naam>{{ params }}

+
+ +{% endblock %} +""" +FORWARD_WEBHOOK_TEMPLATE = """ +{% if data and data.username != 'Nog geen data' %} +
+ Avatar +
+
+ {{ data.username or 'Onbekende Bot' }} + {{ data.received_at }} +
+ {% if data.content %}
{{ data.content }}
{% endif %} + {% for embed in data.embeds %} +
+
+ {% if embed.author %}
{% if embed.author.icon_url %}{% endif %}{% if embed.author.url %}{{ embed.author.name }}{% else %}{{ embed.author.name }}{% endif %}
{% endif %} + {% if embed.title %}
{% if embed.url %}{{ embed.title }}{% else %}{{ embed.title }}{% endif %}
{% endif %} + {% if embed.description %}
{{ embed.description | markdown }}
{% endif %} + {% if embed.fields %} +
+ {% for field in embed.fields %} +
+
{{ field.name }}
+
{{ field.value | markdown }}
+
+ {% endfor %} +
+ {% endif %} +
+ {% if embed.thumbnail and embed.thumbnail.url %} +
+ Thumbnail +
+ {% endif %} + {% if embed.image and embed.image.url %} +
+ Embed Image +
+ {% endif %} + {% if embed.footer %} + + {% endif %} +
+ {% endfor %} +
+
+{% else %} +

{{ data.content }}

+{% endif %} +""" +UI_WEBHOOK_VIEW_TEMPLATE = """ +{% extends "base.html" %} +{% block content %} + ← Terug naar overzicht +

Laatste bericht voor: {{ webhook_id | capitalize }}

+ {{ content | safe }} +{% endblock %} +""" + +# Configureer de Jinja2 loader +app.jinja_loader = DictLoader({ + 'base.html': BASE_TEMPLATE, + 'home.html': HOME_TEMPLATE, + 'forward_webhook.html': FORWARD_WEBHOOK_TEMPLATE, + 'ui_webhook_view.html': UI_WEBHOOK_VIEW_TEMPLATE, +}) + +@app.template_filter('markdown') +def markdown_filter(s): + """Rendert markdown en verwijdert de omringende

tags.""" + if not s: + return "" + html = markdown.markdown(s, extensions=['fenced_code', 'nl2br']) + if html.startswith('

') and html.endswith('

'): + html = html[3:-4] + return html + +def forward_webhook(data, target_url, webhook_id): + """Genereert simpele HTML en stuurt dit door naar de opgegeven target_url.""" + if not target_url: + print(f"Skipping forwarding voor webhook '{webhook_id}': geen uitgaande URL geconfigureerd.") + return + + try: + html_parts = [] + for embed in data.get('embeds', []): + if embed.get('author') and embed.get('author').get('name'): + html_parts.append(f"{embed.get('author').get('name')}") + if embed.get('title'): + title, url = embed.get('title'), embed.get('url') + html_parts.append(f"{title}" if url else f"{title}") + if embed.get('description'): + html_parts.append(markdown_filter(embed.get('description'))) + if embed.get('fields'): + for field in embed.get('fields'): + html_parts.append(f"
{field.get('name', '')}
{markdown_filter(field.get('value', ''))}") + if embed.get('image') and embed.get('image').get('url'): + html_parts.append(f"
Embed Image") + html_content = "
".join(html_parts) + + plain_text_parts = [] + if data.get('username'): plain_text_parts.append(data.get('username')) + if data.get('content'): plain_text_parts.append(data.get('content')) + for embed in data.get('embeds', []): + if embed.get('title'): plain_text_parts.append(embed.get('title')) + if embed.get('description'): plain_text_parts.append(embed.get('description')) + if embed.get('fields'): + for field in embed.get('fields'): plain_text_parts.append(f"{field.get('name', '')}: {field.get('value', '')}") + plain_text_body = "\n".join(plain_text_parts) + + simple_payload = {"text": plain_text_body, "html": html_content, "username": data.get('username')} + headers = {'Content-Type': 'application/json'} + + response = requests.post(target_url, json=simple_payload, headers=headers, timeout=10) + response.raise_for_status() + print(f"Webhook '{webhook_id}' succesvol doorgestuurd als VEREENVOUDIGDE JSON naar {target_url}. Status: {response.status_code}") + + except Exception as e: + print(f"FOUT: Kon webhook '{webhook_id}' niet doorsturen. Error: {e}") + +@app.route('/') +def list_webhooks(): + """Toont de lijst met ontvangen webhooks.""" + return render_template( + 'home.html', + webhooks=webhook_data_store, + base_url=OUTGOING_WEBHOOK_BASE_URL, + params=OUTGOING_WEBHOOK_PARAMS + ) + +@app.route('/view/') +def display_webhook(webhook_id): + """Toont de laatst ontvangen data voor een specifieke webhook.""" + data = webhook_data_store.get(webhook_id) + if not data: + # Toon een wacht-bericht als er nog nooit data is ontvangen voor deze ID + data = { + "username": "Nog geen data", + "content": f"Wacht op de eerste webhook op /webhook/{webhook_id}...", + "embeds": [], + "received_at": "Nooit" + } + + content = render_template('forward_webhook.html', data=data) + return render_template('ui_webhook_view.html', content=content, webhook_id=webhook_id) + +@app.route('/webhook/', methods=['POST']) +def receive_webhook(webhook_id): + """Ontvangt de JSON-payload, slaat deze op en stuurt deze door.""" + if not request.is_json: + return jsonify({"error": "Request must be JSON"}), 400 + + data = request.json + data['received_at'] = datetime.datetime.now().strftime('%d-%m-%Y %H:%M:%S') + data['webhook_id'] = webhook_id + + # Sla de data op in de store. Nieuwe ID's worden automatisch toegevoegd. + webhook_data_store[webhook_id] = data + + # Bouw de uitgaande URL dynamisch op, alleen als de base URL is geconfigureerd. + if OUTGOING_WEBHOOK_BASE_URL: + # Zorg ervoor dat er maar één slash tussen de base url en de id zit. + target_url = f"{OUTGOING_WEBHOOK_BASE_URL.rstrip('/')}/{webhook_id}{OUTGOING_WEBHOOK_PARAMS}" + forward_webhook(data, target_url, webhook_id) + + return jsonify({"status": "succes"}), 200 + +if __name__ == '__main__': + port = 5001 + print(f"Server wordt gestart op http://127.0.0.1:{port}") + print("De app accepteert nu POST-verzoeken op ELK pad onder /webhook/...") + print("Bijvoorbeeld: http://127.0.0.1:5001/webhook/jellyfin") + print("Druk op CTRL+C om te stoppen.") + from waitress import serve + serve(app, host='0.0.0.0', port=port)