diff --git a/app.py b/app.py index 6134177..99dffc9 100644 --- a/app.py +++ b/app.py @@ -861,11 +861,17 @@ def api_get_user_mindmaps(): @app.route('/api/mindmaps/', methods=['GET']) @login_required +@handle_api_exception def api_get_user_mindmap_detail(mindmap_id): - mindmap = UserMindmap.query.filter_by(id=mindmap_id, user_id=current_user.id).first_or_404() - # Bestehende Logik von get_user_mindmap kann hier wiederverwendet oder angepasst werden - # Für eine einfache Detailansicht: - return jsonify({ + # 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, @@ -873,18 +879,44 @@ def api_get_user_mindmap_detail(mindmap_id): 'user_id': mindmap.user_id, 'created_at': mindmap.created_at.isoformat(), 'last_modified': mindmap.last_modified.isoformat(), - # Hier könnten auch Knoten und Notizen hinzugefügt werden, ähnlich wie in get_user_mindmap - }) + '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): - mindmap = UserMindmap.query.filter_by(id=mindmap_id, user_id=current_user.id).first_or_404() + # 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) - mindmap.is_private = data.get('is_private', mindmap.is_private) + + # 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({ @@ -892,16 +924,31 @@ def api_update_user_mindmap(mindmap_id): 'name': mindmap.name, 'description': mindmap.description, 'is_private': mindmap.is_private, - 'last_modified': mindmap.last_modified.isoformat() + '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): - mindmap = UserMindmap.query.filter_by(id=mindmap_id, user_id=current_user.id).first_or_404() + # 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({'message': 'Mindmap erfolgreich gelöscht'}), 200 + + return jsonify({ + 'success': True, + 'message': 'Mindmap erfolgreich gelöscht' + }), 200 # API-Endpunkte für Mindmap-Daten (öffentlich und benutzerspezifisch) @app.route('/api/mindmap/public') diff --git a/templates/user_mindmap.html b/templates/user_mindmap.html index 3690af1..a5098c5 100644 --- a/templates/user_mindmap.html +++ b/templates/user_mindmap.html @@ -410,6 +410,12 @@ Layout speichern + {% if mindmap.user_id == current_user.id %} + + {% endif %} + + + +
+

Aktuelle Freigaben

+
+
Lade Freigaben...
+
+
+ +
+ +
+ + `; + + document.body.appendChild(overlay); + + // Aktuelle Freigaben laden + loadShares(mindmapId); + + // Event-Listener für Buttons + document.getElementById('close-share-dialog').addEventListener('click', function() { + document.getElementById('share-dialog-overlay').remove(); + }); + + document.getElementById('add-share-btn').addEventListener('click', function() { + const email = document.getElementById('share-email').value.trim(); + const permission = document.getElementById('share-permission').value; + + if (!email) { + showUINotification('Bitte geben Sie eine E-Mail-Adresse ein.', 'error'); + return; + } + + // Mindmap freigeben + fetch(`/api/mindmap/${mindmapId}/share`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token() }}' + }, + body: JSON.stringify({ + email: email, + permission: permission + }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showUINotification(data.message, 'success'); + document.getElementById('share-email').value = ''; + loadShares(mindmapId); // Freigaben neu laden + } else { + showUINotification(data.error, 'error'); + } + }) + .catch(error => { + console.error('Fehler beim Freigeben der Mindmap:', error); + showUINotification('Fehler beim Freigeben der Mindmap.', 'error'); + }); + }); + } + + // Funktion zum Laden der aktuellen Freigaben + function loadShares(mindmapId) { + const shareList = document.getElementById('share-list'); + if (!shareList) return; + + shareList.innerHTML = '
Lade Freigaben...
'; + + fetch(`/api/mindmap/${mindmapId}/shares`) + .then(response => response.json()) + .then(data => { + if (data.success) { + const shares = data.shares; + + if (shares.length === 0) { + shareList.innerHTML = '
Keine Freigaben vorhanden.
'; + return; + } + + shareList.innerHTML = ''; + + shares.forEach(share => { + const shareItem = document.createElement('div'); + shareItem.className = 'flex justify-between items-center p-2 border-b dark:border-gray-700 last:border-0'; + + const permissionClass = { + 'READ': 'text-blue-500 dark:text-blue-400', + 'EDIT': 'text-green-500 dark:text-green-400', + 'ADMIN': 'text-purple-500 dark:text-purple-400' + }[share.permission] || 'text-gray-500'; + + shareItem.innerHTML = ` +
+
${share.username}
+
${share.email}
+
+
+ + +
+ `; + + // Event-Listener zum Aktualisieren der Berechtigungen + const permissionSelect = shareItem.querySelector('.share-permission-select'); + permissionSelect.addEventListener('change', function() { + const shareId = this.dataset.shareId; + const newPermission = this.value; + + updateSharePermission(shareId, newPermission); + }); + + // Event-Listener zum Löschen der Freigabe + const deleteButton = shareItem.querySelector('button[data-share-id]'); + deleteButton.addEventListener('click', function() { + const shareId = this.dataset.shareId; + + if (confirm('Möchten Sie diese Freigabe wirklich widerrufen?')) { + revokeShare(shareId, mindmapId); + } + }); + + shareList.appendChild(shareItem); + }); + + } else { + shareList.innerHTML = '
Fehler beim Laden der Freigaben.
'; + } + }) + .catch(error => { + console.error('Fehler beim Laden der Freigaben:', error); + shareList.innerHTML = '
Fehler beim Laden der Freigaben.
'; + }); + } + + // Funktion zum Aktualisieren der Berechtigungen einer Freigabe + function updateSharePermission(shareId, permission) { + fetch(`/api/mindmap/shares/${shareId}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token() }}' + }, + body: JSON.stringify({ + permission: permission + }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showUINotification(data.message, 'success'); + } else { + showUINotification(data.error, 'error'); + } + }) + .catch(error => { + console.error('Fehler beim Aktualisieren der Berechtigungen:', error); + showUINotification('Fehler beim Aktualisieren der Berechtigungen.', 'error'); + }); + } + + // Funktion zum Widerrufen einer Freigabe + function revokeShare(shareId, mindmapId) { + fetch(`/api/mindmap/shares/${shareId}`, { + method: 'DELETE', + headers: { + 'X-CSRFToken': '{{ csrf_token() }}' + } + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showUINotification(data.message, 'success'); + loadShares(mindmapId); // Freigaben neu laden + } else { + showUINotification(data.error, 'error'); + } + }) + .catch(error => { + console.error('Fehler beim Widerrufen der Freigabe:', error); + showUINotification('Fehler beim Widerrufen der Freigabe.', 'error'); + }); + } } else { // Fallback, falls mindmapData null ist