User Profil Fix Versuch 1

This commit is contained in:
2025-05-02 16:48:00 +01:00
parent 34a08c4a6a
commit d49b266d96
9 changed files with 367 additions and 51 deletions

Binary file not shown.

Binary file not shown.

180
app.py
View File

@@ -19,6 +19,7 @@ from openai import OpenAI
from dotenv import load_dotenv
from flask_socketio import SocketIO, emit
from flask_migrate import Migrate
import sqlalchemy
# Modelle importieren
from models import (
@@ -316,15 +317,21 @@ def register():
user = User(username=username, email=email)
user.set_password(password)
db.session.add(user)
db.session.commit() # Commit, um eine ID für den Benutzer zu erhalten
# Erstelle eine Standard-Mindmap für den neuen Benutzer
default_mindmap = UserMindmap(
name='Meine Mindmap',
description='Meine persönliche Wissenslandschaft',
user=user
)
db.session.add(default_mindmap)
db.session.commit()
try:
default_mindmap = UserMindmap(
name='Meine Mindmap',
description='Meine persönliche Wissenslandschaft',
user_id=user.id
)
db.session.add(default_mindmap)
db.session.commit()
except Exception as e:
print(f"Fehler beim Erstellen der Standard-Mindmap: {e}")
# Stelle sicher, dass wir trotzdem weitermachen können
db.session.rollback()
login_user(user)
flash('Dein Konto wurde erfolgreich erstellt!', 'success')
@@ -379,49 +386,96 @@ def mindmap():
@app.route('/profile')
@login_required
def profile():
# Lade Benutzer-Mindmaps
user_mindmaps = UserMindmap.query.filter_by(user_id=current_user.id).all()
# Lade Statistiken
thought_count = Thought.query.filter_by(user_id=current_user.id).count()
bookmark_count = db.session.query(user_thought_bookmark).filter(
user_thought_bookmark.c.user_id == current_user.id).count()
# Berechne tatsächliche Werte für Benutzerstatistiken
contributions_count = Comment.query.filter_by(user_id=current_user.id).count()
# Berechne Verbindungen (Anzahl der Gedankenverknüpfungen)
connections_count = ThoughtRelation.query.filter(
(ThoughtRelation.source_id.in_(
db.session.query(Thought.id).filter_by(user_id=current_user.id)
)) |
(ThoughtRelation.target_id.in_(
db.session.query(Thought.id).filter_by(user_id=current_user.id)
))
).count()
# Berechne durchschnittliche Bewertung der Gedanken des Benutzers
avg_rating = db.session.query(func.avg(ThoughtRating.relevance_score)).join(
Thought, Thought.id == ThoughtRating.thought_id
).filter(Thought.user_id == current_user.id).scalar() or 0
# Hole die Anzahl der Follower (falls implementiert)
# In diesem Beispiel nehmen wir an, dass es keine Follower-Funktionalität gibt
followers_count = 0
# Hole den Standort des Benutzers aus der Datenbank, falls vorhanden
location = "Deutschland" # Standardwert
return render_template('profile.html',
user=current_user,
user_mindmaps=user_mindmaps,
thought_count=thought_count,
bookmark_count=bookmark_count,
connections_count=connections_count,
contributions_count=contributions_count,
followers_count=followers_count,
rating=round(avg_rating, 1),
location=location)
try:
# Versuche auf die neue Benutzermodellstruktur zuzugreifen
_ = current_user.bio # Dies wird fehlschlagen, wenn die Spalte nicht existiert
# Wenn keine Ausnahme, fahre mit normalem Profil fort
# Lade Benutzer-Mindmaps
user_mindmaps = UserMindmap.query.filter_by(user_id=current_user.id).all()
# Prüfe, ob der Benutzer eine Standard-Mindmap hat, sonst erstelle eine
if not user_mindmaps:
try:
default_mindmap = UserMindmap(
name='Meine Mindmap',
description='Meine persönliche Wissenslandschaft',
user_id=current_user.id
)
db.session.add(default_mindmap)
db.session.commit()
# Aktualisiere die Liste nach dem Erstellen
user_mindmaps = [default_mindmap]
except Exception as e:
print(f"Fehler beim Erstellen der Standard-Mindmap in Profil: {e}")
# Flash-Nachricht für den Benutzer
flash('Es gab ein Problem beim Laden deiner Mindmaps. Bitte versuche es später erneut.', 'warning')
# Lade Statistiken
thought_count = Thought.query.filter_by(user_id=current_user.id).count()
bookmark_count = db.session.query(user_thought_bookmark).filter(
user_thought_bookmark.c.user_id == current_user.id).count()
# Berechne tatsächliche Werte für Benutzerstatistiken
contributions_count = Comment.query.filter_by(user_id=current_user.id).count()
# Berechne Verbindungen (Anzahl der Gedankenverknüpfungen)
connections_count = ThoughtRelation.query.filter(
(ThoughtRelation.source_id.in_(
db.session.query(Thought.id).filter_by(user_id=current_user.id)
)) |
(ThoughtRelation.target_id.in_(
db.session.query(Thought.id).filter_by(user_id=current_user.id)
))
).count()
# Berechne durchschnittliche Bewertung der Gedanken des Benutzers
avg_rating = db.session.query(func.avg(ThoughtRating.relevance_score)).join(
Thought, Thought.id == ThoughtRating.thought_id
).filter(Thought.user_id == current_user.id).scalar() or 0
# Sammle alle Statistiken in einem Wörterbuch
stats = {
'thought_count': thought_count,
'bookmark_count': bookmark_count,
'connections_count': connections_count,
'contributions_count': contributions_count,
'followers_count': 0, # Platzhalter für zukünftige Funktionalität
'rating': round(avg_rating, 1)
}
# Hole die letzten Gedanken des Benutzers
thoughts = Thought.query.filter_by(user_id=current_user.id).order_by(Thought.created_at.desc()).limit(5).all()
# Hole den Standort des Benutzers aus der Datenbank, falls vorhanden
location = "Deutschland" # Standardwert
return render_template('profile.html',
user=current_user,
user_mindmaps=user_mindmaps,
stats=stats,
thoughts=thoughts,
location=location)
except (AttributeError, sqlalchemy.exc.OperationalError) as e:
# Die Spalte existiert nicht, verwende stattdessen das einfache Profil
print(f"Verwende einfaches Profil wegen Datenbankfehler: {e}")
flash('Dein Profil wird im einfachen Modus angezeigt, bis die Datenbank aktualisiert wird.', 'warning')
# Lade nur die grundlegenden Informationen
user_mindmaps = UserMindmap.query.filter_by(user_id=current_user.id).all()
thoughts = Thought.query.filter_by(user_id=current_user.id).order_by(Thought.created_at.desc()).limit(5).all()
return render_template('simple_profile.html',
user=current_user,
user_mindmaps=user_mindmaps,
thoughts=thoughts)
except Exception as e:
# Eine andere Ausnahme ist aufgetreten
print(f"Fehler beim Laden des Profils: {e}")
flash('Dein Benutzerprofil konnte nicht geladen werden. Bitte kontaktiere den Support.', 'error')
return redirect(url_for('index'))
# Route für Benutzereinstellungen
@app.route('/settings', methods=['GET', 'POST'])
@@ -1548,4 +1602,28 @@ def redirect_to_index():
@app.route('/static/js/mindmap-init.js')
def serve_mindmap_init_js():
"""Bedient die Mindmap-Initialisierungsdatei."""
return app.send_static_file('js/mindmap-init.js'), 200, {'Content-Type': 'application/javascript'}
return app.send_static_file('js/mindmap-init.js'), 200, {'Content-Type': 'application/javascript'}
# Datenbank-Update-Route (admin-geschützt)
@app.route('/admin/update-database', methods=['GET', 'POST'])
@admin_required
def admin_update_database():
"""Admin-Route zum Aktualisieren der Datenbank"""
message = None
success = None
if request.method == 'POST':
try:
import update_db
update_success = update_db.update_user_table()
if update_success:
message = "Die Datenbank wurde erfolgreich aktualisiert."
success = True
else:
message = "Es gab ein Problem bei der Aktualisierung der Datenbank."
success = False
except Exception as e:
message = f"Fehler: {str(e)}"
success = False
return render_template('admin/update_database.html', message=message, success=success)

Binary file not shown.

View File

@@ -53,11 +53,20 @@ class User(db.Model, UserMixin):
created_at = db.Column(db.DateTime, default=datetime.utcnow)
is_active = db.Column(db.Boolean, default=True)
role = db.Column(db.String(20), default="user") # 'user', 'admin', 'moderator'
bio = db.Column(db.Text, nullable=True) # Profil-Bio
location = db.Column(db.String(100), nullable=True) # Standort
website = db.Column(db.String(200), nullable=True) # Website
avatar = db.Column(db.String(200), nullable=True) # Profilbild-URL
last_login = db.Column(db.DateTime, nullable=True) # Letzter Login
# Relationships
threads = db.relationship('Thread', backref='creator', lazy=True)
messages = db.relationship('Message', backref='author', lazy=True)
projects = db.relationship('Project', backref='owner', lazy=True)
mindmaps = db.relationship('UserMindmap', backref='user', lazy=True)
thoughts = db.relationship('Thought', backref='author', lazy=True)
bookmarked_thoughts = db.relationship('Thought', secondary=user_thought_bookmark,
lazy='dynamic', backref=db.backref('bookmarked_by', lazy='dynamic'))
def __repr__(self):
return f'<User {self.username}>'
@@ -67,6 +76,10 @@ class User(db.Model, UserMixin):
def check_password(self, password):
return check_password_hash(self.password, password)
@property
def is_admin(self):
return self.role == 'admin'
class Category(db.Model):
"""Wissenschaftliche Kategorien für die Gliederung der öffentlichen Mindmap"""

View File

@@ -0,0 +1,46 @@
{% extends "base.html" %}
{% block title %}Datenbank aktualisieren{% endblock %}
{% block content %}
<div class="container mx-auto px-4 py-10">
<div class="bg-gray-800 bg-opacity-70 rounded-lg p-6 mb-6">
<h1 class="text-2xl font-bold text-purple-400 mb-4">Datenbank aktualisieren</h1>
{% if message %}
<div class="mb-6 p-4 rounded-lg {{ 'bg-green-800 bg-opacity-50' if success else 'bg-red-800 bg-opacity-50' }}">
<p class="text-white">{{ message }}</p>
</div>
{% endif %}
<div class="mb-6">
<p class="text-gray-300 mb-4">
Diese Funktion aktualisiert die Datenbankstruktur, um mit dem aktuellen Datenmodell kompatibel zu sein.
Dabei werden folgende Änderungen vorgenommen:
</p>
<ul class="list-disc pl-6 text-gray-300 mb-6">
<li>Hinzufügen von <code>bio</code>, <code>location</code>, <code>website</code>, <code>avatar</code> und <code>last_login</code> zur Benutzer-Tabelle</li>
</ul>
<div class="bg-yellow-800 bg-opacity-30 p-4 rounded-lg mb-6">
<p class="text-yellow-200">
<i class="fas fa-exclamation-triangle mr-2"></i>
<strong>Warnung:</strong> Bitte stelle sicher, dass du ein Backup der Datenbank erstellt hast, bevor du fortfährst.
</p>
</div>
</div>
<form method="POST" action="{{ url_for('admin_update_database') }}">
<div class="flex justify-between">
<a href="{{ url_for('index') }}" class="px-4 py-2 bg-gray-700 text-white rounded-lg hover:bg-gray-600">
Zurück zur Startseite
</a>
<button type="submit" class="px-4 py-2 bg-purple-700 text-white rounded-lg hover:bg-purple-600">
Datenbank aktualisieren
</button>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@@ -559,6 +559,7 @@
<div class="profile-tabs">
<div class="profile-tab active" data-tab="activity">Aktivitäten</div>
<div class="profile-tab" data-tab="thoughts">Gedanken</div>
<div class="profile-tab" data-tab="mindmaps">Mindmaps</div>
<div class="profile-tab" data-tab="collections">Sammlungen</div>
<div class="profile-tab" data-tab="connections">Verbindungen</div>
<div class="profile-tab" data-tab="settings">Einstellungen</div>
@@ -632,6 +633,44 @@
</div>
</div>
<!-- Mindmaps-Tab -->
<div class="tab-content hidden" id="mindmaps-tab">
<div id="mindmaps-container">
{% if user_mindmaps %}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{% for mindmap in user_mindmaps %}
<div class="mindmap-item bg-opacity-70 bg-gray-800 rounded-xl overflow-hidden border border-gray-700 transition-all duration-300 hover:transform hover:scale-105 hover:shadow-lg">
<div class="p-5">
<h3 class="text-xl font-bold text-purple-400 mb-2">{{ mindmap.name }}</h3>
<p class="text-gray-300 mb-4 text-sm">{{ mindmap.description }}</p>
<div class="flex justify-between items-center text-xs text-gray-400">
<span>Erstellt: {{ mindmap.created_at.strftime('%d.%m.%Y') }}</span>
<span>Zuletzt bearbeitet: {{ mindmap.last_modified.strftime('%d.%m.%Y') }}</span>
</div>
</div>
<div class="bg-gray-900 p-3 border-t border-gray-700 flex justify-between">
<a href="{{ url_for('mindmap') }}?id={{ mindmap.id }}" class="text-purple-400 hover:text-purple-300 transition-colors">
<i class="fas fa-eye mr-1"></i> Anzeigen
</a>
<a href="{{ url_for('edit_mindmap', mindmap_id=mindmap.id) }}" class="text-blue-400 hover:text-blue-300 transition-colors">
<i class="fas fa-edit mr-1"></i> Bearbeiten
</a>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-12">
<i class="fas fa-project-diagram text-5xl text-gray-400 mb-4"></i>
<p class="text-gray-500">Noch keine Mindmaps erstellt</p>
<a href="{{ url_for('create_mindmap') }}" class="mt-4 inline-block px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors">
Erste Mindmap erstellen
</a>
</div>
{% endif %}
</div>
</div>
<div class="tab-content hidden" id="collections-tab">
<div id="collections-container">
{% if collections %}

View File

@@ -0,0 +1,75 @@
{% extends "base.html" %}
{% block title %}Einfaches Profil{% endblock %}
{% block content %}
<div class="container mx-auto px-4 py-10">
<div class="bg-gray-800 bg-opacity-70 rounded-lg p-6 mb-6">
<h1 class="text-3xl font-bold text-purple-400 mb-4">Hallo, {{ user.username }}</h1>
<div class="text-gray-300 mb-4">
<p>E-Mail: {{ user.email }}</p>
<p>Mitglied seit: {{ user.created_at.strftime('%d.%m.%Y') }}</p>
</div>
<h2 class="text-xl font-semibold text-purple-300 mt-6 mb-3">Deine Mindmaps</h2>
{% if user_mindmaps %}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{% for mindmap in user_mindmaps %}
<div class="bg-gray-700 bg-opacity-50 p-4 rounded-lg">
<h3 class="text-lg font-medium text-purple-400 mb-2">{{ mindmap.name }}</h3>
<p class="text-gray-300 text-sm mb-3">{{ mindmap.description }}</p>
<div class="flex justify-between text-xs text-gray-400">
<span>Erstellt: {{ mindmap.created_at.strftime('%d.%m.%Y') }}</span>
</div>
<div class="mt-4 flex justify-between">
<a href="{{ url_for('mindmap') }}?id={{ mindmap.id }}" class="text-purple-400 hover:text-purple-300">
<i class="fas fa-eye mr-1"></i> Anzeigen
</a>
<a href="{{ url_for('edit_mindmap', mindmap_id=mindmap.id) }}" class="text-blue-400 hover:text-blue-300">
<i class="fas fa-edit mr-1"></i> Bearbeiten
</a>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-6">
<p class="text-gray-400">Du hast noch keine Mindmaps erstellt</p>
<a href="{{ url_for('create_mindmap') }}" class="mt-3 inline-block px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700">
Erste Mindmap erstellen
</a>
</div>
{% endif %}
<h2 class="text-xl font-semibold text-purple-300 mt-8 mb-3">Deine Gedanken</h2>
{% if thoughts %}
<div class="space-y-4">
{% for thought in thoughts %}
<div class="bg-gray-700 bg-opacity-50 p-4 rounded-lg">
<h3 class="text-lg font-medium text-purple-400 mb-2">{{ thought.title }}</h3>
<p class="text-gray-300 text-sm mb-2">
{{ thought.abstract[:150] ~ '...' if thought.abstract and thought.abstract|length > 150 else thought.abstract }}
</p>
<div class="flex justify-between text-xs text-gray-400">
<span>Erstellt: {{ thought.created_at.strftime('%d.%m.%Y') }}</span>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-6">
<p class="text-gray-400">Du hast noch keine Gedanken erstellt</p>
</div>
{% endif %}
<div class="mt-8 flex justify-between">
<a href="{{ url_for('index') }}" class="px-4 py-2 bg-gray-700 text-white rounded-lg hover:bg-gray-600">
Zurück zur Startseite
</a>
<a href="{{ url_for('logout') }}" class="px-4 py-2 bg-red-700 text-white rounded-lg hover:bg-red-600">
Abmelden
</a>
</div>
</div>
</div>
{% endblock %}

65
update_db.py Normal file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sqlite3
import sys
# Bestimme den absoluten Pfad zur Datenbank
basedir = os.path.abspath(os.path.dirname(__file__))
db_path = os.path.join(basedir, 'database', 'systades.db')
def update_user_table():
"""Aktualisiert die User-Tabelle mit den fehlenden Spalten"""
# Überprüfe, ob die Datenbankdatei existiert
if not os.path.exists(db_path):
print(f"Datenbank nicht gefunden unter: {db_path}")
return False
# Verbindung zur Datenbank herstellen
try:
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Überprüfe, ob die neuen Spalten bereits existieren
cursor.execute("PRAGMA table_info(user)")
columns = [info[1] for info in cursor.fetchall()]
# Neue Spalten, die hinzugefügt werden müssen
new_columns = {
'bio': 'TEXT',
'location': 'VARCHAR(100)',
'website': 'VARCHAR(200)',
'avatar': 'VARCHAR(200)',
'last_login': 'DATETIME'
}
# Spalten hinzufügen, die noch nicht existieren
for col_name, col_type in new_columns.items():
if col_name not in columns:
print(f"Füge Spalte '{col_name}' zur User-Tabelle hinzu...")
cursor.execute(f"ALTER TABLE user ADD COLUMN {col_name} {col_type}")
# Änderungen speichern
conn.commit()
print("User-Tabelle erfolgreich aktualisiert!")
return True
except sqlite3.Error as e:
print(f"Fehler bei der Datenbankaktualisierung: {e}")
return False
finally:
if conn:
conn.close()
if __name__ == "__main__":
# Führe die Aktualisierung durch
success = update_user_table()
if success:
print("Die Datenbank wurde erfolgreich aktualisiert.")
sys.exit(0)
else:
print("Es gab ein Problem bei der Datenbankaktualisierung.")
sys.exit(1)