class Function(db.Model): """ Renamed 'Capability" on logical design diagram - function seems more understandable in the context of limiting access to code functions/methods """ __tablename__ = 'functions' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(30), nullable=False) description = db.Column(db.String(255), nullable=True)
class UserGroup(db.Model): """ Renamed 'SecurityGroup" on logical design diagram - expand system to be more generic and include states such as blocked/restricted """ __tablename__ = 'usergroups' id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(30), nullable=False) permissions = db.relationship('Permission', secondary=permissions, backref=db.backref('usergroups', lazy=True))
class ArticleComment(db.Model): __tablename__ = 'article_comments' id = db.Column(db.Integer, primary_key=True, autoincrement=True) author = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) on_article = db.Column(db.Integer, db.ForeignKey('article.id'), nullable=False) content = db.Column(db.String, nullable=False) submitted_at = db.Column(db.DateTime, nullable=False) last_edited = db.Column(db.DateTime, nullable=False)
class Article(db.Model): __tablename__ = 'articles' id = db.Column(db.Integer, primary_key=True, autoincrement=True) author = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) title = db.Column(db.String(255), nullable=False) content = db.Column(db.String, nullable=False) submitted_at = db.Column(db.DateTime, nullable=False) last_edited = db.Column(db.DateTime, nullable=False) status = db.Column(db.String, nullable=False) # http://docs.sqlalchemy.org/en/rel_0_9/orm/mapped_attributes.html#simple-validators @validates('status') def validate_status(self, key, value): assert value in ['Published', 'Draft', 'Hidden'] return value
""" from finalwhistle import db class UserGroup(db.Model): """ Renamed 'SecurityGroup" on logical design diagram - expand system to be more generic and include states such as blocked/restricted """ __tablename__ = 'usergroups' id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(30), nullable=False) permissions = db.relationship('Permission', secondary=permissions, backref=db.backref('usergroups', lazy=True)) class Function(db.Model): """ Renamed 'Capability" on logical design diagram - function seems more understandable in the context of limiting access to code functions/methods """ __tablename__ = 'functions' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(30), nullable=False) description = db.Column(db.String(255), nullable=True) permissions = db.Table('permissions', db.Column('group_id', db.Integer, db.ForeignKey('usergroups.id')), db.Column('function_id', db.Integer, db.ForeignKey('functions.id')))
class User(db.Model): """ The blocked/restricted fields in the logical diagram could be move to a security group which can be expanded to limit access to the commenting system and basic account actions (e.g. logging in). If we want to keep the functionality of recording the dates the user was moved into the group, we'd need a new table to record instances of a user's group changing Passwords are safely stored via Flask-BCrypt [1] [1]: https://flask-bcrypt.readthedocs.io/en/latest/ """ __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True, autoincrement=True) email = db.Column(db.String(60), nullable=False, unique=True) username = db.Column(db.String(16), nullable=False, unique=True) pw_hash = db.Column(db.Binary(60), nullable=False, unique=True) # Accounts must be activated before they can be used activated = db.Column(db.Boolean, nullable=False, default=False) # The user is emailed the activation token which can be entered by attempting to login or by clicking # a link emailed to them activation_token = db.Column(db.String, nullable=False, default=new_uuid) registered_date = db.Column(db.DateTime, nullable=False, server_default=func.now()) last_login = db.Column(db.DateTime, nullable=False, server_default=func.now()) supported_team_id = db.Column(db.Integer, db.ForeignKey('teams.id'), nullable=True) supported_team = db.relationship('Team') usergroup_id = db.Column(db.Integer, db.ForeignKey('usergroups.id'), nullable=True) usergroup = db.relationship('UserGroup') # Access token is used for password reset requests and the 'remember me' function access_token = db.Column(db.String, nullable=False, default=new_uuid) access_token_expires_at = db.Column(db.DateTime, nullable=False) def __init__(self, email, username, password): """ Creates a new user in the database :param email: :param username: :param password: """ self.email = email self.username = username self.pw_hash = hash_password(password) # TODO: send account activation email def password_valid(self, password): """ Checks if supplied password is valid for the account :param password: :return: True if password is correct """ return bcrypt.check_password_hash(self.pw_hash, password) def activate_account(self): """ :return: True if account has just been activated """ if self.activated is not False: return False def activation_token_valid(self, token): return self.activation_token == token @staticmethod def attempt_login(email, password): """ Attempts to login with a provided email and password :param email: :param password: :return: User object associated with the provided email if password is correct, otherwise None """ user = user_from_email(email) if user.password_valid(password): return user else: # can implement failed login attempt tracker here pass return None
class ArticleCategory(db.Model): __tablename__ = 'article_categories' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(50), unique=True, nullable=False)