chore: Änderungen commited
This commit is contained in:
69
app.py
69
app.py
@@ -861,11 +861,17 @@ def api_get_user_mindmaps():
|
||||
|
||||
@app.route('/api/mindmaps/<int:mindmap_id>', 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/<int:mindmap_id>', 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/<int:mindmap_id>', 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')
|
||||
|
||||
@@ -410,6 +410,12 @@
|
||||
<i class="fas fa-save"></i>
|
||||
<span>Layout speichern</span>
|
||||
</button>
|
||||
{% if mindmap.user_id == current_user.id %}
|
||||
<button id="share-btn" class="mindmap-action-btn">
|
||||
<i class="fas fa-share-alt"></i>
|
||||
<span>Freigeben</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
<button id="export-btn" class="mindmap-action-btn">
|
||||
<i class="fas fa-file-export"></i>
|
||||
<span>Exportieren</span>
|
||||
@@ -1329,6 +1335,239 @@
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Freigabe-Funktionalität implementieren
|
||||
if (document.getElementById('share-btn')) {
|
||||
document.getElementById('share-btn').addEventListener('click', function() {
|
||||
const mindmapId = parseInt("{{ mindmap.id }}");
|
||||
|
||||
// Dialog für Mindmap-Freigabe anzeigen
|
||||
showShareDialog(mindmapId);
|
||||
});
|
||||
}
|
||||
|
||||
// Funktion zum Anzeigen des Freigabe-Dialogs
|
||||
function showShareDialog(mindmapId) {
|
||||
// Dialog erstellen
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'fixed inset-0 bg-black/50 flex items-center justify-center z-50';
|
||||
overlay.id = 'share-dialog-overlay';
|
||||
|
||||
overlay.innerHTML = `
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-6 max-w-lg w-full mx-4">
|
||||
<h3 class="text-xl font-bold mb-4">Mindmap freigeben</h3>
|
||||
|
||||
<div class="mb-6">
|
||||
<div class="flex flex-col space-y-4">
|
||||
<div>
|
||||
<label class="block mb-2 text-sm font-medium">E-Mail-Adresse des Benutzers:</label>
|
||||
<input type="email" id="share-email" class="w-full p-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white"
|
||||
placeholder="beispiel@mail.com">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block mb-2 text-sm font-medium">Berechtigungen:</label>
|
||||
<select id="share-permission" class="w-full p-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white">
|
||||
<option value="READ">Nur-Lesen</option>
|
||||
<option value="EDIT">Bearbeiten</option>
|
||||
<option value="ADMIN">Administrator</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button id="add-share-btn" class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-lg">
|
||||
<i class="fas fa-plus mr-1"></i> Hinzufügen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h4 class="font-semibold mb-2">Aktuelle Freigaben</h4>
|
||||
<div id="share-list" class="max-h-60 overflow-y-auto border rounded-lg p-2 dark:border-gray-700">
|
||||
<div class="text-center text-sm opacity-70 p-4">Lade Freigaben...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<button id="close-share-dialog" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 rounded-lg">Schließen</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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 = '<div class="text-center text-sm opacity-70 p-4">Lade Freigaben...</div>';
|
||||
|
||||
fetch(`/api/mindmap/${mindmapId}/shares`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const shares = data.shares;
|
||||
|
||||
if (shares.length === 0) {
|
||||
shareList.innerHTML = '<div class="text-center text-sm opacity-70 p-4">Keine Freigaben vorhanden.</div>';
|
||||
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 = `
|
||||
<div>
|
||||
<div class="font-medium">${share.username}</div>
|
||||
<div class="text-xs opacity-70">${share.email}</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<select class="share-permission-select text-sm p-1 rounded ${permissionClass}" data-share-id="${share.id}">
|
||||
<option value="READ" ${share.permission === 'READ' ? 'selected' : ''}>Nur-Lesen</option>
|
||||
<option value="EDIT" ${share.permission === 'EDIT' ? 'selected' : ''}>Bearbeiten</option>
|
||||
<option value="ADMIN" ${share.permission === 'ADMIN' ? 'selected' : ''}>Administrator</option>
|
||||
</select>
|
||||
<button class="text-red-500 hover:text-red-700" data-share-id="${share.id}">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 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 = '<div class="text-center text-sm text-red-500 p-4">Fehler beim Laden der Freigaben.</div>';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fehler beim Laden der Freigaben:', error);
|
||||
shareList.innerHTML = '<div class="text-center text-sm text-red-500 p-4">Fehler beim Laden der Freigaben.</div>';
|
||||
});
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user