class Inventory(db.Model): __tablename__ = "inventories" id = db.Column(UUID(as_uuid=True), primary_key=True) book = db.Column(db.String(32), nullable=False) author = db.Column(db.String(32), nullable=True) url = db.Column(db.String(128), unique=True, nullable=False) added_date = db.Column(db.DateTime(), default=datetime.utcnow) readings = db.relationship("Reading", back_populates="book") vacant_date = db.Column(db.DateTime(), default=datetime.utcnow) user_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id')) user = db.relationship('User', back_populates="added_books") def __init__(self, book, author, url): self.id = uuid.uuid4() self.author = author self.book = book self.url = url def __repr__(self): if self.user is not None: return "<<%r>>(Added by: %s): %r" % (self.book, self.user.username, self.url) else: return "<<%r>>: %r" % (self.book, self.url) @staticmethod def exists(url): return Inventory.query.filter_by(url=url).count() > 0 @staticmethod def get_book(book_name): return Inventory.query.filter_by(book=book_name).first()
class Role(db.Model): id = db.Column(db.String(32), default=lambda: str(uuid4()).replace('-', ''), primary_key=True) name = db.Column(db.String(32), unique=True, nullable=False, index=True) permits = db.relationship('Permission', secondary=authority, backref=db.backref('roles', lazy='dynamic')) users = db.relationship('Users', backref='role', lazy='dynamic') def generate_access_key(self): s = Serializer(app.config['SECRET_KEY'], expires_in=app.config['SECURITY']['expiration']) return s.dumps({'id': self.id}).decode('utf-8') @staticmethod def verify_access_authority(page, access_key): s = Serializer(app.config['SECRET_KEY']) try: role_id = s.loads(access_key.encode('utf-8'))['id'] role = Role.query.get(role_id) permissions = role.permits permits = [each.permit for each in permissions] return True if page in permits else False except SignatureExpired and BadSignature: return False def __init__(self, name): self.name = name def __repr__(self): return "用户 <%s>" % self.name
class User(UserMixin, db.Model): __tablename__ = "users" id = db.Column(UUID(as_uuid=True), primary_key=True) username = db.Column(db.String(64), unique=True) password_hash = db.Column(db.String(128)) admin = db.Column(db.BOOLEAN(), default=False, nullable=False) books = db.relationship('Reading', backref='books', lazy=True) added_books = db.relationship("Inventory", back_populates="user") def __init__(self, username): self.username = username self.id = self.get_id() def __repr__(self): return "<User: %r>" % self.username @property def password(self): return self.password_hash @password.setter def password(self, password): self.password_hash = generate_password_hash(password, SECURITY["iterations"]).decode("utf-8") def verify_password(self, password): if self.password_hash is None: return False return check_password_hash(self.password_hash, password) def get_id(self): if self.id is not None: return self.id else: return uuid.uuid4() @staticmethod def find(username): return User.query.filter_by(username=username).first() @staticmethod def get(user_id): try: res = User.query.get(user_id) except OperationalError: res = User.query.get(user_id) return res
class UserStatus(db.Model): id = db.Column(db.String(32), default=lambda: str(uuid4()).replace('-', ''), primary_key=True) state = db.Column(db.String(16), unique=True, nullable=False) user = db.relationship('Users', backref='state', lazy='dynamic') def __repr__(self): return "帐号状态: <%s> " % self.state
class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(20), unique=True, nullable=False) email = db.Column(db.String(80), unique=True, nullable=False) password = db.Column(db.String(64), nullable=False) routes = db.relationship('Routes', backref='author', lazy=True) def __repr__(self): return f'User {self.id}: ({self.username}, {self.email})'
class Reading(db.Model): __tablename__ = "reading" id = db.Column(UUID(as_uuid=True), primary_key=True) book_id = db.Column(UUID(as_uuid=True), db.ForeignKey('inventories.id')) book = db.relationship('Inventory', back_populates="readings") progress = db.Column(db.Integer(), nullable=False) user_id = db.Column(UUID(as_uuid=True), db.ForeignKey("users.id"), nullable=False) chapter_id = db.Column(UUID(as_uuid=True), db.ForeignKey("chapters.id"), nullable=False) def __init__(self, book, user_id): chapter = Chapters.get_first_chapter(book.book) self.book = book self.id = uuid.uuid4() self.user_id = user_id self.chapter_id, self.progress = chapter.id, chapter.index def __repr__(self): return "<User: %r>: 《%r》" % (self.user_id, self.book.book) def get_progress(self): chapter = Chapters.get(self.chapter_id) remains = Chapters.query.filter( Chapters.book == chapter.book, Chapters.index > chapter.index).count() return "%s_%s_%s_%s_%s" % (self.book.book, chapter.chapter, chapter.title, chapter.id, remains) @staticmethod def exists(book, user_id): return Reading.query.filter(Reading.book == book, Reading.user_id == user_id).count() > 0
class Chapters(db.Model): __tablename__ = "chapters" id = db.Column(UUID(as_uuid=True), primary_key=True) url = db.Column(db.String(128), unique=True, nullable=False) book = db.Column(db.String(32), nullable=False) chapter = db.Column(db.String(32), nullable=False) title = db.Column(db.String(32), nullable=False) index = db.Column(db.Integer(), nullable=False) content = db.Column(db.Text(), nullable=False) readers = db.relationship("Reading", backref="chapter", lazy=True) def __init__(self, url, book, chapter, title, index, content): self.id = uuid.uuid4() self.url = url self.book = book self.chapter = chapter self.title = title self.index = index self.content = content def __repr__(self): return "<<%r>>: %r" % (self.book, self.chapter) @staticmethod def get_books(): books = [each.book for each in Chapters.query.distinct(Chapters.book)] last_chapters = [ Chapters.query.filter_by(book=book).order_by( Chapters.index.desc()).first() for book in books ] return [ "%s_%s_%s" % (chapter.book, chapter.chapter, chapter.title) for chapter in last_chapters ] @staticmethod def get_first_chapter(book_name): chapter = Chapters.query.filter_by(book=book_name).order_by( Chapters.index).first() return chapter @staticmethod def get_last_chapter(book_name): chapter = Chapters.query.filter_by(book=book_name).order_by( Chapters.index.desc()).first() return chapter @staticmethod def get(chapter_id): return Chapters.query.get(chapter_id) @staticmethod def download(book_name): chapters = Chapters.query.filter_by(book=book_name).order_by( Chapters.index).all() doc = "" doc += "#%s\n\n" % book_name for c in chapters: doc += "\n\n##%s %s\n\n" % (c.chapter, c.title) doc += c.content return doc def menu(self): return "%s\t%s_%s" % (self.chapter, self.title, self.id)
class Users(db.Model): id = db.Column(db.Integer, primary_key=True) role_id = db.Column( db.String(32), db.ForeignKey('role.id'), index=True, default=lambda: Role.query.filter_by(name='user').first().id) state_id = db.Column( db.String(32), db.ForeignKey('user_status.id'), default=lambda: UserStatus.query.filter_by(state='reserve').first().id) email = db.Column(db.String(32), unique=True) username = db.Column(db.String(16)) password = db.Column(db.String(128)) finger_print = db.Column( db.String(28), default=lambda: ''.join(sample(ascii_letters + digits, 28)), nullable=False) keeper = db.relationship('Keeper', backref='owner', lazy='dynamic') keeper_key = db.Column(db.String(64)) keeper_active = db.Column(db.Boolean, default=False) keeper_length = db.Column(db.SmallInteger, default=12) register_date = db.Column(db.DateTime, default=lambda: datetime.utcnow()) last_signin_date = db.Column(db.DateTime, default=lambda: datetime.utcnow()) @staticmethod def hash_password(password): return crypt.generate_password_hash( password, app.config['SECURITY']['iterations']) @staticmethod def pad(original): data = str(original).encode() padding_length = AES.block_size - len(data) % AES.block_size return original + padding_length * chr(padding_length) @staticmethod def unpad(padded): return padded[:-ord(padded[len(padded) - 1:])] def generate_keeper_key(self, pin): sha = SHA256.new() sha.update(("%s%s" % (self.finger_print, pin)).encode()) return sha.hexdigest() def verify_keeper_key(self, pin): return self.generate_keeper_key(pin) == self.keeper_key def encrypt(self, data, pin, iv): cipher = AES.new("%s%s" % (self.finger_print, pin), AES.MODE_CBC, self.pad(iv)) return "{0}".format(b64encode(cipher.encrypt(self.pad(data))).decode()) def decrypt(self, ciphered, pin, iv): cipher = AES.new("%s%s" % (self.finger_print, pin), AES.MODE_CBC, self.pad(iv)) return self.unpad(cipher.decrypt(b64decode(ciphered))).decode() def verify_password(self, _password): try: return crypt.check_password_hash(self.password, _password) except: return False def generate_auth_token(self): s = Serializer(app.config['SECRET_KEY'], expires_in=app.config['SECURITY']['expiration']) return s.dumps({'id': self.id}).decode('utf-8') @staticmethod def verify_auth_token(token): s = Serializer(app.config['SECRET_KEY']) try: data = s.loads(token.encode('utf-8')) return Users.query.get(data['id']) except SignatureExpired and BadSignature: return None except: return None def user_info(self): return { 'name': self.username, 'access_key': self.role.generate_access_key(), 'keeper_active': self.keeper_active, 'keeper_length': self.keeper_length } def __repr__(self): return '<User %s>' % (self.username)