class ActivityType(PKMixin): """ Each activity ('Activities' record) has its own type. This model is intended to store these kind of data. """ __tablename__ = 'activity_types' description = Column(db.String(256), nullable=True) name = Column(db.String(100)) activity_set = db.relationship('Activities', backref='activity_type') def __repr__(self): return '<ActivityType {}>'.format(self.name)
class Desk(CommonInfoMixin): """ Boards container model. """ __tablename__ = 'desks' # @desc: OneToOne relation. owner_id = Column(db.Integer, db.ForeignKey('profiles.id')) desk_slug = Column(db.String(5), unique=True) board_set = db.relationship('Board', backref='desk', lazy='dynamic') def __repr__(self): return '<Desk {}>'.format(self.desk_slug)
class Label(PKMixin): """ Represents status of task for particular `Sticker` object. """ __tablename__ = 'labels' color = Column(db.String(7)) css_class = db.Column(ChoiceType(CSS_CLASS)) status = db.Column(ChoiceType(TASK_STATUS)) sticker_set = db.relationship('Sticker', backref='label') def __repr__(self): return '<Label {} | {}>'.format(self.status, self.color)
class Sticker(CommonInfoMixin): """ Sticker with task description. """ __tablename__ = 'stickers' __table_args__ = ( UniqueConstraint('board_id', 'sequence', name='_board_sequence_uc'), ) board_id = Column(db.Integer, db.ForeignKey('boards.id')) caption = Column(db.String(100)) # @desc: long text field. description = Column(db.Text()) label_id = Column(db.Integer, db.ForeignKey('labels.id')) sequence = Column(db.Integer) # @desc: choices field. sprint_id = Column( db.Integer, db.ForeignKey('sprints.id'), nullable=True ) @property def object_type(self): return STICKER_TYPE @property def author_display_name(self): """ Return author of sticker. """ return Profile.query.filter_by(id=self.author).scalar().display_name @property def board_sequence(self): """ Return board sequence. """ return Board.query.filter_by(id=self.board_id).scalar().sequence @property def prefix(self): """ Return sticker's board prefix. """ return Board.query.filter_by(id=self.board_id).scalar().prefix def __repr__(self): return '<Sticker {} | {} | {} | {}>'.format( self.board_id, self.sequence, self.caption, self.label_id )
class Board(CommonInfoMixin): """ Stickers container model. """ __tablename__ = 'boards' __table_args__ = ( UniqueConstraint('desk_id', 'sequence', name='_desk_sequence_uc'), ) desk_id = Column(db.Integer, db.ForeignKey('desks.id')) title = Column(db.String(100)) sequence = Column(db.Integer) prefix = Column(db.String(5), unique=True) sticker_sequence = Column(db.Integer, default=1) sprint_set = db.relationship('Sprint', backref='board') sticker_set = db.relationship('Sticker', backref='board') def __repr__(self): return '<Board {} | {}>'.format(self.title, self.desk_id) @property def object_type(self): return BOARD_TYPE @staticmethod def get_next_sequence(profile): """ Return next board sequence """ last_sequence = ( db.session.query(func.max(Board.sequence)).filter_by( desk=profile.desk_owner ).scalar() ) or 0 return last_sequence + 1
class Profile(UserMixin, PKMixin): """ Users' model. """ __tablename__ = 'profiles' username = db.Column(db.String(64), unique=True, index=True) email = db.Column(db.String(64), unique=True, index=True) passwd = db.Column(db.String(128)) avatar = Column(db.String(256), nullable=True) display_name = Column(db.String(128)) # @desc: self and a ManyToMany relation. friends = db.relationship( 'Profile', secondary=friends, primaryjoin=('Profile.id==friends.c.left_profile_id'), secondaryjoin=('Profile.id==friends.c.right_profile_id'), backref='left_friends') motivation_quote = Column(db.String(256), nullable=True) # user = models.OneToOneField(User, verbose_name=_('user')) comments = db.relationship('Comment', backref='profile') desk_author = db.relationship('Desk', uselist=False, backref='desk_author', foreign_keys='Desk.author') desk_owner = db.relationship('Desk', uselist=False, backref='desk_owner', foreign_keys='Desk.owner_id') board_set = db.relationship('Board', backref='board_author') sprint_set = db.relationship('Sprint', backref='sprint_author') sticker_set = db.relationship('Sticker', backref='sticker_author') activity_set = db.relationship('Activities', backref='activity_who') def __repr__(self): return '<Profile {}>'.format(self.display_name) def __str__(self): return '{}'.format(self.display_name) @property def password(self): """ Don't allow to see user's password. """ raise AttributeError('You cannot see a password!') @password.setter def password(self, password): """ Set user's password. """ self.passwd = generate_password_hash(password) def verify_password(self, password): """ Check if given password complies to user's one. """ return check_password_hash(self.passwd, password) def generate_reset_token(self): """ Generate unique token. """ token = TimedJSONWebSignatureSerializer( current_app.config['SECRET_KEY'], current_app.config['TOKEN_EXPIRATION'], ) return token.dumps({'reset': self.id}) def reset_password(self, in_token, new_password): """ Reset password. """ token = TimedJSONWebSignatureSerializer( current_app.config['SECRET_KEY']) try: data = token.loads(in_token) except: return False if data.get('reset') != self.id: return False self.password = new_password db.session.add(self) return True
class Sprint(CommonInfoMixin): """ Sprint for creating next phases of learning. """ __tablename__ = 'sprints' __table_args__ = ( UniqueConstraint('board_id', 'number', name='_board_number_uc'), ) board_id = Column(db.Integer, db.ForeignKey('boards.id')) number = Column(db.String(100)) start_date = Column(db.DateTime()) end_date = Column(db.DateTime()) sticker_set = db.relationship('Sticker', backref='sprint') @property def object_type(self): return SPRINT_TYPE @property def open(self): """ Returns open sprint's stickers. """ label_id = Label.query.filter_by(status=OPEN).scalar().id return Sticker.query.filter_by( label_id=label_id, sprint_id=self.id ).all() @property def in_progress(self): """ Returns in progress sprint's stickers. """ label_id = Label.query.filter_by(status=IN_PROGRESS).scalar().id return Sticker.query.filter_by( label_id=label_id, sprint_id=self.id ).all() @property def in_review(self): """ Returns in review sprint's stickers. """ label_id = Label.query.filter_by(status=IN_REVIEW).scalar().id return Sticker.query.filter_by( label_id=label_id, sprint_id=self.id ).all() @property def done(self): """ Returns done sprint's stickers. """ label_id = Label.query.filter_by(status=DONE).scalar().id return Sticker.query.filter_by( label_id=label_id, sprint_id=self.id ).all() @property def blocked(self): """ Returns blocked sprint's stickers. """ label_id = Label.query.filter_by(status=BLOCKED).scalar().id return Sticker.query.filter_by( label_id=label_id, sprint_id=self.id ).all() def __repr__(self): return '<Sprint {} {}>'.format(self.number, self.board_id)