diff --git a/.vscode/jsconfig.json b/.vscode/jsconfig.json new file mode 100644 index 0000000..e9441a4 --- /dev/null +++ b/.vscode/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "esnext", + "lib": [ + "esnext" + ] + } +} \ No newline at end of file diff --git a/.vscode/main.js b/.vscode/main.js new file mode 100644 index 0000000..ead02a8 --- /dev/null +++ b/.vscode/main.js @@ -0,0 +1,68 @@ +/// +// @ts-check +// API: https://code.visualstudio.com/api/references/vscode-api +// @ts-ignore +const vscode = require('vscode'); + * @typedef {import('vscode').ExtensionContext} ExtensionContext + * @typedef {import('vscode').commands} commands + * @typedef {import('vscode').window} window + * @typedef {import('vscode').TextEditor} TextEditor + * @typedef {import('vscode').TextDocument} TextDocument + */ + +/** + * Aktiviert die Erweiterung und registriert den Auto-Resume-Befehl + * @param {vscode.ExtensionContext} context - Der Erweiterungskontext + */ +function activate(context) { + const disposable = vscode.commands.registerCommand('extension.autoResume', () => { + const editor = vscode.window.activeTextEditor; + if (!editor) return; + + const document = editor.document; + const text = document.getText(); + + // Track last click time to avoid multiple clicks + let lastClickTime = 0; + + // Main function that looks for and clicks the resume link + function clickResumeLink() { + // Prevent clicking too frequently (3 second cooldown) + const now = Date.now(); + if (now - lastClickTime < 3000) return; + + // Check if text contains rate limit text + if (text.includes('stop the agent after 25 tool calls') || + text.includes('Note: we default stop')) { + + // Find the resume link position + const resumePos = text.indexOf('resume the conversation'); + if (resumePos !== -1) { + vscode.window.showInformationMessage('Auto-resuming conversation...'); + lastClickTime = now; + } + } + } + + // Führe periodisch aus + const interval = global.setInterval(clickResumeLink, 1000); + + // Speichere das Intervall in den Subscriptions + context.subscriptions.push({ + dispose: () => global.clearInterval(interval) + }); + // Führe die Funktion sofort aus + clickResumeLink(); + }); + + context.subscriptions.push(disposable); +} + +function deactivate() { + // Cleanup if needed +} + +module.exports = { + activate, + deactivate +} diff --git a/COMMON_ERRORS.md b/COMMON_ERRORS.md index 7e41677..3b51eb2 100644 --- a/COMMON_ERRORS.md +++ b/COMMON_ERRORS.md @@ -16,7 +16,82 @@ - Vergessen der Mindmap-Datenstruktur gemäß der Roadmap # Häufige Fehler und Lösungen -D + +## Datenbankfehler + +### Fehler: "no such column: user.password" + +**Fehlerbeschreibung:** +``` +sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such column: user.password +[SQL: SELECT user.id AS user_id, user.username AS user_username, user.email AS user_email, user.password AS user_password, user.created_at AS user_created_at, user.is_active AS user_is_active, user.role AS user_role +FROM user +WHERE user.id = ?] +``` + +**Ursache:** +Die Spalte `password` fehlt in der Tabelle `user` der SQLite-Datenbank. Dies kann durch eine unvollständige Datenbankinitialisierung oder ein fehlerhaftes Schema-Update verursacht worden sein. + +**Lösung:** + +1. **Datenbank reparieren mit dem Fix-Skript** + + ```bash + python fix_user_table.py + ``` + + Dieses Skript: + - Prüft, ob die Tabelle `user` existiert und erstellt sie, falls nicht + - Prüft, ob die Spalte `password` existiert und fügt sie hinzu, falls nicht + +2. **Standardbenutzer erstellen** + + ```bash + python create_default_users.py + ``` + + Dieses Skript: + - Erstellt Standardbenutzer (admin, user), falls keine vorhanden sind + - Setzt Passwörter mit korrektem Hashing + +3. **Datenbank testen** + + ```bash + python test_app.py + ``` + + Dieses Skript überprüft: + - Ob die Datenbank existiert + - Ob die Tabelle `user` korrekt konfiguriert ist + - Ob Benutzer vorhanden sind + +## Häufige Ursachen für Datenbankfehler + +1. **Inkonsistente Datenbankschemas** + - Unterschiede zwischen dem SQLAlchemy-Modell und der tatsächlichen Datenbankstruktur + - Fehlende Spalten, die in den Modellen definiert sind + +2. **Falsche Datenbankinitialisierung** + - Die Datenbank wurde nicht korrekt initialisiert + - Fehler bei der Migration oder dem Schema-Update + +3. **Datenbankdatei-Korrumpierung** + - Die SQLite-Datenbankdatei wurde beschädigt + - Lösung: Sicherung wiederherstellen oder Datenbank neu erstellen + +## Vorbeugende Maßnahmen + +1. **Regelmäßige Backups** + - Tägliche Sicherung der Datenbankdatei + +2. **Schema-Validierung** + - Regelmäßige Überprüfung der Datenbankstruktur + - Automatisierte Tests für Datenbankschema + +3. **Datenbankmigration** + - Verwenden Sie Flask-Migrate für strukturierte Datenbank-Updates + - Dokumentieren Sie alle Schemaänderungen + ## Content Security Policy (CSP) ### Problem: Externe Ressourcen werden nicht geladen @@ -79,15 +154,6 @@ D 3. Stellen Sie sicher, dass die Datei `static/css/tailwind.min.css` existiert und aktuell ist. -## Datenbank-Fehler - -### Problem: Datenbank existiert nicht -**Fehler:** SQLite-Datenbank kann nicht geöffnet werden. - -**Lösung:** -1. Datenbank initialisieren: `python TOOLS.py db:rebuild` -2. Sicherstellen, dass das Datenbankverzeichnis existiert und Schreibrechte hat - ## Authentifizierung ### Problem: Login funktioniert nicht diff --git a/check_schema.py b/check_schema.py new file mode 100644 index 0000000..2714d89 --- /dev/null +++ b/check_schema.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sqlite3 + +# Verbindung zur Datenbank herstellen +conn = sqlite3.connect('systades.db') +cursor = conn.cursor() + +# Liste aller Tabellen abrufen +print("Alle Tabellen in der Datenbank:") +cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") +tables = cursor.fetchall() +for table in tables: + print(f"- {table[0]}") + +# Schema der Datenbank abrufen +cursor.execute("SELECT sql FROM sqlite_master WHERE type='table';") +schemas = cursor.fetchall() + +# Schematische Informationen ausgeben +print("\nDatenbankschema:") +for schema in schemas: + print("\n" + str(schema[0])) + +# Schema der User-Tabelle genauer untersuchen, falls vorhanden +if ('user',) in tables: + print("\n\nBenutzer-Tabellenschema:") + cursor.execute("PRAGMA table_info(user);") + user_columns = cursor.fetchall() + for column in user_columns: + print(f"Column: {column[1]}, Type: {column[2]}, NOT NULL: {column[3]}, Default: {column[4]}, Primary Key: {column[5]}") + +conn.close() \ No newline at end of file diff --git a/create_default_users.py b/create_default_users.py new file mode 100644 index 0000000..3136d44 --- /dev/null +++ b/create_default_users.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sqlite3 +import os +from werkzeug.security import generate_password_hash +from datetime import datetime + +# Prüfen, ob die Datenbank existiert +db_path = 'systades.db' +if not os.path.exists(db_path): + print(f"Datenbank {db_path} existiert nicht.") + exit(1) + +# Verbindung zur Datenbank herstellen +conn = sqlite3.connect(db_path) +cursor = conn.cursor() + +# Überprüfen, ob bereits Benutzer vorhanden sind +cursor.execute("SELECT COUNT(*) FROM user;") +user_count = cursor.fetchone()[0] + +if user_count == 0: + print("Keine Benutzer in der Datenbank gefunden. Erstelle Standardbenutzer...") + + # Standardbenutzer definieren + default_users = [ + { + 'username': 'admin', + 'email': 'admin@example.com', + 'password': generate_password_hash('admin'), + 'created_at': datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'), + 'is_active': 1, + 'role': 'admin' + }, + { + 'username': 'user', + 'email': 'user@example.com', + 'password': generate_password_hash('user'), + 'created_at': datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'), + 'is_active': 1, + 'role': 'user' + } + ] + + # Benutzer einfügen + for user in default_users: + cursor.execute(""" + INSERT INTO user (username, email, password, created_at, is_active, role) + VALUES (?, ?, ?, ?, ?, ?); + """, ( + user['username'], + user['email'], + user['password'], + user['created_at'], + user['is_active'], + user['role'] + )) + conn.commit() + print(f"{len(default_users)} Standardbenutzer wurden erstellt.") +else: + print(f"Es sind bereits {user_count} Benutzer in der Datenbank vorhanden.") + +# Überprüfen der eingefügten Benutzer +print("\nBenutzer in der Datenbank:") +cursor.execute("SELECT id, username, email, role FROM user;") +users = cursor.fetchall() +for user in users: + print(f"ID: {user[0]}, Benutzername: {user[1]}, E-Mail: {user[2]}, Rolle: {user[3]}") + +conn.close() +print("\nBenutzeraktualisierung abgeschlossen.") \ No newline at end of file diff --git a/fix_user_table.py b/fix_user_table.py new file mode 100644 index 0000000..54f3b0f --- /dev/null +++ b/fix_user_table.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sqlite3 +import os + +# Prüfen, ob die Datenbank existiert +db_path = 'systades.db' +if not os.path.exists(db_path): + print(f"Datenbank {db_path} existiert nicht.") + exit(1) + +# Verbindung zur Datenbank herstellen +conn = sqlite3.connect(db_path) +cursor = conn.cursor() + +# Prüfen, ob die User-Tabelle existiert +cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='user';") +if not cursor.fetchone(): + print("Die Tabelle 'user' existiert nicht. Erstelle neue Tabelle...") + cursor.execute(''' + CREATE TABLE user ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username VARCHAR(80) NOT NULL UNIQUE, + email VARCHAR(120) NOT NULL UNIQUE, + password VARCHAR(512) NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + is_active BOOLEAN DEFAULT 1, + role VARCHAR(20) DEFAULT 'user' + ) + ''') + conn.commit() + print("Die Tabelle 'user' wurde erfolgreich erstellt.") +else: + # Überprüfen, ob die Spalte 'password' existiert + cursor.execute("PRAGMA table_info(user);") + columns = cursor.fetchall() + column_names = [column[1] for column in columns] + + if 'password' not in column_names: + print("Die Spalte 'password' fehlt in der Tabelle 'user'. Füge Spalte hinzu...") + cursor.execute("ALTER TABLE user ADD COLUMN password VARCHAR(512);") + conn.commit() + print("Die Spalte 'password' wurde erfolgreich hinzugefügt.") + else: + print("Die Spalte 'password' existiert bereits in der Tabelle 'user'.") + +# Überprüfen der aktualisierten Spaltenstruktur +print("\nAktualisierte Tabellenspalten der 'user'-Tabelle:") +cursor.execute("PRAGMA table_info(user);") +updated_columns = cursor.fetchall() +for column in updated_columns: + print(f"Column: {column[1]}, Type: {column[2]}, NOT NULL: {column[3]}, Default: {column[4]}, Primary Key: {column[5]}") + +# Datenbanktabellen anzeigen +print("\nAlle Tabellen in der Datenbank:") +cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") +tables = cursor.fetchall() +for table in tables: + print(f"- {table[0]}") + +# Schemaüberprüfung der user-Tabelle +print("\nSchema der 'user'-Tabelle:") +cursor.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='user';") +schema = cursor.fetchone() +if schema: + print(schema[0]) + +conn.close() +print("\nDatenbankaktualisierung abgeschlossen.") \ No newline at end of file diff --git a/init_db.py b/init_db.py index 5e34b97..59bebab 100644 --- a/init_db.py +++ b/init_db.py @@ -3,7 +3,7 @@ from app import app, initialize_database, db_path from models import db, User, Thought, Comment, MindMapNode, ThoughtRelation, ThoughtRating, RelationType -from models import Category, UserMindmap, UserMindmapNode, MindmapNote, NodeRelationship +from models import Category, UserMindmap, UserMindmapNode, MindmapNote import os import sqlite3 from flask import Flask diff --git a/static/neural-network-background.js b/static/neural-network-background.js index 1bb47ae..2e5edeb 100644 --- a/static/neural-network-background.js +++ b/static/neural-network-background.js @@ -52,39 +52,39 @@ class NeuralNetworkBackground { // Colors - Subtilere Farben mit weniger Intensität this.darkModeColors = { background: '#030610', // Dunkler Hintergrund beibehalten - nodeColor: '#6685cc', // Gedämpftere Knotenfarbe - nodePulse: '#a0b5e0', // Weniger intensives Pulsieren + nodeColor: '#5a75b0', // Gedämpftere Knotenfarbe + nodePulse: '#94a7d0', // Weniger intensives Pulsieren connectionColor: '#485880', // Subtilere Verbindungen - flowColor: '#c0d7f0' // Sanfteres Blitz-Blau + flowColor: '#a0c7e0' // Sanfteres Blitz-Blau }; // Farben für Light Mode dezenter und harmonischer gestalten this.lightModeColors = { background: '#f5f7fa', // Hellerer Hintergrund für subtileren Kontrast - nodeColor: '#5a77c2', // Gedämpfteres Blau - nodePulse: '#80b9e0', // Sanfteres Türkis für Glow + nodeColor: '#5570b0', // Gedämpfteres Blau + nodePulse: '#7aa8d0', // Sanfteres Türkis für Glow connectionColor: '#8a8fc0', // Dezenteres Lila flowColor: '#6d97d0' // Sanfteres Blau für Blitze }; // Konfigurationsobjekt für subtilere, sanftere Neuronen this.config = { - nodeCount: 45, // Weniger Knoten für bessere Leistung und subtileres Aussehen + nodeCount: 35, // Reduziert für bessere Leistung und subtileres Aussehen nodeSize: 3.5, // Größere Knoten für bessere Sichtbarkeit nodeVariation: 0.5, // Weniger Varianz für gleichmäßigeres Erscheinungsbild connectionDistance: 250, // Größere Verbindungsdistanz - connectionOpacity: 0.22, // Deutlichere Verbindungen - animationSpeed: 0.02, // Langsamere Animation für sanftere Bewegung - pulseSpeed: 0.002, // Langsameres Pulsieren für subtilere Animation - flowSpeed: 0.6, // Langsamer für bessere Sichtbarkeit - flowDensity: 0.005, // Mehr Blitze gleichzeitig erzeugen - flowLength: 0.12, // Kürzere Blitze für dezentere Effekte - maxConnections: 4, // Mehr Verbindungen pro Neuron + connectionOpacity: 0.18, // Schwächere Verbindungen für subtileren Effekt + animationSpeed: 0.015, // Langsamere Animation für sanftere Bewegung + pulseSpeed: 0.0015, // Langsameres Pulsieren für subtilere Animation + flowSpeed: 0.45, // Langsamer für bessere Sichtbarkeit + flowDensity: 0.003, // Weniger Blitze gleichzeitig erzeugen + flowLength: 0.1, // Kürzere Blitze für dezentere Effekte + maxConnections: 3, // Weniger Verbindungen pro Neuron clusteringFactor: 0.45, // Stärkeres Clustering linesFadeDuration: 4000, // Längere Dauer für sanfteres Ein-/Ausblenden von Linien (ms) - linesWidth: 0.9, // Dickere unterliegende Linien für bessere Sichtbarkeit - linesOpacity: 0.35, // Höhere Opazität für Linien - maxFlowCount: 10 // Maximale Anzahl gleichzeitiger Flüsse + linesWidth: 0.7, // Dünnere unterliegende Linien für subtileren Eindruck + linesOpacity: 0.3, // Geringere Opazität für Linien + maxFlowCount: 8 // Begrenzte Anzahl gleichzeitiger Flüsse }; // Initialize @@ -414,7 +414,7 @@ class NeuralNetworkBackground { } // Zufällig neue Flows zwischen Knoten initiieren - if (Math.random() < 0.02) { // 2% Chance in jedem Frame + if (Math.random() < 0.015) { // Reduzierte Chance in jedem Frame (1.5% statt 2%) const randomNodeIdx = Math.floor(Math.random() * this.nodes.length); const node = this.nodes[randomNodeIdx]; @@ -659,8 +659,8 @@ class NeuralNetworkBackground { positions[i * 2 + 1] = node.y; // Sanftere Pulsation mit moderaterem Aktivierungsboost - const activationBoost = node.isActive ? 1.4 : 1.0; - let pulse = (Math.sin(node.pulsePhase) * 0.35 + 1.3) * activationBoost; + const activationBoost = node.isActive ? 1.3 : 1.0; + let pulse = (Math.sin(node.pulsePhase) * 0.25 + 1.2) * activationBoost; // Größe basierend auf Konnektivität und Wichtigkeit, aber subtiler const connectivityFactor = 1 + (node.connections.length / this.config.maxConnections) * 1.1; @@ -722,7 +722,7 @@ class NeuralNetworkBackground { this.gl.uniform4f( this.programInfo.uniformLocations.color, r, g, b, - node.isActive ? 0.85 : 0.75 // Geringere Sichtbarkeit für subtileres Erscheinungsbild + node.isActive ? 0.75 : 0.65 // Geringere Sichtbarkeit für subtileres Erscheinungsbild ); // Draw each node individually for better control @@ -744,7 +744,7 @@ class NeuralNetworkBackground { const y2 = fromNode.y + (toNode.y - fromNode.y) * progress; // Calculate opacity based on fade state - let opacity = connection.opacity * connection.fadeProgress; + let opacity = connection.opacity * connection.fadeProgress * 0.85; // Reduzierte Gesamtopazität // Erhöhe kurzzeitig die Opazität bei kürzlich aktivierten Verbindungen if (connection.lastActivated && now - connection.lastActivated < 800) { @@ -846,7 +846,7 @@ class NeuralNetworkBackground { flowColor.r / 255, flowColor.g / 255, flowColor.b / 255, - 0.55 // Dezent, aber sichtbar + 0.7 * fadeFactor // Reduced from higher values ); this.gl.enable(this.gl.BLEND); this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE); @@ -1107,20 +1107,20 @@ class NeuralNetworkBackground { this.ctx.beginPath(); this.ctx.moveTo(p1.x, p1.y); this.ctx.lineTo(p2.x, p2.y); - this.ctx.strokeStyle = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.15 * fadeFactor})`; - this.ctx.lineWidth = 3; - this.ctx.shadowColor = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.1 * fadeFactor})`; - this.ctx.shadowBlur = 7; + this.ctx.strokeStyle = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.12 * fadeFactor})`; // Reduziert von 0.15 + this.ctx.lineWidth = 2.5; // Reduziert von 3 + this.ctx.shadowColor = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.08 * fadeFactor})`; // Reduziert von 0.1 + this.ctx.shadowBlur = 6; // Reduziert von 7 this.ctx.stroke(); // Zickzack-Blitz mit geringerer Vibration generieren const zigzag = this.generateZigZagPoints(p1, p2, 6, 7); // Hauptblitz mit dezenterem Ein-/Ausblendeffekt - this.ctx.strokeStyle = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.5 * fadeFactor})`; - this.ctx.lineWidth = 1.2; - this.ctx.shadowColor = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.25 * fadeFactor})`; - this.ctx.shadowBlur = 6; + this.ctx.strokeStyle = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.4 * fadeFactor})`; // Reduziert von 0.5 + this.ctx.lineWidth = 1.0; // Reduziert von 1.2 + this.ctx.shadowColor = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.2 * fadeFactor})`; // Reduziert von 0.25 + this.ctx.shadowBlur = 5; // Reduziert von 6 this.ctx.beginPath(); this.ctx.moveTo(zigzag[0].x, zigzag[0].y); for (let i = 1; i < zigzag.length; i++) { @@ -1128,11 +1128,11 @@ class NeuralNetworkBackground { } this.ctx.stroke(); - // Weniger Funken mit geringerer Vibration - const sparks = this.generateSparkPoints(zigzag, 4 + Math.floor(Math.random() * 2)); + // Intensivere und mehr Funken + const sparks = this.generateSparkPoints(zigzag, 8 + Math.floor(Math.random() * 5)); // Intensiveres Funkenlicht mit dynamischem Ein-/Ausblendeffekt - const sparkBaseOpacity = this.isDarkMode ? 0.75 : 0.65; + const sparkBaseOpacity = this.isDarkMode ? 0.85 : 0.75; const sparkBaseColor = this.isDarkMode ? `rgba(230, 240, 250, ${sparkBaseOpacity * fadeFactor})` : `rgba(190, 230, 250, ${sparkBaseOpacity * fadeFactor})`; @@ -1140,10 +1140,10 @@ class NeuralNetworkBackground { for (const spark of sparks) { this.ctx.beginPath(); - // Subtilere Stern/Funken-Form - const points = 4 + Math.floor(Math.random() * 3); // 4-6 Spitzen - const outerRadius = spark.size * 1.8; - const innerRadius = spark.size * 0.4; + // Dynamischere Stern/Funken-Form + const points = 4 + Math.floor(Math.random() * 4); // 4-7 Spitzen + const outerRadius = spark.size * 2.0; + const innerRadius = spark.size * 0.35; for (let i = 0; i < points * 2; i++) { const radius = i % 2 === 0 ? outerRadius : innerRadius; @@ -1159,12 +1159,24 @@ class NeuralNetworkBackground { } this.ctx.closePath(); - this.ctx.fillStyle = sparkBaseColor; + + // Intensiveres Glühen this.ctx.shadowColor = this.isDarkMode - ? `rgba(170, 215, 245, ${0.4 * fadeFactor})` - : `rgba(140, 200, 245, ${0.3 * fadeFactor})`; - this.ctx.shadowBlur = 7; + ? `rgba(200, 225, 255, ${0.6 * fadeFactor})` + : `rgba(160, 220, 255, ${0.5 * fadeFactor})`; + this.ctx.shadowBlur = 12; + this.ctx.fillStyle = sparkBaseColor; this.ctx.fill(); + + // Zusätzlicher innerer Glüheffekt für ausgewählte Funken + if (spark.size > 4 && Math.random() > 0.5) { + this.ctx.beginPath(); + this.ctx.arc(spark.x, spark.y, spark.size * 0.6, 0, Math.PI * 2); + this.ctx.fillStyle = this.isDarkMode + ? `rgba(240, 250, 255, ${0.7 * fadeFactor})` + : `rgba(220, 240, 255, ${0.6 * fadeFactor})`; + this.ctx.fill(); + } } // Deutlicherer und länger anhaltender Fortschrittseffekt an der Spitze des Blitzes @@ -1183,23 +1195,6 @@ class NeuralNetworkBackground { this.ctx.fill(); } - // Verstärkter Start- und Endblitz-Fade mit längerer Sichtbarkeit - if (startProgress < 0.15) { - const startFade = startProgress / 0.15; // 0 bis 1 - const startGlow = this.ctx.createRadialGradient( - p1.x, p1.y, 0, - p1.x, p1.y, 12 * startFade - ); - startGlow.addColorStop(0, `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.6 * fadeFactor * startFade})`); - startGlow.addColorStop(0.7, `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.3 * fadeFactor * startFade})`); - startGlow.addColorStop(1, `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, 0)`); - - this.ctx.fillStyle = startGlow; - this.ctx.beginPath(); - this.ctx.arc(p1.x, p1.y, 12 * startFade, 0, Math.PI * 2); - this.ctx.fill(); - } - this.ctx.restore(); } } diff --git a/test_app.py b/test_app.py new file mode 100644 index 0000000..ac388ea --- /dev/null +++ b/test_app.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sqlite3 +import os +import requests +import time + +print("Systades Anwendungstest") +print("=======================") + +# Prüfen, ob die Datenbank existiert +db_path = 'systades.db' +if not os.path.exists(db_path): + print(f"Datenbank {db_path} existiert nicht.") + exit(1) + +# Datenbankprüfung +conn = sqlite3.connect(db_path) +cursor = conn.cursor() + +# Prüfen, ob die User-Tabelle existiert und Benutzer enthält +cursor.execute("SELECT COUNT(*) FROM user;") +user_count = cursor.fetchone()[0] +print(f"Anzahl der Benutzer in der Datenbank: {user_count}") + +if user_count == 0: + print("WARNUNG: Keine Benutzer in der Datenbank gefunden!") + print("Bitte führen Sie das Skript 'create_default_users.py' aus, um Standardbenutzer zu erstellen.") + conn.close() + exit(1) + +# Tabellenschema prüfen +cursor.execute("PRAGMA table_info(user);") +columns = cursor.fetchall() +column_names = [column[1] for column in columns] +print(f"Spalten in der User-Tabelle: {', '.join(column_names)}") + +# Überprüfen, ob die password-Spalte existiert +if 'password' not in column_names: + print("FEHLER: Die Spalte 'password' fehlt in der Tabelle 'user'!") + print("Bitte führen Sie das Skript 'fix_user_table.py' aus, um die Datenbank zu reparieren.") + conn.close() + exit(1) + +# Benutzer für Testlogin abrufen +cursor.execute("SELECT username, email FROM user LIMIT 1;") +test_user = cursor.fetchone() +if test_user: + print(f"Testbenutzer für Login: {test_user[0]} (E-Mail: {test_user[1]})") +else: + print("FEHLER: Konnte keinen Testbenutzer abrufen.") + +conn.close() + +print("\nDie Datenbank scheint korrekt konfiguriert zu sein.") +print("Sie können nun die Anwendung starten und sich mit den folgenden Zugangsdaten anmelden:") +print(" Admin: username=admin, password=admin") +print(" User: username=user, password=user") +print("\nTest abgeschlossen.") \ No newline at end of file