diff --git a/demo_tables/northwind.db b/demo_tables/northwind.db new file mode 100755 index 0000000..da01968 Binary files /dev/null and b/demo_tables/northwind.db differ diff --git a/er_model.png b/er_model.png index 9290b1f..bcaf83a 100644 Binary files a/er_model.png and b/er_model.png differ diff --git a/main.py b/main.py index 0049cfd..e37bb23 100644 --- a/main.py +++ b/main.py @@ -2,20 +2,24 @@ from flask import Flask, render_template, request, send_file import sqlite3 import os from graphviz import Digraph +import math +import mysql.connector +from mysql.connector import Error app = Flask(__name__) # Verzeichnis für hochgeladene Dateien -UPLOAD_FOLDER = 'uploads' -app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER +UPLOAD_FOLDER = "uploads" +app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER -def create_er_model(database_file, output_file='er_model.png'): + +def create_er_model(database_file, output_file="er_model.png"): """Erstellt ein ER-Modell für die angegebene SQLite-Datenbank und speichert es als Bild.""" conn = sqlite3.connect(database_file) c = conn.cursor() c.execute("SELECT name FROM sqlite_master WHERE type='table';") tables = c.fetchall() - + # Graphviz-Diagramm erstellen dot = Digraph() @@ -25,16 +29,16 @@ def create_er_model(database_file, output_file='er_model.png'): # Für jede Tabelle Informationen über Spalten abrufen und dem Diagramm hinzufügen for table in tables: table_name = table[0] - dot.node(table_name, shape='rectangle', color='lightblue2', style='filled') - + dot.node(table_name, shape="rectangle", color="lightblue2", style="filled") + # Spalten der Tabelle abrufen c.execute(f"PRAGMA table_info({table_name});") columns = c.fetchall() - + # Jede Spalte als Knoten im Diagramm hinzufügen for column in columns: column_name = column[1] - dot.node(f"{table_name}.{column_name}", label=column_name, shape='ellipse') + dot.node(f"{table_name}.{column_name}", label=column_name, shape="ellipse") # Verbindung von Tabelle zu Spalte erstellen dot.edge(table_name, f"{table_name}.{column_name}") @@ -50,49 +54,105 @@ def create_er_model(database_file, output_file='er_model.png'): parent_column = fk[3] child_table = table child_column = fk[4] - dot.edge(f"{parent_table}.{parent_column}", f"{child_table}.{child_column}", label='1..n') + dot.edge( + f"{parent_table}.{parent_column}", + f"{child_table}.{child_column}", + label="1..n", + ) # ER-Modell als Graphviz-Dot-Datei speichern - dot.render(output_file, format='png', cleanup=True) + dot.render(output_file, format="png", cleanup=True) # Verbindung schließen conn.close() return output_file + +@app.get("/") +def home(): + # HTML-Seite mit den Daten anzeigen + return render_template("index.html") + + # Route für den Index -@app.route('/', methods=['GET', 'POST']) -def index(): +@app.post("/sqlite") +def sqlite_post(): + error = None + er_model = None + table_data = None + # Überprüfen, ob eine Datei hochgeladen wurde + if "file" not in request.files: + error = "Keine Datei hochgeladen" + else: + file = request.files["file"] + # Überprüfen, ob eine Datei ausgewählt wurde + if file.filename == "": + error = "Keine Datei ausgewählt" + # Überprüfen, ob die Datei eine SQLite-Datenbank ist + elif file.filename.endswith(".db"): + # Datei speichern + file_path = os.path.join(app.config["UPLOAD_FOLDER"], file.filename) + file.save(file_path) + # ER-Modell erstellen + er_model_file = create_er_model(file_path) + os.rename("er_model.png.png", "er_model.png") + er_model = er_model_file + # Tabellendaten abrufen + conn = sqlite3.connect(file_path) + cursor = conn.cursor() + cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") + tables = cursor.fetchall() + table_data = {} + for table in tables: + table_name = table[0] + cursor.execute(f"SELECT * FROM {table_name};") + table_data[table_name] = cursor.fetchall() + conn.close() + else: + error = "Die hochgeladene Datei muss eine SQLite-Datenbankdatei sein" + + +@app.post("/mysql") +def mysql_post(): error = None er_model = None table_data = None - if request.method == 'POST': - # Überprüfen, ob eine Datei hochgeladen wurde - if 'file' not in request.files: - error = 'Keine Datei hochgeladen' - else: - file = request.files['file'] + # Retrieve MySQL connection details from the request form + host = request.form.get("host") + user = request.form.get("user") + password = request.form.get("password") - # Überprüfen, ob eine Datei ausgewählt wurde - if file.filename == '': - error = 'Keine Datei ausgewählt' + if not all([host, user, password]): + error = "Alle Verbindungsdetails und der Dateipfad müssen angegeben werden." + else: + # Überprüfen, ob die MySQL-Datenbank erreichbar ist + try: + conn = mysql.connector.connect( + host=host, + user=user, + password=password, + auth_plugin="mysql_native_password", + ) + cursor = conn.cursor() + cursor.execute("SHOW DATABASES;") + databases = cursor.fetchall() + print(databases) + conn.close() - # Überprüfen, ob die Datei eine SQLite-Datenbank ist - elif file.filename.endswith('.db'): - # Datei speichern - file_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename) - file.save(file_path) - - # ER-Modell erstellen - er_model_file = create_er_model(file_path) - os.rename("er_model.png.png", "er_model.png") - er_model = er_model_file - - # Tabellendaten abrufen - conn = sqlite3.connect(file_path) + for database in databases: + db_name = database[0] + print(db_name) + conn = mysql.connector.connect( + host=host, + user=user, + password=password, + database=db_name, + auth_plugin="mysql_native_password", + ) cursor = conn.cursor() - cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") + cursor.execute("SHOW TABLES;") tables = cursor.fetchall() table_data = {} for table in tables: @@ -100,17 +160,26 @@ def index(): cursor.execute(f"SELECT * FROM {table_name};") table_data[table_name] = cursor.fetchall() conn.close() - - else: - error = 'Die hochgeladene Datei muss eine SQLite-Datenbankdatei sein' - + # ER-Modell erstellen + er_model_file = create_er_model(db_name) + os.rename("er_model.png.png", "er_model.png") + er_model = er_model_file + except Error as e: + error = f"Fehler beim Herstellen der Verbindung zur MySQL-Datenbank: {e}" + finally: + if 'conn' in locals() and conn.is_connected(): + conn.close() # HTML-Seite mit den Daten anzeigen - return render_template('index.html', error=error, er_model=er_model, table_data=table_data) + return render_template( + "index.html", error=error, er_model=er_model, table_data=table_data + ) + # Route zum Anzeigen des ER-Modells -@app.route('/er_model/') +@app.route("/er_model/") def show_er_model(filename): - return send_file(os.path.abspath(filename), mimetype='image/png') + return send_file(os.path.abspath(filename), mimetype="image/png") -if __name__ == '__main__': + +if __name__ == "__main__": app.run(debug=True) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a319337 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +blinker==1.9.0 +click==8.1.8 +Flask==3.1.0 +graphviz==0.20.3 +itsdangerous==2.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.2 +mysql-connector==2.2.9 +mysql-connector-python==9.2.0 +Werkzeug==3.1.3 diff --git a/static/css/tabs.css b/static/css/tabs.css new file mode 100755 index 0000000..06577d1 --- /dev/null +++ b/static/css/tabs.css @@ -0,0 +1,44 @@ + /* Style the tab */ + .tab { + overflow: hidden; + border: 1px solid #ccc; + background-color: #f1f1f1; + } + + .tab.dark-mode table { + border-color: #555555; + } + + /* Style the buttons that are used to open the tab content */ + .tab button { + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 14px 16px; + transition: 0.3s; + } + + /* Change background color of buttons on hover */ + .tab button:hover { + background-color: #ddd; + } + + /* Create an active/current tablink class */ + .tab button.active { + background-color: #ccc; + } + + /* Style the tab content */ + .tabcontent { + display: none; + padding: 6px 12px; + border: 1px solid #ccc; + border-top: none; + } + + .tabcontent.dark-mode { + background-color: #333333; + color: #ffffff; + } \ No newline at end of file diff --git a/static/js/tabs.js b/static/js/tabs.js new file mode 100755 index 0000000..8ab88f1 --- /dev/null +++ b/static/js/tabs.js @@ -0,0 +1,20 @@ +function openTab(evt, tabName) { + // Declare all variables + var i, tabcontent, tablinks; + + // Get all elements with class="tabcontent" and hide them + tabcontent = document.getElementsByClassName("tabcontent"); + for (i = 0; i < tabcontent.length; i++) { + tabcontent[i].style.display = "none"; + } + + // Get all elements with class="tablinks" and remove the class "active" + tablinks = document.getElementsByClassName("tablinks"); + for (i = 0; i < tablinks.length; i++) { + tablinks[i].className = tablinks[i].className.replace(" active", ""); + } + + // Show the current tab, and add an "active" class to the button that opened the tab + document.getElementById(tabName).style.display = "block"; + evt.currentTarget.className += " active"; + } \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 66cbfb3..cf49542 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,66 +1,122 @@ + + SQL Analyzer +
-

SQLITE Analyzer

+

SQL Analyzer

-
- Drag & Drop Datei hierhin oder klicken, um hochzuladen. + + +
+ +
-
-
- -
+ +
+
+ Drag & Drop Datei hierhin oder klicken, um hochzuladen. +
+
- {% if error %} +
+ +
+ + {% if error %}

{{ error }}

- {% endif %} + {% endif %} - {% if table_data %} + {% if table_data %} {% for table_name, data in table_data.items() %} -

{{ table_name }}

- - - {% for column_name in data[0] %} - - {% endfor %} - - {% for row in data %} - - {% for value in row %} - - {% endfor %} - +

{{ table_name }}

+
{{ column_name }}
{{ value }}
+ + {% for column_name in data[0] %} + {% endfor %} -
{{ column_name }}
+ + {% for row in data %} + + {% for value in row %} + {{ value }} + {% endfor %} + + {% endfor %} + {% endfor %} - {% endif %} + {% endif %} - {% if er_model %} + {% if er_model %}

ER-Modell

ER-Modell - {% endif %} + {% endif %} + + +
+ +
+ +
+

MySQL

+

Hier können Sie MySQL-Datenbankabfragen durchführen.

+ +
+ + + + +
+ +
+ + +
+ + {% if mysql_result %} +

Abfrageergebnis

+ + + {% for column_name in mysql_result[0] %} + + {% endfor %} + + {% for row in mysql_result %} + + {% for value in row %} + + {% endfor %} + + {% endfor %} +
{{ column_name }}
{{ value }}
+ {% endif %} + +
- -
© fingadumbledore 2024 Version 0.1 + © lucaspalomodevelop 2025 Version 0.2
- - + + + + \ No newline at end of file diff --git a/uploads/1000.db b/uploads/1000.db deleted file mode 100644 index b56ba2f..0000000 Binary files a/uploads/1000.db and /dev/null differ diff --git a/uploads/example.db b/uploads/example.db deleted file mode 100644 index 78e276d..0000000 Binary files a/uploads/example.db and /dev/null differ