modified: app.py

modified:   templates/server_selection.html
This commit is contained in:
SimolZimol
2024-10-23 11:13:02 +02:00
parent 43258f6980
commit 3a171a2cd9
2 changed files with 151 additions and 72 deletions

176
app.py
View File

@@ -1,11 +1,12 @@
__version__ = "dev-0.4.7" __version__ = "dev-0.4.6"
__all__ = ["Discordbot-chatai-webpanel (Discord)"] __all__ = ["Discordbot-chatai-webpanel (Discord)"]
__author__ = "SimolZimol" __author__ = "SimolZimol"
from flask import Flask, render_template, redirect, url_for, request, session, jsonify, flash from flask import Flask, render_template, redirect, url_for, request, session, jsonify, send_file, flash
from requests_oauthlib import OAuth2Session from requests_oauthlib import OAuth2Session
import os import os
import subprocess import subprocess
import psutil
import mysql.connector import mysql.connector
from datetime import datetime from datetime import datetime
@@ -14,27 +15,49 @@ app.secret_key = os.getenv("FLASK_SECRET_KEY")
LOG_FILE_PATH = os.path.join("logs", f"{datetime.now().strftime('%Y-%m-%d')}.log") LOG_FILE_PATH = os.path.join("logs", f"{datetime.now().strftime('%Y-%m-%d')}.log")
# Datenbankverbindung # Verwende Umgebungsvariablen für die Datenbankverbindung
DB_HOST = os.getenv("DB_HOST") DB_HOST = os.getenv("DB_HOST")
DB_PORT = os.getenv("DB_PORT") DB_PORT = os.getenv("DB_PORT")
DB_USER = os.getenv("DB_USER") DB_USER = os.getenv("DB_USER")
DB_PASS = os.getenv("DB_PASSWORD") DB_PASS = os.getenv("DB_PASSWORD")
DB_NAME = os.getenv("DB_DATABASE") DB_NAME = os.getenv("DB_DATABASE")
# Discord OAuth2-Konfiguration
DISCORD_CLIENT_ID = os.getenv("DISCORD_CLIENT_ID") DISCORD_CLIENT_ID = os.getenv("DISCORD_CLIENT_ID")
DISCORD_CLIENT_SECRET = os.getenv("DISCORD_CLIENT_SECRET") DISCORD_CLIENT_SECRET = os.getenv("DISCORD_CLIENT_SECRET")
DISCORD_REDIRECT_URI = os.getenv("DISCORD_REDIRECT_URI") DISCORD_REDIRECT_URI = os.getenv("DISCORD_REDIRECT_URI")
DISCORD_OAUTH2_URL = "https://discord.com/api/oauth2/authorize" DISCORD_OAUTH2_URL = "https://discord.com/api/oauth2/authorize"
DISCORD_TOKEN_URL = "https://discord.com/api/oauth2/token" DISCORD_TOKEN_URL = "https://discord.com/api/oauth2/token"
DISCORD_API_URL = "https://discord.com/api/users/@me" DISCORD_API_URL = "https://discord.com/api/users/@me"
DISCORD_GUILDS_URL = "https://discord.com/api/users/@me/guilds" os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # nur für Entwicklungszwecke # Speichern der Prozess-ID
# Bot-Status
bot_process = None bot_process = None
def bot_status():
"""Überprüft, ob der Bot läuft."""
global bot_process
if bot_process is None:
return False
return bot_process.poll() is None # None bedeutet, dass der Prozess noch läuft
def start_bot():
"""Startet den Bot."""
global bot_process
if not bot_status():
bot_process = subprocess.Popen(["python", "bot.py"], cwd=os.path.dirname(os.path.abspath(__file__)))
else:
print("Bot läuft bereits.")
def stop_bot():
"""Stoppt den Bot."""
global bot_process
if bot_process and bot_status():
bot_process.terminate()
bot_process.wait() # Warten, bis der Prozess beendet ist
bot_process = None
else:
print("Bot läuft nicht.")
def get_db_connection(): def get_db_connection():
"""Stellt eine Verbindung zur MySQL-Datenbank her.""" """Stellt eine Verbindung zur MySQL-Datenbank her."""
return mysql.connector.connect( return mysql.connector.connect(
@@ -45,23 +68,25 @@ def get_db_connection():
database=DB_NAME database=DB_NAME
) )
def token_updater(token):
session['oauth_token'] = token
def make_discord_session(token=None, state=None): def make_discord_session(token=None, state=None):
"""Erstellt eine Discord OAuth2-Session."""
return OAuth2Session( return OAuth2Session(
DISCORD_CLIENT_ID, DISCORD_CLIENT_ID,
token=token, token=token or session.get("oauth_token"),
state=state, state=state,
redirect_uri=DISCORD_REDIRECT_URI, redirect_uri=DISCORD_REDIRECT_URI,
scope=["identify", "guilds"] scope=["identify", "guilds"],
auto_refresh_kwargs={
'client_id': DISCORD_CLIENT_ID,
'client_secret': DISCORD_CLIENT_SECRET,
},
auto_refresh_url=DISCORD_TOKEN_URL,
token_updater=token_updater
) )
def fetch_discord_guilds(discord_session):
"""Lädt die Gilden des Benutzers von der Discord-API."""
try:
return discord_session.get(DISCORD_GUILDS_URL).json()
except Exception as e:
print(f"Fehler beim Abrufen der Gilden: {e}")
return None
def is_bot_admin(): def is_bot_admin():
"""Überprüft, ob der Benutzer globale Admin-Rechte hat.""" """Überprüft, ob der Benutzer globale Admin-Rechte hat."""
@@ -73,6 +98,7 @@ def is_bot_admin():
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT global_permission FROM bot_data WHERE user_id = %s", (user_id,)) cursor.execute("SELECT global_permission FROM bot_data WHERE user_id = %s", (user_id,))
user_data = cursor.fetchone() user_data = cursor.fetchone()
cursor.close() cursor.close()
connection.close() connection.close()
@@ -89,6 +115,7 @@ def is_server_admin(guild_id):
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT permission FROM user_data WHERE user_id = %s AND guild_id = %s", (user_id, guild_id)) cursor.execute("SELECT permission FROM user_data WHERE user_id = %s AND guild_id = %s", (user_id, guild_id))
user_data = cursor.fetchone() user_data = cursor.fetchone()
cursor.close() cursor.close()
connection.close() connection.close()
@@ -112,6 +139,7 @@ def login():
@app.route("/callback") @app.route("/callback")
def callback(): def callback():
"""Verarbeitet den OAuth2-Rückruf von Discord.""" """Verarbeitet den OAuth2-Rückruf von Discord."""
try:
discord = make_discord_session(state=session.get("oauth_state")) discord = make_discord_session(state=session.get("oauth_state"))
token = discord.fetch_token( token = discord.fetch_token(
DISCORD_TOKEN_URL, DISCORD_TOKEN_URL,
@@ -120,33 +148,33 @@ def callback():
) )
session['oauth_token'] = token session['oauth_token'] = token
session['discord_user'] = discord.get(DISCORD_API_URL).json()
# Gilden (Server) nur einmal laden und in der Session speichern # Abrufen der Benutzerinformationen von Discord
session['discord_guilds'] = fetch_discord_guilds(discord) user_info = discord.get(DISCORD_API_URL).json()
session['discord_user'] = user_info
# Hole die Gilden (Server), auf denen der Benutzer ist
guilds_response = discord.get('https://discord.com/api/users/@me/guilds')
if guilds_response.status_code != 200:
flash("Fehler beim Abrufen der Gilden.", "danger")
return redirect(url_for("landing_page"))
guilds = guilds_response.json()
session['discord_guilds'] = guilds # Speichere die Gilden in der Session
# Weiterleitung zur Server-Auswahl
return redirect(url_for("server_selection")) return redirect(url_for("server_selection"))
except Exception as e:
print(f"Error in OAuth2 callback: {e}")
flash("Ein Fehler ist beim Authentifizierungsprozess aufgetreten.", "danger")
return redirect(url_for("landing_page"))
@app.route("/server_selection") @app.route("/server_selection")
def server_selection(): def server_selection():
"""Zeigt dem Benutzer eine Liste aller Server an, auf denen er sich befindet.""" """Zeigt dem Benutzer eine Liste aller Server an, auf denen er sich befindet und die in der Datenbank vorhanden sind."""
if "discord_user" in session:
guilds = session.get('discord_guilds', [])
if not guilds:
flash("Es wurden keine Server gefunden.", "danger")
return redirect(url_for("landing_page"))
if len(guilds) == 1:
return redirect(url_for("user_dashboard", guild_id=guilds[0]['id']))
else:
return render_template("server_selection.html", guilds=guilds)
return redirect(url_for("login"))
@app.route("/user_dashboard/<int:guild_id>")
def user_dashboard(guild_id):
"""Zeigt das User-Dashboard für den ausgewählten Server an."""
if "discord_user" in session: if "discord_user" in session:
user_info = session["discord_user"] user_info = session["discord_user"]
user_id = user_info["id"] user_id = user_info["id"]
@@ -154,6 +182,48 @@ def user_dashboard(guild_id):
connection = get_db_connection() connection = get_db_connection()
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
# Abfrage der Gilden, auf denen der Benutzer in der Datenbank Einträge hat
cursor.execute("""
SELECT DISTINCT user_data.guild_id, guilds.name, guilds.icon
FROM user_data
JOIN guilds ON user_data.guild_id = guilds.guild_id
WHERE user_data.user_id = %s
""", (user_id,))
guilds = cursor.fetchall()
cursor.close()
connection.close()
return render_template("server_selection.html", guilds=guilds)
return redirect(url_for("login"))
@app.route("/admin_dashboard")
def admin_dashboard():
"""Zeigt das Bot-Admin-Dashboard an (nur für globale Admins)."""
if is_bot_admin():
return render_template("admin_dashboard.html", bot_running=bot_status())
return redirect(url_for("landing_page"))
@app.route("/server_admin_dashboard/<int:guild_id>")
def server_admin_dashboard(guild_id):
"""Zeigt das Server-Admin-Dashboard an (nur für Server-Admins)."""
if is_server_admin(guild_id):
return render_template("server_admin_dashboard.html", guild_id=guild_id)
return redirect(url_for("landing_page"))
@app.route("/user_dashboard/<int:guild_id>")
def user_dashboard(guild_id):
"""Zeigt das User-Dashboard für einen spezifischen Server (guild_id) an."""
if "discord_user" in session:
user_info = session["discord_user"]
user_id = user_info["id"]
connection = get_db_connection()
cursor = connection.cursor(dictionary=True)
# Hole Benutzerinformationen für den ausgewählten Server
cursor.execute("SELECT * FROM user_data WHERE user_id = %s AND guild_id = %s", (user_id, guild_id)) cursor.execute("SELECT * FROM user_data WHERE user_id = %s AND guild_id = %s", (user_id, guild_id))
user_data = cursor.fetchone() user_data = cursor.fetchone()
@@ -163,8 +233,7 @@ def user_dashboard(guild_id):
if user_data: if user_data:
return render_template("user_dashboard.html", user_info=user_info, user_data=user_data, guild_id=guild_id) return render_template("user_dashboard.html", user_info=user_info, user_data=user_data, guild_id=guild_id)
else: else:
flash("Keine Daten für diesen Server gefunden.", "danger") return "User data not found", 404
return redirect(url_for("server_selection"))
return redirect(url_for("login")) return redirect(url_for("login"))
@@ -174,17 +243,20 @@ def logout():
session.clear() session.clear()
return redirect(url_for("landing_page")) return redirect(url_for("landing_page"))
# Verbesserte Fehlerbehandlung: Automatisches Logout bei ungültigem Token # Bot Management Routes
@app.before_request @app.route("/start_bot")
def check_oauth_token(): def start():
if "oauth_token" in session: if is_bot_admin():
discord = make_discord_session(token=session["oauth_token"]) start_bot()
try: return redirect(url_for("admin_dashboard"))
discord.get(DISCORD_API_URL) # Test-API-Aufruf, um Token zu validieren return redirect(url_for("landing_page"))
except Exception:
session.clear() @app.route("/stop_bot")
flash("Deine Sitzung ist abgelaufen. Bitte erneut einloggen.", "warning") def stop():
return redirect(url_for("login")) if is_bot_admin():
stop_bot()
return redirect(url_for("admin_dashboard"))
return redirect(url_for("landing_page"))
if __name__ == "__main__": if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True) app.run(host="0.0.0.0", port=5000, debug=True)

View File

@@ -4,18 +4,25 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Server Selection</title> <title>Server Selection</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head> </head>
<body> <body>
<div class="container"> <div class="container mt-5">
<h1 class="mt-5">Wähle einen Server</h1> <h1 class="text-center">Select a Server</h1>
<ul class="list-group mt-3"> <div class="row">
{% for guild in guilds %} {% for guild in session['discord_guilds'] %}
<li class="list-group-item"> <div class="col-md-4 mt-3">
<a href="{{ url_for('user_dashboard', guild_id=guild['id']) }}">{{ guild['name'] }}</a> <div class="card">
</li> <img src="https://cdn.discordapp.com/icons/{{ guild['id'] }}/{{ guild['icon'] }}.png" class="card-img-top" alt="Server Icon">
<div class="card-body">
<h5 class="card-title">{{ guild['name'] }}</h5>
<p class="card-text">You have permission level: {{ guild['permissions'] }}</p>
<a href="{{ url_for('user_dashboard', guild_id=guild['id']) }}" class="btn btn-primary">Enter Server</a>
</div>
</div>
</div>
{% endfor %} {% endfor %}
</ul> </div>
</div> </div>
</body> </body>
</html> </html>