from datetime import datetime, timezone from flask_login import UserMixin from werkzeug.security import check_password_hash, generate_password_hash from app import db class User(UserMixin, db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False, index=True) email = db.Column(db.String(120), unique=True, nullable=False, index=True) password_hash = db.Column(db.String(256), nullable=False) is_admin = db.Column(db.Boolean, nullable=False, default=False) is_active = db.Column(db.Boolean, nullable=False, default=True) created_at = db.Column( db.DateTime, nullable=False, default=lambda: datetime.now(timezone.utc), ) photos = db.relationship("Photo", backref="owner", lazy="dynamic") 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) @property def photo_count(self): return self.photos.count() @property def total_size(self): from sqlalchemy import func result = db.session.query(func.coalesce(func.sum(Photo.file_size), 0)).filter( Photo.user_id == self.id ).scalar() return int(result or 0) class Photo(db.Model): __tablename__ = "photos" id = db.Column(db.Integer, primary_key=True) filename = db.Column(db.String(255), nullable=False) original_name = db.Column(db.String(255), nullable=False) file_size = db.Column(db.Integer, nullable=False, default=0) mime_type = db.Column(db.String(100), nullable=False, default="image/jpeg") user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True, index=True) created_at = db.Column( db.DateTime, nullable=False, default=lambda: datetime.now(timezone.utc), ) @property def url(self): return f"/uploads/{self.filename}" @property def size_human(self): size = self.file_size for unit in ("Б", "КБ", "МБ", "ГБ"): if size < 1024: return f"{size:.0f} {unit}" if unit == "Б" else f"{size:.1f} {unit}" size /= 1024 return f"{size:.1f} ТБ"