From 02d1801fc9c5f3b4505151f748e75381ef829ae2 Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Sat, 10 May 2025 23:17:13 +0200 Subject: [PATCH] "Refactor app log file path update" --- __pycache__/app.cpython-313.pyc | Bin 123139 -> 133504 bytes app.py | 249 ++++++++++++++++++++++++++++++++ logs/app.log | 6 + 3 files changed, 255 insertions(+) diff --git a/__pycache__/app.cpython-313.pyc b/__pycache__/app.cpython-313.pyc index 7cd674d2b6f5972bc46f8af88152e8cea3c519bc..6aa07ecb785250ba28b5c492800f4043303faeb7 100644 GIT binary patch delta 15659 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%0D&l7fiZg~LlhT{a7+my$~y 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 O>JGW`l2YAaRQ?~Up;8bo1L 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 LN=k$`C+vR#3)-Gr diff --git a/app.py b/app.py index faaf2a2..6134177 100644 --- a/app.py +++ b/app.py @@ -2026,6 +2026,255 @@ def reload_env(): '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(): diff --git a/logs/app.log b/logs/app.log index 3d3804f..03626be 100644 --- a/logs/app.log +++ b/logs/app.log @@ -19,3 +19,9 @@ 2025-05-10 23:15:30,739 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76] 2025-05-10 23:15:32,667 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76] 2025-05-10 23:15:32,667 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76] +2025-05-10 23:16:55,581 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76] +2025-05-10 23:16:57,283 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76] +2025-05-10 23:16:57,283 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76] +2025-05-10 23:17:04,727 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76] +2025-05-10 23:17:06,698 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76] +2025-05-10 23:17:06,698 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:76]