Community erstellt
This commit is contained in:
379
app.py
379
app.py
@@ -24,7 +24,7 @@ from flask_migrate import Migrate
|
||||
from models import (
|
||||
db, User, Thought, Comment, MindMapNode, ThoughtRelation, ThoughtRating,
|
||||
RelationType, Category, UserMindmap, UserMindmapNode, MindmapNote,
|
||||
node_thought_association, user_thought_bookmark, node_relationship
|
||||
node_thought_association, user_thought_bookmark, node_relationship, ForumCategory, ForumPost
|
||||
)
|
||||
|
||||
# Lade .env-Datei
|
||||
@@ -190,6 +190,31 @@ def create_default_categories():
|
||||
db.session.commit()
|
||||
print("Standard-Kategorien wurden erstellt!")
|
||||
|
||||
def create_forum_categories():
|
||||
"""Erstellt Forum-Kategorien basierend auf Hauptknotenpunkten der Mindmap"""
|
||||
# Hauptknotenpunkte abrufen (nur die, die keine Elternknoten haben)
|
||||
main_nodes = MindMapNode.query.filter(~MindMapNode.id.in_(
|
||||
db.session.query(node_relationship.c.child_id)
|
||||
)).all()
|
||||
|
||||
for node in main_nodes:
|
||||
# Prüfen, ob eine Forum-Kategorie für diesen Knoten bereits existiert
|
||||
existing_category = ForumCategory.query.filter_by(node_id=node.id).first()
|
||||
if existing_category:
|
||||
continue
|
||||
|
||||
# Neue Kategorie erstellen
|
||||
forum_category = ForumCategory(
|
||||
node_id=node.id,
|
||||
title=node.name,
|
||||
description=node.description,
|
||||
is_active=True
|
||||
)
|
||||
db.session.add(forum_category)
|
||||
|
||||
db.session.commit()
|
||||
print("Forum-Kategorien wurden für alle Hauptknotenpunkte erstellt!")
|
||||
|
||||
def initialize_database():
|
||||
"""Initialisiert die Datenbank mit Grunddaten, falls diese leer ist"""
|
||||
try:
|
||||
@@ -198,97 +223,34 @@ def initialize_database():
|
||||
# Erstelle alle Tabellen
|
||||
db.create_all()
|
||||
|
||||
# Prüfe, ob bereits Benutzer existieren
|
||||
if User.query.count() == 0:
|
||||
print("Erstelle Admin-Benutzer...")
|
||||
admin = User(
|
||||
username="admin",
|
||||
email="admin@example.com",
|
||||
is_admin=True
|
||||
)
|
||||
admin.set_password("admin123") # In echter Umgebung ein sicheres Passwort verwenden!
|
||||
db.session.add(admin)
|
||||
# Prüfen, ob bereits Kategorien existieren
|
||||
categories_count = Category.query.count()
|
||||
users_count = User.query.count()
|
||||
|
||||
# Prüfe, ob bereits Kategorien existieren
|
||||
if Category.query.count() == 0:
|
||||
print("Erstelle Standard-Kategorien...")
|
||||
# Erstelle Standarddaten, wenn es keine Kategorien gibt
|
||||
if categories_count == 0:
|
||||
create_default_categories()
|
||||
|
||||
# Stelle sicher, dass die Standard-Knoten für die öffentliche Mindmap existieren
|
||||
if MindMapNode.query.count() == 0:
|
||||
print("Erstelle Standard-Knoten für die Mindmap...")
|
||||
|
||||
# Hauptknoten: Wissen
|
||||
root_node = MindMapNode(
|
||||
name="Wissen",
|
||||
description="Zentrale Wissensbasis",
|
||||
color_code="#4299E1",
|
||||
is_public=True
|
||||
# Admin-Benutzer erstellen, wenn keine Benutzer vorhanden sind
|
||||
if users_count == 0:
|
||||
admin_user = User(
|
||||
username="admin",
|
||||
email="admin@example.com",
|
||||
role="admin",
|
||||
is_active=True
|
||||
)
|
||||
db.session.add(root_node)
|
||||
db.session.flush() # Um die ID zu generieren
|
||||
|
||||
# Verwandte Kategorien finden
|
||||
philosophy = Category.query.filter_by(name="Philosophie").first()
|
||||
science = Category.query.filter_by(name="Wissenschaft").first()
|
||||
technology = Category.query.filter_by(name="Technologie").first()
|
||||
arts = Category.query.filter_by(name="Künste").first()
|
||||
|
||||
# Erstelle Hauptthemenknoten
|
||||
nodes = [
|
||||
MindMapNode(
|
||||
name="Philosophie",
|
||||
description="Philosophisches Denken",
|
||||
color_code="#9F7AEA",
|
||||
category=philosophy,
|
||||
is_public=True
|
||||
),
|
||||
MindMapNode(
|
||||
name="Wissenschaft",
|
||||
description="Wissenschaftliche Erkenntnisse",
|
||||
color_code="#48BB78",
|
||||
category=science,
|
||||
is_public=True
|
||||
),
|
||||
MindMapNode(
|
||||
name="Technologie",
|
||||
description="Technologische Entwicklungen",
|
||||
color_code="#ED8936",
|
||||
category=technology,
|
||||
is_public=True
|
||||
),
|
||||
MindMapNode(
|
||||
name="Künste",
|
||||
description="Künstlerische Ausdrucksformen",
|
||||
color_code="#ED64A6",
|
||||
category=arts,
|
||||
is_public=True
|
||||
)
|
||||
]
|
||||
|
||||
# Füge Knoten zur Datenbank hinzu
|
||||
for node in nodes:
|
||||
db.session.add(node)
|
||||
|
||||
admin_user.set_password("admin123") # Sicheres Passwort in der Produktion verwenden!
|
||||
db.session.add(admin_user)
|
||||
db.session.commit()
|
||||
|
||||
# Nachdem wir die IDs haben, füge die Verbindungen hinzu
|
||||
all_nodes = MindMapNode.query.all()
|
||||
root = MindMapNode.query.filter_by(name="Wissen").first()
|
||||
|
||||
if root:
|
||||
for node in all_nodes:
|
||||
if node.id != root.id:
|
||||
root.children.append(node)
|
||||
|
||||
# Speichere die Änderungen
|
||||
db.session.commit()
|
||||
|
||||
print("Datenbankinitialisierung abgeschlossen.")
|
||||
print("Admin-Benutzer wurde erstellt!")
|
||||
|
||||
# Forum-Kategorien erstellen
|
||||
create_forum_categories()
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Fehler bei der Datenbankinitialisierung: {str(e)}")
|
||||
db.session.rollback()
|
||||
raise
|
||||
print(f"Fehler bei Datenbank-Initialisierung: {e}")
|
||||
return False
|
||||
|
||||
# Instead of before_first_request, which is deprecated in newer Flask versions
|
||||
# Use a function to initialize the database that will be called during app creation
|
||||
@@ -1521,6 +1483,251 @@ def refresh_mindmap():
|
||||
def mindmap_page():
|
||||
return render_template('mindmap.html')
|
||||
|
||||
# Community-Forum-Routen
|
||||
@app.route('/community')
|
||||
@login_required
|
||||
def community():
|
||||
"""Hauptseite des Community-Forums"""
|
||||
forum_categories = ForumCategory.query.filter_by(is_active=True).all()
|
||||
|
||||
# Statistiken für jede Kategorie berechnen
|
||||
categories_data = []
|
||||
for category in forum_categories:
|
||||
total_posts = ForumPost.query.filter_by(category_id=category.id, parent_id=None).count()
|
||||
total_replies = ForumPost.query.filter(
|
||||
ForumPost.category_id == category.id,
|
||||
ForumPost.parent_id != None
|
||||
).count()
|
||||
latest_post = ForumPost.query.filter_by(category_id=category.id)\
|
||||
.order_by(ForumPost.created_at.desc()).first()
|
||||
|
||||
categories_data.append({
|
||||
'category': category,
|
||||
'total_posts': total_posts,
|
||||
'total_replies': total_replies,
|
||||
'latest_post': latest_post
|
||||
})
|
||||
|
||||
return render_template('community/index.html', categories_data=categories_data)
|
||||
|
||||
@app.route('/community/category/<int:category_id>')
|
||||
@login_required
|
||||
def forum_category(category_id):
|
||||
"""Zeigt alle Themen in einer bestimmten Kategorie an"""
|
||||
category = ForumCategory.query.get_or_404(category_id)
|
||||
|
||||
# Haupt-Beiträge (Threads) in dieser Kategorie
|
||||
threads = ForumPost.query.filter_by(
|
||||
category_id=category_id,
|
||||
parent_id=None
|
||||
).order_by(ForumPost.is_pinned.desc(), ForumPost.created_at.desc()).all()
|
||||
|
||||
# Zähle Antworten und hole den neuesten Beitrag für jeden Thread
|
||||
threads_data = []
|
||||
for thread in threads:
|
||||
reply_count = ForumPost.query.filter_by(parent_id=thread.id).count()
|
||||
latest_reply = ForumPost.query.filter_by(parent_id=thread.id)\
|
||||
.order_by(ForumPost.created_at.desc()).first()
|
||||
|
||||
threads_data.append({
|
||||
'thread': thread,
|
||||
'reply_count': reply_count,
|
||||
'latest_reply': latest_reply
|
||||
})
|
||||
|
||||
return render_template('community/category.html',
|
||||
category=category,
|
||||
threads_data=threads_data,
|
||||
node=category.node)
|
||||
|
||||
@app.route('/community/post/<int:post_id>')
|
||||
@login_required
|
||||
def forum_post(post_id):
|
||||
"""Zeigt einen Beitrag und alle seine Antworten an"""
|
||||
post = ForumPost.query.get_or_404(post_id)
|
||||
|
||||
# Wenn es sich um eine Antwort handelt, leite zur übergeordneten Beitragsseite weiter
|
||||
if post.parent_id:
|
||||
return redirect(url_for('forum_post', post_id=post.parent_id))
|
||||
|
||||
# Erhöhe die Ansichtszahl
|
||||
post.view_count += 1
|
||||
db.session.commit()
|
||||
|
||||
# Hole alle Antworten zu diesem Beitrag
|
||||
replies = ForumPost.query.filter_by(parent_id=post_id)\
|
||||
.order_by(ForumPost.created_at).all()
|
||||
|
||||
return render_template('community/post.html',
|
||||
post=post,
|
||||
replies=replies,
|
||||
category=post.category)
|
||||
|
||||
@app.route('/community/new-post/<int:category_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def new_post(category_id):
|
||||
"""Erstellt einen neuen Beitrag in einer Kategorie"""
|
||||
category = ForumCategory.query.get_or_404(category_id)
|
||||
|
||||
if request.method == 'POST':
|
||||
title = request.form.get('title')
|
||||
content = request.form.get('content')
|
||||
|
||||
if not title or not content:
|
||||
flash('Bitte fülle alle Pflichtfelder aus.', 'error')
|
||||
return redirect(url_for('new_post', category_id=category_id))
|
||||
|
||||
# Neuen Beitrag erstellen
|
||||
post = ForumPost(
|
||||
title=title,
|
||||
content=content,
|
||||
user_id=current_user.id,
|
||||
category_id=category_id
|
||||
)
|
||||
db.session.add(post)
|
||||
db.session.commit()
|
||||
|
||||
flash('Dein Beitrag wurde erfolgreich erstellt.', 'success')
|
||||
return redirect(url_for('forum_post', post_id=post.id))
|
||||
|
||||
return render_template('community/new_post.html', category=category)
|
||||
|
||||
@app.route('/community/reply/<int:post_id>', methods=['POST'])
|
||||
@login_required
|
||||
def reply_to_post(post_id):
|
||||
"""Antwortet auf einen bestehenden Beitrag"""
|
||||
parent_post = ForumPost.query.get_or_404(post_id)
|
||||
|
||||
# Stelle sicher, dass der Beitrag nicht gesperrt ist
|
||||
if parent_post.is_locked:
|
||||
flash('Dieser Beitrag ist gesperrt und kann keine Antworten mehr erhalten.', 'error')
|
||||
return redirect(url_for('forum_post', post_id=post_id))
|
||||
|
||||
content = request.form.get('content')
|
||||
|
||||
if not content:
|
||||
flash('Die Antwort darf nicht leer sein.', 'error')
|
||||
return redirect(url_for('forum_post', post_id=post_id))
|
||||
|
||||
# Erstelle eine Antwort
|
||||
reply = ForumPost(
|
||||
title=f"Re: {parent_post.title}",
|
||||
content=content,
|
||||
user_id=current_user.id,
|
||||
category_id=parent_post.category_id,
|
||||
parent_id=post_id
|
||||
)
|
||||
db.session.add(reply)
|
||||
db.session.commit()
|
||||
|
||||
flash('Deine Antwort wurde erfolgreich hinzugefügt.', 'success')
|
||||
return redirect(url_for('forum_post', post_id=post_id))
|
||||
|
||||
@app.route('/community/edit-post/<int:post_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_post(post_id):
|
||||
"""Bearbeitet einen bestehenden Beitrag"""
|
||||
post = ForumPost.query.get_or_404(post_id)
|
||||
|
||||
# Überprüfe, ob der Benutzer der Autor ist oder Admin-Rechte hat
|
||||
if post.user_id != current_user.id and current_user.role != 'admin':
|
||||
flash('Du hast keine Berechtigung, diesen Beitrag zu bearbeiten.', 'error')
|
||||
return redirect(url_for('forum_post', post_id=post.parent_id or post.id))
|
||||
|
||||
if request.method == 'POST':
|
||||
title = request.form.get('title')
|
||||
content = request.form.get('content')
|
||||
|
||||
if not title or not content:
|
||||
flash('Bitte fülle alle Pflichtfelder aus.', 'error')
|
||||
return redirect(url_for('edit_post', post_id=post_id))
|
||||
|
||||
# Aktualisiere den Beitrag
|
||||
post.title = title
|
||||
post.content = content
|
||||
post.updated_at = datetime.utcnow()
|
||||
db.session.commit()
|
||||
|
||||
flash('Dein Beitrag wurde erfolgreich aktualisiert.', 'success')
|
||||
return redirect(url_for('forum_post', post_id=post.parent_id or post.id))
|
||||
|
||||
return render_template('community/edit_post.html', post=post)
|
||||
|
||||
@app.route('/community/delete-post/<int:post_id>', methods=['POST'])
|
||||
@login_required
|
||||
def delete_post(post_id):
|
||||
"""Löscht einen Beitrag"""
|
||||
post = ForumPost.query.get_or_404(post_id)
|
||||
|
||||
# Überprüfe, ob der Benutzer der Autor ist oder Admin-Rechte hat
|
||||
if post.user_id != current_user.id and current_user.role != 'admin':
|
||||
flash('Du hast keine Berechtigung, diesen Beitrag zu löschen.', 'error')
|
||||
return redirect(url_for('forum_post', post_id=post.parent_id or post.id))
|
||||
|
||||
# Bestimme, wohin nach dem Löschen weitergeleitet wird
|
||||
if post.parent_id:
|
||||
redirect_url = url_for('forum_post', post_id=post.parent_id)
|
||||
else:
|
||||
redirect_url = url_for('forum_category', category_id=post.category_id)
|
||||
|
||||
# Lösche den Beitrag und seine Antworten
|
||||
if not post.parent_id: # Wenn es ein Hauptbeitrag ist, lösche auch alle Antworten
|
||||
ForumPost.query.filter_by(parent_id=post_id).delete()
|
||||
|
||||
db.session.delete(post)
|
||||
db.session.commit()
|
||||
|
||||
flash('Der Beitrag wurde erfolgreich gelöscht.', 'success')
|
||||
return redirect(redirect_url)
|
||||
|
||||
@app.route('/community/toggle-pin/<int:post_id>', methods=['POST'])
|
||||
@login_required
|
||||
def toggle_pin_post(post_id):
|
||||
"""Fixiert oder löst einen Beitrag von der Fixierung"""
|
||||
# Nur Admins und Moderatoren können Beiträge fixieren
|
||||
if current_user.role not in ['admin', 'moderator']:
|
||||
flash('Du hast keine Berechtigung, Beiträge zu fixieren.', 'error')
|
||||
return redirect(url_for('forum_post', post_id=post_id))
|
||||
|
||||
post = ForumPost.query.get_or_404(post_id)
|
||||
|
||||
# Nur Hauptbeiträge können fixiert werden
|
||||
if post.parent_id:
|
||||
flash('Nur Hauptbeiträge können fixiert werden.', 'error')
|
||||
return redirect(url_for('forum_post', post_id=post.parent_id))
|
||||
|
||||
# Ändere den Status
|
||||
post.is_pinned = not post.is_pinned
|
||||
db.session.commit()
|
||||
|
||||
status = 'fixiert' if post.is_pinned else 'nicht mehr fixiert'
|
||||
flash(f'Der Beitrag ist jetzt {status}.', 'success')
|
||||
return redirect(url_for('forum_post', post_id=post_id))
|
||||
|
||||
@app.route('/community/toggle-lock/<int:post_id>', methods=['POST'])
|
||||
@login_required
|
||||
def toggle_lock_post(post_id):
|
||||
"""Sperrt oder entsperrt einen Beitrag für weitere Antworten"""
|
||||
# Nur Admins und Moderatoren können Beiträge sperren
|
||||
if current_user.role not in ['admin', 'moderator']:
|
||||
flash('Du hast keine Berechtigung, Beiträge zu sperren.', 'error')
|
||||
return redirect(url_for('forum_post', post_id=post_id))
|
||||
|
||||
post = ForumPost.query.get_or_404(post_id)
|
||||
|
||||
# Nur Hauptbeiträge können gesperrt werden
|
||||
if post.parent_id:
|
||||
flash('Nur Hauptbeiträge können gesperrt werden.', 'error')
|
||||
return redirect(url_for('forum_post', post_id=post.parent_id))
|
||||
|
||||
# Ändere den Status
|
||||
post.is_locked = not post.is_locked
|
||||
db.session.commit()
|
||||
|
||||
status = 'gesperrt' if post.is_locked else 'entsperrt'
|
||||
flash(f'Der Beitrag ist jetzt {status}.', 'success')
|
||||
return redirect(url_for('forum_post', post_id=post_id))
|
||||
|
||||
# Fehlerbehandlung
|
||||
@app.errorhandler(404)
|
||||
def not_found(e):
|
||||
|
||||
Reference in New Issue
Block a user