import os from datetime import datetime, timezone from typing import Optional import sqlalchemy as sa import sqlalchemy.orm as so from werkzeug.security import generate_password_hash, check_password_hash import pydenticon, hashlib, base64 from app import db, login from flask_login import UserMixin class User(UserMixin, db.Model): id: so.Mapped[int] = so.mapped_column(primary_key=True) username: so.Mapped[str] = so.mapped_column(sa.String(64), index=True, unique=True) email: so.Mapped[str] = so.mapped_column(sa.String(120), index=True, unique=True) password_hash: so.Mapped[Optional[str]] = so.mapped_column(sa.String(256)) posts: so.WriteOnlyMapped['Post'] = so.relationship(back_populates='author') about_me: so.Mapped[Optional[str]] = so.mapped_column(sa.String(140)) last_seen: so.Mapped[Optional[datetime]] = so.mapped_column(default=lambda: datetime.now(timezone.utc)) 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 gen_avatar(self, write_png=True): foreground = [ "rgb(45,79,255)", "rgb(254,180,44)", "rgb(226,121,234)", "rgb(30,179,253)", "rgb(232,77,65)", "rgb(49,203,115)", "rgb(141,69,170)" ] background = "rgb(22,22,22)" digest = hashlib.md5(self.email.lower().encode('utf-8')).hexdigest() basedir = os.path.abspath(os.path.dirname(__file__)) pngloc = os.path.join(basedir, 'usercontent', 'identicon', str(digest) + '.png') icongen = pydenticon.Generator(5, 5, digest=hashlib.md5, foreground=foreground, background=background) pngicon = icongen.generate(self.email, 120, 120, padding=(10, 10, 10, 10), inverted=False, output_format="png") if write_png: pngfile = open(pngloc, "wb") pngfile.write(pngicon) pngfile.close() else: return str(base64.b64encode(pngicon))[2:-1] def avatar_path(self): digest = hashlib.md5(self.email.lower().encode('utf-8')).hexdigest() basedir = os.path.abspath(os.path.dirname(__file__)) pngloc = os.path.join(basedir, 'usercontent', 'identicon', digest + '.png') return pngloc def __repr__(self): return ''.format(self.username) class Post(db.Model): id: so.Mapped[int] = so.mapped_column(primary_key=True) body: so.Mapped[str] = so.mapped_column(sa.String(140)) timestamp: so.Mapped[datetime] = so.mapped_column(index=True, default=lambda: datetime.now(timezone.utc)) user_id: so.Mapped[int] = so.mapped_column(sa.ForeignKey(User.id), index=True) author: so.Mapped[User] = so.relationship(back_populates='posts') def __repr__(self): return ''.format(self.body) @login.user_loader def load_user(id): return db.session.get(User, int(id))