#!/usr/bin/env python # -*- coding: utf-8 -*- from flask_sqlalchemy import SQLAlchemy from flask_login import UserMixin from datetime import datetime from werkzeug.security import generate_password_hash, check_password_hash from enum import Enum import uuid as uuid_pkg import os db = SQLAlchemy() # Beziehungstypen für Gedankenverknüpfungen class RelationType(Enum): SUPPORTS = "stützt" CONTRADICTS = "widerspricht" BUILDS_UPON = "baut auf auf" GENERALIZES = "verallgemeinert" SPECIFIES = "spezifiziert" INSPIRES = "inspiriert" # Beziehungstabelle für viele-zu-viele Beziehung zwischen MindMapNodes node_relationship = db.Table('node_relationship', db.Column('parent_id', db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True), db.Column('child_id', db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True) ) # Beziehungstabelle für öffentliche Knoten und Gedanken node_thought_association = db.Table('node_thought_association', db.Column('node_id', db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True), db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True) ) # Beziehungstabelle für Benutzer-spezifische Mindmap-Knoten und Gedanken user_mindmap_thought_association = db.Table('user_mindmap_thought_association', db.Column('user_mindmap_id', db.Integer, db.ForeignKey('user_mindmap.id'), primary_key=True), db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True) ) # Beziehungstabelle für Benutzer-Bookmarks von Gedanken user_thought_bookmark = db.Table('user_thought_bookmark', db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True), db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True), db.Column('created_at', db.DateTime, default=datetime.utcnow) ) # Beziehungstabelle für Benutzer-Freundschaften user_friendships = db.Table('user_friendships', db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True), db.Column('friend_id', db.Integer, db.ForeignKey('user.id'), primary_key=True), db.Column('created_at', db.DateTime, default=datetime.utcnow), db.Column('status', db.String(20), default='pending') # pending, accepted, blocked ) # Beziehungstabelle für Benutzer-Follows user_follows = db.Table('user_follows', db.Column('follower_id', db.Integer, db.ForeignKey('user.id'), primary_key=True), db.Column('followed_id', db.Integer, db.ForeignKey('user.id'), primary_key=True), db.Column('created_at', db.DateTime, default=datetime.utcnow) ) # Beziehungstabelle für Post-Likes post_likes = db.Table('post_likes', db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True), db.Column('post_id', db.Integer, db.ForeignKey('social_post.id'), primary_key=True), db.Column('created_at', db.DateTime, default=datetime.utcnow) ) # Beziehungstabelle für Comment-Likes comment_likes = db.Table('comment_likes', db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True), db.Column('comment_id', db.Integer, db.ForeignKey('social_comment.id'), primary_key=True), db.Column('created_at', db.DateTime, default=datetime.utcnow) ) class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password = db.Column(db.String(512), nullable=False) 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 # Social Network Felder display_name = db.Column(db.String(100), nullable=True) # Anzeigename birth_date = db.Column(db.Date, nullable=True) # Geburtsdatum gender = db.Column(db.String(20), nullable=True) # Geschlecht phone = db.Column(db.String(20), nullable=True) # Telefonnummer is_verified = db.Column(db.Boolean, default=False) # Verifizierter Account is_private = db.Column(db.Boolean, default=False) # Privater Account follower_count = db.Column(db.Integer, default=0) # Follower-Anzahl following_count = db.Column(db.Integer, default=0) # Following-Anzahl post_count = db.Column(db.Integer, default=0) # Post-Anzahl online_status = db.Column(db.String(20), default='offline') # online, offline, away last_seen = db.Column(db.DateTime, nullable=True) # Zuletzt gesehen # Beziehungen 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')) # Social Network Beziehungen posts = db.relationship('SocialPost', backref='author', lazy=True, cascade="all, delete-orphan") comments = db.relationship('SocialComment', backref='author', lazy=True, cascade="all, delete-orphan") notifications = db.relationship('Notification', foreign_keys='Notification.user_id', backref='user', lazy=True, cascade="all, delete-orphan") # Freundschaften (bidirektional) friends = db.relationship( 'User', secondary=user_friendships, primaryjoin=id == user_friendships.c.user_id, secondaryjoin=id == user_friendships.c.friend_id, backref='friend_of', lazy='dynamic' ) # Following/Followers following = db.relationship( 'User', secondary=user_follows, primaryjoin=id == user_follows.c.follower_id, secondaryjoin=id == user_follows.c.followed_id, backref=db.backref('followers', lazy='dynamic'), lazy='dynamic' ) # Liked Posts und Comments liked_posts = db.relationship('SocialPost', secondary=post_likes, backref=db.backref('liked_by', lazy='dynamic'), lazy='dynamic') liked_comments = db.relationship('SocialComment', secondary=comment_likes, backref=db.backref('liked_by', lazy='dynamic'), lazy='dynamic') def __repr__(self): return f'' def set_password(self, password): self.password = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password, password) @property def is_admin(self): return self.role == 'admin' @is_admin.setter def is_admin(self, value): self.role = 'admin' if value else 'user' # Social Network Methoden def follow(self, user): """Folgt einem anderen Benutzer""" if not self.is_following(user): self.following.append(user) user.follower_count += 1 user.following_count += 1 # Notification erstellen notification = Notification( user_id=user.id, type='follow', message=f'{self.username} folgt dir jetzt', related_user_id=self.id ) db.session.add(notification) def unfollow(self, user): """Entfolgt einem Benutzer""" if self.is_following(user): self.following.remove(user) user.follower_count -= 1 user.following_count -= 1 def is_following(self, user): """Prüft ob der Benutzer einem anderen folgt""" return self.following.filter(user_follows.c.followed_id == user.id).count() > 0 def get_feed_posts(self, limit=20): """Holt Posts für den Feed (von gefolgten Benutzern)""" # Hole alle User-IDs von Benutzern, denen ich folge + meine eigene followed_user_ids = [user.id for user in self.following] all_user_ids = followed_user_ids + [self.id] # Hole Posts von diesen Benutzern return SocialPost.query.filter( SocialPost.user_id.in_(all_user_ids) ).order_by(SocialPost.created_at.desc()).limit(limit) class Category(db.Model): """Wissenschaftliche Kategorien für die Gliederung der öffentlichen Mindmap""" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True, nullable=False) description = db.Column(db.Text) color_code = db.Column(db.String(7)) # Hex color icon = db.Column(db.String(50)) parent_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=True) # Beziehungen children = db.relationship('Category', backref=db.backref('parent', remote_side=[id])) nodes = db.relationship('MindMapNode', backref='category', lazy=True) def __repr__(self): return f'' class MindMapNode(db.Model): """Öffentliche Mindmap-Knoten, die für alle Benutzer sichtbar sind""" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) description = db.Column(db.Text) color_code = db.Column(db.String(7)) icon = db.Column(db.String(50)) is_public = db.Column(db.Boolean, default=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) created_by_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=True) __table_args__ = {'extend_existing': True} # Beziehungen für Baumstruktur (mehrere Eltern möglich) parents = db.relationship( 'MindMapNode', secondary=node_relationship, primaryjoin=(node_relationship.c.child_id == id), secondaryjoin=(node_relationship.c.parent_id == id), backref=db.backref('children', lazy='dynamic'), lazy='dynamic' ) # Beziehungen zu Gedanken thoughts = db.relationship('Thought', secondary=node_thought_association, backref=db.backref('nodes', lazy='dynamic')) # Beziehung zum Ersteller created_by = db.relationship('User', backref='created_nodes') def __repr__(self): return f'' def to_dict(self): return { 'id': self.id, 'name': self.name, 'description': self.description, 'color_code': self.color_code, 'icon': self.icon, 'category_id': self.category_id, 'created_at': self.created_at.isoformat() if self.created_at else None } class UserMindmap(db.Model): """Benutzerspezifische Mindmap, die vom Benutzer personalisierbar ist""" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) description = db.Column(db.Text) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) last_modified = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) is_private = db.Column(db.Boolean, default=True) # Beziehungen zu öffentlichen Knoten public_nodes = db.relationship('MindMapNode', secondary='user_mindmap_node', backref=db.backref('in_user_mindmaps', lazy='dynamic')) # Beziehungen zu Gedanken thoughts = db.relationship('Thought', secondary=user_mindmap_thought_association, backref=db.backref('in_user_mindmaps', lazy='dynamic')) # Notizen zu dieser Mindmap notes = db.relationship('MindmapNote', backref='mindmap', lazy=True) # Beziehungstabelle für benutzerorientierte Mindmaps und öffentliche Knoten class UserMindmapNode(db.Model): """Speichert die Beziehung zwischen Benutzer-Mindmaps und öffentlichen Knoten inkl. Position""" user_mindmap_id = db.Column(db.Integer, db.ForeignKey('user_mindmap.id'), primary_key=True) node_id = db.Column(db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True) x_position = db.Column(db.Float, default=0) # Position X auf der Mindmap y_position = db.Column(db.Float, default=0) # Position Y auf der Mindmap scale = db.Column(db.Float, default=1.0) # Größe des Knotens added_at = db.Column(db.DateTime, default=datetime.utcnow) class MindmapNote(db.Model): """Private Notizen der Benutzer zu ihrer Mindmap""" id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) mindmap_id = db.Column(db.Integer, db.ForeignKey('user_mindmap.id'), nullable=False) node_id = db.Column(db.Integer, db.ForeignKey('mind_map_node.id'), nullable=True) thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=True) content = db.Column(db.Text, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) last_modified = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) color_code = db.Column(db.String(7), default="#FFF59D") # Farbe der Notiz class Thought(db.Model): """Gedanken und Inhalte, die in der Mindmap verknüpft werden können""" id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(200), nullable=False) content = db.Column(db.Text, nullable=False) abstract = db.Column(db.Text) keywords = db.Column(db.String(500)) color_code = db.Column(db.String(7)) # Hex color code source_type = db.Column(db.String(50)) # PDF, Markdown, Text etc. branch = db.Column(db.String(100), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) last_modified = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Beziehungen comments = db.relationship('Comment', backref='thought', lazy=True, cascade="all, delete-orphan") ratings = db.relationship('ThoughtRating', backref='thought', lazy=True) outgoing_relations = db.relationship( 'ThoughtRelation', foreign_keys='ThoughtRelation.source_id', backref='source_thought', lazy=True ) incoming_relations = db.relationship( 'ThoughtRelation', foreign_keys='ThoughtRelation.target_id', backref='target_thought', lazy=True ) @property def average_rating(self): if not self.ratings: return 0 return sum(r.relevance_score for r in self.ratings) / len(self.ratings) class ThoughtRelation(db.Model): """Beziehungen zwischen Gedanken""" id = db.Column(db.Integer, primary_key=True) source_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False) target_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False) relation_type = db.Column(db.Enum(RelationType), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) created_by_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) # Beziehung zum Ersteller created_by = db.relationship('User', backref='created_relations') class ThoughtRating(db.Model): """Bewertungen von Gedanken durch Benutzer""" id = db.Column(db.Integer, primary_key=True) thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) relevance_score = db.Column(db.Integer, nullable=False) # 1-5 created_at = db.Column(db.DateTime, default=datetime.utcnow) __table_args__ = ( db.UniqueConstraint('thought_id', 'user_id', name='unique_thought_rating'), ) # Beziehung zum Benutzer user = db.relationship('User', backref='ratings') class Comment(db.Model): """Kommentare zu Gedanken""" id = db.Column(db.Integer, primary_key=True) content = db.Column(db.Text, nullable=False) thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) last_modified = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Thread model class Thread(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(200), nullable=False) description = db.Column(db.Text) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) # Relationships messages = db.relationship('Message', backref='thread', lazy=True, cascade="all, delete-orphan") def __repr__(self): return f'' # Message model class Message(db.Model): id = db.Column(db.Integer, primary_key=True) content = db.Column(db.Text, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) thread_id = db.Column(db.Integer, db.ForeignKey('thread.id'), nullable=False) role = db.Column(db.String(20), default="user") # 'user', 'assistant', 'system' def __repr__(self): return f'' # Project model class Project(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(150), nullable=False) description = db.Column(db.Text) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) category_id = db.Column(db.Integer, db.ForeignKey('category.id')) # Relationships documents = db.relationship('Document', backref='project', lazy=True, cascade="all, delete-orphan") def __repr__(self): return f'' # Document model class Document(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(150), nullable=False) content = db.Column(db.Text) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) project_id = db.Column(db.Integer, db.ForeignKey('project.id'), nullable=False) filename = db.Column(db.String(150), nullable=True) file_path = db.Column(db.String(300), nullable=True) file_type = db.Column(db.String(50), nullable=True) file_size = db.Column(db.Integer, nullable=True) def __repr__(self): return f'' # Forum-Kategorie-Modell - entspricht den Hauptknotenpunkten der Mindmap class ForumCategory(db.Model): id = db.Column(db.Integer, primary_key=True) node_id = db.Column(db.Integer, db.ForeignKey('mind_map_node.id'), nullable=False) title = db.Column(db.String(200), nullable=False) description = db.Column(db.Text) created_at = db.Column(db.DateTime, default=datetime.utcnow) is_active = db.Column(db.Boolean, default=True) # Beziehungen node = db.relationship('MindMapNode', backref='forum_category') posts = db.relationship('ForumPost', backref='category', lazy=True, cascade="all, delete-orphan") def __repr__(self): return f'' # Forum-Beitrag-Modell class ForumPost(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(200), nullable=False) content = db.Column(db.Text, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) category_id = db.Column(db.Integer, db.ForeignKey('forum_category.id'), nullable=False) parent_id = db.Column(db.Integer, db.ForeignKey('forum_post.id'), nullable=True) is_pinned = db.Column(db.Boolean, default=False) is_locked = db.Column(db.Boolean, default=False) view_count = db.Column(db.Integer, default=0) # Beziehungen author = db.relationship('User', backref='forum_posts') replies = db.relationship('ForumPost', backref=db.backref('parent', remote_side=[id]), lazy=True) def __repr__(self): return f'' # Berechtigungstypen für Mindmap-Freigaben class PermissionType(Enum): READ = "Nur-Lesen" EDIT = "Bearbeiten" ADMIN = "Administrator" # Freigabemodell für Mindmaps class MindmapShare(db.Model): """Speichert Informationen über freigegebene Mindmaps und Berechtigungen""" id = db.Column(db.Integer, primary_key=True) mindmap_id = db.Column(db.Integer, db.ForeignKey('user_mindmap.id'), nullable=False) shared_by_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) shared_with_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) permission_type = db.Column(db.Enum(PermissionType), nullable=False, default=PermissionType.READ) created_at = db.Column(db.DateTime, default=datetime.utcnow) last_accessed = db.Column(db.DateTime, nullable=True) # Beziehungen mindmap = db.relationship('UserMindmap', backref=db.backref('shares', lazy='dynamic')) shared_by = db.relationship('User', foreign_keys=[shared_by_id], backref=db.backref('shared_mindmaps', lazy='dynamic')) shared_with = db.relationship('User', foreign_keys=[shared_with_id], backref=db.backref('accessible_mindmaps', lazy='dynamic')) __table_args__ = ( db.UniqueConstraint('mindmap_id', 'shared_with_id', name='unique_mindmap_share'), ) def __repr__(self): return f'' class SocialPost(db.Model): """Posts im Social Network""" id = db.Column(db.Integer, primary_key=True) content = db.Column(db.Text, nullable=False) image_url = db.Column(db.String(500), nullable=True) # Bild-URL video_url = db.Column(db.String(500), nullable=True) # Video-URL link_url = db.Column(db.String(500), nullable=True) # Link-URL link_title = db.Column(db.String(200), nullable=True) # Link-Titel link_description = db.Column(db.Text, nullable=True) # Link-Beschreibung post_type = db.Column(db.String(20), default='text') # text, image, video, link, thought_share visibility = db.Column(db.String(20), default='public') # public, friends, private is_pinned = db.Column(db.Boolean, default=False) like_count = db.Column(db.Integer, default=0) comment_count = db.Column(db.Integer, default=0) share_count = db.Column(db.Integer, default=0) view_count = db.Column(db.Integer, default=0) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) # Verknüpfung zu Gedanken (falls der Post einen Gedanken teilt) shared_thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=True) shared_thought = db.relationship('Thought', backref='shared_in_posts') # Verknüpfung zu Mindmap-Knoten shared_node_id = db.Column(db.Integer, db.ForeignKey('mind_map_node.id'), nullable=True) shared_node = db.relationship('MindMapNode', backref='shared_in_posts') # Kommentare zu diesem Post comments = db.relationship('SocialComment', backref='post', lazy=True, cascade="all, delete-orphan") def __repr__(self): return f'' def to_dict(self): return { 'id': self.id, 'content': self.content, 'post_type': self.post_type, 'image_url': self.image_url, 'video_url': self.video_url, 'link_url': self.link_url, 'link_title': self.link_title, 'link_description': self.link_description, 'visibility': self.visibility, 'is_pinned': self.is_pinned, 'like_count': self.like_count, 'comment_count': self.comment_count, 'share_count': self.share_count, 'view_count': self.view_count, 'created_at': self.created_at.isoformat(), 'updated_at': self.updated_at.isoformat(), 'author': { 'id': self.author.id, 'username': self.author.username, 'display_name': self.author.display_name or self.author.username, 'avatar': self.author.avatar, 'is_verified': self.author.is_verified }, 'shared_thought': self.shared_thought.to_dict() if self.shared_thought else None, 'shared_node': self.shared_node.to_dict() if self.shared_node else None } class SocialComment(db.Model): """Kommentare zu Posts""" id = db.Column(db.Integer, primary_key=True) content = db.Column(db.Text, nullable=False) like_count = db.Column(db.Integer, default=0) reply_count = db.Column(db.Integer, default=0) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) post_id = db.Column(db.Integer, db.ForeignKey('social_post.id'), nullable=False) parent_id = db.Column(db.Integer, db.ForeignKey('social_comment.id'), nullable=True) # Antworten auf diesen Kommentar replies = db.relationship('SocialComment', backref=db.backref('parent', remote_side=[id]), lazy=True) def __repr__(self): return f'' def to_dict(self): return { 'id': self.id, 'content': self.content, 'like_count': self.like_count, 'reply_count': self.reply_count, 'created_at': self.created_at.isoformat(), 'updated_at': self.updated_at.isoformat(), 'author': { 'id': self.author.id, 'username': self.author.username, 'display_name': self.author.display_name or self.author.username, 'avatar': self.author.avatar, 'is_verified': self.author.is_verified }, 'parent_id': self.parent_id } class Notification(db.Model): """Benachrichtigungen für Benutzer""" id = db.Column(db.Integer, primary_key=True) type = db.Column(db.String(50), nullable=False) # follow, like, comment, mention, friend_request, etc. message = db.Column(db.String(500), nullable=False) is_read = db.Column(db.Boolean, default=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) # Verknüpfungen zu anderen Entitäten related_user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) related_post_id = db.Column(db.Integer, db.ForeignKey('social_post.id'), nullable=True) related_comment_id = db.Column(db.Integer, db.ForeignKey('social_comment.id'), nullable=True) related_thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=True) # Beziehungen related_user = db.relationship('User', foreign_keys=[related_user_id]) related_post = db.relationship('SocialPost', foreign_keys=[related_post_id]) related_comment = db.relationship('SocialComment', foreign_keys=[related_comment_id]) related_thought = db.relationship('Thought', foreign_keys=[related_thought_id]) def __repr__(self): return f'' def to_dict(self): return { 'id': self.id, 'type': self.type, 'message': self.message, 'is_read': self.is_read, 'created_at': self.created_at.isoformat(), 'related_user': self.related_user.username if self.related_user else None, 'related_post_id': self.related_post_id, 'related_comment_id': self.related_comment_id, 'related_thought_id': self.related_thought_id } class UserSettings(db.Model): """Benutzereinstellungen""" id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False, unique=True) # Datenschutz-Einstellungen profile_visibility = db.Column(db.String(20), default='public') # public, friends, private show_email = db.Column(db.Boolean, default=False) show_birth_date = db.Column(db.Boolean, default=False) show_location = db.Column(db.Boolean, default=True) allow_friend_requests = db.Column(db.Boolean, default=True) allow_messages = db.Column(db.String(20), default='everyone') # everyone, friends, none # Benachrichtigungs-Einstellungen email_notifications = db.Column(db.Boolean, default=True) push_notifications = db.Column(db.Boolean, default=True) notify_on_follow = db.Column(db.Boolean, default=True) notify_on_like = db.Column(db.Boolean, default=True) notify_on_comment = db.Column(db.Boolean, default=True) notify_on_mention = db.Column(db.Boolean, default=True) notify_on_friend_request = db.Column(db.Boolean, default=True) # Interface-Einstellungen dark_mode = db.Column(db.Boolean, default=False) language = db.Column(db.String(10), default='de') # Beziehung user = db.relationship('User', backref=db.backref('settings', uselist=False)) def __repr__(self): return f'' class Activity(db.Model): """Aktivitätsprotokoll für Benutzer""" id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) action = db.Column(db.String(100), nullable=False) # login, logout, post_created, thought_shared, etc. description = db.Column(db.String(500), nullable=True) ip_address = db.Column(db.String(45), nullable=True) # IPv4/IPv6 user_agent = db.Column(db.String(500), nullable=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) # Verknüpfungen zu anderen Entitäten related_post_id = db.Column(db.Integer, db.ForeignKey('social_post.id'), nullable=True) related_thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=True) related_mindmap_id = db.Column(db.Integer, db.ForeignKey('user_mindmap.id'), nullable=True) # Beziehungen user = db.relationship('User', backref='activities') related_post = db.relationship('SocialPost') related_thought = db.relationship('Thought') related_mindmap = db.relationship('UserMindmap') def __repr__(self): return f''