backend/models/postgis/message.py (119 lines of code) (raw):

from sqlalchemy.sql.expression import false from backend import db from flask import current_app from enum import Enum from backend.models.dtos.message_dto import MessageDTO, MessagesDTO from backend.models.postgis.user import User from backend.models.postgis.task import Task from backend.models.postgis.project import Project from backend.models.postgis.utils import timestamp, NotFound class MessageType(Enum): """ Describes the various kinds of messages a user might receive """ SYSTEM = 1 # Generic system-generated message BROADCAST = 2 # Broadcast message from a project manager MENTION_NOTIFICATION = 3 # Notification that user was mentioned in a comment/chat VALIDATION_NOTIFICATION = 4 # Notification that user's mapped task was validated INVALIDATION_NOTIFICATION = ( 5 # Notification that user's mapped task was invalidated ) REQUEST_TEAM_NOTIFICATION = 6 INVITATION_NOTIFICATION = 7 TASK_COMMENT_NOTIFICATION = 8 PROJECT_CHAT_NOTIFICATION = 9 PROJECT_ACTIVITY_NOTIFICATION = 10 TEAM_BROADCAST = 11 # Broadcast message from a team manager class Message(db.Model): """ Describes an individual Message a user can send """ __tablename__ = "messages" __table_args__ = ( db.ForeignKeyConstraint( ["task_id", "project_id"], ["tasks.id", "tasks.project_id"] ), ) id = db.Column(db.Integer, primary_key=True) message = db.Column(db.String) subject = db.Column(db.String) from_user_id = db.Column(db.BigInteger, db.ForeignKey("users.id")) to_user_id = db.Column(db.BigInteger, db.ForeignKey("users.id"), index=True) project_id = db.Column(db.Integer, db.ForeignKey("projects.id"), index=True) task_id = db.Column(db.Integer, index=True) message_type = db.Column(db.Integer, index=True) date = db.Column(db.DateTime, default=timestamp) read = db.Column(db.Boolean, default=False) # Relationships from_user = db.relationship(User, foreign_keys=[from_user_id]) to_user = db.relationship(User, foreign_keys=[to_user_id], backref="messages") project = db.relationship(Project, foreign_keys=[project_id], backref="messages") task = db.relationship( Task, primaryjoin="and_(Task.id == foreign(Message.task_id), Task.project_id == Message.project_id)", backref="messages", ) @classmethod def from_dto(cls, to_user_id: int, dto: MessageDTO): """ Creates new message from DTO """ message = cls() message.subject = dto.subject message.message = dto.message message.from_user_id = dto.from_user_id message.to_user_id = to_user_id message.project_id = dto.project_id message.task_id = dto.task_id if dto.message_type is not None: message.message_type = MessageType(dto.message_type) return message def as_dto(self) -> MessageDTO: """ Casts message object to DTO """ dto = MessageDTO() dto.message_id = self.id dto.message = self.message dto.sent_date = self.date dto.read = self.read dto.subject = self.subject dto.project_id = self.project_id dto.task_id = self.task_id if self.message_type is not None: dto.message_type = MessageType(self.message_type).name if self.from_user_id: dto.from_username = self.from_user.username return dto def add_message(self): """ Add message into current transaction - DO NOT COMMIT HERE AS MESSAGES ARE PART OF LARGER TRANSACTIONS""" current_app.logger.debug("Adding message to session") db.session.add(self) def save(self): """ Save """ db.session.add(self) db.session.commit() @staticmethod def get_all_contributors(project_id: int): """ Get all contributors to a project """ contributors = ( db.session.query(Task.mapped_by) .filter(Task.project_id == project_id) .filter(Task.mapped_by.isnot(None)) .union( db.session.query(Task.validated_by) .filter(Task.project_id == project_id) .filter(Task.validated_by.isnot(None)) ) ) return contributors def mark_as_read(self): """ Mark the message in scope as Read """ self.read = True db.session.commit() @staticmethod def get_unread_message_count(user_id: int): """ Get count of unread messages for user """ return Message.query.filter( Message.to_user_id == user_id, Message.read == false() ).count() @staticmethod def get_all_messages(user_id: int) -> MessagesDTO: """ Gets all messages to the user """ user_messages = Message.query.filter(Message.to_user_id == user_id).all() if len(user_messages) == 0: raise NotFound() messages_dto = MessagesDTO() for message in user_messages: messages_dto.user_messages.append(message.as_dto()) return messages_dto @staticmethod def delete_multiple_messages(message_ids: list, user_id: int): """ Deletes the specified messages to the user """ Message.query.filter( Message.to_user_id == user_id, Message.id.in_(message_ids) ).delete(synchronize_session=False) db.session.commit() def delete(self): """ Deletes the current model from the DB """ db.session.delete(self) db.session.commit()