Exemplo n.º 1
0
class ChatParticipant(CRUDMixin, db.Model):
    __tablename__ = 'chat_participant'

    chat_id = db.Column(
        db.ForeignKey(
            column='chat.id',
            name='fk_chat_participant_chat_id',
            onupdate='CASCADE',
            ondelete='CASCADE'
        ),
        primary_key=True
    )
    participant_id = db.Column(
        db.ForeignKey(
            column='user.id',
            name='fk_chat_participant_participant',
            onupdate='CASCADE',
            ondelete='CASCADE'
        ),
        primary_key=True
    )
    nickname = db.Column(db.String(255), nullable=True, unique=False)

    __table_args__ = (
        db.PrimaryKeyConstraint('chat_id', 'participant_id',
                                name='pk_chat_participant'),
    )

    @property
    def name(self):
        return self.nickname or self.participant.profile.name

    def to_public_json(self):
        return self.to_json(operations=[('difference', {'chat_id'})])
Exemplo n.º 2
0
class Message(CRUDMixin, db.Model):
    __tablename__ = 'message'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    chat_id = db.Column(db.ForeignKey(column='chat.id',
                                      name='fk_message_chat_id',
                                      onupdate='CASCADE',
                                      ondelete='CASCADE'),
                        nullable=False,
                        unique=False)
    author_id = db.Column(db.ForeignKey(column='user.id',
                                        name='fk_message_author_id',
                                        onupdate='CASCADE',
                                        ondelete='CASCADE'),
                          nullable=False,
                          unique=False)
    timestamp = db.Column(db.DateTime,
                          nullable=False,
                          unique=False,
                          server_default=func.now())
    parent_id = db.Column(db.ForeignKey(column='message.id',
                                        name='fk_message_parent_id',
                                        onupdate='CASCADE',
                                        ondelete='CASCADE'),
                          nullable=True,
                          unique=False)

    children = db.relationship('Message',
                               uselist=True,
                               backref=db.backref('parent', remote_side=[id]),
                               cascade='all, delete',
                               passive_updates=True,
                               passive_deletes=True)
    text = db.relationship('MessageText',
                           uselist=False,
                           backref='message',
                           cascade='all, delete',
                           passive_updates=True,
                           passive_deletes=True)

    def to_json(self, operations=None):
        return super().to_json(operations) | {'timestamp': str(self.timestamp)}

    def to_public_json(self):
        return self.to_json(operations=[(
            'difference',
            {'chat_id'})]) | self.text.to_json() if self.text else {}
Exemplo n.º 3
0
class DirectChat(CRUDMixin, db.Model):
    __tablename__ = 'direct_chat'

    id = db.Column(
        db.ForeignKey(
            column='chat.id',
            name='fk_direct_chat_chat_id',
            onupdate='CASCADE',
            ondelete='CASCADE'
        ),
        primary_key=True
    )
Exemplo n.º 4
0
class UserProfile(CRUDMixin, db.Model):
    __tablename__ = 'user_profile'

    id = db.Column(db.Integer,
                   db.ForeignKey(column='user.id',
                                 name='fk_user_profile_id',
                                 onupdate='CASCADE',
                                 ondelete='CASCADE'),
                   primary_key=True)
    email = db.Column(db.String(254), nullable=False, unique=True)
    name = db.Column(db.String(255), nullable=False, unique=False)

    email_regex = r'[^@]+@[^@]+\.[^@]+'

    __table_args__ = (db.CheckConstraint(f"email ~ '{email_regex}'",
                                         name='cc_user_profile_email'),
                      db.CheckConstraint('char_length(name) > 0',
                                         name='cc_user_profile_name'))

    @validates('email')
    def validate_email(self, key, value):
        if not value or not re.fullmatch(self.email_regex, value):
            raise ValueError('Please enter a valid email address')

        return value

    @classmethod
    def get_filtered(cls, **kwargs):
        email = kwargs.pop('email', None)

        if email:
            return (cls.query.filter_by(**kwargs).filter(
                cls.email.ilike(email)))
        else:
            return cls.query.filter_by(**kwargs)

    @classmethod
    def get_first_active(cls, **kwargs):
        first = cls.get_first(**kwargs)
        return first if (first and first.user.is_active) else None

    @classmethod
    def get_first_inactive(cls, **kwargs):
        first = cls.get_first(**kwargs)
        return first if (first and not first.user.is_active) else None

    @classmethod
    def get_active(cls):
        return cls.query.join(User).filter(User.date_activated.isnot(None))

    def to_public_json(self):
        return self.to_json(operations=[('intersection', {'id', 'name'})])
Exemplo n.º 5
0
class GroupChat(CRUDMixin, db.Model):
    __tablename__ = 'group_chat'

    id = db.Column(
        db.ForeignKey(
            column='chat.id',
            name='fk_group_chat_chat_id',
            onupdate='CASCADE',
            ondelete='CASCADE'
        ),
        primary_key=True
    )
    name = db.Column(db.String(255), nullable=True, unique=False)
Exemplo n.º 6
0
class MessageText(CRUDMixin, db.Model):
    __tablename__ = 'message_text'

    id = db.Column(db.Integer,
                   db.ForeignKey(column='message.id',
                                 name='fk_message_text_id',
                                 onupdate='CASCADE',
                                 ondelete='CASCADE'),
                   primary_key=True)
    content = db.Column(db.String(512), nullable=False, unique=False)

    __table_args__ = (db.CheckConstraint('char_length(content) > 0',
                                         name='cc_message_text_content'), )
Exemplo n.º 7
0
class JWTBlacklist(CRUDMixin, db.Model):
    __tablename__ = 'jwt_blacklist'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    audience = db.Column(db.Integer,
                         db.ForeignKey(column='user.id',
                                       name='fk_jwt_blacklist_audience',
                                       onupdate='CASCADE',
                                       ondelete='SET NULL'),
                         nullable=True,
                         unique=False)
    jti = db.Column(db.String(255), nullable=False, unique=True)
    token_type = db.Column(db.String(255), nullable=False, unique=False)
    issue_date = db.Column(db.DateTime, nullable=False, unique=False)
    expiration_date = db.Column(db.DateTime, nullable=False, unique=False)

    @classmethod
    def insert_if_not_exists(cls, decoded_token):
        return super().insert_if_not_exists(
            audience=decoded_token['identity'],
            jti=decoded_token['jti'],
            token_type=decoded_token['type'],
            issue_date=dt.fromtimestamp(decoded_token['iat']),
            expiration_date=dt.fromtimestamp(decoded_token['exp']))
Exemplo n.º 8
0
class UserRelationship(CRUDMixin, db.Model):
    __tablename__ = 'user_relationship'

    user_a = db.Column(db.Integer,
                       db.ForeignKey(column='user.id',
                                     name='fk_user_relationship_user_a',
                                     onupdate='CASCADE',
                                     ondelete='CASCADE'),
                       primary_key=True)
    user_b = db.Column(db.Integer,
                       db.ForeignKey(column='user.id',
                                     name='fk_user_relationship_user_b',
                                     onupdate='CASCADE',
                                     ondelete='CASCADE'),
                       primary_key=True)
    relation = db.Column(db.String(2), nullable=True, unique=False)
    since = db.Column(db.DateTime, nullable=True, unique=False)

    __table_args__ = (db.PrimaryKeyConstraint('user_a',
                                              'user_b',
                                              name='pk_user_relation'),
                      db.CheckConstraint('user_a < user_b',
                                         name='cc_user_relation_pk'),
                      db.CheckConstraint(
                          f'relation IN ({UserRelation.to_quoted_csv_str()})',
                          name='cc_user_relation_relation'))

    @validates('user_a', 'user_b')
    def validates_user_id_pair(self, key, value):
        lhs = value if key == 'user_a' else self.user_a
        rhs = value if key == 'user_b' else self.user_b

        if lhs is not None and rhs is not None and not lhs < rhs:
            raise ValueError('Value of user_a must be less than user_b')

        return value

    @validates('relation')
    def validates(self, key, value):
        if value not in UserRelation.to_list():
            raise ValueError('Relation must be one of the following values: ' +
                             UserRelation.to_csv_str())

        return value

    @classmethod
    def sort_user_id_pair(cls, user_id_pair):
        return {
            'user_a': min(user_id_pair[0], user_id_pair[1]),
            'user_b': max(user_id_pair[0], user_id_pair[1])
        }

    @classmethod
    def resolve_friend_requester(cls, sorted_user_id_pair, current_user_id):
        if sorted_user_id_pair['user_a'] == current_user_id:
            return UserRelation.FRIEND_REQUEST_FROM_A_TO_B.value
        else:
            return UserRelation.FRIEND_REQUEST_FROM_B_TO_A.value

    @classmethod
    def resolve_friend_requestee(cls, sorted_user_id_pair, current_user_id):
        if sorted_user_id_pair['user_a'] == current_user_id:
            return UserRelation.FRIEND_REQUEST_FROM_B_TO_A.value
        else:
            return UserRelation.FRIEND_REQUEST_FROM_A_TO_B.value

    @classmethod
    def get_filtered(cls, **kwargs):
        user_id = kwargs.pop('user_id', None)
        user_id_pair = kwargs.pop('user_id_pair', None)
        status = kwargs.pop('status', None)
        values = deque()

        if user_id:
            values.appendleft(
                cls.query.filter_by(**kwargs).filter(
                    or_(cls.user_a == user_id, cls.user_b == user_id)))
            return values
        elif user_id_pair:
            sorted_user_id_pair = cls.sort_user_id_pair(user_id_pair)
            kwargs |= sorted_user_id_pair

            if status:
                current_user_id = status.get('current_user_id')
                assert isinstance(current_user_id, int)

                if status.get('requester'):
                    relation = cls.resolve_friend_requester(
                        sorted_user_id_pair, current_user_id)
                else:
                    relation = cls.resolve_friend_requestee(
                        sorted_user_id_pair, current_user_id)

                if status.get('insert'):
                    kwargs['relation'] = relation

                values.appendleft(relation)

            values.appendleft(sorted_user_id_pair)

        values.appendleft(cls.query.filter_by(**kwargs))
        return values

    @classmethod
    def get_first(cls, **kwargs):
        filtered, *args = cls.get_filtered(**kwargs)
        return (filtered.first(), *args)

    @classmethod
    def has_row(cls, **kwargs):
        filtered, *args = cls.get_filtered(**kwargs)
        return (filtered.scalar() is not None, *args)

    def other_user(self, user_id):
        id = self.user_a if self.user_a != user_id else self.user_b
        return User.get_first(id=id)

    def user_is_requester(self, user_id):
        p = 0b10 if self.user_a == user_id else 0b01
        q = UserRelation.to_binary(self.relation)
        return p & q

    def user_is_requestee(self, user_id):
        return not self.user_is_requester(user_id)

    def to_json(self, operations=None):
        return super().to_json(operations) | {'since': str(self.since)}