Remove deprecated database management scripts and admin user creation functionality: Delete create_admin.py, fix_db.py, rebuild_db.py, and test_db.py to streamline the project structure and eliminate unused code. Update README.md with installation instructions and management tools for improved user guidance.
This commit is contained in:
@@ -12,6 +12,44 @@ Das MindMapProjekt ist eine interaktive Plattform zum Visualisieren, Erforschen
|
|||||||
- **Datenbank**: SQLite mit SQLAlchemy
|
- **Datenbank**: SQLite mit SQLAlchemy
|
||||||
- **KI-Integration**: OpenAI API für intelligente Assistenz
|
- **KI-Integration**: OpenAI API für intelligente Assistenz
|
||||||
|
|
||||||
|
## Installation und Verwendung
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
1. Repository klonen
|
||||||
|
2. Virtuelle Umgebung erstellen: `python -m venv venv`
|
||||||
|
3. Virtuelle Umgebung aktivieren:
|
||||||
|
- Windows: `venv\Scripts\activate`
|
||||||
|
- Unix/MacOS: `source venv/bin/activate`
|
||||||
|
4. Abhängigkeiten installieren: `pip install -r requirements.txt`
|
||||||
|
5. Datenbank initialisieren: `python TOOLS.py db:rebuild`
|
||||||
|
6. Admin-Benutzer erstellen: `python TOOLS.py user:admin`
|
||||||
|
7. Server starten: `python TOOLS.py server:run`
|
||||||
|
|
||||||
|
### Standardbenutzer
|
||||||
|
- **Admin-Benutzer**: Username: `admin` / Passwort: `admin`
|
||||||
|
- **Testbenutzer**: Username: `user` / Passwort: `user`
|
||||||
|
|
||||||
|
### Verwaltungswerkzeuge mit TOOLS.py
|
||||||
|
Das Projekt enthält ein zentrales Verwaltungsskript `TOOLS.py`, das verschiedene Hilfsfunktionen bietet:
|
||||||
|
|
||||||
|
#### Datenbankverwaltung
|
||||||
|
- `python TOOLS.py db:fix` - Reparieren der Datenbankstruktur
|
||||||
|
- `python TOOLS.py db:rebuild` - Datenbank neu aufbauen (löscht alle Daten!)
|
||||||
|
- `python TOOLS.py db:test` - Datenbankverbindung und Modelle testen
|
||||||
|
- `python TOOLS.py db:stats` - Datenbankstatistiken anzeigen
|
||||||
|
|
||||||
|
#### Benutzerverwaltung
|
||||||
|
- `python TOOLS.py user:list` - Alle Benutzer anzeigen
|
||||||
|
- `python TOOLS.py user:create -u USERNAME -e EMAIL -p PASSWORD [-a]` - Neuen Benutzer erstellen
|
||||||
|
- `python TOOLS.py user:admin` - Admin-Benutzer erstellen (admin/admin)
|
||||||
|
- `python TOOLS.py user:reset-pw -u USERNAME -p NEWPASSWORD` - Benutzerpasswort zurücksetzen
|
||||||
|
- `python TOOLS.py user:delete -u USERNAME` - Benutzer löschen
|
||||||
|
|
||||||
|
#### Serververwaltung
|
||||||
|
- `python TOOLS.py server:run [--host HOST] [--port PORT] [--no-debug]` - Entwicklungsserver starten
|
||||||
|
|
||||||
|
Für detaillierte Hilfe: `python TOOLS.py -h`
|
||||||
|
|
||||||
## Roadmap der Überarbeitung
|
## Roadmap der Überarbeitung
|
||||||
|
|
||||||
### Phase 1: Grundlegende Infrastruktur ✅
|
### Phase 1: Grundlegende Infrastruktur ✅
|
||||||
|
|||||||
125
website/TOOLS.py
Executable file
125
website/TOOLS.py
Executable file
@@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
TOOLS.py - Main utility script for the website application.
|
||||||
|
|
||||||
|
This script provides a command-line interface to all utilities
|
||||||
|
for database management, user management, and server administration.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 TOOLS.py [command] [options]
|
||||||
|
|
||||||
|
Available commands:
|
||||||
|
- db:fix Fix database schema
|
||||||
|
- db:rebuild Completely rebuild the database
|
||||||
|
- db:test Test database connection and models
|
||||||
|
- db:stats Show database statistics
|
||||||
|
|
||||||
|
- user:list List all users
|
||||||
|
- user:create Create a new user
|
||||||
|
- user:admin Create admin user (username: admin, password: admin)
|
||||||
|
- user:reset-pw Reset user password
|
||||||
|
- user:delete Delete a user
|
||||||
|
|
||||||
|
- server:run Run the development server
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
python3 TOOLS.py db:rebuild
|
||||||
|
python3 TOOLS.py user:admin
|
||||||
|
python3 TOOLS.py server:run --port 8080
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
from utils import (
|
||||||
|
fix_database_schema, rebuild_database, run_all_tests, print_database_stats,
|
||||||
|
list_users, create_user, reset_password, delete_user, create_admin_user,
|
||||||
|
run_development_server
|
||||||
|
)
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Website Administration Tools',
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog=__doc__
|
||||||
|
)
|
||||||
|
|
||||||
|
# Main command argument
|
||||||
|
parser.add_argument('command', help='Command to execute')
|
||||||
|
|
||||||
|
# Additional arguments
|
||||||
|
parser.add_argument('--username', '-u', help='Username for user commands')
|
||||||
|
parser.add_argument('--email', '-e', help='Email for user creation')
|
||||||
|
parser.add_argument('--password', '-p', help='Password for user creation/reset')
|
||||||
|
parser.add_argument('--admin', '-a', action='store_true', help='Make user an admin')
|
||||||
|
parser.add_argument('--host', help='Host for server (default: 127.0.0.1)')
|
||||||
|
parser.add_argument('--port', type=int, help='Port for server (default: 5000)')
|
||||||
|
parser.add_argument('--no-debug', action='store_true', help='Disable debug mode for server')
|
||||||
|
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
|
||||||
|
# Database commands
|
||||||
|
if args.command == 'db:fix':
|
||||||
|
fix_database_schema()
|
||||||
|
|
||||||
|
elif args.command == 'db:rebuild':
|
||||||
|
print("WARNING: This will delete all data in the database!")
|
||||||
|
confirm = input("Are you sure you want to continue? (y/n): ").lower()
|
||||||
|
if confirm == 'y':
|
||||||
|
rebuild_database()
|
||||||
|
else:
|
||||||
|
print("Aborted.")
|
||||||
|
|
||||||
|
elif args.command == 'db:test':
|
||||||
|
run_all_tests()
|
||||||
|
|
||||||
|
elif args.command == 'db:stats':
|
||||||
|
print_database_stats()
|
||||||
|
|
||||||
|
# User commands
|
||||||
|
elif args.command == 'user:list':
|
||||||
|
list_users()
|
||||||
|
|
||||||
|
elif args.command == 'user:create':
|
||||||
|
if not args.username or not args.email or not args.password:
|
||||||
|
print("Error: Username, email, and password are required.")
|
||||||
|
print("Example: python3 TOOLS.py user:create -u username -e email -p password [-a]")
|
||||||
|
sys.exit(1)
|
||||||
|
create_user(args.username, args.email, args.password, args.admin)
|
||||||
|
|
||||||
|
elif args.command == 'user:admin':
|
||||||
|
create_admin_user()
|
||||||
|
|
||||||
|
elif args.command == 'user:reset-pw':
|
||||||
|
if not args.username or not args.password:
|
||||||
|
print("Error: Username and password are required.")
|
||||||
|
print("Example: python3 TOOLS.py user:reset-pw -u username -p new_password")
|
||||||
|
sys.exit(1)
|
||||||
|
reset_password(args.username, args.password)
|
||||||
|
|
||||||
|
elif args.command == 'user:delete':
|
||||||
|
if not args.username:
|
||||||
|
print("Error: Username is required.")
|
||||||
|
print("Example: python3 TOOLS.py user:delete -u username")
|
||||||
|
sys.exit(1)
|
||||||
|
delete_user(args.username)
|
||||||
|
|
||||||
|
# Server commands
|
||||||
|
elif args.command == 'server:run':
|
||||||
|
host = args.host or '127.0.0.1'
|
||||||
|
port = args.port or 5000
|
||||||
|
debug = not args.no_debug
|
||||||
|
run_development_server(host=host, port=port, debug=debug)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f"Unknown command: {args.command}")
|
||||||
|
print("Run 'python3 TOOLS.py -h' for usage information")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from app import app
|
|
||||||
from models import db, User
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
def create_admin_user():
|
|
||||||
"""Create an admin user in the database."""
|
|
||||||
with app.app_context():
|
|
||||||
try:
|
|
||||||
# Check if admin user already exists
|
|
||||||
admin = User.query.filter_by(username='admin').first()
|
|
||||||
if admin:
|
|
||||||
print("Admin user already exists")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Create admin user
|
|
||||||
admin = User(
|
|
||||||
username='admin',
|
|
||||||
email='admin@example.com',
|
|
||||||
is_admin=True,
|
|
||||||
created_at=datetime.utcnow()
|
|
||||||
)
|
|
||||||
admin.set_password('admin')
|
|
||||||
|
|
||||||
# Add and commit
|
|
||||||
db.session.add(admin)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
print("Admin user created successfully!")
|
|
||||||
|
|
||||||
# Verify user was added
|
|
||||||
user = User.query.filter_by(username='admin').first()
|
|
||||||
if user:
|
|
||||||
print(f"Verified: Admin user exists with ID {user.id}")
|
|
||||||
else:
|
|
||||||
print("WARNING: Failed to verify admin user creation")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error creating admin user: {e}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
create_admin_user()
|
|
||||||
@@ -730,18 +730,53 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
tooltipEnabled: true,
|
tooltipEnabled: true,
|
||||||
onNodeClick: function(node) {
|
onNodeClick: function(node) {
|
||||||
console.log('Node clicked:', node);
|
console.log('Node clicked:', node);
|
||||||
// Hier könnten wir weitere Informationen zum Knoten anzeigen
|
|
||||||
// oder mehr Daten vom Server abrufen
|
|
||||||
|
|
||||||
// Beispiel: Gedanken zu diesem Knoten laden
|
// Gedanken zu diesem Knoten laden
|
||||||
fetch(`/api/nodes/${node.id}/thoughts`)
|
fetch(`/api/nodes/${node.id}/thoughts`)
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Netzwerkantwort war nicht ok');
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log('Gedanken zu diesem Knoten:', data);
|
console.log('Gedanken zu diesem Knoten:', data);
|
||||||
// Hier könnte die Anzeige aktualisiert werden
|
|
||||||
|
// Gedanken im Seitenbereich anzeigen
|
||||||
|
const thoughtsContainer = document.getElementById('thoughts-container');
|
||||||
|
if (thoughtsContainer) {
|
||||||
|
thoughtsContainer.innerHTML = '';
|
||||||
|
|
||||||
|
if (data.thoughts && data.thoughts.length > 0) {
|
||||||
|
data.thoughts.forEach(thought => {
|
||||||
|
const thoughtElement = document.createElement('div');
|
||||||
|
thoughtElement.className = 'thought-item bg-gray-800 rounded-lg p-4 mb-3';
|
||||||
|
thoughtElement.innerHTML = `
|
||||||
|
<h3 class="text-lg font-semibold text-white">${thought.title}</h3>
|
||||||
|
<p class="text-gray-300 mt-2">${thought.content}</p>
|
||||||
|
<div class="flex justify-between mt-3">
|
||||||
|
<span class="text-sm text-gray-400">${new Date(thought.created_at).toLocaleDateString('de-DE')}</span>
|
||||||
|
<button class="text-blue-400 hover:text-blue-300" data-thought-id="${thought.id}">
|
||||||
|
<i class="fas fa-bookmark"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
thoughtsContainer.appendChild(thoughtElement);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
thoughtsContainer.innerHTML = '<p class="text-gray-400">Keine Gedanken für diesen Knoten vorhanden.</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aktualisiere das Formular zum Hinzufügen von Gedanken
|
||||||
|
document.getElementById('thought-node-id').value = node.id;
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Fehler beim Laden der Gedanken:', error);
|
console.error('Fehler beim Laden der Gedanken:', error);
|
||||||
|
// Benutzer über den Fehler informieren
|
||||||
|
if (window.mindmap && window.mindmap.showFlash) {
|
||||||
|
window.mindmap.showFlash('Fehler beim Laden der Gedanken', 'error');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -858,8 +893,30 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
alert('Gedanke wurde hinzugefügt!');
|
// Erfolgsmeldung anzeigen
|
||||||
// Optional: Knoten neu laden oder Zähler aktualisieren
|
const notification = document.createElement('div');
|
||||||
|
notification.className = 'fixed top-4 right-4 bg-green-600 text-white p-4 rounded-lg shadow-lg z-50 animate-fade-in';
|
||||||
|
notification.innerHTML = `
|
||||||
|
<div class="flex items-center">
|
||||||
|
<i class="fas fa-check-circle mr-2"></i>
|
||||||
|
<p>Gedanke wurde erfolgreich hinzugefügt!</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
document.body.appendChild(notification);
|
||||||
|
|
||||||
|
// Notification nach 3 Sekunden ausblenden
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.classList.add('animate-fade-out');
|
||||||
|
setTimeout(() => document.body.removeChild(notification), 500);
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
// Aktualisiere den Gedankenzähler am Knoten, falls vorhanden
|
||||||
|
const nodeElement = document.getElementById(`node-${window.mindmap.selectedNode.id}`);
|
||||||
|
const countElement = nodeElement.querySelector('.thought-count');
|
||||||
|
if (countElement) {
|
||||||
|
const currentCount = parseInt(countElement.textContent);
|
||||||
|
countElement.textContent = (currentCount + 1).toString();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Fehler beim Hinzufügen des Gedankens:', error);
|
console.error('Fehler beim Hinzufügen des Gedankens:', error);
|
||||||
@@ -874,9 +931,37 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
document.getElementById('connect-btn').addEventListener('click', function() {
|
document.getElementById('connect-btn').addEventListener('click', function() {
|
||||||
if (window.mindmap && window.mindmap.selectedNode) {
|
if (window.mindmap && window.mindmap.selectedNode) {
|
||||||
alert('Bitte wähle einen weiteren Knoten aus, um eine Verbindung herzustellen.');
|
// Speichere den ersten ausgewählten Knoten
|
||||||
// Hier könnte ein spezieller Modus aktiviert werden, der auf den nächsten Klick wartet
|
window.mindmap.sourceNode = window.mindmap.selectedNode;
|
||||||
|
|
||||||
|
// Visuelles Feedback für den Benutzer
|
||||||
|
const selectedCircle = d3.select(`#node-${window.mindmap.selectedNode.id} circle`);
|
||||||
|
selectedCircle.classed('connection-source', true);
|
||||||
|
|
||||||
|
// Benutzerfreundlichere Benachrichtigung mit Statusanzeige
|
||||||
|
const notification = document.createElement('div');
|
||||||
|
notification.id = 'connection-notification';
|
||||||
|
notification.className = 'fixed top-4 right-4 bg-purple-600 text-white p-4 rounded-lg shadow-lg z-50';
|
||||||
|
notification.innerHTML = `
|
||||||
|
<p class="font-bold mb-1">Verbindungsmodus aktiv</p>
|
||||||
|
<p class="text-sm">Wähle einen zweiten Knoten aus, um eine Verbindung herzustellen</p>
|
||||||
|
<button id="cancel-connection" class="mt-2 px-3 py-1 bg-purple-800 rounded hover:bg-purple-900 text-sm">Abbrechen</button>
|
||||||
|
`;
|
||||||
|
document.body.appendChild(notification);
|
||||||
|
|
||||||
|
// Abbrechen-Button-Funktionalität
|
||||||
|
document.getElementById('cancel-connection').addEventListener('click', function() {
|
||||||
|
window.mindmap.connectMode = false;
|
||||||
|
window.mindmap.sourceNode = null;
|
||||||
|
selectedCircle.classed('connection-source', false);
|
||||||
|
document.body.removeChild(notification);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Aktiviere den Verbindungsmodus
|
||||||
window.mindmap.connectMode = true;
|
window.mindmap.connectMode = true;
|
||||||
|
|
||||||
|
// Cursor-Stil ändern, um den Verbindungsmodus anzuzeigen
|
||||||
|
document.getElementById('mindmap-container').style.cursor = 'crosshair';
|
||||||
} else {
|
} else {
|
||||||
alert('Bitte wähle zuerst einen Knoten aus.');
|
alert('Bitte wähle zuerst einen Knoten aus.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from app import app
|
|
||||||
from models import db, User
|
|
||||||
|
|
||||||
def test_user_query():
|
|
||||||
"""Test if we can query the user table."""
|
|
||||||
with app.app_context():
|
|
||||||
try:
|
|
||||||
# Try to query all users
|
|
||||||
users = User.query.all()
|
|
||||||
print(f"Found {len(users)} users")
|
|
||||||
|
|
||||||
for user in users:
|
|
||||||
print(f"User: {user.username}, Email: {user.email}")
|
|
||||||
|
|
||||||
# Try to query by username - this is where the error happens
|
|
||||||
user = User.query.filter_by(username='admin').first()
|
|
||||||
if user:
|
|
||||||
print(f"Found admin user: {user.username}")
|
|
||||||
else:
|
|
||||||
print("Admin user not found")
|
|
||||||
|
|
||||||
print("All queries completed successfully!")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error: {e}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
test_user_query()
|
|
||||||
34
website/utils/__init__.py
Executable file
34
website/utils/__init__.py
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Utility functions for the website application.
|
||||||
|
This package contains various utilities for database management,
|
||||||
|
user management, and server administration.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .db_fix import fix_database_schema
|
||||||
|
from .db_rebuild import rebuild_database
|
||||||
|
from .db_test import test_database_connection, test_models, print_database_stats, run_all_tests
|
||||||
|
from .user_manager import list_users, create_user, reset_password, delete_user, create_admin_user
|
||||||
|
from .server import run_development_server
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
# Database utilities
|
||||||
|
'fix_database_schema',
|
||||||
|
'rebuild_database',
|
||||||
|
'test_database_connection',
|
||||||
|
'test_models',
|
||||||
|
'print_database_stats',
|
||||||
|
'run_all_tests',
|
||||||
|
|
||||||
|
# User management
|
||||||
|
'list_users',
|
||||||
|
'create_user',
|
||||||
|
'reset_password',
|
||||||
|
'delete_user',
|
||||||
|
'create_admin_user',
|
||||||
|
|
||||||
|
# Server management
|
||||||
|
'run_development_server',
|
||||||
|
]
|
||||||
BIN
website/utils/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
website/utils/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
website/utils/__pycache__/db_fix.cpython-311.pyc
Normal file
BIN
website/utils/__pycache__/db_fix.cpython-311.pyc
Normal file
Binary file not shown.
BIN
website/utils/__pycache__/db_rebuild.cpython-311.pyc
Normal file
BIN
website/utils/__pycache__/db_rebuild.cpython-311.pyc
Normal file
Binary file not shown.
BIN
website/utils/__pycache__/db_test.cpython-311.pyc
Normal file
BIN
website/utils/__pycache__/db_test.cpython-311.pyc
Normal file
Binary file not shown.
BIN
website/utils/__pycache__/server.cpython-311.pyc
Normal file
BIN
website/utils/__pycache__/server.cpython-311.pyc
Normal file
Binary file not shown.
BIN
website/utils/__pycache__/user_manager.cpython-311.pyc
Normal file
BIN
website/utils/__pycache__/user_manager.cpython-311.pyc
Normal file
Binary file not shown.
@@ -4,6 +4,13 @@
|
|||||||
import os
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import sys
|
||||||
|
import importlib.util
|
||||||
|
|
||||||
|
# Add the parent directory to path so we can import the app
|
||||||
|
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
sys.path.insert(0, parent_dir)
|
||||||
|
|
||||||
from app import app, db_path
|
from app import app, db_path
|
||||||
from models import db
|
from models import db
|
||||||
|
|
||||||
@@ -65,6 +72,7 @@ def fix_database_schema():
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
print("Database schema updated successfully!")
|
print("Database schema updated successfully!")
|
||||||
|
return True
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
fix_database_schema()
|
fix_database_schema()
|
||||||
8
website/rebuild_db.py → website/utils/db_rebuild.py
Normal file → Executable file
8
website/rebuild_db.py → website/utils/db_rebuild.py
Normal file → Executable file
@@ -4,6 +4,13 @@
|
|||||||
import os
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import sys
|
||||||
|
import importlib.util
|
||||||
|
|
||||||
|
# Add the parent directory to path so we can import the app
|
||||||
|
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
sys.path.insert(0, parent_dir)
|
||||||
|
|
||||||
from app import app, db_path, create_default_categories
|
from app import app, db_path, create_default_categories
|
||||||
from models import db, User, Category
|
from models import db, User, Category
|
||||||
|
|
||||||
@@ -64,6 +71,7 @@ def rebuild_database():
|
|||||||
create_default_categories()
|
create_default_categories()
|
||||||
|
|
||||||
print("Database rebuild completed successfully!")
|
print("Database rebuild completed successfully!")
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.session.rollback()
|
db.session.rollback()
|
||||||
print(f"Error during database rebuild: {str(e)}")
|
print(f"Error during database rebuild: {str(e)}")
|
||||||
120
website/utils/db_test.py
Executable file
120
website/utils/db_test.py
Executable file
@@ -0,0 +1,120 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
# Add the parent directory to path so we can import the app
|
||||||
|
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
sys.path.insert(0, parent_dir)
|
||||||
|
|
||||||
|
from app import app, db_path
|
||||||
|
from models import db, User, Thought, MindMapNode, Category
|
||||||
|
|
||||||
|
def test_database_connection():
|
||||||
|
"""Test if the database exists and can be connected to."""
|
||||||
|
try:
|
||||||
|
if not os.path.exists(db_path):
|
||||||
|
print(f"Database file does not exist: {db_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("PRAGMA integrity_check")
|
||||||
|
result = cursor.fetchone()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
if result and result[0] == "ok":
|
||||||
|
print(f"Database integrity check passed: {db_path}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"Database integrity check failed: {result}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error testing database connection: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_models():
|
||||||
|
"""Test if all models are properly defined and can be queried."""
|
||||||
|
with app.app_context():
|
||||||
|
try:
|
||||||
|
print("\nTesting User model...")
|
||||||
|
user_count = User.query.count()
|
||||||
|
print(f" Found {user_count} users")
|
||||||
|
|
||||||
|
print("\nTesting Category model...")
|
||||||
|
category_count = Category.query.count()
|
||||||
|
print(f" Found {category_count} categories")
|
||||||
|
|
||||||
|
print("\nTesting MindMapNode model...")
|
||||||
|
node_count = MindMapNode.query.count()
|
||||||
|
print(f" Found {node_count} mindmap nodes")
|
||||||
|
|
||||||
|
print("\nTesting Thought model...")
|
||||||
|
thought_count = Thought.query.count()
|
||||||
|
print(f" Found {thought_count} thoughts")
|
||||||
|
|
||||||
|
if user_count == 0:
|
||||||
|
print("\nWARNING: No users found in the database. You might need to create an admin user.")
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error testing models: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def print_database_stats():
|
||||||
|
"""Print database statistics."""
|
||||||
|
with app.app_context():
|
||||||
|
try:
|
||||||
|
stats = []
|
||||||
|
stats.append(("Users", User.query.count()))
|
||||||
|
stats.append(("Categories", Category.query.count()))
|
||||||
|
stats.append(("Mindmap Nodes", MindMapNode.query.count()))
|
||||||
|
stats.append(("Thoughts", Thought.query.count()))
|
||||||
|
|
||||||
|
print("\nDatabase Statistics:")
|
||||||
|
print("-" * 40)
|
||||||
|
for name, count in stats:
|
||||||
|
print(f"{name:<20} : {count}")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error generating database statistics: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_all_tests():
|
||||||
|
"""Run all database tests."""
|
||||||
|
success = True
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print("STARTING DATABASE TESTS")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# Test database connection
|
||||||
|
print("\n1. Testing database connection...")
|
||||||
|
if not test_database_connection():
|
||||||
|
success = False
|
||||||
|
|
||||||
|
# Test models
|
||||||
|
print("\n2. Testing database models...")
|
||||||
|
if not test_models():
|
||||||
|
success = False
|
||||||
|
|
||||||
|
# Print statistics
|
||||||
|
print("\n3. Database statistics:")
|
||||||
|
if not print_database_stats():
|
||||||
|
success = False
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
if success:
|
||||||
|
print("All database tests completed successfully!")
|
||||||
|
else:
|
||||||
|
print("Some database tests failed. Check the output above for details.")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
return success
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run_all_tests()
|
||||||
34
website/utils/server.py
Executable file
34
website/utils/server.py
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Add the parent directory to path so we can import the app
|
||||||
|
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
sys.path.insert(0, parent_dir)
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
|
||||||
|
def run_development_server(host='127.0.0.1', port=5000, debug=True):
|
||||||
|
"""Run the Flask development server."""
|
||||||
|
try:
|
||||||
|
print(f"Starting development server on http://{host}:{port}")
|
||||||
|
print("Press CTRL+C to stop the server")
|
||||||
|
app.run(host=host, port=port, debug=debug)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error starting development server: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Run the development server')
|
||||||
|
parser.add_argument('--host', default='127.0.0.1', help='Host to bind to')
|
||||||
|
parser.add_argument('--port', type=int, default=5000, help='Port to bind to')
|
||||||
|
parser.add_argument('--debug', action='store_true', default=True, help='Enable debug mode')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
run_development_server(host=args.host, port=args.port, debug=args.debug)
|
||||||
159
website/utils/user_manager.py
Executable file
159
website/utils/user_manager.py
Executable file
@@ -0,0 +1,159 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# Add the parent directory to path so we can import the app
|
||||||
|
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
sys.path.insert(0, parent_dir)
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
from models import db, User
|
||||||
|
|
||||||
|
def list_users():
|
||||||
|
"""List all users in the database."""
|
||||||
|
with app.app_context():
|
||||||
|
try:
|
||||||
|
users = User.query.all()
|
||||||
|
if not users:
|
||||||
|
print("No users found in the database.")
|
||||||
|
return []
|
||||||
|
|
||||||
|
print("Found {} users:".format(len(users)))
|
||||||
|
print("-" * 60)
|
||||||
|
print("{:<5} {:<20} {:<30} {:<10}".format("ID", "Username", "Email", "Admin"))
|
||||||
|
print("-" * 60)
|
||||||
|
|
||||||
|
for user in users:
|
||||||
|
print("{:<5} {:<20} {:<30} {:<10}".format(
|
||||||
|
user.id, user.username, user.email, "Yes" if user.is_admin else "No"
|
||||||
|
))
|
||||||
|
return users
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error listing users: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def create_user(username, email, password, is_admin=False):
|
||||||
|
"""Create a new user in the database."""
|
||||||
|
with app.app_context():
|
||||||
|
try:
|
||||||
|
# Check if user already exists
|
||||||
|
existing_user = User.query.filter_by(username=username).first()
|
||||||
|
if existing_user:
|
||||||
|
print(f"User with username '{username}' already exists.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check if email already exists
|
||||||
|
existing_email = User.query.filter_by(email=email).first()
|
||||||
|
if existing_email:
|
||||||
|
print(f"User with email '{email}' already exists.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Create new user
|
||||||
|
user = User(
|
||||||
|
username=username,
|
||||||
|
email=email,
|
||||||
|
is_admin=is_admin,
|
||||||
|
created_at=datetime.utcnow()
|
||||||
|
)
|
||||||
|
user.set_password(password)
|
||||||
|
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
print(f"User '{username}' created successfully!")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
db.session.rollback()
|
||||||
|
print(f"Error creating user: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def reset_password(username, new_password):
|
||||||
|
"""Reset password for a user."""
|
||||||
|
with app.app_context():
|
||||||
|
try:
|
||||||
|
user = User.query.filter_by(username=username).first()
|
||||||
|
if not user:
|
||||||
|
print(f"User '{username}' not found.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
user.set_password(new_password)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
print(f"Password for user '{username}' reset successfully!")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
db.session.rollback()
|
||||||
|
print(f"Error resetting password: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete_user(username):
|
||||||
|
"""Delete a user from the database."""
|
||||||
|
with app.app_context():
|
||||||
|
try:
|
||||||
|
user = User.query.filter_by(username=username).first()
|
||||||
|
if not user:
|
||||||
|
print(f"User '{username}' not found.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
db.session.delete(user)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
print(f"User '{username}' deleted successfully!")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
db.session.rollback()
|
||||||
|
print(f"Error deleting user: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def create_admin_user():
|
||||||
|
"""Create an admin user in the database."""
|
||||||
|
return create_user('admin', 'admin@example.com', 'admin', is_admin=True)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='User management utility')
|
||||||
|
subparsers = parser.add_subparsers(dest='command', help='Command to execute')
|
||||||
|
|
||||||
|
# List users command
|
||||||
|
list_parser = subparsers.add_parser('list', help='List all users')
|
||||||
|
|
||||||
|
# Create user command
|
||||||
|
create_parser = subparsers.add_parser('create', help='Create a new user')
|
||||||
|
create_parser.add_argument('--username', '-u', required=True, help='Username')
|
||||||
|
create_parser.add_argument('--email', '-e', required=True, help='Email address')
|
||||||
|
create_parser.add_argument('--password', '-p', required=True, help='Password')
|
||||||
|
create_parser.add_argument('--admin', '-a', action='store_true', help='Make user an admin')
|
||||||
|
|
||||||
|
# Reset password command
|
||||||
|
reset_parser = subparsers.add_parser('reset-password', help='Reset a user password')
|
||||||
|
reset_parser.add_argument('--username', '-u', required=True, help='Username')
|
||||||
|
reset_parser.add_argument('--password', '-p', required=True, help='New password')
|
||||||
|
|
||||||
|
# Delete user command
|
||||||
|
delete_parser = subparsers.add_parser('delete', help='Delete a user')
|
||||||
|
delete_parser.add_argument('--username', '-u', required=True, help='Username to delete')
|
||||||
|
|
||||||
|
# Create admin command (shortcut)
|
||||||
|
admin_parser = subparsers.add_parser('create-admin', help='Create the default admin user')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.command == 'list':
|
||||||
|
list_users()
|
||||||
|
elif args.command == 'create':
|
||||||
|
create_user(args.username, args.email, args.password, args.admin)
|
||||||
|
elif args.command == 'reset-password':
|
||||||
|
reset_password(args.username, args.password)
|
||||||
|
elif args.command == 'delete':
|
||||||
|
delete_user(args.username)
|
||||||
|
elif args.command == 'create-admin':
|
||||||
|
create_admin_user()
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
Reference in New Issue
Block a user