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'])
|
@app.route('/api/mindmaps/<int:mindmap_id>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
|
@handle_api_exception
|
||||||
def api_get_user_mindmap_detail(mindmap_id):
|
def api_get_user_mindmap_detail(mindmap_id):
|
||||||
mindmap = UserMindmap.query.filter_by(id=mindmap_id, user_id=current_user.id).first_or_404()
|
# Berechtigungsprüfung (mindestens READ-Zugriff)
|
||||||
# Bestehende Logik von get_user_mindmap kann hier wiederverwendet oder angepasst werden
|
has_permission, error_msg = check_mindmap_permission(mindmap_id, "READ")
|
||||||
# Für eine einfache Detailansicht:
|
if not has_permission:
|
||||||
return jsonify({
|
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,
|
'id': mindmap.id,
|
||||||
'name': mindmap.name,
|
'name': mindmap.name,
|
||||||
'description': mindmap.description,
|
'description': mindmap.description,
|
||||||
@@ -873,18 +879,44 @@ def api_get_user_mindmap_detail(mindmap_id):
|
|||||||
'user_id': mindmap.user_id,
|
'user_id': mindmap.user_id,
|
||||||
'created_at': mindmap.created_at.isoformat(),
|
'created_at': mindmap.created_at.isoformat(),
|
||||||
'last_modified': mindmap.last_modified.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'])
|
@app.route('/api/mindmaps/<int:mindmap_id>', methods=['PUT'])
|
||||||
@login_required
|
@login_required
|
||||||
|
@handle_api_exception
|
||||||
def api_update_user_mindmap(mindmap_id):
|
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()
|
data = request.get_json()
|
||||||
|
|
||||||
|
# Grundlegende Informationen aktualisieren
|
||||||
mindmap.name = data.get('name', mindmap.name)
|
mindmap.name = data.get('name', mindmap.name)
|
||||||
mindmap.description = data.get('description', mindmap.description)
|
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()
|
db.session.commit()
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@@ -892,16 +924,31 @@ def api_update_user_mindmap(mindmap_id):
|
|||||||
'name': mindmap.name,
|
'name': mindmap.name,
|
||||||
'description': mindmap.description,
|
'description': mindmap.description,
|
||||||
'is_private': mindmap.is_private,
|
'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'])
|
@app.route('/api/mindmaps/<int:mindmap_id>', methods=['DELETE'])
|
||||||
@login_required
|
@login_required
|
||||||
|
@handle_api_exception
|
||||||
def api_delete_user_mindmap(mindmap_id):
|
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.delete(mindmap)
|
||||||
db.session.commit()
|
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)
|
# API-Endpunkte für Mindmap-Daten (öffentlich und benutzerspezifisch)
|
||||||
@app.route('/api/mindmap/public')
|
@app.route('/api/mindmap/public')
|
||||||
|
|||||||
@@ -410,6 +410,12 @@
|
|||||||
<i class="fas fa-save"></i>
|
<i class="fas fa-save"></i>
|
||||||
<span>Layout speichern</span>
|
<span>Layout speichern</span>
|
||||||
</button>
|
</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">
|
<button id="export-btn" class="mindmap-action-btn">
|
||||||
<i class="fas fa-file-export"></i>
|
<i class="fas fa-file-export"></i>
|
||||||
<span>Exportieren</span>
|
<span>Exportieren</span>
|
||||||
@@ -1330,6 +1336,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 {
|
} else {
|
||||||
// Fallback, falls mindmapData null ist
|
// Fallback, falls mindmapData null ist
|
||||||
if(mindmapNameH1) mindmapNameH1.textContent = "Mindmap nicht gefunden";
|
if(mindmapNameH1) mindmapNameH1.textContent = "Mindmap nicht gefunden";
|
||||||
|
|||||||
Reference in New Issue
Block a user