From fab8d10f035ce41d441322aa9b9a826bd12a9e91 Mon Sep 17 00:00:00 2001 From: marwin Date: Mon, 12 May 2025 19:54:41 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20chore:=20Aktualisierung=20der=20?= =?UTF-8?q?Protokollierung=20mit=20zus=C3=A4tzlichen=20404-Fehlern=20und?= =?UTF-8?q?=20Anwendungsstartmeldungen=20in=20app.log;=20Aktualisierung=20?= =?UTF-8?q?der=20Bytecode-Datei=20in=20=5F=5Fpycache=5F=5F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/app.cpython-313.pyc | Bin 110931 -> 110931 bytes app.py.bak | 2526 ++++++++++++++++++++++++++ fix_routes.py | Bin 0 -> 894 bytes logs/app.log | 714 ++++++++ static/js/update_mindmap.js.bak | 1078 +++++++++++ static/js/update_mindmap.js.new | Bin 0 -> 164 bytes static/js/update_mindmap.js.original | 1078 +++++++++++ update_routes.py | Bin 0 -> 506 bytes 8 files changed, 5396 insertions(+) create mode 100644 app.py.bak create mode 100644 fix_routes.py create mode 100644 static/js/update_mindmap.js.bak create mode 100644 static/js/update_mindmap.js.new create mode 100644 static/js/update_mindmap.js.original create mode 100644 update_routes.py diff --git a/__pycache__/app.cpython-313.pyc b/__pycache__/app.cpython-313.pyc index 3e91d7bae7cb257ce02bdc9e7b2a4f5f0826bd0a..0c47771184e9150554c5501d5dda492fade831c2 100644 GIT binary patch delta 24 ecmccoi0$$tHm=XSyj%=GP;B4GwUvv}b0Yw4&IgYG delta 24 ecmccoi0$$tHm=XSyj%=Gu*as6YbzI{=SBc') +@login_required +def user_mindmap(mindmap_id): + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck: Nur eigene Mindmaps oder öffentliche Mindmaps + if mindmap.user_id != current_user.id and mindmap.is_private: + flash("Du hast keinen Zugriff auf diese Mindmap.", "error") + return redirect(url_for('profile')) + + return render_template('user_mindmap.html', mindmap=mindmap) + +@app.route('/mindmap/create', methods=['GET', 'POST']) +@login_required +def create_mindmap(): + if request.method == 'POST': + name = request.form.get('name') + description = request.form.get('description') + is_private = request.form.get('is_private') == 'on' + + new_mindmap = UserMindmap( + name=name, + description=description, + user_id=current_user.id, + is_private=is_private + ) + + db.session.add(new_mindmap) + db.session.commit() + + flash('Neue Mindmap erfolgreich erstellt!', 'success') + return redirect(url_for('user_mindmap', mindmap_id=new_mindmap.id)) + + return render_template('create_mindmap.html') + +@app.route('/mindmap//edit', methods=['GET', 'POST']) +@login_required +def edit_mindmap(mindmap_id): + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck + if mindmap.user_id != current_user.id: + flash("Du kannst nur deine eigenen Mindmaps bearbeiten.", "error") + return redirect(url_for('profile')) + + if request.method == 'POST': + mindmap.name = request.form.get('name') + mindmap.description = request.form.get('description') + mindmap.is_private = request.form.get('is_private') == 'on' + + db.session.commit() + flash('Mindmap erfolgreich aktualisiert!', 'success') + return redirect(url_for('user_mindmap', mindmap_id=mindmap.id)) + + return render_template('edit_mindmap.html', mindmap=mindmap) + +@app.route('/mindmap//delete', methods=['POST']) +@login_required +def delete_mindmap(mindmap_id): + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck + if mindmap.user_id != current_user.id: + flash("Du kannst nur deine eigenen Mindmaps löschen.", "error") + return redirect(url_for('profile')) + + db.session.delete(mindmap) + db.session.commit() + + flash('Mindmap erfolgreich gelöscht!', 'success') + return redirect(url_for('profile')) + +# API-Endpunkte für UserMindmap CRUD-Operationen +@app.route('/api/mindmaps', methods=['POST']) +@login_required +def api_create_user_mindmap(): + data = request.get_json() + name = data.get('name') + description = data.get('description') + is_private = data.get('is_private', True) + + if not name: + return jsonify({'error': 'Name ist erforderlich'}), 400 + + new_mindmap = UserMindmap( + name=name, + description=description, + user_id=current_user.id, + is_private=is_private + ) + db.session.add(new_mindmap) + db.session.commit() + return jsonify({ + 'id': new_mindmap.id, + 'name': new_mindmap.name, + 'description': new_mindmap.description, + 'is_private': new_mindmap.is_private, + 'user_id': new_mindmap.user_id, + 'created_at': new_mindmap.created_at.isoformat(), + 'last_modified': new_mindmap.last_modified.isoformat() + }), 201 + +@app.route('/api/mindmaps', methods=['GET']) +@login_required +def api_get_user_mindmaps(): + mindmaps = UserMindmap.query.filter_by(user_id=current_user.id).all() + return jsonify([{ + 'id': m.id, + 'name': m.name, + 'description': m.description, + 'is_private': m.is_private, + 'created_at': m.created_at.isoformat(), + 'last_modified': m.last_modified.isoformat() + } for m in mindmaps]) + +@app.route('/api/mindmaps/', methods=['GET']) +@login_required +@handle_api_exception +def api_get_user_mindmap_detail(mindmap_id): + # Berechtigungsprüfung (mindestens READ-Zugriff) + has_permission, error_msg = check_mindmap_permission(mindmap_id, "READ") + if not has_permission: + return ErrorHandler.api_error(error_msg, 403) + + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Logik für eine detaillierte Ansicht + result = { + 'id': mindmap.id, + 'name': mindmap.name, + 'description': mindmap.description, + 'is_private': mindmap.is_private, + 'user_id': mindmap.user_id, + 'created_at': mindmap.created_at.isoformat(), + 'last_modified': mindmap.last_modified.isoformat(), + 'is_owner': mindmap.user_id == current_user.id + } + + # Berechtigungsinformationen hinzufügen, falls nicht der Eigentümer + if mindmap.user_id != current_user.id: + share = MindmapShare.query.filter_by( + mindmap_id=mindmap_id, + shared_with_id=current_user.id + ).first() + + if share: + result['permission'] = share.permission_type.name + result['owner'] = { + 'id': mindmap.user_id, + 'username': User.query.get(mindmap.user_id).username + } + + return jsonify(result) + +@app.route('/api/mindmaps/', methods=['PUT']) +@login_required +@handle_api_exception +def api_update_user_mindmap(mindmap_id): + # Berechtigungsprüfung (mindestens EDIT-Zugriff) + has_permission, error_msg = check_mindmap_permission(mindmap_id, "EDIT") + if not has_permission: + return ErrorHandler.api_error(error_msg, 403) + + mindmap = UserMindmap.query.get_or_404(mindmap_id) + data = request.get_json() + + # Grundlegende Informationen aktualisieren + mindmap.name = data.get('name', mindmap.name) + mindmap.description = data.get('description', mindmap.description) + + # is_private kann nur vom Eigentümer geändert werden + if mindmap.user_id == current_user.id and 'is_private' in data: + mindmap.is_private = data.get('is_private') + + db.session.commit() + return jsonify({ + 'id': mindmap.id, + 'name': mindmap.name, + 'description': mindmap.description, + 'is_private': mindmap.is_private, + 'last_modified': mindmap.last_modified.isoformat(), + 'success': True + }) + +@app.route('/api/mindmaps/', methods=['DELETE']) +@login_required +@handle_api_exception +def api_delete_user_mindmap(mindmap_id): + # Nur der Eigentümer kann eine Mindmap löschen + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + if mindmap.user_id != current_user.id: + return ErrorHandler.api_error("Nur der Eigentümer kann eine Mindmap löschen.", 403) + + # Alle Freigaben löschen + MindmapShare.query.filter_by(mindmap_id=mindmap_id).delete() + + # Mindmap löschen + db.session.delete(mindmap) + db.session.commit() + + return jsonify({ + 'success': True, + 'message': 'Mindmap erfolgreich gelöscht' + }), 200 + +# API-Endpunkte für Mindmap-Daten (öffentlich und benutzerspezifisch) +@app.route('/api/mindmap/public') +def get_public_mindmap(): + """Liefert die Standard-Mindmap-Struktur basierend auf Kategorien.""" + try: + # Hole alle Hauptkategorien + categories = Category.query.filter_by(parent_id=None).all() + + # Transformiere zu einer Baumstruktur + category_tree = [build_category_tree(cat) for cat in categories] + + return jsonify(category_tree) + except Exception as e: + print(f"Fehler beim Abrufen der Mindmap: {str(e)}") + return jsonify({ + 'success': False, + 'error': 'Mindmap konnte nicht geladen werden' + }), 500 + +@app.route('/api/mindmap/public/add_node', methods=['POST']) +@login_required +def add_node_to_public_mindmap(): + """Fügt einen neuen Knoten zur öffentlichen Mindmap hinzu.""" + try: + data = request.json + + name = data.get('name') + description = data.get('description', '') + color_code = data.get('color_code', '#8b5cf6') + x_position = data.get('x_position', 0) + y_position = data.get('y_position', 0) + + if not name: + return jsonify({ + 'success': False, + 'error': 'Knotenname ist erforderlich' + }), 400 + + # Neuen Knoten erstellen + new_node = MindMapNode( + name=name, + description=description, + color_code=color_code + ) + + db.session.add(new_node) + db.session.flush() # ID generieren + + # Als Beitrag des aktuellen Benutzers markieren + new_node.contributed_by = current_user.id + + db.session.commit() + + return jsonify({ + 'success': True, + 'node_id': new_node.id, + 'message': 'Knoten erfolgreich hinzugefügt' + }) + except Exception as e: + db.session.rollback() + print(f"Fehler beim Hinzufügen des Knotens: {str(e)}") + return jsonify({ + 'success': False, + 'error': f'Fehler beim Hinzufügen des Knotens: {str(e)}' + }), 500 + +@app.route('/api/mindmap/public/update_node/', methods=['PUT']) +@login_required +def update_public_node(node_id): + """Aktualisiert einen Knoten in der öffentlichen Mindmap.""" + try: + node = MindMapNode.query.get_or_404(node_id) + data = request.json + + # Aktualisiere Knotendaten + if 'name' in data: + node.name = data['name'] + if 'description' in data: + node.description = data['description'] + if 'color_code' in data: + node.color_code = data['color_code'] + + # Als bearbeitet markieren + node.last_modified = datetime.now(timezone.utc) + node.last_modified_by = current_user.id + + db.session.commit() + + return jsonify({ + 'success': True, + 'message': 'Knoten erfolgreich aktualisiert' + }) + except Exception as e: + db.session.rollback() + print(f"Fehler beim Aktualisieren des Knotens: {str(e)}") + return jsonify({ + 'success': False, + 'error': f'Fehler beim Aktualisieren des Knotens: {str(e)}' + }), 500 + +@app.route('/api/mindmap/public/remove_node/', methods=['DELETE']) +@login_required +def remove_node_from_public_mindmap(node_id): + """Entfernt einen Knoten aus der öffentlichen Mindmap.""" + try: + node = MindMapNode.query.get_or_404(node_id) + + # Lösche den Knoten + db.session.delete(node) + db.session.commit() + + return jsonify({ + 'success': True, + 'message': 'Knoten erfolgreich entfernt' + }) + except Exception as e: + db.session.rollback() + print(f"Fehler beim Entfernen des Knotens: {str(e)}") + return jsonify({ + 'success': False, + 'error': f'Fehler beim Entfernen des Knotens: {str(e)}' + }), 500 + +@app.route('/api/mindmap/public/update_layout', methods=['POST']) +@login_required +def update_public_layout(): + """Aktualisiert die Positionen der Knoten in der öffentlichen Mindmap.""" + try: + data = request.json + positions = data.get('positions', []) + + for pos in positions: + node_id = pos.get('node_id') + node = MindMapNode.query.get(node_id) + + if node: + # Position aktualisieren + node.x_position = pos.get('x_position', 0) + node.y_position = pos.get('y_position', 0) + + db.session.commit() + + return jsonify({ + 'success': True, + 'message': 'Layout erfolgreich aktualisiert' + }) + except Exception as e: + db.session.rollback() + print(f"Fehler beim Aktualisieren des Layouts: {str(e)}") + return jsonify({ + 'success': False, + 'error': f'Fehler beim Aktualisieren des Layouts: {str(e)}' + }), 500 + +def build_category_tree(category): + """ + Erstellt eine Baumstruktur für eine Kategorie mit all ihren Unterkategorien + und dazugehörigen Knoten + + Args: + category: Ein Category-Objekt + + Returns: + dict: Eine JSON-serialisierbare Darstellung der Kategoriestruktur + """ + # Kategorie-Basisinformationen + category_dict = { + 'id': category.id, + 'name': category.name, + 'description': category.description, + 'color_code': category.color_code, + 'icon': category.icon, + 'nodes': [], + 'children': [] + } + + # Knoten zur Kategorie hinzufügen + if category.nodes: + for node in category.nodes: + category_dict['nodes'].append({ + 'id': node.id, + 'name': node.name, + 'description': node.description or '', + 'color_code': node.color_code or '#9F7AEA', + 'thought_count': len(node.thoughts) if hasattr(node, 'thoughts') else 0 + }) + + # Rekursiv Unterkategorien hinzufügen + if category.children: + for child in category.children: + category_dict['children'].append(build_category_tree(child)) + + return category_dict + +@app.route('/api/mindmap/user/') +@login_required +def get_user_mindmap(mindmap_id): + """Liefert die benutzerdefinierte Mindmap-Struktur.""" + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck + if mindmap.user_id != current_user.id and mindmap.is_private: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + # Hole alle verknüpften Knoten mit Position + nodes_data = db.session.query( + MindMapNode, UserMindmapNode + ).join( + UserMindmapNode, UserMindmapNode.node_id == MindMapNode.id + ).filter( + UserMindmapNode.user_mindmap_id == mindmap_id + ).all() + + # Knoten formatieren + nodes = [] + for node, user_node in nodes_data: + nodes.append({ + 'id': node.id, + 'name': node.name, + 'description': node.description, + 'color_code': node.color_code, + 'x': user_node.x_position, + 'y': user_node.y_position, + 'scale': user_node.scale, + 'thought_count': len(node.thoughts) + }) + + # Hole Notizen zu dieser Mindmap + notes = MindmapNote.query.filter_by( + mindmap_id=mindmap_id, + user_id=current_user.id + ).all() + + notes_data = [{ + 'id': note.id, + 'content': note.content, + 'node_id': note.node_id, + 'thought_id': note.thought_id, + 'color_code': note.color_code, + 'created_at': note.created_at.isoformat() + } for note in notes] + + return jsonify({ + 'id': mindmap.id, + 'name': mindmap.name, + 'description': mindmap.description, + 'is_private': mindmap.is_private, + 'nodes': nodes, + 'notes': notes_data + }) + +@app.route('/api/mindmap/id//add_node', methods=['POST']) +@login_required +def add_node_to_mindmap(mindmap_id): + """Fügt einen öffentlichen Knoten zur Benutzer-Mindmap hinzu.""" + data = request.json + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck + if mindmap.user_id != current_user.id: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + node_id = data.get('node_id') + parent_id = data.get('parent_id') # Optional: Elternknoten für die Verknüpfung + x_pos = data.get('x', 0) + y_pos = data.get('y', 0) + + # Knoten abrufen + node = MindMapNode.query.get_or_404(node_id) + + # Prüfen, ob der Knoten bereits in der Mindmap existiert + existing = UserMindmapNode.query.filter_by( + user_mindmap_id=mindmap_id, + node_id=node_id + ).first() + + if existing: + # Update Position + existing.x_position = x_pos + existing.y_position = y_pos + else: + # Neuen Knoten hinzufügen + user_node = UserMindmapNode( + user_mindmap_id=mindmap_id, + node_id=node_id, + x_position=x_pos, + y_position=y_pos + ) + db.session.add(user_node) + + # Wenn ein Elternknoten angegeben wurde, Verbindung erstellen + if parent_id: + # Existenz des Elternknotens in der Mindmap prüfen + parent_node = MindMapNode.query.get(parent_id) + parent_user_node = UserMindmapNode.query.filter_by( + user_mindmap_id=mindmap_id, + node_id=parent_id + ).first() + + if parent_node and parent_user_node: + # Beziehung zwischen den Knoten erstellen + try: + parent_node.children.append(node) + db.session.flush() + except Exception as e: + print(f"Warnung: Fehler beim Erstellen der Beziehung: {e}") + + db.session.commit() + + return jsonify({ + 'success': True, + 'node_id': node_id, + 'x': x_pos, + 'y': y_pos + }) + +@app.route('/api/mindmap/id//remove_node/', methods=['DELETE']) +@login_required +def remove_node_from_mindmap(mindmap_id, node_id): + """Entfernt einen Knoten aus der Benutzer-Mindmap.""" + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck + if mindmap.user_id != current_user.id: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + user_node = UserMindmapNode.query.filter_by( + user_mindmap_id=mindmap_id, + node_id=node_id + ).first_or_404() + + db.session.delete(user_node) + db.session.commit() + + return jsonify({'success': True}) + +@app.route('/api/mindmap/node/', methods=['GET']) +@login_required +def get_node_info(node_id): + """Liefert Detailinformationen zu einem einzelnen Knoten""" + try: + # Knoten abrufen + node = MindMapNode.query.get_or_404(node_id) + + return jsonify({ + 'id': node.id, + 'name': node.name, + 'description': node.description or '', + 'color_code': node.color_code or '#9F7AEA' + }) + except Exception as e: + print(f"Fehler in get_node_info: {str(e)}") + return jsonify({'success': False, 'message': str(e)}), 500 + +@app.route('/api/mindmap/id//update_node_position', methods=['POST']) +@login_required +def update_node_position(mindmap_id): + """Aktualisiert die Position eines Knotens in der Benutzer-Mindmap.""" + data = request.json + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck + if mindmap.user_id != current_user.id: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + node_id = data.get('node_id') + x_pos = data.get('x') + y_pos = data.get('y') + scale = data.get('scale') + + user_node = UserMindmapNode.query.filter_by( + user_mindmap_id=mindmap_id, + node_id=node_id + ).first_or_404() + + if x_pos is not None: + user_node.x_position = x_pos + if y_pos is not None: + user_node.y_position = y_pos + if scale is not None: + user_node.scale = scale + + db.session.commit() + + return jsonify({'success': True}) + +# Notizen-Funktionalität +@app.route('/api/mindmap//notes', methods=['GET']) +@login_required +def get_mindmap_notes(mindmap_id): + """Liefert alle Notizen zu einer Mindmap.""" + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck + if mindmap.user_id != current_user.id: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + notes = MindmapNote.query.filter_by( + mindmap_id=mindmap_id, + user_id=current_user.id + ).all() + + return jsonify([{ + 'id': note.id, + 'content': note.content, + 'node_id': note.node_id, + 'thought_id': note.thought_id, + 'color_code': note.color_code, + 'created_at': note.created_at.isoformat(), + 'last_modified': note.last_modified.isoformat() + } for note in notes]) + +@app.route('/api/mindmap//notes', methods=['POST']) +@login_required +def add_mindmap_note(mindmap_id): + """Fügt eine neue Notiz zur Mindmap hinzu.""" + data = request.json + mindmap = UserMindmap.query.get_or_404(mindmap_id) + + # Sicherheitscheck + if mindmap.user_id != current_user.id: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + content = data.get('content') + node_id = data.get('node_id') + thought_id = data.get('thought_id') + color_code = data.get('color_code', "#FFF59D") # Gelber Standard + + note = MindmapNote( + user_id=current_user.id, + mindmap_id=mindmap_id, + node_id=node_id, + thought_id=thought_id, + content=content, + color_code=color_code + ) + + db.session.add(note) + db.session.commit() + + return jsonify({ + 'id': note.id, + 'content': note.content, + 'node_id': note.node_id, + 'thought_id': note.thought_id, + 'color_code': note.color_code, + 'created_at': note.created_at.isoformat(), + 'last_modified': note.last_modified.isoformat() + }) + +@app.route('/api/notes/', methods=['PUT']) +@login_required +def update_note(note_id): + """Aktualisiert eine bestehende Notiz.""" + data = request.json + note = MindmapNote.query.get_or_404(note_id) + + # Sicherheitscheck + if note.user_id != current_user.id: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + content = data.get('content') + color_code = data.get('color_code') + + if content: + note.content = content + if color_code: + note.color_code = color_code + + note.last_modified = datetime.now(timezone.utc) + db.session.commit() + + return jsonify({ + 'id': note.id, + 'content': note.content, + 'color_code': note.color_code, + 'last_modified': note.last_modified.isoformat() + }) + +@app.route('/api/notes/', methods=['DELETE']) +@login_required +def delete_note(note_id): + """Löscht eine Notiz.""" + note = MindmapNote.query.get_or_404(note_id) + + # Sicherheitscheck + if note.user_id != current_user.id: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + db.session.delete(note) + db.session.commit() + + return jsonify({'success': True}) + +# API routes for mindmap and thoughts +@app.route('/api/mindmap') +def get_mindmap(): + """Gibt die Mindmap-Struktur zurück""" + try: + # Hauptknoten abrufen (Root-Knoten) + wissen_node = MindMapNode.query.filter_by(name="Wissen").first() + if not wissen_node: + # Wissen-Knoten erstellen, falls nicht vorhanden + wissen_node = MindMapNode( + name="Wissen", + description="Zentrale Wissensbasis", + color_code="#4299E1", + is_public=True + ) + db.session.add(wissen_node) + db.session.commit() + + # Alle anderen aktiven Knoten holen + nodes = MindMapNode.query.filter(MindMapNode.is_public == True).all() + + # Ergebnisdaten vorbereiten + nodes_data = [] + edges_data = [] + + # Knoten 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' + }) + + # Wenn es nicht der Wissen-Knoten ist, Verbindung zum Wissen-Knoten hinzufügen + if node.id != wissen_node.id: + edges_data.append({ + 'source': wissen_node.id, + 'target': node.id + }) + + # Beziehungen zwischen Knoten abfragen und hinzufügen + relationships = db.session.query(node_relationship).all() + for rel in relationships: + if rel.parent_id != wissen_node.id: # Doppelte Kanten vermeiden + edges_data.append({ + 'source': rel.parent_id, + 'target': rel.child_id + }) + + return jsonify({ + 'nodes': nodes_data, + 'edges': edges_data + }) + + except Exception as e: + print(f"Fehler beim Abrufen der Mindmap: {str(e)}") + return jsonify({ + 'success': False, + 'error': 'Mindmap konnte nicht geladen werden' + }), 500 + +@app.route('/api/nodes//thoughts') +def get_node_thoughts(node_id): + """Liefert alle Gedanken, die mit einem Knoten verknüpft sind.""" + node = MindMapNode.query.get_or_404(node_id) + + thoughts = [] + for thought in node.thoughts: + author = thought.author + thoughts.append({ + 'id': thought.id, + 'title': thought.title, + 'abstract': thought.abstract, + 'content': thought.content[:200] + '...' if len(thought.content) > 200 else thought.content, + 'keywords': thought.keywords, + 'author': { + 'id': author.id, + 'username': author.username + }, + 'created_at': thought.created_at.isoformat(), + 'color_code': thought.color_code, + 'avg_rating': thought.average_rating, + 'bookmarked': current_user.is_authenticated and thought in current_user.bookmarked_thoughts + }) + + return jsonify(thoughts) + +@app.route('/api/nodes//thoughts', methods=['POST']) +@login_required +def add_node_thought(node_id): + """Fügt einen neuen Gedanken zu einem Knoten hinzu.""" + data = request.json + node = MindMapNode.query.get_or_404(node_id) + + title = data.get('title') + content = data.get('content') + abstract = data.get('abstract', '') + keywords = data.get('keywords', '') + color_code = data.get('color_code', '#B39DDB') # Standard-Lila + + # Kategorie des Knotens bestimmen + category_name = node.category.name if node.category else "Allgemein" + + thought = Thought( + title=title, + content=content, + abstract=abstract, + keywords=keywords, + color_code=color_code, + branch=category_name, + user_id=current_user.id, + source_type='User Input' + ) + + node.thoughts.append(thought) + db.session.add(thought) + db.session.commit() + + return jsonify({ + 'id': thought.id, + 'title': thought.title, + 'success': True + }) + +@app.route('/api/thoughts/', methods=['GET']) +def get_thought(thought_id): + """Liefert Details zu einem Gedanken.""" + thought = Thought.query.get_or_404(thought_id) + + author = thought.author + is_bookmarked = False + if current_user.is_authenticated: + is_bookmarked = thought in current_user.bookmarked_thoughts + + # Verknüpfte Knoten abrufen + nodes = [{ + 'id': node.id, + 'name': node.name, + 'category': node.category.name if node.category else None + } for node in thought.nodes] + + return jsonify({ + 'id': thought.id, + 'title': thought.title, + 'content': thought.content, + 'abstract': thought.abstract, + 'keywords': thought.keywords, + 'branch': thought.branch, + 'color_code': thought.color_code, + 'created_at': thought.created_at.isoformat(), + 'author': { + 'id': author.id, + 'username': author.username, + 'avatar': author.avatar + }, + 'avg_rating': thought.average_rating, + 'bookmarked': is_bookmarked, + 'nodes': nodes, + 'source_type': thought.source_type + }) + +@app.route('/api/thoughts', methods=['POST']) +@login_required +def add_thought(): + """Erstellt einen neuen Gedanken.""" + data = request.json + + title = data.get('title') + content = data.get('content') + abstract = data.get('abstract', '') + keywords = data.get('keywords', '') + branch = data.get('branch', 'Allgemein') + color_code = data.get('color_code', '#B39DDB') + + thought = Thought( + title=title, + content=content, + abstract=abstract, + keywords=keywords, + branch=branch, + color_code=color_code, + user_id=current_user.id, + source_type='User Input' + ) + + # Knoten-IDs, falls vorhanden + node_ids = data.get('node_ids', []) + for node_id in node_ids: + node = MindMapNode.query.get(node_id) + if node: + thought.nodes.append(node) + + db.session.add(thought) + db.session.commit() + + return jsonify({ + 'id': thought.id, + 'title': thought.title, + 'success': True + }) + +@app.route('/api/thoughts/', methods=['PUT']) +@login_required +def update_thought(thought_id): + """Aktualisiert einen bestehenden Gedanken.""" + thought = Thought.query.get_or_404(thought_id) + + # Sicherheitscheck + if thought.user_id != current_user.id and not current_user.is_admin: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + data = request.json + + # Aktualisiere Felder, die gesendet wurden + if 'title' in data: + thought.title = data['title'] + if 'content' in data: + thought.content = data['content'] + if 'abstract' in data: + thought.abstract = data['abstract'] + if 'keywords' in data: + thought.keywords = data['keywords'] + if 'color_code' in data: + thought.color_code = data['color_code'] + + thought.last_modified = datetime.now(timezone.utc) + db.session.commit() + + return jsonify({ + 'id': thought.id, + 'success': True + }) + +@app.route('/api/thoughts/', methods=['DELETE']) +@login_required +def delete_thought(thought_id): + """Löscht einen Gedanken.""" + thought = Thought.query.get_or_404(thought_id) + + # Sicherheitscheck + if thought.user_id != current_user.id and not current_user.is_admin: + return jsonify({'error': 'Nicht autorisiert'}), 403 + + db.session.delete(thought) + db.session.commit() + + return jsonify({'success': True}) + +@app.route('/api/thoughts//bookmark', methods=['POST']) +@login_required +def bookmark_thought(thought_id): + """Fügt einen Gedanken zu den Bookmarks des Benutzers hinzu oder entfernt ihn.""" + thought = Thought.query.get_or_404(thought_id) + + # Toggle Bookmark-Status + if thought in current_user.bookmarked_thoughts: + current_user.bookmarked_thoughts.remove(thought) + action = 'removed' + else: + current_user.bookmarked_thoughts.append(thought) + action = 'added' + + db.session.commit() + + return jsonify({ + 'success': True, + 'action': action + }) + +@app.route('/api/categories') +def get_categories(): + """API-Endpunkt, der alle Kategorien als hierarchische Struktur zurückgibt""" + try: + # Hole alle Kategorien der obersten Ebene + categories = Category.query.filter_by(parent_id=None).all() + + # Transformiere zu einer Baumstruktur + category_tree = [build_category_tree(cat) for cat in categories] + + return jsonify(category_tree) + except Exception as e: + print(f"Fehler beim Abrufen der Kategorien: {str(e)}") + return jsonify({ + 'success': False, + 'error': 'Kategorien konnten nicht geladen werden' + }), 500 + +@app.route('/api/set_dark_mode', methods=['POST']) +def set_dark_mode(): + """Speichert die Dark Mode-Einstellung in der Session.""" + data = request.json + dark_mode = data.get('darkMode', False) + + session['dark_mode'] = 'true' if dark_mode else 'false' + session.permanent = True + + return jsonify({ + 'success': True, + 'darkMode': dark_mode + }) + +@app.route('/api/get_dark_mode', methods=['GET']) +def get_dark_mode(): + """Liefert die aktuelle Dark Mode-Einstellung.""" + dark_mode = session.get('dark_mode', 'true') # Standard: Dark Mode aktiviert + + return jsonify({ + 'success': True, + 'darkMode': dark_mode + }) + +# Fehlerhandler +@app.errorhandler(404) +def page_not_found(e): + """404 Fehler - Seite nicht gefunden""" + ErrorHandler.log_exception(e, code=404) + is_api_request = request.path.startswith('/api/') + + if is_api_request: + return ErrorHandler.api_error("Die angeforderte Ressource wurde nicht gefunden.", 404) + return render_template('errors/404.html'), 404 + +@app.errorhandler(403) +def forbidden(e): + """403 Fehler - Zugriff verweigert""" + ErrorHandler.log_exception(e, code=403) + is_api_request = request.path.startswith('/api/') + + if is_api_request: + return ErrorHandler.api_error("Sie haben keine Berechtigung, auf diese Ressource zuzugreifen.", 403) + return render_template('errors/403.html'), 403 + +@app.errorhandler(500) +def internal_server_error(e): + """500 Fehler - Interner Serverfehler""" + ErrorHandler.log_exception(e, code=500) + is_api_request = request.path.startswith('/api/') + + if is_api_request: + return ErrorHandler.api_error("Ein interner Serverfehler ist aufgetreten.", 500) + return render_template('errors/500.html'), 500 + +@app.errorhandler(429) +def too_many_requests(e): + """429 Fehler - Zu viele Anfragen""" + ErrorHandler.log_exception(e, code=429) + is_api_request = request.path.startswith('/api/') + + if is_api_request: + return ErrorHandler.api_error("Zu viele Anfragen. Bitte versuchen Sie es später erneut.", 429) + return render_template('errors/429.html'), 429 + +@app.errorhandler(400) +def bad_request(e): + """400 Fehler - Ungültige Anfrage""" + ErrorHandler.log_exception(e, code=400) + is_api_request = request.path.startswith('/api/') + + if is_api_request: + return ErrorHandler.api_error("Die Anfrage konnte nicht verarbeitet werden.", 400) + flash("Die Anfrage konnte nicht verarbeitet werden. Bitte überprüfen Sie Ihre Eingaben.", "error") + return render_template('errors/400.html', error=str(e)), 400 + +@app.errorhandler(401) +def unauthorized(e): + """401 Fehler - Nicht autorisiert""" + ErrorHandler.log_exception(e, code=401) + is_api_request = request.path.startswith('/api/') + + if is_api_request: + return ErrorHandler.api_error("Authentifizierung erforderlich.", 401) + flash("Sie müssen sich anmelden, um auf diese Seite zuzugreifen.", "error") + return redirect(url_for('login')) + +# OpenAI-Integration für KI-Assistenz +@app.route('/api/assistant', methods=['POST']) +def chat_with_assistant(): + """Chat mit dem KI-Assistenten""" + data = request.json + user_message = data.get('message', '') + + # Überprüfe, ob die OpenAI-API verfügbar ist + if not openai_available or client is None: + # Fallback-Antwort, wenn OpenAI nicht verfügbar ist + fallback_message = { + "response": "Der KI-Assistent ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut oder kontaktieren Sie den Administrator.", + "thoughts": "Leider konnte keine Verbindung zur OpenAI-API hergestellt werden. Dies kann an SSL-Zertifikatsproblemen, Netzwerkproblemen oder API-Schlüsselproblemen liegen." + } + return jsonify(fallback_message) + + # Versuche, eine Antwort von OpenAI zu erhalten + try: + # Check, ob es eine Datenbankanfrage ist + is_db_query, db_query_result = check_database_query(user_message) + if is_db_query: + return jsonify({ + "response": db_query_result, + "thoughts": "Ihre Anfrage wurde als Datenbankanfrage erkannt und direkt beantwortet." + }) + + system_message = """Du bist SysTades, ein intelligenter Assistent in einer Wissensmanagement-Anwendung. + Deine Aufgabe ist es, tiefe, reflektierte Antworten auf Fragen der Benutzer zu geben. + Beziehe dich auf vorhandene Konzepte und betrachte Fragen stets aus mehreren Perspektiven. + Vermeide pauschale Antworten und beziehe immer verschiedene Denkansätze ein. + Antworte stets auf Deutsch und in einem nachdenklichen, philosophischen Ton. + """ + + response = client.chat.completions.create( + model="gpt-4o-mini", + messages=[ + {"role": "system", "content": system_message}, + {"role": "user", "content": user_message} + ], + temperature=0.7, + timeout=60 # Erhöht auf 60 Sekunden für bessere Zuverlässigkeit + ) + + # Extrahiere die Antwort + assistant_response = response.choices[0].message.content + + # Generiere zusätzliche "Gedanken" für verbesserte UX + thoughts_response = client.chat.completions.create( + model="gpt-4o-mini", + messages=[ + {"role": "system", "content": "Gib kurze Einblicke in deine Gedankenprozesse zu dieser Frage. Schreibe 1-3 Sätze zur Reflexion über die Frage und die wichtigsten Aspekte deiner Antwort. Bleibe dabei informell und persönlich. Schreibe auf Deutsch."}, + {"role": "user", "content": user_message}, + {"role": "assistant", "content": assistant_response} + ], + temperature=0.7, + max_tokens=150 + ) + thoughts = thoughts_response.choices[0].message.content + + return jsonify({ + "response": assistant_response, + "thoughts": thoughts + }) + except Exception as e: + print(f"Fehler bei der OpenAI-Anfrage: {e}") + import traceback + print(f"Stack Trace: {traceback.format_exc()}") + + # Fallback-Antwort bei Fehler + fallback_message = { + "response": "Es tut mir leid, aber ich konnte Ihre Anfrage nicht verarbeiten. Bitte versuchen Sie es später erneut.", + "thoughts": "Ein technisches Problem ist aufgetreten. Dies könnte an Netzwerkproblemen, API-Grenzen oder Serverauslastung liegen." + } + return jsonify(fallback_message) + +def check_database_query(user_message): + """ + Prüft, ob die Benutzeranfrage nach Datenbankinformationen sucht + und gibt relevante Informationen aus der Datenbank zurück. + + Returns: + (bool, str): Tupel aus (ist_db_anfrage, db_antwort) + """ + user_message = user_message.lower() + + # Schlüsselwörter, die auf eine Datenbankanfrage hindeuten + db_keywords = [ + 'wie viele', 'wieviele', 'anzahl', 'liste', 'zeige', 'zeig mir', 'datenbank', + 'statistik', 'stats', 'benutzer', 'gedanken', 'kategorien', 'mindmap', + 'neueste', 'kürzlich', 'gespeichert', 'zähle', 'suche nach', 'finde' + ] + + # Überprüfen, ob die Nachricht eine Datenbankanfrage sein könnte + is_db_query = any(keyword in user_message for keyword in db_keywords) + + if not is_db_query: + return False, "" + + # Datenbank-Antwort vorbereiten + response = "Hier sind Informationen aus der Datenbank:\n\n" + + try: + # 1. Benutzer-Statistiken + if any(kw in user_message for kw in ['benutzer', 'user', 'nutzer']): + user_count = User.query.count() + active_users = User.query.filter_by(is_active=True).count() + admins = User.query.filter_by(role='admin').count() + + response += f"**Benutzer-Statistiken:**\n" + response += f"- Gesamt: {user_count} Benutzer\n" + response += f"- Aktiv: {active_users} Benutzer\n" + response += f"- Administratoren: {admins} Benutzer\n\n" + + # 2. Gedanken-Statistiken + if any(kw in user_message for kw in ['gedanken', 'thought', 'inhalt']): + thought_count = Thought.query.count() + + if thought_count > 0: + avg_rating = db.session.query(func.avg(ThoughtRating.relevance_score)).scalar() or 0 + avg_rating = round(avg_rating, 1) + + recent_thoughts = Thought.query.order_by(Thought.created_at.desc()).limit(5).all() + + response += f"**Gedanken-Statistiken:**\n" + response += f"- Gesamt: {thought_count} Gedanken\n" + response += f"- Durchschnittliche Bewertung: {avg_rating}/5\n\n" + + if recent_thoughts: + response += "**Neueste Gedanken:**\n" + for thought in recent_thoughts: + response += f"- {thought.title} (von {thought.author.username})\n" + response += "\n" + else: + response += "Es sind noch keine Gedanken in der Datenbank gespeichert.\n\n" + + # 3. Kategorien-Statistiken + if any(kw in user_message for kw in ['kategorie', 'category', 'thema']): + category_count = Category.query.filter_by(parent_id=None).count() + subcategory_count = Category.query.filter(Category.parent_id != None).count() + + response += f"**Kategorien-Statistiken:**\n" + response += f"- Hauptkategorien: {category_count}\n" + response += f"- Unterkategorien: {subcategory_count}\n\n" + + main_categories = Category.query.filter_by(parent_id=None).all() + if main_categories: + response += "**Hauptkategorien:**\n" + for category in main_categories: + subcats = Category.query.filter_by(parent_id=category.id).count() + response += f"- {category.name} ({subcats} Unterkategorien)\n" + response += "\n" + + # 4. Mindmap-Statistiken + if any(kw in user_message for kw in ['mindmap', 'karte', 'map', 'knoten']): + public_nodes = MindMapNode.query.count() + user_mindmaps = UserMindmap.query.count() + + response += f"**Mindmap-Statistiken:**\n" + response += f"- Öffentliche Knoten: {public_nodes}\n" + response += f"- Benutzerdefinierte Mindmaps: {user_mindmaps}\n\n" + + if user_mindmaps > 0: + recent_mindmaps = UserMindmap.query.order_by(UserMindmap.created_at.desc()).limit(3).all() + + if recent_mindmaps: + response += "**Neueste Mindmaps:**\n" + for mindmap in recent_mindmaps: + response += f"- {mindmap.name} (von {mindmap.user.username})\n" + response += "\n" + + # Wenn keine spezifischen Daten angefordert wurden, allgemeine Übersicht geben + if not any(kw in user_message for kw in ['benutzer', 'user', 'gedanken', 'thought', 'kategorie', 'category', 'mindmap']): + users = User.query.count() + thoughts = Thought.query.count() + categories = Category.query.count() + nodes = MindMapNode.query.count() + user_maps = UserMindmap.query.count() + + response += f"**Übersicht über die Datenbank:**\n" + response += f"- Benutzer: {users}\n" + response += f"- Gedanken: {thoughts}\n" + response += f"- Kategorien: {categories}\n" + response += f"- Mindmap-Knoten: {nodes}\n" + response += f"- Benutzerdefinierte Mindmaps: {user_maps}\n" + + return True, response + + except Exception as e: + import traceback + print(f"Fehler bei der Datenbankabfrage: {e}") + print(traceback.format_exc()) + return True, "Es ist ein Fehler bei der Abfrage der Datenbank aufgetreten. Bitte versuchen Sie es später erneut." + +@app.route('/search') +def search_thoughts_page(): + """Seite zur Gedankensuche anzeigen.""" + return render_template('search.html') + +@app.route('/my_account') +def my_account(): + """Zeigt die persönliche Merkliste an.""" + if not current_user.is_authenticated: + flash('Bitte melde dich an, um auf deine Merkliste zuzugreifen.', 'warning') + return redirect(url_for('login')) + + # Hole die Lesezeichen des Benutzers + bookmarked_thoughts = current_user.bookmarked_thoughts + + return render_template('my_account.html', bookmarked_thoughts=bookmarked_thoughts) + +# Dummy-Route, um 404-Fehler für fehlende Netzwerk-Hintergrundbilder zu vermeiden +@app.route('/static/network-bg.jpg') +@app.route('/static/network-bg.svg') +def dummy_network_bg(): + """Leere Antwort für die nicht mehr verwendeten Netzwerk-Hintergrundbilder.""" + return '', 200 + +# Route zum expliziten Neu-Laden der Umgebungsvariablen +@app.route('/admin/reload-env', methods=['POST']) +@admin_required +def reload_env(): + """Lädt die Umgebungsvariablen aus der .env-Datei neu.""" + try: + # Erzwinge das Neuladen der .env-Datei + load_dotenv(override=True, force=True) + + # OpenAI API-Key ist bereits fest kodiert + # client wurde bereits mit festem API-Key initialisiert + + # Weitere Umgebungsvariablen hier aktualisieren, falls nötig + app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', app.config['SECRET_KEY']) + + return jsonify({ + 'success': True, + 'message': 'Umgebungsvariablen wurden erfolgreich neu geladen.' + }) + except Exception as e: + return jsonify({ + 'success': False, + 'message': f'Fehler beim Neuladen der Umgebungsvariablen: {str(e)}' + }), 500 + +# Berechtigungsverwaltung für Mindmaps +@app.route('/api/mindmap//shares', methods=['GET']) +@login_required +@handle_api_exception +def get_mindmap_shares(mindmap_id): + """Listet alle Benutzer auf, mit denen eine Mindmap geteilt wurde.""" + # Überprüfen, ob die Mindmap dem Benutzer gehört + mindmap = UserMindmap.query.get_or_404(mindmap_id) + if mindmap.user_id != current_user.id: + return ErrorHandler.api_error("Sie haben keine Berechtigung, die Freigaben dieser Mindmap einzusehen.", 403) + + # Alle Freigaben für diese Mindmap abrufen + shares = MindmapShare.query.filter_by(mindmap_id=mindmap_id).all() + + result = [] + for share in shares: + # Benutzerinformationen abrufen + shared_with_user = User.query.get(share.shared_with_id) + + if shared_with_user: + result.append({ + 'id': share.id, + 'user_id': shared_with_user.id, + 'username': shared_with_user.username, + 'email': shared_with_user.email, + 'permission': share.permission_type.name, + 'created_at': share.created_at.isoformat(), + 'last_accessed': share.last_accessed.isoformat() if share.last_accessed else None + }) + + return jsonify({ + 'success': True, + 'shares': result + }) + +@app.route('/api/mindmap//share', methods=['POST']) +@login_required +@handle_api_exception +def share_mindmap(mindmap_id): + """Teilt eine Mindmap mit einem anderen Benutzer.""" + # Überprüfen, ob die Mindmap dem Benutzer gehört + mindmap = UserMindmap.query.get_or_404(mindmap_id) + if mindmap.user_id != current_user.id: + return ErrorHandler.api_error("Sie haben keine Berechtigung, diese Mindmap zu teilen.", 403) + + data = request.json + if not data or 'email' not in data or 'permission' not in data: + return ErrorHandler.api_error("E-Mail-Adresse und Berechtigungstyp sind erforderlich.", 400) + + # Benutzer anhand der E-Mail-Adresse finden + user_to_share_with = User.query.filter_by(email=data['email']).first() + if not user_to_share_with: + return ErrorHandler.api_error("Kein Benutzer mit dieser E-Mail-Adresse gefunden.", 404) + + # Prüfen, ob der Benutzer versucht, mit sich selbst zu teilen + if user_to_share_with.id == current_user.id: + return ErrorHandler.api_error("Sie können die Mindmap nicht mit sich selbst teilen.", 400) + + # Prüfen, ob die Mindmap bereits mit diesem Benutzer geteilt wurde + existing_share = MindmapShare.query.filter_by( + mindmap_id=mindmap_id, + shared_with_id=user_to_share_with.id + ).first() + + # Berechtigungstyp validieren und konvertieren + try: + permission_type = PermissionType[data['permission']] + except (KeyError, ValueError): + return ErrorHandler.api_error( + "Ungültiger Berechtigungstyp. Erlaubte Werte sind: READ, EDIT, ADMIN.", + 400 + ) + + if existing_share: + # Wenn bereits geteilt, aktualisiere die Berechtigungen + existing_share.permission_type = permission_type + message = "Berechtigungen erfolgreich aktualisiert." + else: + # Wenn noch nicht geteilt, erstelle eine neue Freigabe + new_share = MindmapShare( + mindmap_id=mindmap_id, + shared_by_id=current_user.id, + shared_with_id=user_to_share_with.id, + permission_type=permission_type + ) + db.session.add(new_share) + message = "Mindmap erfolgreich geteilt." + + # Wenn die Mindmap bisher privat war, mache sie jetzt nicht mehr privat + if mindmap.is_private: + mindmap.is_private = False + + db.session.commit() + + return jsonify({ + 'success': True, + 'message': message + }) + +@app.route('/api/mindmap/shares/', methods=['PUT']) +@login_required +@handle_api_exception +def update_mindmap_share(share_id): + """Aktualisiert die Berechtigungen für eine geteilte Mindmap.""" + # Freigabe finden + share = MindmapShare.query.get_or_404(share_id) + + # Prüfen, ob der Benutzer der Eigentümer der Mindmap ist + mindmap = UserMindmap.query.get(share.mindmap_id) + if not mindmap or mindmap.user_id != current_user.id: + return ErrorHandler.api_error("Sie haben keine Berechtigung, diese Freigabe zu ändern.", 403) + + data = request.json + if not data or 'permission' not in data: + return ErrorHandler.api_error("Berechtigungstyp ist erforderlich.", 400) + + # Berechtigungstyp validieren und konvertieren + try: + permission_type = PermissionType[data['permission']] + except (KeyError, ValueError): + return ErrorHandler.api_error( + "Ungültiger Berechtigungstyp. Erlaubte Werte sind: READ, EDIT, ADMIN.", + 400 + ) + + # Berechtigungen aktualisieren + share.permission_type = permission_type + db.session.commit() + + return jsonify({ + 'success': True, + 'message': "Berechtigungen erfolgreich aktualisiert." + }) + +@app.route('/api/mindmap/shares/', methods=['DELETE']) +@login_required +@handle_api_exception +def revoke_mindmap_share(share_id): + """Widerruft die Freigabe einer Mindmap für einen Benutzer.""" + # Freigabe finden + share = MindmapShare.query.get_or_404(share_id) + + # Prüfen, ob der Benutzer der Eigentümer der Mindmap ist + mindmap = UserMindmap.query.get(share.mindmap_id) + if not mindmap or mindmap.user_id != current_user.id: + return ErrorHandler.api_error("Sie haben keine Berechtigung, diese Freigabe zu widerrufen.", 403) + + # Freigabe löschen + db.session.delete(share) + + # Prüfen, ob dies die letzte Freigabe war und ggf. Mindmap wieder privat setzen + remaining_shares = MindmapShare.query.filter_by(mindmap_id=mindmap.id).count() + if remaining_shares == 0: + mindmap.is_private = True + + db.session.commit() + + return jsonify({ + 'success': True, + 'message': "Freigabe erfolgreich widerrufen." + }) + +@app.route('/api/mindmaps/shared-with-me', methods=['GET']) +@login_required +@handle_api_exception +def get_shared_mindmaps(): + """Listet alle Mindmaps auf, die mit dem aktuellen Benutzer geteilt wurden.""" + shares = MindmapShare.query.filter_by(shared_with_id=current_user.id).all() + + result = [] + for share in shares: + mindmap = UserMindmap.query.get(share.mindmap_id) + owner = User.query.get(mindmap.user_id) + + if mindmap and owner: + # Zugriffsdatum aktualisieren + share.last_accessed = datetime.now(timezone.utc) + + result.append({ + 'id': mindmap.id, + 'name': mindmap.name, + 'description': mindmap.description, + 'owner': { + 'id': owner.id, + 'username': owner.username + }, + 'created_at': mindmap.created_at.isoformat(), + 'last_modified': mindmap.last_modified.isoformat(), + 'permission': share.permission_type.name + }) + + db.session.commit() # Speichere die aktualisierten Zugriffsdaten + + return jsonify({ + 'success': True, + 'mindmaps': result + }) + +# Hilfsfunktion zur Überprüfung der Berechtigungen +def check_mindmap_permission(mindmap_id, permission_type=None): + """ + Überprüft, ob der aktuelle Benutzer Zugriff auf eine Mindmap hat. + + Args: + mindmap_id: ID der Mindmap + permission_type: Mindestberechtigung, die erforderlich ist (READ, EDIT, ADMIN) + Wenn None, wird nur der Zugriff überprüft. + + Returns: + (bool, str): Tupel aus (hat_berechtigung, fehlermeldung) + """ + mindmap = UserMindmap.query.get(mindmap_id) + if not mindmap: + return False, "Mindmap nicht gefunden." + + # Wenn der Benutzer der Eigentümer ist, hat er vollen Zugriff + if mindmap.user_id == current_user.id: + return True, "" + + # Wenn die Mindmap privat ist und der Benutzer nicht der Eigentümer ist + if mindmap.is_private: + share = MindmapShare.query.filter_by( + mindmap_id=mindmap_id, + shared_with_id=current_user.id + ).first() + + if not share: + return False, "Sie haben keinen Zugriff auf diese Mindmap." + + # Wenn eine bestimmte Berechtigungsstufe erforderlich ist + if permission_type: + required_level = PermissionType[permission_type].value + user_level = share.permission_type.value + + if required_level not in [p.value for p in PermissionType]: + return False, f"Ungültiger Berechtigungstyp: {permission_type}" + + # Berechtigungshierarchie prüfen + permission_hierarchy = { + PermissionType.READ.name: 1, + PermissionType.EDIT.name: 2, + PermissionType.ADMIN.name: 3 + } + + if permission_hierarchy[share.permission_type.name] < permission_hierarchy[permission_type]: + return False, f"Sie benötigen {permission_type}-Berechtigungen für diese Aktion." + + return True, "" + +# Flask starten +if __name__ == '__main__': + with app.app_context(): + # Make sure tables exist + db.create_all() + socketio.run(app, debug=True, host='0.0.0.0') + +def get_category_mindmap_data(category_name): + """Generische Funktion zum Abrufen der Mindmap-Daten für eine Kategorie.""" + try: + # Kategorie mit allen Unterkategorien in einer Abfrage laden + category = Category.query.filter_by(name=category_name).options( + joinedload(Category.children) + ).first_or_404() + + # Basis-Knoten erstellen + nodes = [{ + 'id': f'cat_{category.id}', + 'name': category.name, + 'description': category.description or '', + 'color_code': category.color_code or '#9F7AEA', + 'is_center': True, + 'has_children': bool(category.children), + 'icon': category.icon or 'fa-solid fa-circle' + }] + + # Unterkategorien hinzufügen + for subcat in category.children: + nodes.append({ + 'id': f'cat_{subcat.id}', + 'name': subcat.name, + 'description': subcat.description or '', + 'color_code': subcat.color_code or '#9F7AEA', + 'category': category_name, + 'has_children': bool(subcat.children), + 'icon': subcat.icon or 'fa-solid fa-circle' + }) + + # Kanten erstellen (vereinheitlichte Schlüssel) + edges = [{ + 'source': f'cat_{category.id}', + 'target': f'cat_{subcat.id}', + 'strength': 0.8 + } for subcat in category.children] + + return jsonify({ + 'success': True, + 'nodes': nodes, + 'edges': edges + }) + except Exception as e: + print(f"Fehler beim Abrufen der {category_name}-Mindmap: {str(e)}") + return jsonify({ + 'success': False, + 'error': f'{category_name}-Mindmap konnte nicht geladen werden', + 'details': str(e) + }), 500 + +@app.route('/api/mindmap/root') +def get_root_mindmap_data(): + """Liefert die Daten für die Root-Mindmap.""" + try: + # Hauptkategorien mit Unterkategorien in einer Abfrage laden + categories = Category.query.filter_by(parent_id=None).options( + joinedload(Category.children) + ).all() + + # Basis-Knoten erstellen + nodes = [{ + 'id': 'root', + 'name': 'Wissen', + 'description': 'Zentrale Wissensbasis', + 'color_code': '#4299E1', + 'is_center': True, + 'has_children': bool(categories), + 'icon': 'fa-solid fa-circle' + }] + + # Kategorien als Knoten hinzufügen + for category in categories: + nodes.append({ + 'id': f'cat_{category.id}', + 'name': category.name, + 'description': category.description or '', + 'color_code': category.color_code or '#9F7AEA', + 'category': category.name, + 'has_children': bool(category.children), + 'icon': category.icon or 'fa-solid fa-circle' + }) + + # Kanten erstellen (vereinheitlichte Schlüssel) + edges = [{ + 'source': 'root', + 'target': f'cat_{category.id}', + 'strength': 0.8 + } for category in categories] + + return jsonify({ + 'success': True, + 'nodes': nodes, + 'edges': edges + }) + except Exception as e: + print(f"Fehler beim Abrufen der Root-Mindmap: {str(e)}") + return jsonify({ + 'success': False, + 'error': 'Root-Mindmap konnte nicht geladen werden', + 'details': str(e) + }), 500 + +# Spezifische Routen für Kategorien +@app.route('/api/mindmap/philosophy') +def get_philosophy_mindmap_data(): + return get_category_mindmap_data('Philosophie') + +@app.route('/api/mindmap/science') +def get_science_mindmap_data(): + return get_category_mindmap_data('Wissenschaft') + +@app.route('/api/mindmap/technology') +def get_technology_mindmap_data(): + return get_category_mindmap_data('Technologie') + +@app.route('/api/mindmap/arts') +def get_arts_mindmap_data(): + return get_category_mindmap_data('Künste') + +# Generische Route für spezifische Knoten +@app.route('/api/mindmap/') +def get_mindmap_data(node_id): + """Liefert die Daten für einen spezifischen Mindmap-Knoten.""" + try: + # Prüfen, ob es sich um eine spezielle Route handelt + if node_id in ['root', 'philosophy', 'science', 'technology', 'arts']: + return jsonify({ + 'success': False, + 'error': 'Ungültige Knoten-ID', + 'details': 'Diese ID ist für spezielle Routen reserviert' + }), 400 + + # Knoten mit Unterknoten in einer Abfrage laden + node = MindMapNode.query.options( + joinedload(MindMapNode.children) + ).get_or_404(node_id) + + # Basis-Knoten erstellen + nodes = [{ + 'id': str(node.id), + 'name': node.name, + 'description': node.description or '', + 'color_code': node.color_code or '#9F7AEA', + 'is_center': True, + 'has_children': bool(node.children), + 'icon': node.icon or 'fa-solid fa-circle' + }] + + # Unterknoten hinzufügen + for child in node.children: + nodes.append({ + 'id': str(child.id), + 'name': child.name, + 'description': child.description or '', + 'color_code': child.color_code or '#9F7AEA', + 'category': node.name, + 'has_children': bool(child.children), + 'icon': child.icon or 'fa-solid fa-circle' + }) + + # Kanten erstellen (vereinheitlichte Schlüssel) + edges = [{ + 'source': str(node.id), + 'target': str(child.id), + 'strength': 0.8 + } for child in node.children] + + return jsonify({ + 'success': True, + 'nodes': nodes, + 'edges': edges + }) + except Exception as e: + print(f"Fehler beim Abrufen der Mindmap-Daten für Knoten {node_id}: {str(e)}") + return jsonify({ + 'success': False, + 'error': 'Mindmap-Daten konnten nicht geladen werden', + 'details': str(e) + }), 500 + diff --git a/fix_routes.py b/fix_routes.py new file mode 100644 index 0000000000000000000000000000000000000000..6a8357c53561f459b641f0b4d31d24d3bd033d1d GIT binary patch literal 894 zcmb_bO-sX25S+8%e|X}dEtvEw(u$&@qPEcLtsu2Y^kExA8VUY+b!L;O0X>NFNb+`f zcJ?!GuO2I8ctVZ>j_(+o*g#vm#si*d_gI?ss~loM?+h>KqJuea8A6jg*db$E7vheX z1s=(l(bhA*lFS8TIAe;D{>YWnN36mqZbZ)%_ZU*I3=;&{HD1R!Ya$cNI>w$wa@6R^ zHzi&?s(Z+%L59|aIk~%ae&3YGe^gy;`5%0ABWE;aC;g1s_08h>U0MDSzv^5c z1LmWuV%*XaVc+n*y6O(Lndd1^Fyb@8Ii@(m8SjqL7&o}Kdq8kv_B_Xa<?{LQ%ce`DE&vC5wz2qZO)DNhA6N_<|^7dF2az0 literal 0 HcmV?d00001 diff --git a/logs/app.log b/logs/app.log index 7f5b424..346ab8c 100644 --- a/logs/app.log +++ b/logs/app.log @@ -5156,3 +5156,717 @@ Traceback (most recent call last): raise NotFound() from None werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:25:21,454 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:25:25,071 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:25:25,071 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:25:30,856 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:25:33,586 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:25:33,586 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:25:50,836 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:25:50,836 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:26:06,618 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:26:06,618 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:27:22,814 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:27:24,332 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:27:24,332 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:27:34,642 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:27:34,642 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:27:35,419 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:27:35,419 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:28:38,905 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:28:41,398 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:28:41,398 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:29:48,833 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:29:48,833 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:29:49,665 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:29:49,665 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:32:50,271 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:32:52,600 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:32:52,600 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:07,890 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:09,409 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:09,409 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:16,821 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:18,575 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:18,575 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:20,126 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:33:20,126 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:33:21,061 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:33:21,061 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:33:44,252 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:44,961 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:45,883 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:45,883 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:46,542 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:46,542 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:33:53,216 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:33:53,216 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:33:54,067 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:33:54,067 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:35:37,972 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:35:37,973 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:35:40,362 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:35:40,362 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:35:40,367 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:35:40,367 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:42:59,077 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:42:59,077 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:42:59,899 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:42:59,899 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:43:19,226 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:43:21,247 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:43:21,247 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:43:27,066 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:43:28,899 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:43:28,899 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:44:16,881 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:44:16,881 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:44:26,325 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:44:26,325 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:45:56,014 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:45:56,065 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:45:56,229 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:45:59,031 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:45:59,031 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:45:59,032 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:45:59,032 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:45:59,854 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:45:59,854 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:10,909 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:12,768 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:12,768 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:14,800 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:15,083 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:16,933 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:16,933 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:17,585 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:17,585 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:24,785 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:25,851 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:26,145 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:26,145 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:27,523 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:46:27,523 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:34,321 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:34,351 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:34,362 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:36,593 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:36,593 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:36,732 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:36,732 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:36,764 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:36,764 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:48,050 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:48,178 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:48,204 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:50,329 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:50,329 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:50,544 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:50,544 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:50,612 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:49:50,612 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:01,719 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:01,804 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:01,817 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:04,382 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:04,382 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:04,478 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:04,478 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:04,958 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:04,958 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:42,672 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:45,133 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:45,133 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:51,320 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:53,720 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:50:53,720 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:52:01,840 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:52:01,840 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:52:02,894 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:52:02,894 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:53:19,350 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:53:21,503 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:53:21,503 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:53:29,390 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:53:31,988 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:53:31,988 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77] +2025-05-12 19:54:22,250 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] +2025-05-12 19:54:22,250 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +Endpoint: /api/mindmap/root, Method: GET, IP: 127.0.0.1 +Nicht angemeldet +Traceback (most recent call last): + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request + rv = self.dispatch_request() + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request + self.raise_routing_exception(req) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception + raise request.routing_exception # type: ignore + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. + [in C:\Users\firem\Desktop\111\Systades\website\app.py:93] diff --git a/static/js/update_mindmap.js.bak b/static/js/update_mindmap.js.bak new file mode 100644 index 0000000..f75977e --- /dev/null +++ b/static/js/update_mindmap.js.bak @@ -0,0 +1,1078 @@ +/** + * Update Mindmap + * Dieses Skript fügt Knoten zur Mindmap hinzu und stellt sicher, + * dass sie im neuronalen Netzwerk-Design angezeigt werden. + * Implementiert Lazy Loading & Progressive Disclosure + */ + +// Neue zentrale Konfiguration +const mindmapConfig = { + categories: { + 'Philosophie': { + icon: 'fa-solid fa-lightbulb', + color: '#b71c1c', + description: 'Die Lehre vom Denken und der Erkenntnis' + }, + 'Wissenschaft': { + icon: 'fa-solid fa-atom', + color: '#f4b400', + description: 'Systematische Erforschung der Natur und Gesellschaft' + }, + 'Technologie': { + icon: 'fa-solid fa-microchip', + color: '#0d47a1', + description: 'Anwendung wissenschaftlicher Erkenntnisse' + }, + 'Künste': { + icon: 'fa-solid fa-palette', + color: '#c2185b', + description: 'Kreativer Ausdruck und künstlerische Gestaltung' + } + }, + defaultNodeStyle: { + fontSize: 18, + fontColor: '#fff', + neuronSize: 8, + neuronActivity: 0.8 + }, + centerNodeStyle: { + fontSize: 22, + fontColor: '#222', + neuronSize: 12, + neuronActivity: 1.0, + color: '#f5f5f5', + icon: 'fa-solid fa-circle' + } +}; + +// Zentrale Styling-Konfiguration +const mindmapStyles = { + node: { + base: { + 'background-color': 'data(color)', + 'label': 'data(label)', + 'color': '#ffffff', + 'text-background-color': 'rgba(0, 0, 0, 0.7)', + 'text-background-opacity': 0.8, + 'text-background-padding': '4px', + 'text-valign': 'center', + 'text-halign': 'center', + 'font-size': 16, + 'width': 'mapData(neuronSize, 3, 10, 30, 60)', + 'height': 'mapData(neuronSize, 3, 10, 30, 60)', + 'border-width': 2, + 'border-color': '#ffffff', + 'border-opacity': 0.8, + 'shape': 'ellipse', + 'background-opacity': 0.85 + }, + center: { + 'background-color': '#f5f5f5', + 'color': '#222', + 'font-size': 20, + 'border-width': 3, + 'width': 100, + 'height': 100 + }, + selected: { + 'border-color': '#f59e42', + 'border-width': 3, + 'background-opacity': 1 + } + }, + edge: { + base: { + 'width': function(ele) { + return ele.data('strength') ? ele.data('strength') * 2 : 1; + }, + 'line-color': function(ele) { + const sourceColor = ele.source().data('color'); + return sourceColor || '#8a8aaa'; + }, + 'line-opacity': function(ele) { + return ele.data('strength') ? ele.data('strength') * 0.6 : 0.4; + }, + 'curve-style': 'bezier', + 'target-arrow-shape': 'none', + 'control-point-distances': [30, -30], + 'control-point-weights': [0.5, 0.5] + } + }, + layout: { + base: { + name: 'cose', + animate: true, + animationDuration: 500, + refresh: 20, + fit: true, + padding: 30, + nodeRepulsion: 4500, + idealEdgeLength: 50, + edgeElasticity: 0.45, + randomize: true, + componentSpacing: 100, + nodeOverlap: 20, + gravity: 0.25, + initialTemp: 1000, + coolingFactor: 0.95, + minTemp: 1 + } + } +}; + +// Globale Variable für die Mindmap-Daten +let mindmapData = null; + +// Funktion zum Laden der Mindmap-Daten aus der Datenbank +async function loadMindmapData(nodeId = null) { + try { + const apiUrl = nodeId ? `/api/mindmap/${nodeId}` : '/api/mindmap/root'; + console.log('Lade Mindmap-Daten von:', apiUrl); + + const response = await fetch(apiUrl); + console.log('API-Antwort Status:', response.status); + + if (!response.ok) { + let errorData; + try { + errorData = await response.json(); + console.log('API-Fehler Details:', { + status: response.status, + statusText: response.statusText, + errorData + }); + } catch (e) { + console.error('Fehler beim Parsen der Fehlerantwort:', e); + errorData = { + error: `HTTP-Fehler ${response.status}: ${response.statusText}` + }; + } + + // Fehlerobjekt für die Benachrichtigung erstellen + const errorMessage = { + error: errorData.error || errorData.message || 'Unbekannter Fehler', + details: errorData.details || null + }; + + showUINotification(errorMessage, 'error'); + throw new Error(errorMessage.error); + } + + const data = await response.json(); + console.log('Geladene Mindmap-Daten:', data); + + if (!data.success) { + const errorMessage = { + error: data.error || 'Mindmap-Daten konnten nicht geladen werden', + details: data.details || null + }; + showUINotification(errorMessage, 'error'); + throw new Error(errorMessage.error); + } + + // Erfolgreiche Antwort + mindmapData = data; // Speichere die Daten in der globalen Variable + showUINotification('Mindmap-Daten erfolgreich geladen', 'success'); + return data; + } catch (error) { + console.error('Fehler beim Laden der Mindmap-Daten:', { + message: error.message, + stack: error.stack, + nodeId + }); + + // Stelle sicher, dass wir eine aussagekräftige Fehlermeldung haben + const errorMessage = { + error: error.message || 'Unbekannter Fehler beim Laden der Mindmap-Daten', + details: error.stack + }; + + showUINotification(errorMessage, 'error'); + throw error; + } +} + +// Funktion zum Initialisieren der Mindmap +async function initializeMindmap() { + try { + const data = await loadMindmapData(); + if (!data || !data.nodes || !data.edges) { + throw new Error('Ungültiges Datenformat: Mindmap-Daten fehlen oder sind unvollständig'); + } + + const elements = [ + // Knoten + ...data.nodes.map(node => ({ + data: { + id: node.id, + label: node.name, + category: node.category, + description: node.description, + hasChildren: node.has_children, + expanded: false, + color: node.color_code, + fontColor: '#ffffff', + fontSize: node.is_center ? 20 : 16 + } + })), + // Kanten + ...data.edges.map(edge => ({ + data: { + source: edge.source, + target: edge.target, + strength: edge.strength || 0.5 + } + })) + ]; + + // Bestehende Cytoscape-Instanz entfernen, falls vorhanden + if (window.cy) { + window.cy.destroy(); + } + + window.cy = cytoscape({ + container: document.getElementById('cy'), + elements: elements, + style: mindmapStyles, + layout: mindmapStyles.layout.base + }); + + // Event-Listener für Knoten-Klicks + cy.on('tap', 'node', async function(evt) { + const node = evt.target; + if (node.data('hasChildren') && !node.data('expanded')) { + await loadSubthemes(node); + } + }); + + // Layout ausführen + cy.layout(mindmapStyles.layout.base).run(); + + return true; + } catch (error) { + console.error('Fehler bei der Mindmap-Initialisierung:', error); + showUINotification({ + error: 'Mindmap konnte nicht initialisiert werden', + details: error.message + }, 'error'); + return false; + } +} + +// Warte bis DOM geladen ist +document.addEventListener('DOMContentLoaded', function() { + console.log('DOMContentLoaded Event ausgelöst'); + + // Prüfe, ob der Container existiert + const cyContainer = document.getElementById('cy'); + console.log('Container gefunden:', cyContainer); + + if (!cyContainer) { + console.error('Mindmap-Container #cy nicht gefunden!'); + return; + } + + // Prüfe, ob Cytoscape verfügbar ist + if (typeof cytoscape === 'undefined') { + console.error('Cytoscape ist nicht definiert!'); + return; + } + console.log('Cytoscape ist verfügbar'); + + // Beispiel-Daten entfernt, stattdessen große Mindmap-Daten verwenden + const elements = [ + // Knoten + ...mindmapData.nodes.map(node => ({ + data: { + id: node.id, + label: node.label, + category: node.category, + description: node.description, + hasChildren: node.hasChildren, + expanded: node.expanded, + neuronSize: node.neuronSize, + neuronActivity: node.neuronActivity, + color: node.color, + icon: node.icon, + fontColor: node.fontColor, + fontSize: node.fontSize + } + })), + // Kanten + ...mindmapData.edges.map(edge => ({ + data: { + source: edge.source, + target: edge.target, + label: edge.label, + strength: edge.strength + } + })) + ]; + + console.log('Initialisiere Cytoscape...'); + + // Initialisiere Cytoscape mit einem schlichten, modernen Design + window.cy = cytoscape({ + container: cyContainer, + elements: elements, + style: [ + { + selector: 'node', + style: mindmapStyles.node.base + }, + { + selector: 'node[isCenter]', + style: mindmapStyles.node.center + }, + { + selector: 'node:selected', + style: mindmapStyles.node.selected + }, + { + selector: 'edge', + style: mindmapStyles.edge.base + } + ], + layout: mindmapStyles.layout.base + }); + + console.log('Cytoscape initialisiert'); + + // Füge neuronale Eigenschaften zu allen Knoten hinzu + cy.nodes().forEach(node => { + const data = node.data(); + node.data({ + ...data, + neuronSize: data.neuronSize || 8, + neuronActivity: data.neuronActivity || 0.8, + refractionPeriod: Math.random() * 300 + 700, + threshold: Math.random() * 0.3 + 0.6, + lastFired: 0, + color: categoryColors[data.category] || '#60a5fa' + }); + }); + + // Füge synaptische Eigenschaften zu allen Kanten hinzu + cy.edges().forEach(edge => { + const data = edge.data(); + edge.data({ + ...data, + strength: data.strength || 0.5, + conductionVelocity: Math.random() * 0.5 + 0.3, + latency: Math.random() * 100 + 50 + }); + }); + + // Starte neuronale Aktivitätssimulation + startNeuralActivitySimulation(cy); + + // Mindmap mit echten Daten befüllen (Styles, Farben etc.) + updateMindmap(); + + // Event auslösen, damit andere Scripte reagieren können + document.dispatchEvent(new Event('mindmap-loaded')); + console.log('mindmap-loaded Event ausgelöst'); + + // Event-Listener für Knoten-Klicks + cy.on('tap', 'node', async function(evt) { + const node = evt.target; + console.log('Node clicked:', node.id(), 'hasChildren:', node.data('hasChildren'), 'expanded:', node.data('expanded')); + + if (node.data('hasChildren') && !node.data('expanded')) { + await loadSubthemes(node); + } + }); + + // Entferne den Icon-Overlay-Code + setTimeout(() => { + // Entferne alle existierenden Icon-Overlays + document.querySelectorAll('.cy-node-icon').forEach(icon => icon.remove()); + }, 0); +}); + +// Funktion zum Initialisieren des neuronalen Designs +function initializeNeuralDesign(cy) { + // Füge neuronale Eigenschaften zu allen Knoten hinzu + cy.nodes().forEach(node => { + const data = node.data(); + node.data({ + ...data, + neuronSize: data.neuronSize || 8, + neuronActivity: data.neuronActivity || 0.8, + refractionPeriod: Math.random() * 300 + 700, + threshold: Math.random() * 0.3 + 0.6, + lastFired: 0, + color: categoryColors[data.category] || '#60a5fa' + }); + }); + + // Füge synaptische Eigenschaften zu allen Kanten hinzu + cy.edges().forEach(edge => { + const data = edge.data(); + edge.data({ + ...data, + strength: data.strength || 0.5, + conductionVelocity: Math.random() * 0.5 + 0.3, + latency: Math.random() * 100 + 50 + }); + }); + + // Wende neuronales Styling an + cy.style() + .selector('node') + .style({ + 'background-color': 'data(color)', + 'label': 'data(label)', + 'color': '#fff', + 'text-background-color': 'rgba(0, 0, 0, 0.7)', + 'text-background-opacity': 0.8, + 'text-background-padding': '4px', + 'text-valign': 'center', + 'text-halign': 'center', + 'font-size': 16, + 'width': 'mapData(neuronSize, 3, 10, 30, 60)', + 'height': 'mapData(neuronSize, 3, 10, 30, 60)', + 'border-width': 2, + 'border-color': '#fff', + 'border-opacity': 0.8, + 'overlay-padding': 4, + 'z-index': 10, + 'shape': 'ellipse', + 'background-opacity': 0.85, + 'shadow-blur': 'mapData(neuronActivity, 0.3, 1, 10, 20)', + 'shadow-color': 'data(color)', + 'shadow-opacity': 0.6, + 'shadow-offset-x': 0, + 'shadow-offset-y': 0 + }) + .selector('edge') + .style({ + 'width': 'mapData(strength, 0.2, 1, 1, 3)', + 'line-color': '#a78bfa', + 'line-opacity': 'mapData(strength, 0.2, 1, 0.4, 0.8)', + 'target-arrow-color': '#a78bfa', + 'target-arrow-shape': 'none', + 'curve-style': 'bezier', + 'control-point-distances': [20, -20], + 'control-point-weights': [0.5, 0.5], + 'edge-distances': 'intersection', + 'loop-direction': '-45deg', + 'loop-sweep': '-90deg', + 'line-style': function(ele) { + const strength = ele.data('strength'); + if (strength <= 0.4) return 'dotted'; + if (strength <= 0.6) return 'dashed'; + return 'solid'; + } + }) + .update(); + + // Starte neuronale Aktivitätssimulation + startNeuralActivitySimulation(cy); +} + +// Modifiziere die updateMindmap Funktion +function updateMindmap() { + if (!cy) return; + + // Bestehende Elemente entfernen + cy.elements().remove(); + + // Neue Knoten hinzufügen + mindmapData.nodes.forEach(node => { + cy.add({ + group: 'nodes', + data: { + id: node.id, + label: node.name, + category: node.category, + description: node.description, + hasChildren: node.has_children, + expanded: false, + color: node.color_code || mindmapConfig.categories[node.category]?.color || '#60a5fa', + icon: node.icon || mindmapConfig.categories[node.category]?.icon || 'fa-solid fa-circle' + } + }); + }); + + // Neue Kanten hinzufügen + mindmapData.edges.forEach(edge => { + cy.add({ + group: 'edges', + data: { + source: edge.source, + target: edge.target, + strength: edge.strength || 0.5 + } + }); + }); + + // Layout aktualisieren + cy.layout(mindmapStyles.layout.base).run(); +} + +/** + * Erweitert die Mindmap mit dem neuronalen Netzwerk-Design + */ +function enhanceMindmap() { + // Auf die bestehende Cytoscape-Instanz zugreifen + const cy = window.cy; + + if (!cy) { + console.error('Keine Cytoscape-Instanz gefunden.'); + return; + } + + // Aktualisiere das Layout für eine bessere Verteilung + cy.layout({ + name: 'cose', + animate: true, + animationDuration: 2000, + nodeDimensionsIncludeLabels: true, + padding: 100, + spacingFactor: 2, + randomize: true, + fit: true, + componentSpacing: 150, + nodeRepulsion: 10000, + edgeElasticity: 150, + nestingFactor: 1.5, + gravity: 100, + initialTemp: 1000, + coolingFactor: 0.95, + minTemp: 1 + }).run(); + + // Neuronen-Namen mit besserer Lesbarkeit umgestalten + cy.style() + .selector('node') + .style({ + 'text-background-color': 'rgba(10, 14, 25, 0.7)', + 'text-background-opacity': 0.7, + 'text-background-padding': '2px', + 'text-border-opacity': 0.2, + 'text-border-width': 1, + 'text-border-color': '#8b5cf6' + }) + .update(); + + // Sicherstellen, dass alle Knoten Neuronen-Eigenschaften haben + cy.nodes().forEach(node => { + if (!node.data('neuronSize')) { + const neuronSize = Math.floor(Math.random() * 8) + 3; + node.data('neuronSize', neuronSize); + } + + if (!node.data('neuronActivity')) { + const neuronActivity = Math.random() * 0.7 + 0.3; + node.data('neuronActivity', neuronActivity); + } + + // Zusätzliche Neuronale Eigenschaften + node.data('pulseFrequency', Math.random() * 4 + 2); // Pulsfrequenz (2-6 Hz) + node.data('refractionPeriod', Math.random() * 300 + 700); // Refraktionszeit (700-1000ms) + node.data('threshold', Math.random() * 0.3 + 0.6); // Aktivierungsschwelle (0.6-0.9) + }); + + // Sicherstellen, dass alle Kanten Synapse-Eigenschaften haben + cy.edges().forEach(edge => { + if (!edge.data('strength')) { + const strength = Math.random() * 0.6 + 0.2; + edge.data('strength', strength); + } + + // Zusätzliche synaptische Eigenschaften + edge.data('conductionVelocity', Math.random() * 0.5 + 0.3); // Leitungsgeschwindigkeit (0.3-0.8) + edge.data('latency', Math.random() * 100 + 50); // Signalverzögerung (50-150ms) + }); + + // Neuronales Netzwerk-Stil anwenden + applyNeuralNetworkStyle(cy); + + console.log('Mindmap wurde erfolgreich im neuronalen Netzwerk-Stil aktualisiert'); + + // Spezielle Effekte für das neuronale Netzwerk hinzufügen + startNeuralActivitySimulation(cy); +} + +/** + * Wendet detaillierte neuronale Netzwerkstile auf die Mindmap an + * @param {Object} cy - Cytoscape-Instanz + */ +function applyNeuralNetworkStyle(cy) { + cy.style() + .selector('node') + .style({ + 'label': 'data(label)', + 'text-valign': 'center', + 'text-halign': 'center', + 'color': 'data(fontColor)', + 'text-outline-width': 2, + 'text-outline-color': 'rgba(0,0,0,0.8)', + 'text-outline-opacity': 0.9, + 'font-size': 'data(fontSize)', + 'font-weight': '500', + 'text-margin-y': 8, + 'width': function(ele) { + if (ele.data('isCenter')) return 120; + return ele.data('neuronSize') ? ele.data('neuronSize') * 10 : 80; + }, + 'height': function(ele) { + if (ele.data('isCenter')) return 120; + return ele.data('neuronSize') ? ele.data('neuronSize') * 10 : 80; + }, + 'background-color': 'data(color)', + 'background-opacity': 0.9, + 'border-width': 2, + 'border-color': '#ffffff', + 'border-opacity': 0.8, + 'shape': 'ellipse', + 'transition-property': 'background-color, background-opacity, border-width', + 'transition-duration': '0.3s', + 'transition-timing-function': 'ease-in-out' + }) + .selector('edge') + .style({ + 'width': function(ele) { + return ele.data('strength') ? ele.data('strength') * 3 : 1; + }, + 'curve-style': 'bezier', + 'line-color': function(ele) { + const sourceColor = ele.source().data('color'); + return sourceColor || '#8a8aaa'; + }, + 'line-opacity': function(ele) { + return ele.data('strength') ? ele.data('strength') * 0.8 : 0.4; + }, + 'line-style': function(ele) { + const strength = ele.data('strength'); + if (!strength) return 'solid'; + if (strength <= 0.4) return 'dotted'; + if (strength <= 0.6) return 'dashed'; + return 'solid'; + }, + 'target-arrow-shape': 'none', + 'source-endpoint': '0% 50%', + 'target-endpoint': '100% 50%', + 'transition-property': 'line-opacity, width', + 'transition-duration': '0.3s', + 'transition-timing-function': 'ease-in-out' + }) + .update(); +} + +// Vereinfachte neuronale Aktivitätssimulation +function startNeuralActivitySimulation(cy) { + if (window.neuralInterval) clearInterval(window.neuralInterval); + + const nodes = cy.nodes(); + let currentTime = Date.now(); + + function simulateNeuralActivity() { + currentTime = Date.now(); + + nodes.forEach(node => { + const data = node.data(); + const lastFired = data.lastFired || 0; + const timeSinceLastFire = currentTime - lastFired; + + if (timeSinceLastFire > data.refractionPeriod) { + if (Math.random() < data.neuronActivity * 0.1) { + fireNeuron(node, true, currentTime); + } + } + }); + } + + function fireNeuron(node, state, currentTime) { + const data = node.data(); + data.lastFired = currentTime; + + node.style({ + 'background-opacity': 1, + 'border-width': 3 + }); + + setTimeout(() => { + node.style({ + 'background-opacity': 0.9, + 'border-width': 2 + }); + }, 200); + + if (state) { + propagateSignal(node, currentTime); + } + } + + function propagateSignal(sourceNode, currentTime) { + const outgoingEdges = sourceNode.connectedEdges(); + + outgoingEdges.forEach(edge => { + const targetNode = edge.target(); + const edgeData = edge.data(); + const latency = edgeData.latency; + + edge.style({ + 'line-opacity': 0.8, + 'width': edgeData.strength * 3 + }); + + setTimeout(() => { + edge.style({ + 'line-opacity': edgeData.strength * 0.6, + 'width': edgeData.strength * 2 + }); + }, 200); + + setTimeout(() => { + const targetData = targetNode.data(); + const timeSinceLastFire = currentTime - (targetData.lastFired || 0); + + if (timeSinceLastFire > targetData.refractionPeriod) { + const signalStrength = edgeData.strength * + edgeData.conductionVelocity * + sourceNode.data('neuronActivity'); + + if (signalStrength > targetData.threshold) { + fireNeuron(targetNode, true, currentTime + latency); + } + } + }, latency); + }); + } + + window.neuralInterval = setInterval(simulateNeuralActivity, 100); +} + +// Hilfe-Funktion zum Hinzufügen eines Flash-Hinweises +function showFlash(message, type = 'info') { + const flashContainer = createFlashContainer(); + const flash = document.createElement('div'); + flash.className = `flash-message ${type}`; + flash.textContent = message; + flashContainer.appendChild(flash); + document.body.appendChild(flashContainer); + + setTimeout(() => { + flash.classList.add('show'); + setTimeout(() => { + flash.classList.remove('show'); + setTimeout(() => { + flashContainer.remove(); + }, 300); + }, 3000); + }, 100); +} + +/** + * Zeigt eine Benachrichtigung in der UI an + * @param {string|object} message - Die anzuzeigende Nachricht oder ein Fehlerobjekt + * @param {string} type - Der Typ der Benachrichtigung ('info', 'success', 'warning', 'error') + * @param {number} duration - Die Anzeigedauer in Millisekunden (Standard: 3000) + */ +function showUINotification(message, type = 'info', duration = 3000) { + // Überprüfe und formatiere die Nachricht + let displayMessage; + if (typeof message === 'object') { + if (message.message) { + displayMessage = message.message; + } else if (message.error) { + displayMessage = message.error; + } else if (message.details) { + displayMessage = message.details; + } else { + console.error('Ungültiges Nachrichtenobjekt:', message); + displayMessage = 'Ein unbekannter Fehler ist aufgetreten'; + } + } else if (typeof message === 'string') { + displayMessage = message; + } else { + console.error('Ungültige Nachricht für UI-Benachrichtigung:', message); + displayMessage = 'Ein unbekannter Fehler ist aufgetreten'; + } + + // Validiere den Typ + const validTypes = ['info', 'success', 'warning', 'error']; + if (!validTypes.includes(type)) { + console.warn(`Ungültiger Benachrichtigungstyp: ${type}. Verwende 'info' als Fallback.`); + type = 'info'; + } + + // Validiere die Dauer + if (typeof duration !== 'number' || duration < 1000 || duration > 10000) { + console.warn(`Ungültige Dauer: ${duration}ms. Verwende 3000ms als Fallback.`); + duration = 3000; + } + + // Zeige die Benachrichtigung an + showFlash(displayMessage, type); + + // Logging für Debugging-Zwecke + console.log(`UI-Benachrichtigung [${type}]:`, displayMessage); +} + +// Hilfsfunktion zum Erstellen eines Flash-Containers, falls keiner existiert +function createFlashContainer() { + const container = document.createElement('div'); + container.id = 'flash-messages'; + container.className = 'fixed top-4 right-4 z-50 w-64'; + document.body.appendChild(container); + return container; +} + +// Funktion zum Laden der Subthemen +async function loadSubthemes(node) { + try { + const mindmapData = await loadMindmapData(node.id()); + if (!mindmapData) return; + + showFlash('Lade Subthemen...', 'info'); + + const mindmapContainer = document.querySelector('.mindmap-container'); + const newPage = document.createElement('div'); + newPage.className = 'mindmap-page'; + newPage.style.display = 'none'; + + const header = document.createElement('div'); + header.className = 'mindmap-header'; + header.innerHTML = ` + +

${node.data('label')}

+ `; + + const newContainer = document.createElement('div'); + newContainer.id = `cy-${node.id()}`; + newContainer.className = 'mindmap-view'; + + newPage.appendChild(header); + newPage.appendChild(newContainer); + mindmapContainer.appendChild(newPage); + + const newCy = cytoscape({ + container: newContainer, + elements: [ + ...mindmapData.nodes.map(node => ({ + data: { + id: node.id, + label: node.name, + category: node.category, + description: node.description, + hasChildren: node.has_children, + expanded: false, + color: node.color_code, + fontColor: '#ffffff', + fontSize: 16 + } + })), + ...mindmapData.edges.map(edge => ({ + data: { + source: edge.source_id, + target: edge.target_id, + strength: edge.strength || 0.5 + } + })) + ], + style: cy.style(), + layout: mindmapStyles.layout.base + }); + + // Event-Listener für die neue Mindmap + newCy.on('tap', 'node', async function(evt) { + const clickedNode = evt.target; + if (clickedNode.data('hasChildren') && !clickedNode.data('expanded')) { + await loadSubthemes(clickedNode); + } + }); + + // Alte Seite ausblenden und neue anzeigen + cy.container().style.display = 'none'; + newPage.style.display = 'block'; + + showFlash('Subthemen erfolgreich geladen', 'success'); + + } catch (error) { + console.error('Fehler beim Laden der Subthemen:', error); + showFlash('Fehler beim Laden der Subthemen', 'error'); + } +} + +// Funktion zum Zurücknavigieren +function goBack() { + const currentPage = document.querySelector('.mindmap-page:not([style*="display: none"])'); + if (currentPage) { + currentPage.style.display = 'none'; + cy.container().style.display = 'block'; + } +} + +// CSS-Styles für die neue Seite +const style = document.createElement('style'); +style.textContent = ` + .mindmap-page { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--bg-color, #1a1a1a); + z-index: 1000; + } + + .mindmap-header { + display: flex; + align-items: center; + padding: 1rem; + background: rgba(0, 0, 0, 0.2); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + } + + .back-button { + background: none; + border: none; + color: #fff; + cursor: pointer; + padding: 0.5rem; + margin-right: 1rem; + border-radius: 50%; + transition: background-color 0.3s; + } + + .back-button:hover { + background: rgba(255, 255, 255, 0.1); + } + + .mindmap-title { + color: #fff; + font-size: 1.5rem; + font-weight: 600; + margin: 0; + } + + .mindmap-view { + width: 100%; + height: calc(100% - 4rem); + } + + /* Neuronale Effekte */ + .cy-container { + background: linear-gradient(45deg, #1a1a1a, #2a2a2a); + } + + .cy-container node { + transition: all 0.3s ease; + } + + .cy-container node:hover { + filter: brightness(1.2); + } + + .cy-node-icon { + position: absolute; + pointer-events: none; + z-index: 1001; + color: #fff; + text-shadow: 0 2px 8px rgba(0,0,0,0.25); + } + + /* Verbesserte Flash-Benachrichtigungen */ + #flash-messages { + position: fixed; + top: 1rem; + right: 1rem; + z-index: 9999; + display: flex; + flex-direction: column; + gap: 0.5rem; + max-width: 24rem; + } + + .flash-message { + padding: 1rem 1.25rem; + border-radius: 0.5rem; + background: rgba(17, 24, 39, 0.95); + color: #fff; + font-size: 0.875rem; + line-height: 1.25rem; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); + transform: translateX(120%); + opacity: 0; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + backdrop-filter: blur(8px); + border: 1px solid rgba(255, 255, 255, 0.1); + } + + .flash-message.show { + transform: translateX(0); + opacity: 1; + } + + .flash-message.info { + border-left: 4px solid #3b82f6; + background: linear-gradient(to right, rgba(59, 130, 246, 0.1), rgba(17, 24, 39, 0.95)); + } + + .flash-message.success { + border-left: 4px solid #10b981; + background: linear-gradient(to right, rgba(16, 185, 129, 0.1), rgba(17, 24, 39, 0.95)); + } + + .flash-message.warning { + border-left: 4px solid #f59e0b; + background: linear-gradient(to right, rgba(245, 158, 11, 0.1), rgba(17, 24, 39, 0.95)); + } + + .flash-message.error { + border-left: 4px solid #ef4444; + background: linear-gradient(to right, rgba(239, 68, 68, 0.1), rgba(17, 24, 39, 0.95)); + } + + .flash-message::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, + rgba(255, 255, 255, 0.1) 0%, + rgba(255, 255, 255, 0) 100%); + pointer-events: none; + } + + @keyframes pulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.02); } + 100% { transform: scale(1); } + } + + .flash-message.show { + animation: pulse 0.3s ease-in-out; + } + + /* Neuronale Effekte für Benachrichtigungen */ + .flash-message.info:hover { + box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); + } + + .flash-message.success:hover { + box-shadow: 0 0 15px rgba(16, 185, 129, 0.3); + } + + .flash-message.warning:hover { + box-shadow: 0 0 15px rgba(245, 158, 11, 0.3); + } + + .flash-message.error:hover { + box-shadow: 0 0 15px rgba(239, 68, 68, 0.3); + } +`; +document.head.appendChild(style); + +// Initialisiere die Mindmap beim Laden der Seite +document.addEventListener('DOMContentLoaded', initializeMindmap); \ No newline at end of file diff --git a/static/js/update_mindmap.js.new b/static/js/update_mindmap.js.new new file mode 100644 index 0000000000000000000000000000000000000000..22ba1bfeb7e7302bd5b5e9dd301cfa9bf770e4fd GIT binary patch literal 164 zcmYjKK?;B{49i*Y4?BC=Lqt63!JFVFf}3N`@2gpHAf>cPlk~YY8di-8ic?`gz=9bG zhN!~^PwdEqpQJlBs3ONV60ssyrQ$nY(;xMQ`a_aS5NZOU4VB CE*cB~ literal 0 HcmV?d00001 diff --git a/static/js/update_mindmap.js.original b/static/js/update_mindmap.js.original new file mode 100644 index 0000000..f75977e --- /dev/null +++ b/static/js/update_mindmap.js.original @@ -0,0 +1,1078 @@ +/** + * Update Mindmap + * Dieses Skript fügt Knoten zur Mindmap hinzu und stellt sicher, + * dass sie im neuronalen Netzwerk-Design angezeigt werden. + * Implementiert Lazy Loading & Progressive Disclosure + */ + +// Neue zentrale Konfiguration +const mindmapConfig = { + categories: { + 'Philosophie': { + icon: 'fa-solid fa-lightbulb', + color: '#b71c1c', + description: 'Die Lehre vom Denken und der Erkenntnis' + }, + 'Wissenschaft': { + icon: 'fa-solid fa-atom', + color: '#f4b400', + description: 'Systematische Erforschung der Natur und Gesellschaft' + }, + 'Technologie': { + icon: 'fa-solid fa-microchip', + color: '#0d47a1', + description: 'Anwendung wissenschaftlicher Erkenntnisse' + }, + 'Künste': { + icon: 'fa-solid fa-palette', + color: '#c2185b', + description: 'Kreativer Ausdruck und künstlerische Gestaltung' + } + }, + defaultNodeStyle: { + fontSize: 18, + fontColor: '#fff', + neuronSize: 8, + neuronActivity: 0.8 + }, + centerNodeStyle: { + fontSize: 22, + fontColor: '#222', + neuronSize: 12, + neuronActivity: 1.0, + color: '#f5f5f5', + icon: 'fa-solid fa-circle' + } +}; + +// Zentrale Styling-Konfiguration +const mindmapStyles = { + node: { + base: { + 'background-color': 'data(color)', + 'label': 'data(label)', + 'color': '#ffffff', + 'text-background-color': 'rgba(0, 0, 0, 0.7)', + 'text-background-opacity': 0.8, + 'text-background-padding': '4px', + 'text-valign': 'center', + 'text-halign': 'center', + 'font-size': 16, + 'width': 'mapData(neuronSize, 3, 10, 30, 60)', + 'height': 'mapData(neuronSize, 3, 10, 30, 60)', + 'border-width': 2, + 'border-color': '#ffffff', + 'border-opacity': 0.8, + 'shape': 'ellipse', + 'background-opacity': 0.85 + }, + center: { + 'background-color': '#f5f5f5', + 'color': '#222', + 'font-size': 20, + 'border-width': 3, + 'width': 100, + 'height': 100 + }, + selected: { + 'border-color': '#f59e42', + 'border-width': 3, + 'background-opacity': 1 + } + }, + edge: { + base: { + 'width': function(ele) { + return ele.data('strength') ? ele.data('strength') * 2 : 1; + }, + 'line-color': function(ele) { + const sourceColor = ele.source().data('color'); + return sourceColor || '#8a8aaa'; + }, + 'line-opacity': function(ele) { + return ele.data('strength') ? ele.data('strength') * 0.6 : 0.4; + }, + 'curve-style': 'bezier', + 'target-arrow-shape': 'none', + 'control-point-distances': [30, -30], + 'control-point-weights': [0.5, 0.5] + } + }, + layout: { + base: { + name: 'cose', + animate: true, + animationDuration: 500, + refresh: 20, + fit: true, + padding: 30, + nodeRepulsion: 4500, + idealEdgeLength: 50, + edgeElasticity: 0.45, + randomize: true, + componentSpacing: 100, + nodeOverlap: 20, + gravity: 0.25, + initialTemp: 1000, + coolingFactor: 0.95, + minTemp: 1 + } + } +}; + +// Globale Variable für die Mindmap-Daten +let mindmapData = null; + +// Funktion zum Laden der Mindmap-Daten aus der Datenbank +async function loadMindmapData(nodeId = null) { + try { + const apiUrl = nodeId ? `/api/mindmap/${nodeId}` : '/api/mindmap/root'; + console.log('Lade Mindmap-Daten von:', apiUrl); + + const response = await fetch(apiUrl); + console.log('API-Antwort Status:', response.status); + + if (!response.ok) { + let errorData; + try { + errorData = await response.json(); + console.log('API-Fehler Details:', { + status: response.status, + statusText: response.statusText, + errorData + }); + } catch (e) { + console.error('Fehler beim Parsen der Fehlerantwort:', e); + errorData = { + error: `HTTP-Fehler ${response.status}: ${response.statusText}` + }; + } + + // Fehlerobjekt für die Benachrichtigung erstellen + const errorMessage = { + error: errorData.error || errorData.message || 'Unbekannter Fehler', + details: errorData.details || null + }; + + showUINotification(errorMessage, 'error'); + throw new Error(errorMessage.error); + } + + const data = await response.json(); + console.log('Geladene Mindmap-Daten:', data); + + if (!data.success) { + const errorMessage = { + error: data.error || 'Mindmap-Daten konnten nicht geladen werden', + details: data.details || null + }; + showUINotification(errorMessage, 'error'); + throw new Error(errorMessage.error); + } + + // Erfolgreiche Antwort + mindmapData = data; // Speichere die Daten in der globalen Variable + showUINotification('Mindmap-Daten erfolgreich geladen', 'success'); + return data; + } catch (error) { + console.error('Fehler beim Laden der Mindmap-Daten:', { + message: error.message, + stack: error.stack, + nodeId + }); + + // Stelle sicher, dass wir eine aussagekräftige Fehlermeldung haben + const errorMessage = { + error: error.message || 'Unbekannter Fehler beim Laden der Mindmap-Daten', + details: error.stack + }; + + showUINotification(errorMessage, 'error'); + throw error; + } +} + +// Funktion zum Initialisieren der Mindmap +async function initializeMindmap() { + try { + const data = await loadMindmapData(); + if (!data || !data.nodes || !data.edges) { + throw new Error('Ungültiges Datenformat: Mindmap-Daten fehlen oder sind unvollständig'); + } + + const elements = [ + // Knoten + ...data.nodes.map(node => ({ + data: { + id: node.id, + label: node.name, + category: node.category, + description: node.description, + hasChildren: node.has_children, + expanded: false, + color: node.color_code, + fontColor: '#ffffff', + fontSize: node.is_center ? 20 : 16 + } + })), + // Kanten + ...data.edges.map(edge => ({ + data: { + source: edge.source, + target: edge.target, + strength: edge.strength || 0.5 + } + })) + ]; + + // Bestehende Cytoscape-Instanz entfernen, falls vorhanden + if (window.cy) { + window.cy.destroy(); + } + + window.cy = cytoscape({ + container: document.getElementById('cy'), + elements: elements, + style: mindmapStyles, + layout: mindmapStyles.layout.base + }); + + // Event-Listener für Knoten-Klicks + cy.on('tap', 'node', async function(evt) { + const node = evt.target; + if (node.data('hasChildren') && !node.data('expanded')) { + await loadSubthemes(node); + } + }); + + // Layout ausführen + cy.layout(mindmapStyles.layout.base).run(); + + return true; + } catch (error) { + console.error('Fehler bei der Mindmap-Initialisierung:', error); + showUINotification({ + error: 'Mindmap konnte nicht initialisiert werden', + details: error.message + }, 'error'); + return false; + } +} + +// Warte bis DOM geladen ist +document.addEventListener('DOMContentLoaded', function() { + console.log('DOMContentLoaded Event ausgelöst'); + + // Prüfe, ob der Container existiert + const cyContainer = document.getElementById('cy'); + console.log('Container gefunden:', cyContainer); + + if (!cyContainer) { + console.error('Mindmap-Container #cy nicht gefunden!'); + return; + } + + // Prüfe, ob Cytoscape verfügbar ist + if (typeof cytoscape === 'undefined') { + console.error('Cytoscape ist nicht definiert!'); + return; + } + console.log('Cytoscape ist verfügbar'); + + // Beispiel-Daten entfernt, stattdessen große Mindmap-Daten verwenden + const elements = [ + // Knoten + ...mindmapData.nodes.map(node => ({ + data: { + id: node.id, + label: node.label, + category: node.category, + description: node.description, + hasChildren: node.hasChildren, + expanded: node.expanded, + neuronSize: node.neuronSize, + neuronActivity: node.neuronActivity, + color: node.color, + icon: node.icon, + fontColor: node.fontColor, + fontSize: node.fontSize + } + })), + // Kanten + ...mindmapData.edges.map(edge => ({ + data: { + source: edge.source, + target: edge.target, + label: edge.label, + strength: edge.strength + } + })) + ]; + + console.log('Initialisiere Cytoscape...'); + + // Initialisiere Cytoscape mit einem schlichten, modernen Design + window.cy = cytoscape({ + container: cyContainer, + elements: elements, + style: [ + { + selector: 'node', + style: mindmapStyles.node.base + }, + { + selector: 'node[isCenter]', + style: mindmapStyles.node.center + }, + { + selector: 'node:selected', + style: mindmapStyles.node.selected + }, + { + selector: 'edge', + style: mindmapStyles.edge.base + } + ], + layout: mindmapStyles.layout.base + }); + + console.log('Cytoscape initialisiert'); + + // Füge neuronale Eigenschaften zu allen Knoten hinzu + cy.nodes().forEach(node => { + const data = node.data(); + node.data({ + ...data, + neuronSize: data.neuronSize || 8, + neuronActivity: data.neuronActivity || 0.8, + refractionPeriod: Math.random() * 300 + 700, + threshold: Math.random() * 0.3 + 0.6, + lastFired: 0, + color: categoryColors[data.category] || '#60a5fa' + }); + }); + + // Füge synaptische Eigenschaften zu allen Kanten hinzu + cy.edges().forEach(edge => { + const data = edge.data(); + edge.data({ + ...data, + strength: data.strength || 0.5, + conductionVelocity: Math.random() * 0.5 + 0.3, + latency: Math.random() * 100 + 50 + }); + }); + + // Starte neuronale Aktivitätssimulation + startNeuralActivitySimulation(cy); + + // Mindmap mit echten Daten befüllen (Styles, Farben etc.) + updateMindmap(); + + // Event auslösen, damit andere Scripte reagieren können + document.dispatchEvent(new Event('mindmap-loaded')); + console.log('mindmap-loaded Event ausgelöst'); + + // Event-Listener für Knoten-Klicks + cy.on('tap', 'node', async function(evt) { + const node = evt.target; + console.log('Node clicked:', node.id(), 'hasChildren:', node.data('hasChildren'), 'expanded:', node.data('expanded')); + + if (node.data('hasChildren') && !node.data('expanded')) { + await loadSubthemes(node); + } + }); + + // Entferne den Icon-Overlay-Code + setTimeout(() => { + // Entferne alle existierenden Icon-Overlays + document.querySelectorAll('.cy-node-icon').forEach(icon => icon.remove()); + }, 0); +}); + +// Funktion zum Initialisieren des neuronalen Designs +function initializeNeuralDesign(cy) { + // Füge neuronale Eigenschaften zu allen Knoten hinzu + cy.nodes().forEach(node => { + const data = node.data(); + node.data({ + ...data, + neuronSize: data.neuronSize || 8, + neuronActivity: data.neuronActivity || 0.8, + refractionPeriod: Math.random() * 300 + 700, + threshold: Math.random() * 0.3 + 0.6, + lastFired: 0, + color: categoryColors[data.category] || '#60a5fa' + }); + }); + + // Füge synaptische Eigenschaften zu allen Kanten hinzu + cy.edges().forEach(edge => { + const data = edge.data(); + edge.data({ + ...data, + strength: data.strength || 0.5, + conductionVelocity: Math.random() * 0.5 + 0.3, + latency: Math.random() * 100 + 50 + }); + }); + + // Wende neuronales Styling an + cy.style() + .selector('node') + .style({ + 'background-color': 'data(color)', + 'label': 'data(label)', + 'color': '#fff', + 'text-background-color': 'rgba(0, 0, 0, 0.7)', + 'text-background-opacity': 0.8, + 'text-background-padding': '4px', + 'text-valign': 'center', + 'text-halign': 'center', + 'font-size': 16, + 'width': 'mapData(neuronSize, 3, 10, 30, 60)', + 'height': 'mapData(neuronSize, 3, 10, 30, 60)', + 'border-width': 2, + 'border-color': '#fff', + 'border-opacity': 0.8, + 'overlay-padding': 4, + 'z-index': 10, + 'shape': 'ellipse', + 'background-opacity': 0.85, + 'shadow-blur': 'mapData(neuronActivity, 0.3, 1, 10, 20)', + 'shadow-color': 'data(color)', + 'shadow-opacity': 0.6, + 'shadow-offset-x': 0, + 'shadow-offset-y': 0 + }) + .selector('edge') + .style({ + 'width': 'mapData(strength, 0.2, 1, 1, 3)', + 'line-color': '#a78bfa', + 'line-opacity': 'mapData(strength, 0.2, 1, 0.4, 0.8)', + 'target-arrow-color': '#a78bfa', + 'target-arrow-shape': 'none', + 'curve-style': 'bezier', + 'control-point-distances': [20, -20], + 'control-point-weights': [0.5, 0.5], + 'edge-distances': 'intersection', + 'loop-direction': '-45deg', + 'loop-sweep': '-90deg', + 'line-style': function(ele) { + const strength = ele.data('strength'); + if (strength <= 0.4) return 'dotted'; + if (strength <= 0.6) return 'dashed'; + return 'solid'; + } + }) + .update(); + + // Starte neuronale Aktivitätssimulation + startNeuralActivitySimulation(cy); +} + +// Modifiziere die updateMindmap Funktion +function updateMindmap() { + if (!cy) return; + + // Bestehende Elemente entfernen + cy.elements().remove(); + + // Neue Knoten hinzufügen + mindmapData.nodes.forEach(node => { + cy.add({ + group: 'nodes', + data: { + id: node.id, + label: node.name, + category: node.category, + description: node.description, + hasChildren: node.has_children, + expanded: false, + color: node.color_code || mindmapConfig.categories[node.category]?.color || '#60a5fa', + icon: node.icon || mindmapConfig.categories[node.category]?.icon || 'fa-solid fa-circle' + } + }); + }); + + // Neue Kanten hinzufügen + mindmapData.edges.forEach(edge => { + cy.add({ + group: 'edges', + data: { + source: edge.source, + target: edge.target, + strength: edge.strength || 0.5 + } + }); + }); + + // Layout aktualisieren + cy.layout(mindmapStyles.layout.base).run(); +} + +/** + * Erweitert die Mindmap mit dem neuronalen Netzwerk-Design + */ +function enhanceMindmap() { + // Auf die bestehende Cytoscape-Instanz zugreifen + const cy = window.cy; + + if (!cy) { + console.error('Keine Cytoscape-Instanz gefunden.'); + return; + } + + // Aktualisiere das Layout für eine bessere Verteilung + cy.layout({ + name: 'cose', + animate: true, + animationDuration: 2000, + nodeDimensionsIncludeLabels: true, + padding: 100, + spacingFactor: 2, + randomize: true, + fit: true, + componentSpacing: 150, + nodeRepulsion: 10000, + edgeElasticity: 150, + nestingFactor: 1.5, + gravity: 100, + initialTemp: 1000, + coolingFactor: 0.95, + minTemp: 1 + }).run(); + + // Neuronen-Namen mit besserer Lesbarkeit umgestalten + cy.style() + .selector('node') + .style({ + 'text-background-color': 'rgba(10, 14, 25, 0.7)', + 'text-background-opacity': 0.7, + 'text-background-padding': '2px', + 'text-border-opacity': 0.2, + 'text-border-width': 1, + 'text-border-color': '#8b5cf6' + }) + .update(); + + // Sicherstellen, dass alle Knoten Neuronen-Eigenschaften haben + cy.nodes().forEach(node => { + if (!node.data('neuronSize')) { + const neuronSize = Math.floor(Math.random() * 8) + 3; + node.data('neuronSize', neuronSize); + } + + if (!node.data('neuronActivity')) { + const neuronActivity = Math.random() * 0.7 + 0.3; + node.data('neuronActivity', neuronActivity); + } + + // Zusätzliche Neuronale Eigenschaften + node.data('pulseFrequency', Math.random() * 4 + 2); // Pulsfrequenz (2-6 Hz) + node.data('refractionPeriod', Math.random() * 300 + 700); // Refraktionszeit (700-1000ms) + node.data('threshold', Math.random() * 0.3 + 0.6); // Aktivierungsschwelle (0.6-0.9) + }); + + // Sicherstellen, dass alle Kanten Synapse-Eigenschaften haben + cy.edges().forEach(edge => { + if (!edge.data('strength')) { + const strength = Math.random() * 0.6 + 0.2; + edge.data('strength', strength); + } + + // Zusätzliche synaptische Eigenschaften + edge.data('conductionVelocity', Math.random() * 0.5 + 0.3); // Leitungsgeschwindigkeit (0.3-0.8) + edge.data('latency', Math.random() * 100 + 50); // Signalverzögerung (50-150ms) + }); + + // Neuronales Netzwerk-Stil anwenden + applyNeuralNetworkStyle(cy); + + console.log('Mindmap wurde erfolgreich im neuronalen Netzwerk-Stil aktualisiert'); + + // Spezielle Effekte für das neuronale Netzwerk hinzufügen + startNeuralActivitySimulation(cy); +} + +/** + * Wendet detaillierte neuronale Netzwerkstile auf die Mindmap an + * @param {Object} cy - Cytoscape-Instanz + */ +function applyNeuralNetworkStyle(cy) { + cy.style() + .selector('node') + .style({ + 'label': 'data(label)', + 'text-valign': 'center', + 'text-halign': 'center', + 'color': 'data(fontColor)', + 'text-outline-width': 2, + 'text-outline-color': 'rgba(0,0,0,0.8)', + 'text-outline-opacity': 0.9, + 'font-size': 'data(fontSize)', + 'font-weight': '500', + 'text-margin-y': 8, + 'width': function(ele) { + if (ele.data('isCenter')) return 120; + return ele.data('neuronSize') ? ele.data('neuronSize') * 10 : 80; + }, + 'height': function(ele) { + if (ele.data('isCenter')) return 120; + return ele.data('neuronSize') ? ele.data('neuronSize') * 10 : 80; + }, + 'background-color': 'data(color)', + 'background-opacity': 0.9, + 'border-width': 2, + 'border-color': '#ffffff', + 'border-opacity': 0.8, + 'shape': 'ellipse', + 'transition-property': 'background-color, background-opacity, border-width', + 'transition-duration': '0.3s', + 'transition-timing-function': 'ease-in-out' + }) + .selector('edge') + .style({ + 'width': function(ele) { + return ele.data('strength') ? ele.data('strength') * 3 : 1; + }, + 'curve-style': 'bezier', + 'line-color': function(ele) { + const sourceColor = ele.source().data('color'); + return sourceColor || '#8a8aaa'; + }, + 'line-opacity': function(ele) { + return ele.data('strength') ? ele.data('strength') * 0.8 : 0.4; + }, + 'line-style': function(ele) { + const strength = ele.data('strength'); + if (!strength) return 'solid'; + if (strength <= 0.4) return 'dotted'; + if (strength <= 0.6) return 'dashed'; + return 'solid'; + }, + 'target-arrow-shape': 'none', + 'source-endpoint': '0% 50%', + 'target-endpoint': '100% 50%', + 'transition-property': 'line-opacity, width', + 'transition-duration': '0.3s', + 'transition-timing-function': 'ease-in-out' + }) + .update(); +} + +// Vereinfachte neuronale Aktivitätssimulation +function startNeuralActivitySimulation(cy) { + if (window.neuralInterval) clearInterval(window.neuralInterval); + + const nodes = cy.nodes(); + let currentTime = Date.now(); + + function simulateNeuralActivity() { + currentTime = Date.now(); + + nodes.forEach(node => { + const data = node.data(); + const lastFired = data.lastFired || 0; + const timeSinceLastFire = currentTime - lastFired; + + if (timeSinceLastFire > data.refractionPeriod) { + if (Math.random() < data.neuronActivity * 0.1) { + fireNeuron(node, true, currentTime); + } + } + }); + } + + function fireNeuron(node, state, currentTime) { + const data = node.data(); + data.lastFired = currentTime; + + node.style({ + 'background-opacity': 1, + 'border-width': 3 + }); + + setTimeout(() => { + node.style({ + 'background-opacity': 0.9, + 'border-width': 2 + }); + }, 200); + + if (state) { + propagateSignal(node, currentTime); + } + } + + function propagateSignal(sourceNode, currentTime) { + const outgoingEdges = sourceNode.connectedEdges(); + + outgoingEdges.forEach(edge => { + const targetNode = edge.target(); + const edgeData = edge.data(); + const latency = edgeData.latency; + + edge.style({ + 'line-opacity': 0.8, + 'width': edgeData.strength * 3 + }); + + setTimeout(() => { + edge.style({ + 'line-opacity': edgeData.strength * 0.6, + 'width': edgeData.strength * 2 + }); + }, 200); + + setTimeout(() => { + const targetData = targetNode.data(); + const timeSinceLastFire = currentTime - (targetData.lastFired || 0); + + if (timeSinceLastFire > targetData.refractionPeriod) { + const signalStrength = edgeData.strength * + edgeData.conductionVelocity * + sourceNode.data('neuronActivity'); + + if (signalStrength > targetData.threshold) { + fireNeuron(targetNode, true, currentTime + latency); + } + } + }, latency); + }); + } + + window.neuralInterval = setInterval(simulateNeuralActivity, 100); +} + +// Hilfe-Funktion zum Hinzufügen eines Flash-Hinweises +function showFlash(message, type = 'info') { + const flashContainer = createFlashContainer(); + const flash = document.createElement('div'); + flash.className = `flash-message ${type}`; + flash.textContent = message; + flashContainer.appendChild(flash); + document.body.appendChild(flashContainer); + + setTimeout(() => { + flash.classList.add('show'); + setTimeout(() => { + flash.classList.remove('show'); + setTimeout(() => { + flashContainer.remove(); + }, 300); + }, 3000); + }, 100); +} + +/** + * Zeigt eine Benachrichtigung in der UI an + * @param {string|object} message - Die anzuzeigende Nachricht oder ein Fehlerobjekt + * @param {string} type - Der Typ der Benachrichtigung ('info', 'success', 'warning', 'error') + * @param {number} duration - Die Anzeigedauer in Millisekunden (Standard: 3000) + */ +function showUINotification(message, type = 'info', duration = 3000) { + // Überprüfe und formatiere die Nachricht + let displayMessage; + if (typeof message === 'object') { + if (message.message) { + displayMessage = message.message; + } else if (message.error) { + displayMessage = message.error; + } else if (message.details) { + displayMessage = message.details; + } else { + console.error('Ungültiges Nachrichtenobjekt:', message); + displayMessage = 'Ein unbekannter Fehler ist aufgetreten'; + } + } else if (typeof message === 'string') { + displayMessage = message; + } else { + console.error('Ungültige Nachricht für UI-Benachrichtigung:', message); + displayMessage = 'Ein unbekannter Fehler ist aufgetreten'; + } + + // Validiere den Typ + const validTypes = ['info', 'success', 'warning', 'error']; + if (!validTypes.includes(type)) { + console.warn(`Ungültiger Benachrichtigungstyp: ${type}. Verwende 'info' als Fallback.`); + type = 'info'; + } + + // Validiere die Dauer + if (typeof duration !== 'number' || duration < 1000 || duration > 10000) { + console.warn(`Ungültige Dauer: ${duration}ms. Verwende 3000ms als Fallback.`); + duration = 3000; + } + + // Zeige die Benachrichtigung an + showFlash(displayMessage, type); + + // Logging für Debugging-Zwecke + console.log(`UI-Benachrichtigung [${type}]:`, displayMessage); +} + +// Hilfsfunktion zum Erstellen eines Flash-Containers, falls keiner existiert +function createFlashContainer() { + const container = document.createElement('div'); + container.id = 'flash-messages'; + container.className = 'fixed top-4 right-4 z-50 w-64'; + document.body.appendChild(container); + return container; +} + +// Funktion zum Laden der Subthemen +async function loadSubthemes(node) { + try { + const mindmapData = await loadMindmapData(node.id()); + if (!mindmapData) return; + + showFlash('Lade Subthemen...', 'info'); + + const mindmapContainer = document.querySelector('.mindmap-container'); + const newPage = document.createElement('div'); + newPage.className = 'mindmap-page'; + newPage.style.display = 'none'; + + const header = document.createElement('div'); + header.className = 'mindmap-header'; + header.innerHTML = ` + +

${node.data('label')}

+ `; + + const newContainer = document.createElement('div'); + newContainer.id = `cy-${node.id()}`; + newContainer.className = 'mindmap-view'; + + newPage.appendChild(header); + newPage.appendChild(newContainer); + mindmapContainer.appendChild(newPage); + + const newCy = cytoscape({ + container: newContainer, + elements: [ + ...mindmapData.nodes.map(node => ({ + data: { + id: node.id, + label: node.name, + category: node.category, + description: node.description, + hasChildren: node.has_children, + expanded: false, + color: node.color_code, + fontColor: '#ffffff', + fontSize: 16 + } + })), + ...mindmapData.edges.map(edge => ({ + data: { + source: edge.source_id, + target: edge.target_id, + strength: edge.strength || 0.5 + } + })) + ], + style: cy.style(), + layout: mindmapStyles.layout.base + }); + + // Event-Listener für die neue Mindmap + newCy.on('tap', 'node', async function(evt) { + const clickedNode = evt.target; + if (clickedNode.data('hasChildren') && !clickedNode.data('expanded')) { + await loadSubthemes(clickedNode); + } + }); + + // Alte Seite ausblenden und neue anzeigen + cy.container().style.display = 'none'; + newPage.style.display = 'block'; + + showFlash('Subthemen erfolgreich geladen', 'success'); + + } catch (error) { + console.error('Fehler beim Laden der Subthemen:', error); + showFlash('Fehler beim Laden der Subthemen', 'error'); + } +} + +// Funktion zum Zurücknavigieren +function goBack() { + const currentPage = document.querySelector('.mindmap-page:not([style*="display: none"])'); + if (currentPage) { + currentPage.style.display = 'none'; + cy.container().style.display = 'block'; + } +} + +// CSS-Styles für die neue Seite +const style = document.createElement('style'); +style.textContent = ` + .mindmap-page { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--bg-color, #1a1a1a); + z-index: 1000; + } + + .mindmap-header { + display: flex; + align-items: center; + padding: 1rem; + background: rgba(0, 0, 0, 0.2); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + } + + .back-button { + background: none; + border: none; + color: #fff; + cursor: pointer; + padding: 0.5rem; + margin-right: 1rem; + border-radius: 50%; + transition: background-color 0.3s; + } + + .back-button:hover { + background: rgba(255, 255, 255, 0.1); + } + + .mindmap-title { + color: #fff; + font-size: 1.5rem; + font-weight: 600; + margin: 0; + } + + .mindmap-view { + width: 100%; + height: calc(100% - 4rem); + } + + /* Neuronale Effekte */ + .cy-container { + background: linear-gradient(45deg, #1a1a1a, #2a2a2a); + } + + .cy-container node { + transition: all 0.3s ease; + } + + .cy-container node:hover { + filter: brightness(1.2); + } + + .cy-node-icon { + position: absolute; + pointer-events: none; + z-index: 1001; + color: #fff; + text-shadow: 0 2px 8px rgba(0,0,0,0.25); + } + + /* Verbesserte Flash-Benachrichtigungen */ + #flash-messages { + position: fixed; + top: 1rem; + right: 1rem; + z-index: 9999; + display: flex; + flex-direction: column; + gap: 0.5rem; + max-width: 24rem; + } + + .flash-message { + padding: 1rem 1.25rem; + border-radius: 0.5rem; + background: rgba(17, 24, 39, 0.95); + color: #fff; + font-size: 0.875rem; + line-height: 1.25rem; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); + transform: translateX(120%); + opacity: 0; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + backdrop-filter: blur(8px); + border: 1px solid rgba(255, 255, 255, 0.1); + } + + .flash-message.show { + transform: translateX(0); + opacity: 1; + } + + .flash-message.info { + border-left: 4px solid #3b82f6; + background: linear-gradient(to right, rgba(59, 130, 246, 0.1), rgba(17, 24, 39, 0.95)); + } + + .flash-message.success { + border-left: 4px solid #10b981; + background: linear-gradient(to right, rgba(16, 185, 129, 0.1), rgba(17, 24, 39, 0.95)); + } + + .flash-message.warning { + border-left: 4px solid #f59e0b; + background: linear-gradient(to right, rgba(245, 158, 11, 0.1), rgba(17, 24, 39, 0.95)); + } + + .flash-message.error { + border-left: 4px solid #ef4444; + background: linear-gradient(to right, rgba(239, 68, 68, 0.1), rgba(17, 24, 39, 0.95)); + } + + .flash-message::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, + rgba(255, 255, 255, 0.1) 0%, + rgba(255, 255, 255, 0) 100%); + pointer-events: none; + } + + @keyframes pulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.02); } + 100% { transform: scale(1); } + } + + .flash-message.show { + animation: pulse 0.3s ease-in-out; + } + + /* Neuronale Effekte für Benachrichtigungen */ + .flash-message.info:hover { + box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); + } + + .flash-message.success:hover { + box-shadow: 0 0 15px rgba(16, 185, 129, 0.3); + } + + .flash-message.warning:hover { + box-shadow: 0 0 15px rgba(245, 158, 11, 0.3); + } + + .flash-message.error:hover { + box-shadow: 0 0 15px rgba(239, 68, 68, 0.3); + } +`; +document.head.appendChild(style); + +// Initialisiere die Mindmap beim Laden der Seite +document.addEventListener('DOMContentLoaded', initializeMindmap); \ No newline at end of file diff --git a/update_routes.py b/update_routes.py new file mode 100644 index 0000000000000000000000000000000000000000..fc2130a3f39c4270483dd4e0c5dcdb84a6ca1811 GIT binary patch literal 506 zcmZ`$!3x4K6w6ug9||6(pgoJ=&6_v(1yiRE=O%VT_Va4;#JM3d+R`+6$=-WDMsQf8 z#1$D*+_)SP-mdUmjooqto-r9aoQzeYz!5_Xh+W7lsjSG6{ud2Y)qKy8+p9c(s|B3f z9L`(