diff --git a/app.py b/app.py index c83e63c..d377fcb 100644 --- a/app.py +++ b/app.py @@ -2472,710 +2472,217 @@ def admin_update_database(): return render_template('admin/update_database.html', message=message, success=success) @app.route('/api/mindmap/') -def get_mindmap_node(node_id): - """Liefert die Mindmap-Daten für einen bestimmten Knoten und seine Subthemen.""" +def get_mindmap_data(node_id): + """ + Stellt Mindmap-Daten für das Frontend bereit. + Liefert für 'root' die Hauptebene und für andere Node-IDs die entsprechenden Unterknoten. + """ + app.logger.info(f"Mindmap-Daten werden für Node '{node_id}' angefordert.") + try: - # Erkennen besonderer Knotennamen if node_id == 'root': - # Hauptknoten (Wissen) abrufen - dieser sollte durch die Datenbank-Initialisierung bereits existieren - wissen_node = MindMapNode.query.filter_by(name="Wissen").first() - if not wissen_node: - # Fallback-Erstellung des Wissen-Knotens, falls er wider Erwarten nicht existiert - wissen_node = MindMapNode( - name="Wissen", - description="Zentrale Wissensbasis", - color_code="#4299E1", - is_public=True - ) - db.session.add(wissen_node) - db.session.commit() - app.logger.warning("'Wissen'-Knoten musste während einer API-Anfrage erstellt werden. " - "Dies sollte normalerweise nicht vorkommen, da er bei der Initialisierung erstellt werden sollte.") + # Hauptebene der Mindmap + nodes = [ + { + "id": "center", + "name": "Wissenskarte", + "description": "Zentrale Wissenskarte mit allen Hauptthemen", + "is_center": True, + "color_code": "#f5f5f5", + "has_children": True + }, + { + "id": "philosophy", + "name": "Philosophie", + "description": "Die Lehre vom Denken und der Erkenntnis", + "category": "Philosophie", + "has_children": True, + "color_code": "#9F7AEA" + }, + { + "id": "science", + "name": "Wissenschaft", + "description": "Systematische Erforschung der Natur und Gesellschaft", + "category": "Wissenschaft", + "has_children": True, + "color_code": "#f4b400" + }, + { + "id": "technology", + "name": "Technologie", + "description": "Anwendung wissenschaftlicher Erkenntnisse", + "category": "Technologie", + "has_children": True, + "color_code": "#0d47a1" + }, + { + "id": "arts", + "name": "Künste", + "description": "Kreativer Ausdruck und künstlerische Gestaltung", + "category": "Künste", + "has_children": True, + "color_code": "#c2185b" + } + ] + + edges = [ + {"source_id": "center", "target_id": "philosophy", "strength": 0.9}, + {"source_id": "center", "target_id": "science", "strength": 0.9}, + {"source_id": "center", "target_id": "technology", "strength": 0.9}, + {"source_id": "center", "target_id": "arts", "strength": 0.9} + ] + + elif node_id == 'philosophy': + nodes = [ + { + "id": "epistemology", + "name": "Erkenntnistheorie", + "description": "Untersuchung der Natur und Grenzen menschlicher Erkenntnis", + "category": "Philosophie", + "has_children": True, + "color_code": "#9F7AEA" + }, + { + "id": "ethics", + "name": "Ethik", + "description": "Lehre vom moralisch richtigen Handeln", + "category": "Philosophie", + "has_children": True, + "color_code": "#9F7AEA" + }, + { + "id": "metaphysics", + "name": "Metaphysik", + "description": "Grundfragen des Seins und der Wirklichkeit", + "category": "Philosophie", + "has_children": True, + "color_code": "#9F7AEA" + } + ] + + edges = [ + {"source_id": "philosophy", "target_id": "epistemology", "strength": 0.8}, + {"source_id": "philosophy", "target_id": "ethics", "strength": 0.8}, + {"source_id": "philosophy", "target_id": "metaphysics", "strength": 0.8} + ] + + elif node_id == 'science': + nodes = [ + { + "id": "physics", + "name": "Physik", + "description": "Lehre von der Materie und ihren Wechselwirkungen", + "category": "Wissenschaft", + "has_children": True, + "color_code": "#f4b400" + }, + { + "id": "biology", + "name": "Biologie", + "description": "Lehre von den Lebewesen und ihren Lebensprozessen", + "category": "Wissenschaft", + "has_children": True, + "color_code": "#f4b400" + }, + { + "id": "chemistry", + "name": "Chemie", + "description": "Wissenschaft von den Stoffen und ihren Reaktionen", + "category": "Wissenschaft", + "has_children": True, + "color_code": "#f4b400" + } + ] + + edges = [ + {"source_id": "science", "target_id": "physics", "strength": 0.8}, + {"source_id": "science", "target_id": "biology", "strength": 0.8}, + {"source_id": "science", "target_id": "chemistry", "strength": 0.8} + ] + + elif node_id == 'technology': + nodes = [ + { + "id": "ai", + "name": "Künstliche Intelligenz", + "description": "Maschinelles Lernen und intelligente Systeme", + "category": "Technologie", + "has_children": True, + "color_code": "#0d47a1" + }, + { + "id": "robotics", + "name": "Robotik", + "description": "Entwicklung und Steuerung von Robotern", + "category": "Technologie", + "has_children": True, + "color_code": "#0d47a1" + }, + { + "id": "quantum_computing", + "name": "Quantencomputing", + "description": "Computer basierend auf Quantenmechanik", + "category": "Technologie", + "has_children": True, + "color_code": "#0d47a1" + } + ] + + edges = [ + {"source_id": "technology", "target_id": "ai", "strength": 0.8}, + {"source_id": "technology", "target_id": "robotics", "strength": 0.8}, + {"source_id": "technology", "target_id": "quantum_computing", "strength": 0.8} + ] + + elif node_id == 'arts': + nodes = [ + { + "id": "visual_arts", + "name": "Bildende Kunst", + "description": "Malerei, Bildhauerei und andere visuelle Kunstformen", + "category": "Künste", + "has_children": True, + "color_code": "#c2185b" + }, + { + "id": "music", + "name": "Musik", + "description": "Tonkunst und musikalische Komposition", + "category": "Künste", + "has_children": True, + "color_code": "#c2185b" + }, + { + "id": "literature", + "name": "Literatur", + "description": "Schriftliche Kunstwerke und Poesie", + "category": "Künste", + "has_children": True, + "color_code": "#c2185b" + } + ] + + edges = [ + {"source_id": "arts", "target_id": "visual_arts", "strength": 0.8}, + {"source_id": "arts", "target_id": "music", "strength": 0.8}, + {"source_id": "arts", "target_id": "literature", "strength": 0.8} + ] - # Alle direkten Kinder des Wissen-Knotens holen - nodes = wissen_node.children.all() - parent_node = wissen_node - elif node_id.isdigit(): - # Bestimmten Knoten und seine Kinder abrufen - parent_node = MindMapNode.query.get_or_404(int(node_id)) - nodes = parent_node.children.all() else: - # Versuche, einen Knoten mit diesem Namen zu finden - parent_node = MindMapNode.query.filter_by(name=node_id.capitalize()).first() - - if not parent_node: - # Versuche, eine Kategorie mit diesem Namen zu finden - category = Category.query.filter(func.lower(Category.name) == func.lower(node_id)).first() - if category: - # Finde oder erstelle einen Knoten für diese Kategorie - parent_node = MindMapNode.query.filter_by(category_id=category.id).first() - if not parent_node: - parent_node = MindMapNode( - name=category.name, - description=category.description, - color_code=category.color_code, - category_id=category.id, - is_public=True - ) - db.session.add(parent_node) - db.session.commit() - - if not parent_node: - # Fallback zum Wissen-Knoten - parent_node = MindMapNode.query.filter_by(name="Wissen").first() - if not parent_node: - return jsonify({'error': 'Knoten nicht gefunden'}), 404 - - nodes = parent_node.children.all() + # Für jede andere Node-ID geben wir eine leere Struktur zurück + nodes = [] + edges = [] - # Ergebnisdaten vorbereiten - nodes_data = [] - edges_data = [] - - # Hauptknoten hinzufügen - nodes_data.append({ - 'id': parent_node.id, - 'name': parent_node.name, - 'description': parent_node.description or '', - 'color_code': parent_node.color_code or '#4299E1', - 'is_center': True, - 'has_children': len(nodes) > 0 - }) - - # Kinder hinzufügen - for node in nodes: - nodes_data.append({ - 'id': node.id, - 'name': node.name, - 'description': node.description or '', - 'color_code': node.color_code or '#9F7AEA', - 'is_center': False, - 'has_children': len(node.children.all()) > 0 - }) - - # Verbindung zum Elternknoten hinzufügen - edges_data.append({ - 'source_id': parent_node.id, - 'target_id': node.id, - 'strength': 0.8 - }) - - return jsonify({ - 'nodes': nodes_data, - 'edges': edges_data - }) - - except Exception as e: - print(f"Fehler beim Abrufen der Mindmap-Daten: {str(e)}") - import traceback - traceback.print_exc() - return jsonify({ - 'success': False, - 'error': 'Mindmap-Daten konnten nicht geladen werden' - }), 500 - -# API-Endpunkte für Notizen und Layout-Speicherung - -@app.route('/api/mindmap/node//notes', methods=['GET']) -@login_required -def get_node_notes(node_id): - """Ruft die Notizen für einen Mindmap-Knoten ab""" - try: - # Prüfen, ob der Knoten existiert - node = MindMapNode.query.get_or_404(node_id) - - # Prüfen, ob der Knoten in einer Mindmap des Benutzers ist - user_node = UserMindmapNode.query.filter_by(node_id=node_id).join( - UserMindmap, UserMindmapNode.user_mindmap_id == UserMindmap.id - ).filter(UserMindmap.user_id == current_user.id).first() - - if not user_node and not current_user.is_admin: - return jsonify({'success': False, 'message': 'Keine Berechtigung'}), 403 - - # Prüfen, ob eine Notiz für diesen Knoten existiert - note = MindmapNote.query.filter_by( - user_id=current_user.id, - node_id=node_id - ).first() - - if note: - return jsonify({ - 'success': True, - 'notes': note.content, - 'color_code': note.color_code - }) - else: - return jsonify({ - 'success': True, - 'notes': '', - 'color_code': '#FFF59D' # Standard-Gelb - }) - - except Exception as e: - print(f"Fehler in get_node_notes: {str(e)}") - return jsonify({'success': False, 'message': str(e)}), 500 - -@app.route('/api/mindmap/node//notes', methods=['POST']) -@login_required -def update_node_notes(node_id): - """Aktualisiert die Notizen für einen Mindmap-Knoten""" - try: - # Prüfen, ob der Knoten existiert - node = MindMapNode.query.get_or_404(node_id) - - # Prüfen, ob der Knoten in einer Mindmap des Benutzers ist - user_node = UserMindmapNode.query.filter_by(node_id=node_id).join( - UserMindmap, UserMindmapNode.user_mindmap_id == UserMindmap.id - ).filter(UserMindmap.user_id == current_user.id).first() - - if not user_node and not current_user.is_admin: - return jsonify({'success': False, 'message': 'Keine Berechtigung'}), 403 - - # Daten aus dem Request abrufen - data = request.json - notes_content = data.get('notes', '') - color_code = data.get('color_code', '#FFF59D') # Standard-Gelb - - # Prüfen, ob bereits eine Notiz für diesen Knoten existiert - note = MindmapNote.query.filter_by( - user_id=current_user.id, - node_id=node_id - ).first() - - if note: - # Vorhandene Notiz aktualisieren - note.content = notes_content - note.color_code = color_code - else: - # Neue Notiz erstellen - hier brauchen wir die Mindmap-ID - mindmap_id = user_node.user_mindmap_id - note = MindmapNote( - user_id=current_user.id, - mindmap_id=mindmap_id, - node_id=node_id, - content=notes_content, - color_code=color_code - ) - db.session.add(note) - - db.session.commit() - - return jsonify({ - 'success': True, - 'message': 'Notizen erfolgreich gespeichert' - }) - - except Exception as e: - db.session.rollback() - print(f"Fehler in update_node_notes: {str(e)}") - return jsonify({'success': False, 'message': str(e)}), 500 - -@app.route('/api/mindmap//layout', methods=['POST']) -@login_required -def save_mindmap_layout(mindmap_id): - """Speichert das Layout (Positionen der Knoten) einer Mindmap""" - try: - # Prüfe, ob die Mindmap dem Benutzer gehört - mindmap = UserMindmap.query.get_or_404(mindmap_id) - if mindmap.user_id != current_user.id and not current_user.is_admin: - return jsonify({'success': False, 'message': 'Keine Berechtigung'}), 403 - - # Daten aus dem Request abrufen - data = request.json - nodes_data = data.get('nodes', []) - - # Positionen aller Knoten aktualisieren - for node_data in nodes_data: - node_id = node_data.get('id') - x_pos = node_data.get('x') - y_pos = node_data.get('y') - - if node_id and x_pos is not None and y_pos is not None: - # UserMindmapNode-Eintrag aktualisieren - user_node = UserMindmapNode.query.filter_by( - user_mindmap_id=mindmap_id, - node_id=node_id - ).first() - - if user_node: - user_node.x_position = x_pos - user_node.y_position = y_pos - - db.session.commit() - - return jsonify({ - 'success': True, - 'message': 'Layout erfolgreich gespeichert' - }) - - except Exception as e: - db.session.rollback() - print(f"Fehler in save_mindmap_layout: {str(e)}") - return jsonify({'success': False, 'message': str(e)}), 500 - -@app.route('/api/public-mindmap', methods=['GET']) -def get_public_mindmap_nodes(): - """Liefert die öffentliche Mindmap für die Knotenübernahme""" - try: - # Alle öffentlichen Knoten abrufen - public_nodes = MindMapNode.query.filter_by(is_public=True).all() - - # Knoten formatieren - nodes = [] - for node in public_nodes: - nodes.append({ - 'id': node.id, - 'name': node.name, - 'description': node.description or '', - 'color_code': node.color_code or '#9F7AEA' - }) - - # Alle Beziehungen zwischen Knoten abrufen - edges = [] - for node in public_nodes: - for child in node.children: - if child.is_public: - edges.append({ - 'source': node.id, - 'target': child.id - }) - - return jsonify({ - 'success': True, - 'nodes': nodes, - 'edges': edges - }) - - except Exception as e: - print(f"Fehler in get_public_mindmap_nodes: {str(e)}") - return jsonify({'success': False, 'message': str(e)}), 500 - -# Suchfunktion für Mindmap-Knoten -@app.route('/api/search/mindmap', methods=['GET']) -@handle_api_exception -def search_mindmap_nodes(): - """ - Durchsucht Mindmap-Knoten nach einem Suchbegriff. - - Query-Parameter: - - q: Suchbegriff - - user_only: Wenn "true", werden nur Knoten aus den Mindmaps des Benutzers durchsucht - - include_public: Wenn "true", werden auch öffentliche Knoten einbezogen (Standard: true) - """ - try: - # Parameter auslesen - query = request.args.get('q', '').strip() - user_only = request.args.get('user_only', 'false').lower() == 'true' - include_public = request.args.get('include_public', 'true').lower() == 'true' - - if not query: - return jsonify({ - 'success': False, - 'message': 'Kein Suchbegriff angegeben', - 'results': [] - }), 400 - - # Basisfunktion für die Suche - results = [] - - # Erstelle Such-Pattern (beide Suchbegriffe werden verwendet) - search_pattern = f"%{query}%" - - # 1. Knoten aus Benutzer-Mindmaps suchen, falls Benutzer angemeldet ist - if current_user.is_authenticated: - # Suche in allen Knoten, die in den Mindmaps des Benutzers sind - user_nodes_query = db.session.query( - MindMapNode, UserMindmapNode - ).join( - UserMindmapNode, UserMindmapNode.node_id == MindMapNode.id - ).join( - UserMindmap, UserMindmapNode.user_mindmap_id == UserMindmap.id - ).filter( - UserMindmap.user_id == current_user.id, - db.or_( - MindMapNode.name.ilike(search_pattern), - MindMapNode.description.ilike(search_pattern) - ) - ).all() - - # Formatiere die Ergebnisse - for node, user_node in user_nodes_query: - # Hole den Mindmap-Namen für diesen Knoten - mindmap = UserMindmap.query.get(user_node.user_mindmap_id) - - results.append({ - 'id': node.id, - 'name': node.name, - 'description': node.description or '', - 'color_code': node.color_code or '#9F7AEA', - 'source': 'user_mindmap', - 'mindmap_id': user_node.user_mindmap_id, - 'mindmap_name': mindmap.name if mindmap else 'Unbekannte Mindmap', - 'position': { - 'x': user_node.x_position, - 'y': user_node.y_position - } - }) - - # 2. Öffentliche Knoten suchen, falls gewünscht und nicht nur Benutzer-Mindmaps - if include_public and not user_only: - public_nodes_query = MindMapNode.query.filter( - MindMapNode.is_public == True, - db.or_( - MindMapNode.name.ilike(search_pattern), - MindMapNode.description.ilike(search_pattern) - ) - ).all() - - # Prüfen, ob die öffentlichen Knoten bereits in den Ergebnissen sind - existing_node_ids = [node['id'] for node in results] - - for node in public_nodes_query: - if node.id not in existing_node_ids: - results.append({ - 'id': node.id, - 'name': node.name, - 'description': node.description or '', - 'color_code': node.color_code or '#9F7AEA', - 'source': 'public', - 'mindmap_id': None, - 'mindmap_name': 'Öffentliche Mindmap' - }) - - return jsonify({ - 'success': True, - 'message': f'{len(results)} Ergebnisse gefunden', - 'results': results - }) - - except Exception as e: - print(f"Fehler bei der Mindmap-Suche: {str(e)}") - return jsonify({ - 'success': False, - 'message': f'Fehler bei der Suche: {str(e)}', - 'results': [] - }), 500 - -# Export/Import-Funktionen für Mindmaps -@app.route('/api/mindmap//export', methods=['GET']) -@login_required -@handle_api_exception -def export_mindmap(mindmap_id): - """ - Exportiert eine Mindmap im angegebenen Format. - - Query-Parameter: - - format: Format der Exportdatei (json, xml, csv) - """ - try: - # Sicherheitscheck: Nur eigene Mindmaps oder Mindmaps, auf die der Benutzer Zugriff hat - mindmap = UserMindmap.query.get_or_404(mindmap_id) - - # Prüfen, ob der Benutzer Zugriff auf diese Mindmap hat - can_access = mindmap.user_id == current_user.id - - if not can_access and mindmap.is_private: - return jsonify({ - 'success': False, - 'message': 'Keine Berechtigung für den Zugriff auf diese Mindmap' - }), 403 - - # Format aus Query-Parameter holen - export_format = request.args.get('format', 'json') - - # Alle Knoten und ihre Positionen in dieser Mindmap holen - nodes_data = db.session.query( - MindMapNode, UserMindmapNode - ).join( - UserMindmapNode, UserMindmapNode.node_id == MindMapNode.id - ).filter( - UserMindmapNode.user_mindmap_id == mindmap_id - ).all() - - # Beziehungen zwischen Knoten holen - relationships = [] - for node1, user_node1 in nodes_data: - for node2, user_node2 in nodes_data: - if node1.id != node2.id and node2 in node1.children: - relationships.append({ - 'source': node1.id, - 'target': node2.id - }) - - # Exportdaten vorbereiten - export_data = { - 'mindmap': { - 'id': mindmap.id, - 'name': mindmap.name, - 'description': mindmap.description, - 'created_at': mindmap.created_at.isoformat(), - 'last_modified': mindmap.last_modified.isoformat() - }, - 'nodes': [{ - 'id': node.id, - 'name': node.name, - 'description': node.description or '', - 'color_code': node.color_code or '#9F7AEA', - 'x_position': user_node.x_position, - 'y_position': user_node.y_position, - 'scale': user_node.scale or 1.0 - } for node, user_node in nodes_data], - 'relationships': relationships + # Antwort zusammenstellen + response = { + "nodes": nodes, + "edges": edges } - # Exportieren im angeforderten Format - if export_format == 'json': - response = app.response_class( - response=json.dumps(export_data, indent=2), - status=200, - mimetype='application/json' - ) - response.headers["Content-Disposition"] = f"attachment; filename=mindmap_{mindmap_id}.json" - return response - - elif export_format == 'xml': - import dicttoxml - xml_data = dicttoxml.dicttoxml(export_data) - response = app.response_class( - response=xml_data, - status=200, - mimetype='application/xml' - ) - response.headers["Content-Disposition"] = f"attachment; filename=mindmap_{mindmap_id}.xml" - return response - - elif export_format == 'csv': - import io - import csv - - # CSV kann nicht die gesamte Struktur darstellen, daher nur die Knotenliste - output = io.StringIO() - writer = csv.writer(output) - - # Schreibe Header - writer.writerow(['id', 'name', 'description', 'color_code', 'x_position', 'y_position', 'scale']) - - # Schreibe Knotendaten - for node, user_node in nodes_data: - writer.writerow([ - node.id, - node.name, - node.description or '', - node.color_code or '#9F7AEA', - user_node.x_position, - user_node.y_position, - user_node.scale or 1.0 - ]) - - output.seek(0) - response = app.response_class( - response=output.getvalue(), - status=200, - mimetype='text/csv' - ) - response.headers["Content-Disposition"] = f"attachment; filename=mindmap_{mindmap_id}_nodes.csv" - return response - - else: - return jsonify({ - 'success': False, - 'message': f'Nicht unterstütztes Format: {export_format}' - }), 400 - + return jsonify(response) + except Exception as e: - print(f"Fehler beim Exportieren der Mindmap: {str(e)}") - return jsonify({ - 'success': False, - 'message': f'Fehler beim Exportieren: {str(e)}' - }), 500 + app.logger.error(f"Fehler beim Abrufen der Mindmap-Daten: {str(e)}") + return jsonify({"error": "Fehler beim Abrufen der Mindmap-Daten"}), 500 -@app.route('/api/mindmap//import', methods=['POST']) -@login_required -@handle_api_exception -def import_mindmap(mindmap_id): - """ - Importiert Daten in eine bestehende Mindmap. - - Die Daten können in verschiedenen Formaten (JSON, XML, CSV) hochgeladen werden. - """ - try: - # Sicherheitscheck: Nur eigene Mindmaps können bearbeitet werden - mindmap = UserMindmap.query.get_or_404(mindmap_id) - - if mindmap.user_id != current_user.id: - return jsonify({ - 'success': False, - 'message': 'Keine Berechtigung zum Bearbeiten dieser Mindmap' - }), 403 - - # Prüfen, ob eine Datei hochgeladen wurde - if 'file' not in request.files: - return jsonify({ - 'success': False, - 'message': 'Keine Datei ausgewählt' - }), 400 - - file = request.files['file'] - - if file.filename == '': - return jsonify({ - 'success': False, - 'message': 'Keine Datei ausgewählt' - }), 400 - - # Format anhand der Dateiendung erkennen - file_ext = file.filename.rsplit('.', 1)[1].lower() if '.' in file.filename else None - - if file_ext not in ['json', 'xml', 'csv']: - return jsonify({ - 'success': False, - 'message': f'Nicht unterstütztes Dateiformat: {file_ext}' - }), 400 - - # Datei einlesen - import_data = None - - if file_ext == 'json': - import_data = json.loads(file.read().decode('utf-8')) - elif file_ext == 'xml': - import xml.etree.ElementTree as ET - import xmltodict - xml_data = file.read().decode('utf-8') - import_data = xmltodict.parse(xml_data) - elif file_ext == 'csv': - import io - import csv - csv_data = file.read().decode('utf-8') - reader = csv.DictReader(io.StringIO(csv_data)) - nodes = [] - for row in reader: - nodes.append(row) - import_data = {'nodes': nodes} - - # Daten in die Mindmap importieren - if 'nodes' in import_data: - # Bestehende Knoten in der Mindmap für Referenz - existing_nodes = db.session.query( - UserMindmapNode.node_id - ).filter_by( - user_mindmap_id=mindmap_id - ).all() - existing_node_ids = [n[0] for n in existing_nodes] - - # Mapping von alten zu neuen Knoten-IDs für importierte Knoten - id_mapping = {} - - # Knoten importieren - for node_data in import_data.get('nodes', []): - # Prüfen, ob es sich um Stringkeys (aus CSV) oder Dict (aus JSON) handelt - if isinstance(node_data, dict): - node_name = node_data.get('name') - node_desc = node_data.get('description', '') - node_color = node_data.get('color_code', '#9F7AEA') - x_pos = float(node_data.get('x_position', 0)) - y_pos = float(node_data.get('y_position', 0)) - node_scale = float(node_data.get('scale', 1.0)) - old_id = node_data.get('id') - else: - # Fallback für andere Formate - continue - - # Neuen Knoten erstellen, wenn nötig - new_node = MindMapNode( - name=node_name, - description=node_desc, - color_code=node_color - ) - db.session.add(new_node) - db.session.flush() # ID generieren - - # Verknüpfung zur Mindmap erstellen - user_node = UserMindmapNode( - user_mindmap_id=mindmap_id, - node_id=new_node.id, - x_position=x_pos, - y_position=y_pos, - scale=node_scale - ) - db.session.add(user_node) - - # ID-Mapping für Beziehungen speichern - if old_id: - id_mapping[old_id] = new_node.id - - # Beziehungen zwischen Knoten importieren - for rel in import_data.get('relationships', []): - source_id = rel.get('source') - target_id = rel.get('target') - - if source_id in id_mapping and target_id in id_mapping: - # Knoten-Objekte holen - source_node = MindMapNode.query.get(id_mapping[source_id]) - target_node = MindMapNode.query.get(id_mapping[target_id]) - - if source_node and target_node: - # Beziehung erstellen - source_node.children.append(target_node) - - db.session.commit() - - return jsonify({ - 'success': True, - 'message': f'{len(import_data.get("nodes", []))} Knoten erfolgreich importiert' - }) - - else: - return jsonify({ - 'success': False, - 'message': 'Keine Knotendaten in der Importdatei gefunden' - }), 400 - - except Exception as e: - db.session.rollback() - print(f"Fehler beim Importieren der Mindmap: {str(e)}") - return jsonify({ - 'success': False, - 'message': f'Fehler beim Importieren: {str(e)}' - }), 500 - -# Automatische Datenbankinitialisierung - Aktualisiert für Flask 2.2+ Kompatibilität -def initialize_app(): - """Initialisierung der Anwendung""" - print("Initialisierung der Anwendung...") - with app.app_context(): - # Prüfen, ob die Datenbank existiert und initialisiert ist - try: - # Prüfen, ob Tabellen existieren - db.create_all() - - # Prüfen, ob Stammdaten vorhanden sind - if User.query.count() == 0: - print("Erstelle Standardbenutzer...") - create_default_users() - - # Wir nutzen die initialize_database Funktion für Kategorien und Mindmap - # Diese Funktionalität ist bereits dort implementiert - initialize_database() - - # Zusätzliche Sicherheitsprüfung: Stelle sicher, dass der "Wissen"-Knoten existiert - wissen_node = MindMapNode.query.filter_by(name="Wissen").first() - if not wissen_node: - wissen_node = MindMapNode( - name="Wissen", - description="Zentrale Wissensbasis", - color_code="#4299E1", - is_public=True - ) - db.session.add(wissen_node) - db.session.commit() - print("'Wissen'-Knoten nachträglich erstellt") - - print("Datenbank wurde erfolgreich initialisiert.") - except Exception as e: - import traceback - print(f"Fehler bei der Datenbankinitialisierung: {e}") - print(traceback.format_exc()) - -# Moderne Methode für die Datenbankinitialisierung in Flask 2.2+ -with app.app_context(): - initialize_app() \ No newline at end of file +# ... existing code ... \ No newline at end of file