diff --git a/website/README.md b/website/README.md index 46e5eae..cf56801 100644 --- a/website/README.md +++ b/website/README.md @@ -12,6 +12,44 @@ Das MindMapProjekt ist eine interaktive Plattform zum Visualisieren, Erforschen - **Datenbank**: SQLite mit SQLAlchemy - **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 ### Phase 1: Grundlegende Infrastruktur ✅ diff --git a/website/TOOLS.py b/website/TOOLS.py new file mode 100755 index 0000000..ebea075 --- /dev/null +++ b/website/TOOLS.py @@ -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() \ No newline at end of file diff --git a/website/create_admin.py b/website/create_admin.py deleted file mode 100644 index 3de3c2d..0000000 --- a/website/create_admin.py +++ /dev/null @@ -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() \ No newline at end of file diff --git a/website/templates/mindmap.html b/website/templates/mindmap.html index c06af0f..958e7cb 100644 --- a/website/templates/mindmap.html +++ b/website/templates/mindmap.html @@ -730,18 +730,53 @@ document.addEventListener('DOMContentLoaded', function() { tooltipEnabled: true, onNodeClick: function(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`) - .then(response => response.json()) + .then(response => { + if (!response.ok) { + throw new Error('Netzwerkantwort war nicht ok'); + } + return response.json(); + }) .then(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 = ` +

${thought.title}

+

${thought.content}

+
+ ${new Date(thought.created_at).toLocaleDateString('de-DE')} + +
+ `; + thoughtsContainer.appendChild(thoughtElement); + }); + } else { + thoughtsContainer.innerHTML = '

Keine Gedanken für diesen Knoten vorhanden.

'; + } + } + + // Aktualisiere das Formular zum Hinzufügen von Gedanken + document.getElementById('thought-node-id').value = node.id; }) .catch(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(data => { - alert('Gedanke wurde hinzugefügt!'); - // Optional: Knoten neu laden oder Zähler aktualisieren + // Erfolgsmeldung anzeigen + 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 = ` +
+ +

Gedanke wurde erfolgreich hinzugefügt!

+
+ `; + 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 => { console.error('Fehler beim Hinzufügen des Gedankens:', error); @@ -874,9 +931,37 @@ document.addEventListener('DOMContentLoaded', function() { document.getElementById('connect-btn').addEventListener('click', function() { if (window.mindmap && window.mindmap.selectedNode) { - alert('Bitte wähle einen weiteren Knoten aus, um eine Verbindung herzustellen.'); - // Hier könnte ein spezieller Modus aktiviert werden, der auf den nächsten Klick wartet + // Speichere den ersten ausgewählten Knoten + 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 = ` +

Verbindungsmodus aktiv

+

Wähle einen zweiten Knoten aus, um eine Verbindung herzustellen

+ + `; + 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; + + // Cursor-Stil ändern, um den Verbindungsmodus anzuzeigen + document.getElementById('mindmap-container').style.cursor = 'crosshair'; } else { alert('Bitte wähle zuerst einen Knoten aus.'); } diff --git a/website/test_db.py b/website/test_db.py deleted file mode 100644 index 683f354..0000000 --- a/website/test_db.py +++ /dev/null @@ -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() \ No newline at end of file diff --git a/website/utils/__init__.py b/website/utils/__init__.py new file mode 100755 index 0000000..2a25a25 --- /dev/null +++ b/website/utils/__init__.py @@ -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', +] \ No newline at end of file diff --git a/website/utils/__pycache__/__init__.cpython-311.pyc b/website/utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..3a362b9 Binary files /dev/null and b/website/utils/__pycache__/__init__.cpython-311.pyc differ diff --git a/website/utils/__pycache__/db_fix.cpython-311.pyc b/website/utils/__pycache__/db_fix.cpython-311.pyc new file mode 100644 index 0000000..6c05a3d Binary files /dev/null and b/website/utils/__pycache__/db_fix.cpython-311.pyc differ diff --git a/website/utils/__pycache__/db_rebuild.cpython-311.pyc b/website/utils/__pycache__/db_rebuild.cpython-311.pyc new file mode 100644 index 0000000..1d4f21d Binary files /dev/null and b/website/utils/__pycache__/db_rebuild.cpython-311.pyc differ diff --git a/website/utils/__pycache__/db_test.cpython-311.pyc b/website/utils/__pycache__/db_test.cpython-311.pyc new file mode 100644 index 0000000..b4d3fa5 Binary files /dev/null and b/website/utils/__pycache__/db_test.cpython-311.pyc differ diff --git a/website/utils/__pycache__/server.cpython-311.pyc b/website/utils/__pycache__/server.cpython-311.pyc new file mode 100644 index 0000000..40209bf Binary files /dev/null and b/website/utils/__pycache__/server.cpython-311.pyc differ diff --git a/website/utils/__pycache__/user_manager.cpython-311.pyc b/website/utils/__pycache__/user_manager.cpython-311.pyc new file mode 100644 index 0000000..d13d2ac Binary files /dev/null and b/website/utils/__pycache__/user_manager.cpython-311.pyc differ diff --git a/website/fix_db.py b/website/utils/db_fix.py similarity index 92% rename from website/fix_db.py rename to website/utils/db_fix.py index 9bfbc93..2271457 100755 --- a/website/fix_db.py +++ b/website/utils/db_fix.py @@ -4,6 +4,13 @@ import os import sqlite3 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 models import db @@ -65,6 +72,7 @@ def fix_database_schema(): conn.commit() conn.close() print("Database schema updated successfully!") + return True if __name__ == "__main__": fix_database_schema() \ No newline at end of file diff --git a/website/rebuild_db.py b/website/utils/db_rebuild.py old mode 100644 new mode 100755 similarity index 91% rename from website/rebuild_db.py rename to website/utils/db_rebuild.py index 159eb08..cc10d92 --- a/website/rebuild_db.py +++ b/website/utils/db_rebuild.py @@ -4,6 +4,13 @@ import os import sqlite3 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 models import db, User, Category @@ -64,6 +71,7 @@ def rebuild_database(): create_default_categories() print("Database rebuild completed successfully!") + return True except Exception as e: db.session.rollback() print(f"Error during database rebuild: {str(e)}") diff --git a/website/utils/db_test.py b/website/utils/db_test.py new file mode 100755 index 0000000..f3653fa --- /dev/null +++ b/website/utils/db_test.py @@ -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() \ No newline at end of file diff --git a/website/utils/server.py b/website/utils/server.py new file mode 100755 index 0000000..2f36df4 --- /dev/null +++ b/website/utils/server.py @@ -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) \ No newline at end of file diff --git a/website/utils/user_manager.py b/website/utils/user_manager.py new file mode 100755 index 0000000..081fff0 --- /dev/null +++ b/website/utils/user_manager.py @@ -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() \ No newline at end of file