Compare commits

...

3 Commits

Author SHA1 Message Date
49ccf3908a Merge remote-tracking branch 'origin/tills-branch' into tills-branch 2025-04-29 10:28:36 +02:00
9514645904 keine ahnung ehrlich 2025-04-29 10:28:15 +02:00
63f45abb3e background, mindmap 2025-04-29 10:27:07 +02:00
9 changed files with 442 additions and 69 deletions

8
.vscode/jsconfig.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"compilerOptions": {
"target": "esnext",
"lib": [
"esnext"
]
}
}

68
.vscode/main.js vendored Normal file
View File

@@ -0,0 +1,68 @@
/// <reference types="vscode" />
// @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
}

View File

@@ -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

34
check_schema.py Normal file
View File

@@ -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()

72
create_default_users.py Normal file
View File

@@ -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.")

70
fix_user_table.py Normal file
View File

@@ -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.")

View File

@@ -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

View File

@@ -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();
}
}

60
test_app.py Normal file
View File

@@ -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.")