from flask import current_app from flask_login import UserMixin from itsdangerous import TimedJSONWebSignatureSerializer from werkzeug.security import generate_password_hash, check_password_hash from app import db, login_manager @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) users = db.relationship('User', backref='role', lazy='dynamic') def __repr__(self): return f'' class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(64), unique=True, index=True) username = db.Column(db.String(64), unique=True, index=True) role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) password_hash = db.Column(db.String(128)) confirmed = db.Column(db.Boolean, default=False) def __repr__(self): return f'' @property def password(self): raise AttributeError('password is not a readable attribute') @password.setter def password(self, password): self.password_hash = generate_password_hash(password, method='pbkdf2:sha256', salt_length=20) def verify_password(self, password): return check_password_hash(self.password_hash, password) def generate_confirmation_token(self, expiration=3600): s = TimedJSONWebSignatureSerializer(current_app, expiration) return s.dumps({'confirm': self.id}).decode('utf-8') def confirm(self, token): s = TimedJSONWebSignatureSerializer(current_app.config['SECRET_KEY']) try: data = s.loads(token.encode('utf-8')) except: return False if data.get('confirm') != self.id: return False self.confirmed = True db.session.add(self) db.session.commit() return True class ComicMeta(db.Model): __tablename__ = 'comicmeta' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(256), unique=True, index=True) issue = db.Column(db.Integer, nullable=True, index=True) category = db.Column(db.String(128), index=True, nullable=True) previous_issue = db.Column(db.String(256), nullable=True) next_issue = db.Column(db.String(256), nullable=True) cover_path = db.Column(db.String(256)) archive_path = db.Column(db.String(256))