from flask_sqlalchemy import SQLAlchemy from flask_login import UserMixin from werkzeug.security import generate_password_hash, check_password_hash from datetime import datetime from sqlalchemy.orm import relationship db = SQLAlchemy() # Association table for room members room_members = db.Table('room_members', db.Column('room_id', db.Integer, db.ForeignKey('room.id'), primary_key=True), db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True) ) class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(150), unique=True, nullable=False) last_name = db.Column(db.String(150), nullable=False, default='(You)') email = db.Column(db.String(150), unique=True, nullable=False) password_hash = db.Column(db.String(256)) is_admin = db.Column(db.Boolean, default=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) phone = db.Column(db.String(20)) company = db.Column(db.String(100)) position = db.Column(db.String(100)) notes = db.Column(db.Text) is_active = db.Column(db.Boolean, default=True) profile_picture = db.Column(db.String(255)) preferred_view = db.Column(db.String(10), default='grid', nullable=False) # 'grid' or 'list' room_permissions = relationship('RoomMemberPermission', back_populates='user') def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) def __repr__(self): return f'' class Room(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) description = db.Column(db.Text) created_at = db.Column(db.DateTime, default=datetime.utcnow) created_by = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) # Relationships creator = db.relationship('User', backref='created_rooms', foreign_keys=[created_by]) members = db.relationship('User', secondary=room_members, backref=db.backref('rooms', lazy='dynamic')) member_permissions = relationship('RoomMemberPermission', back_populates='room', cascade='all, delete-orphan') def __repr__(self): return f'' # Association table for room members with permissions class RoomMemberPermission(db.Model): __tablename__ = 'room_member_permissions' room_id = db.Column(db.Integer, db.ForeignKey('room.id'), primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) can_view = db.Column(db.Boolean, default=True, nullable=False) can_download = db.Column(db.Boolean, default=False, nullable=False) can_upload = db.Column(db.Boolean, default=False, nullable=False) can_delete = db.Column(db.Boolean, default=False, nullable=False) can_rename = db.Column(db.Boolean, default=False, nullable=False) can_move = db.Column(db.Boolean, default=False, nullable=False) can_share = db.Column(db.Boolean, default=False, nullable=False) # Relationships user = relationship('User', back_populates='room_permissions') room = relationship('Room', back_populates='member_permissions') class RoomFile(db.Model): __tablename__ = 'room_file' id = db.Column(db.Integer, primary_key=True) room_id = db.Column(db.Integer, db.ForeignKey('room.id'), nullable=False) name = db.Column(db.String(255), nullable=False) path = db.Column(db.String(255), nullable=False, default='') type = db.Column(db.String(10), nullable=False) # 'file' or 'folder' size = db.Column(db.Integer) # in bytes, null for folders modified = db.Column(db.Float) # timestamp uploaded_by = db.Column(db.Integer, db.ForeignKey('user.id')) uploaded_at = db.Column(db.DateTime, default=datetime.utcnow) deleted = db.Column(db.Boolean, default=False) # New field for deleted status deleted_by = db.Column(db.Integer, db.ForeignKey('user.id')) # New field for tracking who deleted the file deleted_at = db.Column(db.DateTime) # New field for tracking when the file was deleted uploader = db.relationship('User', backref='uploaded_files', foreign_keys=[uploaded_by]) deleter = db.relationship('User', backref='deleted_room_files', foreign_keys=[deleted_by]) room = db.relationship('Room', backref='files') starred_by = db.relationship('User', secondary='user_starred_file', backref='starred_files') def __repr__(self): return f'' class UserStarredFile(db.Model): __tablename__ = 'user_starred_file' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) file_id = db.Column(db.Integer, db.ForeignKey('room_file.id'), nullable=False) starred_at = db.Column(db.DateTime, default=datetime.utcnow) # Add unique constraint to prevent duplicate stars __table_args__ = ( db.UniqueConstraint('user_id', 'file_id', name='unique_user_file_star'), ) def __repr__(self): return f'' class TrashedFile(db.Model): __tablename__ = 'trashed_file' id = db.Column(db.Integer, primary_key=True) room_id = db.Column(db.Integer, db.ForeignKey('room.id'), nullable=False) name = db.Column(db.String(255), nullable=False) original_path = db.Column(db.String(255), nullable=False, default='') type = db.Column(db.String(10), nullable=False) # 'file' or 'folder' size = db.Column(db.Integer) # in bytes, null for folders modified = db.Column(db.Float) # timestamp uploaded_by = db.Column(db.Integer, db.ForeignKey('user.id')) uploaded_at = db.Column(db.DateTime, default=datetime.utcnow) deleted_by = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) deleted_at = db.Column(db.DateTime, default=datetime.utcnow) room = db.relationship('Room', backref='trashed_files') uploader = db.relationship('User', foreign_keys=[uploaded_by], backref='uploaded_trashed_files') deleter = db.relationship('User', foreign_keys=[deleted_by], backref='deleted_trashed_files') # Changed from deleted_files to deleted_trashed_files def __repr__(self): return f'' class SiteSettings(db.Model): id = db.Column(db.Integer, primary_key=True) primary_color = db.Column(db.String(7), default='#16767b') # Default from colors.css secondary_color = db.Column(db.String(7), default='#741b5f') # Default from colors.css updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) @classmethod def get_settings(cls): settings = cls.query.first() if not settings: settings = cls() db.session.add(settings) db.session.commit() return settings