class User(db.Model): __tablename__ = 'USER' user_id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(32), index=True) email = db.Column(db.String(64), index=True) password_hash = db.Column(db.String(250)) creation_date = db.Column(db.DateTime(timezone=True), default=func.now()) def as_dict(self): return {c.name: getattr(self, c.name) for c in self.__table__.columns} def hash_password(self, password: str): self.password_hash = pwd_context.hash(password) def verify_password(self, password: str): return pwd_context.verify(password, self.password_hash)
class Comment(Base): __tablename__ = 'COMMENT' id = db.Column(db.Integer, primary_key=True) post_id = db.Column(db.Integer, db.ForeignKey('POST.id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('USER.id'), nullable=False) text = db.Column(db.String(300), nullable=False) created = db.Column(db.DateTime(timezone=True), default=sqlalchemy.sql.func.now(), nullable=False) post = db.relationship('Post', back_populates='comments', lazy=True) user = db.relationship('User') subcomments = db.relationship('SubComment', cascade="all,delete", back_populates='comments', lazy=True, order_by='SubComment.created.desc()') def output(self): output = self.as_dict() output['username'] = self.user.username return output def output_with_permissions(self, auth_user: User): output = self.output() output['subcomments'] = [ subcomment.output_with_permissions(auth_user) for subcomment in self.subcomments ] output['edit_allowed'] = True \ if self.user_id == auth_user.user_id else False return output def save(self, form_data: dict, post: Post, user: User): self.post_id = post.id self.user_id = user.user_id self.text = form_data.get('text') self.user = user db.session.add(self) db.session.commit() return self
class SubComment(Base): __tablename__ = 'SUBCOMMENT' id = db.Column(db.Integer, primary_key=True) comment_id = db.Column(db.Integer, db.ForeignKey('COMMENT.id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('USER.id'), nullable=False) text = db.Column(db.String(300), nullable=False) created = db.Column(db.DateTime(timezone=True), default=sqlalchemy.sql.func.now(), nullable=False) comments = db.relationship('Comment', back_populates='subcomments', lazy=True) user = db.relationship('User') def output(self): output = self.as_dict() output['username'] = self.user.username return output def output_with_permissions(self, auth_user: User): output = self.output() output['edit_allowed'] = True \ if self.user_id == auth_user.user_id else False return output def save(self, form_data: dict, comment: Comment, user: User): self.comment_id = comment.id self.user_id = user.user_id self.text = form_data.get('text') self.user = user db.session.add(self) db.session.commit() return self
class User(Base): __tablename__ = 'USER' id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(64), index=True, unique=True) first_name = db.Column(db.String(32)) last_name = db.Column(db.String(128)) birthday = db.Column(db.Date) username = db.Column(db.String(32), index=True, unique=True) password_hash = db.Column(db.String(250)) profile_image = db.Column(db.String(256)) created = db.Column(db.DateTime(timezone=True), default=sqlalchemy.sql.func.now()) post = db.relationship('Post', cascade="all,delete", back_populates='user', lazy=True) comments = db.relationship('Comment', cascade="all,delete") subwcomments = db.relationship('SubComment', cascade="all,delete") _IGNORE_ATTRS_ON_UPDATE = {'id', 'password_hash', 'created', 'email'} _IGNORE_ATTRS_ON_OUTPUT = {'id', 'password_hash'} def output(self): output = self.as_dict() for field in self._IGNORE_ATTRS_ON_OUTPUT: del output[field] output['profile_image'] = app.config['MEDIA_BASE_URL'] \ .format(file_name=output['profile_image']) return output def hash_password(self, password): self.password_hash = pwd_context.hash(password) def verify_password(self, password): return pwd_context.verify(password, self.password_hash) def update(self, data: dict, file: werkzeug.datastructures.FileStorage): self.update_attrs(data=data, ignore_attrs=self._IGNORE_ATTRS_ON_UPDATE) if file is not None: if not self._allowed_file(file.filename): return None # TODO: Create a util that generates unique (random) image names filename = werkzeug.utils.secure_filename(file.filename) response = utils.File.upload(file=file, filename=filename) self.profile_image = filename changed_flag = True if changed_flag is True: db.session.commit() return self def update_password(self, old_password: str, new_password: str): if not self.verify_password(old_password): return None self.hash_password(new_password) db.session.commit() return self @staticmethod def verify_auth_token(token): serializer = itsdangerous.TimedJSONWebSignatureSerializer( app.config['SECRET_KEY']) try: data = serializer.loads(token) except itsdangerous.SignatureExpired: return None # valid token, but expired except itsdangerous.BadSignature: return None # invalid token return data @staticmethod def _allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() \ in app.config['MEDIA_ALLOWED_EXTENSIONS']
class Post(Base): __tablename__ = 'POST' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('USER.id'), nullable=False) resource = db.Column(db.String(256), nullable=False) description = db.Column(db.String(500)) created = db.Column(db.DateTime(timezone=True), default=sqlalchemy.sql.func.now()) user = db.relationship('User', back_populates='post', lazy=True) comments = db.relationship('Comment', cascade="all,delete", back_populates='post', lazy=True, order_by='Comment.created.desc()') _IGNORE_ATTRS_ON_UPDATE = {'id', 'created', 'user_id'} def output(self): output = self.as_dict() output['resource'] = app.config['MEDIA_BASE_URL'] \ .format(file_name=output['resource']) return output def output_with_permissions(self, auth_user: User): output = self.output() output['edit_allowed'] = True \ if self.user_id == auth_user.user_id else False return output def output_with_permissions_and_users(self, auth_user: int): output = self.output_with_permissions(auth_user) output['user'] = self.user.output() output['comments'] = [ comment.output_with_permissions(auth_user) for comment in self.comments ] return output def save(self, form_data: dict, file: werkzeug.datastructures.FileStorage, user: User): if not self._allowed_file(file.filename): return None # TODO: Create a util that generates unique (random) image names filename = werkzeug.utils.secure_filename(file.filename) response = utils.File.upload(file=file, filename=filename) # TODO: validate response self.user_id = user.user_id self.resource = filename self.description = form_data.get('description') db.session.add(self) db.session.commit() return self def update(self, form_data: dict, file: werkzeug.datastructures.FileStorage, user: User): self.update_attrs(data=form_data, ignore_attrs=self._IGNORE_ATTRS_ON_UPDATE) if file is not None: if not self._allowed_file(file.filename): return None # TODO: Create a util that generates unique (random) image names filename = werkzeug.utils.secure_filename(file.filename) response = utils.File.upload(file=file, filename=filename) self.resource = filename changed_flag = True if changed_flag is True: db.session.commit() return self @staticmethod def _allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() \ in app.config['MEDIA_ALLOWED_EXTENSIONS']