Compare commits

...

3 Commits

10 changed files with 241 additions and 139 deletions

View File

@@ -3,15 +3,20 @@
- Implementierung von Content Security Policy (CSP) - UNTER KEINEN UMSTÄNDEN! - Implementierung von Content Security Policy (CSP) - UNTER KEINEN UMSTÄNDEN!
- Implementierung von Cross-Site Request Forgery (CSRF) Schutz - Implementierung von Cross-Site Request Forgery (CSRF) Schutz
- Implementierung von Security Headers - Implementierung von Security Headers
- Verwendung von TypeScript anstelle von JavaScript
- Implementierung von OAuth oder anderen externen Authentifizierungsmethoden
# HÄUFIGE FEHLER: # HÄUFIGE FEHLER:
- Verwendung der falschen Datenbank (die korrekte ist: database/systades.db) - Verwendung der falschen Datenbank (die korrekte ist: database/systades.db)
- Falsche Pfadangaben bei statischen Dateien - Falsche Pfadangaben bei statischen Dateien
- Vergessen der deutschen Spracheinstellungen in Templates - Vergessen der deutschen Spracheinstellungen in Templates
- Nicht beachten der vorhandenen Projektstruktur - Nicht beachten der vorhandenen Projektstruktur
- Falsche Einbindung der Neural Network Background Animation
- Verwendung von englischen Variablennamen in deutschen Funktionen
- Vergessen der Mindmap-Datenstruktur gemäß der Roadmap
# Häufige Fehler und Lösungen # Häufige Fehler und Lösungen
D
## Content Security Policy (CSP) ## Content Security Policy (CSP)
### Problem: Externe Ressourcen werden nicht geladen ### Problem: Externe Ressourcen werden nicht geladen
@@ -29,6 +34,35 @@
```html ```html
<link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet">
``` ```
### Problem: CSP-Fehler (script-src-elem 'none', font-src 'none', etc.)
**Fehler:** Skripte werden aufgrund von CSP-Einschränkungen blockiert.
**Lösung:**
1. WICHTIG: CSP-Einschränkungen NICHT implementieren! Diese sind im Projekt unerwünscht.
2. Falls CSP-Header bereits vorhanden sind, entfernen Sie diese aus der Anwendung:
```python
# Entfernen Sie diesen Code, falls vorhanden:
# @app.after_request
# def add_security_headers(response):
# response.headers['Content-Security-Policy'] = '...'
# return response
```
3. Stellen Sie sicher, dass externe Ressourcen direkt geladen werden:
```html
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="{{ url_for('static', filename='js/alpine.min.js') }}" defer></script>
```
4. Für Inline-Skripte keine Nonce verwenden:
```html
<script>
// Inline-JavaScript-Code ohne Einschränkungen
</script>
```
### Problem: Tailwind CSS CDN wird blockiert ### Problem: Tailwind CSS CDN wird blockiert
**Fehler:** Tailwind CSS kann nicht von CDN geladen werden. **Fehler:** Tailwind CSS kann nicht von CDN geladen werden.
@@ -62,3 +96,78 @@
**Lösung:** **Lösung:**
1. Standard-Admin-Benutzer erstellen: `python TOOLS.py user:admin` 1. Standard-Admin-Benutzer erstellen: `python TOOLS.py user:admin`
2. Passwort zurücksetzen: `python TOOLS.py user:reset-pw -u USERNAME -p NEWPASSWORD` 2. Passwort zurücksetzen: `python TOOLS.py user:reset-pw -u USERNAME -p NEWPASSWORD`
## Neural Network Background
### Problem: Hintergrund-Animation wird nicht angezeigt
**Fehler:** Die Neural Network Animation im Hintergrund erscheint nicht.
**Lösung:**
1. Überprüfen Sie, ob die Datei `static/neural-network-background.js` korrekt eingebunden ist:
```html
<script src="{{ url_for('static', filename='neural-network-background.js') }}"></script>
```
2. Initialisieren Sie die Animation im Template:
```html
<script>
document.addEventListener('DOMContentLoaded', () => {
const background = new NeuralNetworkBackground();
background.initialize();
background.animate();
});
</script>
```
3. Stellen Sie sicher, dass keine CSS-Regeln die Animation überdecken:
```css
#neural-network-background {
z-index: -10;
opacity: 1;
}
```
## Mindmap-Funktionalität
### Problem: Mindmap-Daten werden nicht geladen
**Fehler:** Die dynamische Mindmap zeigt keine Daten an.
**Lösung:**
1. Überprüfen Sie die API-Endpunkte für die Mindmap-Daten:
```python
@app.route('/api/mindmap/nodes', methods=['GET'])
def get_mindmap_nodes():
# Implementierung...
```
2. Stellen Sie sicher, dass die AJAX-Anfragen korrekt implementiert sind:
```javascript
fetch('/api/mindmap/nodes')
.then(response => response.json())
.then(data => {
// Verarbeitung der Mindmap-Daten
});
```
3. Überprüfen Sie die Datenbankeinträge für Mindmap-Knoten und -Verbindungen.
## ChatGPT-Assistent
### Problem: Assistent reagiert nicht auf Eingaben
**Fehler:** Der ChatGPT-Assistent verarbeitet keine Benutzereingaben.
**Lösung:**
1. Überprüfen Sie die Einbindung der JavaScript-Datei:
```html
<script src="{{ url_for('static', filename='js/modules/chatgpt-assistant.js') }}"></script>
```
2. Stellen Sie sicher, dass der Assistent korrekt initialisiert wird:
```javascript
document.addEventListener('DOMContentLoaded', () => {
const assistant = new ChatGPTAssistant();
assistant.initialize();
});
```
3. Überprüfen Sie die API-Endpunkte für die Kommunikation mit dem Assistenten.

Binary file not shown.

2
app.py
View File

@@ -73,7 +73,7 @@ def inject_globals():
'current_year': datetime.now().year 'current_year': datetime.now().year
} }
# Kontext-Prozessor für alle Templates # Context-Prozessor für alle Templates
@app.context_processor @app.context_processor
def inject_current_year(): def inject_current_year():
return {'current_year': datetime.now().year} return {'current_year': datetime.now().year}

View File

@@ -1,16 +1,6 @@
/* /**
* Tailwind CSS v3.4.16 * Failed to bundle using Rollup v2.79.2: the file imports a not supported node.js built-in module "fs".
* * If you believe this to be an issue with jsDelivr, and not with the package itself, please open an issue at https://github.com/jsdelivr/jsdelivr
* This is a placeholder file. For production, you should:
* 1. Install Tailwind CSS as a PostCSS plugin: https://tailwindcss.com/docs/installation
* 2. Run the Tailwind CLI to compile this file with your custom configuration
* 3. Replace this file with the compiled CSS
*
* The actual file should be generated using:
* npx tailwindcss -i ./src/input.css -o ./static/css/tailwind.min.css --minify
*/ */
/* Base Tailwind imports */ throw new Error('Failed to bundle using Rollup v2.79.2: the file imports a not supported node.js built-in module "fs". If you believe this to be an issue with jsDelivr, and not with the package itself, please open an issue at https://github.com/jsdelivr/jsdelivr');
@tailwind base;
@tailwind components;
@tailwind utilities;

File diff suppressed because one or more lines are too long

View File

@@ -2,9 +2,6 @@
* MindMap - Hauptdatei für globale JavaScript-Funktionen * MindMap - Hauptdatei für globale JavaScript-Funktionen
*/ */
// Import des ChatGPT-Assistenten
import ChatGPTAssistant from './modules/chatgpt-assistant.js';
/** /**
* Hauptmodul für die MindMap-Anwendung * Hauptmodul für die MindMap-Anwendung
* Verwaltet die globale Anwendungslogik * Verwaltet die globale Anwendungslogik
@@ -38,10 +35,12 @@ const MindMap = {
console.log('MindMap-Anwendung wird initialisiert...'); console.log('MindMap-Anwendung wird initialisiert...');
// Initialisiere den ChatGPT-Assistenten // Initialisiere den ChatGPT-Assistenten
if (typeof ChatGPTAssistant !== 'undefined') {
const assistant = new ChatGPTAssistant(); const assistant = new ChatGPTAssistant();
assistant.init(); assistant.init();
// Speichere als Teil von MindMap // Speichere als Teil von MindMap
this.assistant = assistant; this.assistant = assistant;
}
// Seiten-spezifische Initialisierer aufrufen // Seiten-spezifische Initialisierer aufrufen
if (this.currentPage && this.pageInitializers[this.currentPage]) { if (this.currentPage && this.pageInitializers[this.currentPage]) {
@@ -74,6 +73,12 @@ const MindMap = {
try { try {
console.log('Initialisiere Mindmap...'); console.log('Initialisiere Mindmap...');
// Prüfe, ob MindMapVisualization geladen ist
if (typeof MindMapVisualization === 'undefined') {
console.error('MindMapVisualization-Klasse ist nicht definiert!');
return;
}
// Initialisiere die Mindmap // Initialisiere die Mindmap
const mindmap = new MindMapVisualization('#mindmap-container', { const mindmap = new MindMapVisualization('#mindmap-container', {
height: mindmapContainer.clientHeight || 600, height: mindmapContainer.clientHeight || 600,
@@ -227,6 +232,3 @@ const MindMap = {
// Globale Export für andere Module // Globale Export für andere Module
window.MindMap = MindMap; window.MindMap = MindMap;
// Export als Modul
export default MindMap;

View File

@@ -568,5 +568,5 @@ class ChatGPTAssistant {
} }
} }
// Exportiere die Klasse für die Verwendung in anderen Modulen // Mache die Klasse global verfügbar
export default ChatGPTAssistant; window.ChatGPTAssistant = ChatGPTAssistant;

View File

@@ -3,12 +3,18 @@
* Spezifische Funktionen für die Mindmap-Seite * Spezifische Funktionen für die Mindmap-Seite
*/ */
document.addEventListener('DOMContentLoaded', function() { // Füge das Modul zum globalen MindMap-Objekt hinzu
if (!window.MindMap) {
window.MindMap = {};
}
// Registriere den Initialisierer im MindMap-Objekt // Registriere den Initialisierer im MindMap-Objekt
if (window.MindMap) { if (window.MindMap) {
window.MindMap.pageInitializers = window.MindMap.pageInitializers || {};
window.MindMap.pageInitializers.mindmap = initMindmapPage; window.MindMap.pageInitializers.mindmap = initMindmapPage;
} }
document.addEventListener('DOMContentLoaded', function() {
// Prüfe, ob wir auf der Mindmap-Seite sind und initialisiere // Prüfe, ob wir auf der Mindmap-Seite sind und initialisiere
if (document.body.dataset.page === 'mindmap') { if (document.body.dataset.page === 'mindmap') {
initMindmapPage(); initMindmapPage();
@@ -461,13 +467,13 @@ function initMindmapPage() {
// Erfolgsbenachrichtigung // Erfolgsbenachrichtigung
if (window.MindMap && window.MindMap.showNotification) { if (window.MindMap && window.MindMap.showNotification) {
MindMap.showNotification('Gedanke erfolgreich gespeichert.', 'success'); window.MindMap.showNotification('Gedanke erfolgreich gespeichert.', 'success');
} }
} catch (error) { } catch (error) {
console.error('Fehler beim Speichern:', error); console.error('Fehler beim Speichern:', error);
if (window.MindMap && window.MindMap.showNotification) { if (window.MindMap && window.MindMap.showNotification) {
MindMap.showNotification('Fehler beim Speichern des Gedankens.', 'error'); window.MindMap.showNotification('Fehler beim Speichern des Gedankens.', 'error');
} }
} }
}); });
@@ -483,7 +489,7 @@ function initMindmapPage() {
} }
/** /**
* Zeigt die Kommentare zu einem Gedanken an * Füge globale Funktionen für das Mindmap-Objekt hinzu
*/ */
window.showComments = async function(thoughtId) { window.showComments = async function(thoughtId) {
try { try {
@@ -505,7 +511,11 @@ window.showComments = async function(thoughtId) {
} catch (error) { } catch (error) {
console.error('Fehler beim Laden der Kommentare:', error); console.error('Fehler beim Laden der Kommentare:', error);
MindMap.showNotification('Fehler beim Laden der Kommentare.', 'error'); if (window.MindMap && window.MindMap.showNotification) {
window.MindMap.showNotification('Fehler beim Laden der Kommentare.', 'error');
} else {
alert('Fehler beim Laden der Kommentare.');
}
} }
}; };
@@ -532,7 +542,11 @@ window.showRelations = async function(thoughtId) {
} catch (error) { } catch (error) {
console.error('Fehler beim Laden der Beziehungen:', error); console.error('Fehler beim Laden der Beziehungen:', error);
MindMap.showNotification('Fehler beim Laden der Beziehungen.', 'error'); if (window.MindMap && window.MindMap.showNotification) {
window.MindMap.showNotification('Fehler beim Laden der Beziehungen.', 'error');
} else {
alert('Fehler beim Laden der Beziehungen.');
}
} }
}; };

View File

@@ -14,9 +14,11 @@
<meta name="keywords" content="systades, wissen, visualisierung, lernen, gedanken, theorie"> <meta name="keywords" content="systades, wissen, visualisierung, lernen, gedanken, theorie">
<meta name="author" content="Systades-Team"> <meta name="author" content="Systades-Team">
<!-- Tailwind CSS - CDN Version --> <!-- Tailwind CSS - Beide Optionen verfügbar -->
<script src="https://cdn.tailwindcss.com" nonce="{{ csp_nonce }}"></script> <script src="https://cdn.tailwindcss.com"></script>
<script nonce="{{ csp_nonce }}"> <!-- Alternative lokale Version, falls die CDN-Version blockiert wird -->
<link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet">
<script>
tailwind.config = { tailwind.config = {
darkMode: 'class', darkMode: 'class',
theme: { theme: {
@@ -79,88 +81,32 @@
<!-- Base-Styles ausgelagert in eigene Datei --> <!-- Base-Styles ausgelagert in eigene Datei -->
<link href="{{ url_for('static', filename='css/base-styles.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/base-styles.css') }}" rel="stylesheet">
<!-- Alpine.js - Self-hosted --> <!-- Alpine.js - CDN Version -->
<script src="{{ url_for('static', filename='js/alpine.min.js') }}" defer nonce="{{ csp_nonce }}"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.3/dist/cdn.min.js"></script>
<!-- Neural Network Background CSS --> <!-- Neural Network Background CSS -->
<link href="{{ url_for('static', filename='css/neural-network-background.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/neural-network-background.css') }}" rel="stylesheet">
<!-- D3.js für Visualisierungen -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<!-- Marked.js für Markdown-Parsing -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<!-- ChatGPT Assistant -->
<script src="{{ url_for('static', filename='js/modules/chatgpt-assistant.js') }}"></script>
<!-- MindMap Visualization Module -->
<script src="{{ url_for('static', filename='js/modules/mindmap.js') }}"></script>
<!-- MindMap Page Module -->
<script src="{{ url_for('static', filename='js/modules/mindmap-page.js') }}"></script>
<!-- Neural Network Background Script --> <!-- Neural Network Background Script -->
<script src="{{ url_for('static', filename='neural-network-background.js') }}" nonce="{{ csp_nonce }}"></script> <script src="{{ url_for('static', filename='neural-network-background.js') }}"></script>
<!-- Hauptmodul laden (als ES6 Modul) --> <!-- Hauptmodul laden (als traditionelles Skript) -->
<script type="module" nonce="{{ csp_nonce }}"> <script src="{{ url_for('static', filename='js/main.js') }}"></script>
import MindMap from "{{ url_for('static', filename='js/main.js') }}";
// Alpine.js-Integration
document.addEventListener('alpine:init', () => {
Alpine.data('layout', () => ({
darkMode: true, // Default to dark mode
mobileMenuOpen: false, // Mobile Menü standardmäßig geschlossen
userMenuOpen: false,
showSettingsModal: false,
init() {
this.fetchDarkModeFromSession();
},
fetchDarkModeFromSession() {
// Lade den Dark Mode-Status vom Server
fetch('/api/get_dark_mode')
.then(response => response.json())
.then(data => {
if (data.success) {
this.darkMode = data.darkMode === 'true';
document.querySelector('html').classList.toggle('dark', this.darkMode);
}
})
.catch(error => {
console.error('Fehler beim Laden der Dark Mode-Einstellung:', error);
});
},
toggleDarkMode() {
this.darkMode = !this.darkMode;
document.querySelector('html').classList.toggle('dark', this.darkMode);
// Speichere den Dark Mode-Status auf dem Server
fetch('/api/set_dark_mode', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ darkMode: this.darkMode })
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Zusätzlich im localStorage speichern für sofortige Reaktion bei Seitenwechsel
localStorage.setItem('darkMode', this.darkMode ? 'dark' : 'light');
// Event auslösen für andere Komponenten
document.dispatchEvent(new CustomEvent('darkModeToggled', {
detail: { isDark: this.darkMode }
}));
} else {
console.error('Fehler beim Speichern der Dark Mode-Einstellung:', data.error);
}
})
.catch(error => {
console.error('Fehler beim Speichern der Dark Mode-Einstellung:', error);
});
}
}));
});
// Setze einen globalen Alpine-Initialisierer
window.addEventListener('DOMContentLoaded', () => {
// Fallback für Alpine-Initialisierung
if (typeof Alpine !== 'undefined' && !document.body.hasAttribute('x-data')) {
document.body.setAttribute('x-data', 'layout()');
}
});
// MindMap global verfügbar machen (für Alpine.js und andere nicht-Module Skripte)
window.MindMap = MindMap;
</script>
<!-- Seitenspezifische Styles --> <!-- Seitenspezifische Styles -->
{% block extra_css %}{% endblock %} {% block extra_css %}{% endblock %}
@@ -243,7 +189,57 @@
} }
</style> </style>
</head> </head>
<body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="layout()"> <body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="{
darkMode: true,
mobileMenuOpen: false,
userMenuOpen: false,
showSettingsModal: false,
init() {
this.fetchDarkModeFromSession();
},
fetchDarkModeFromSession() {
fetch('/api/get_dark_mode')
.then(response => response.json())
.then(data => {
if (data.success) {
this.darkMode = data.darkMode === 'true';
document.querySelector('html').classList.toggle('dark', this.darkMode);
}
})
.catch(error => {
console.error('Fehler beim Laden der Dark Mode-Einstellung:', error);
});
},
toggleDarkMode() {
this.darkMode = !this.darkMode;
document.querySelector('html').classList.toggle('dark', this.darkMode);
fetch('/api/set_dark_mode', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ darkMode: this.darkMode })
})
.then(response => response.json())
.then(data => {
if (data.success) {
localStorage.setItem('darkMode', this.darkMode ? 'dark' : 'light');
document.dispatchEvent(new CustomEvent('darkModeToggled', {
detail: { isDark: this.darkMode }
}));
} else {
console.error('Fehler beim Speichern der Dark Mode-Einstellung:', data.error);
}
})
.catch(error => {
console.error('Fehler beim Speichern der Dark Mode-Einstellung:', error);
});
}
}">
<!-- App-Container --> <!-- App-Container -->
<div id="app-container" class="flex flex-col min-h-screen"> <div id="app-container" class="flex flex-col min-h-screen">
<!-- Hauptnavigation --> <!-- Hauptnavigation -->
@@ -597,11 +593,9 @@
{% block scripts %}{% endblock %} {% block scripts %}{% endblock %}
<!-- KI-Chat Initialisierung --> <!-- KI-Chat Initialisierung -->
<script type="module" nonce="{{ csp_nonce }}"> <script>
// Importiere und initialisiere den ChatGPT-Assistenten direkt, um sicherzustellen, // Initialisiere den ChatGPT-Assistenten direkt, um sicherzustellen,
// dass er auf jeder Seite verfügbar ist, selbst wenn MindMap nicht geladen ist // dass er auf jeder Seite verfügbar ist, selbst wenn MindMap nicht geladen ist
import ChatGPTAssistant from "{{ url_for('static', filename='js/modules/chatgpt-assistant.js') }}";
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// Prüfen, ob der Assistent bereits durch MindMap initialisiert wurde // Prüfen, ob der Assistent bereits durch MindMap initialisiert wurde
if (!window.MindMap || !window.MindMap.assistant) { if (!window.MindMap || !window.MindMap.assistant) {

View File

@@ -391,7 +391,7 @@
<div id="mindmap-canvas"></div> <div id="mindmap-canvas"></div>
<!-- Control Panel --> <!-- Control Panel -->
<div class="control-panel p-4 w-64" id="control-panel" x-data="{ isExpanded: true }"> <div class="control-panel p-4 w-64">
<div class="panel-toggle" @click="isExpanded = !isExpanded"> <div class="panel-toggle" @click="isExpanded = !isExpanded">
<i class="fa-solid" :class="isExpanded ? 'fa-chevron-left' : 'fa-chevron-right'"></i> <i class="fa-solid" :class="isExpanded ? 'fa-chevron-left' : 'fa-chevron-right'"></i>
</div> </div>
@@ -432,7 +432,7 @@
<!-- User Mindmaps Section --> <!-- User Mindmaps Section -->
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
<div class="user-mindmap-section p-4 w-64" x-data="{ isExpanded: true }"> <div class="user-mindmap-section p-4 w-64">
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">Meine Mindmaps</h2> <h2 class="text-lg font-semibold text-gray-900 dark:text-white">Meine Mindmaps</h2>
<button @click="isExpanded = !isExpanded" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200"> <button @click="isExpanded = !isExpanded" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200">