Exemplo n.º 1
0
    def get_or_open(cls, org, user, message, summary, assignee):
        from casepro.profiles.models import Notification

        r = get_redis_connection()
        with r.lock(CASE_LOCK_KEY % (org.pk, message.contact.uuid)):
            message.refresh_from_db()

            # if message is already associated with a case, return that
            if message.case:
                message.case.is_new = False
                return message.case

            # suspend from groups, expire flows and archive messages
            message.contact.prepare_for_case()

            case = cls.objects.create(org=org, assignee=assignee, initial_message=message, contact=message.contact,
                                      summary=summary)
            case.is_new = True
            case.labels.add(*list(message.labels.all()))  # copy labels from message to new case
            case.watchers.add(user)

            # attach message to this case
            message.case = case
            message.save(update_fields=('case',))

            action = CaseAction.create(case, user, CaseAction.OPEN, assignee=assignee)

            for assignee_user in assignee.get_users():
                if assignee_user != user:
                    Notification.new_case_assignment(org, assignee_user, action)

        return case
Exemplo n.º 2
0
    def reassign(self, user, partner, note=None):
        from casepro.profiles.models import Notification

        self.assignee = partner
        self.save(update_fields=('assignee',))

        action = CaseAction.create(self, user, CaseAction.REASSIGN, assignee=partner, note=note)

        self.notify_watchers(action=action)

        # also notify users in the assigned partner that this case has been assigned to them
        for user in partner.get_users():
            Notification.new_case_assignment(self.org, user, action)
Exemplo n.º 3
0
    def reassign(self, user, partner, note=None, user_assignee=None):
        from casepro.profiles.models import Notification

        self.assignee = partner
        self.user_assignee = user_assignee
        self.save(update_fields=("assignee", "user_assignee"))

        action = CaseAction.create(
            self, user, CaseAction.REASSIGN, assignee=partner, note=note, user_assignee=user_assignee
        )

        self.notify_watchers(action=action)

        # also notify users in the assigned partner that this case has been assigned to them
        for user in partner.get_users():
            Notification.new_case_assignment(self.org, user, action)
Exemplo n.º 4
0
    def get_or_open(cls, org, user, message, summary, assignee, user_assignee=None, contact=None):
        """
        Get an existing case, or open a new case if one doesn't exist. If message=None, then contact is required, and
        any open case for that contact will be returned. If no open cases exist for the contact, a new case will be
        created.
        """
        if not message and not contact:
            raise ValueError("Opening a case requires a message or contact")

        from casepro.profiles.models import Notification
        r = get_redis_connection()
        contact = message.contact if message else contact

        with r.lock(CASE_LOCK_KEY % (org.pk, contact.uuid)):
            if message:
                message.refresh_from_db()
                case = message.case
            else:
                message = None
                case = contact.cases.filter(closed_on=None).first()
            # if there is already an associated case, return that
            if case:
                case.is_new = False
                return case

            # suspend from groups, expire flows and archive messages
            contact.prepare_for_case()

            case = cls.objects.create(org=org, assignee=assignee, initial_message=message, contact=contact,
                                      summary=summary, user_assignee=user_assignee)

            if message:
                case.labels.add(*list(message.labels.all()))  # copy labels from message to new case

                # attach message to this case
                message.case = case
                message.save(update_fields=('case',))

            case.is_new = True
            case.watchers.add(user)
            action = CaseAction.create(case, user, CaseAction.OPEN, assignee=assignee, user_assignee=user_assignee)

            for assignee_user in assignee.get_users():
                if assignee_user != user:
                    Notification.new_case_assignment(org, assignee_user, action)
        return case
Exemplo n.º 5
0
class Case(models.Model):
    """
    A case between a partner organization and a contact
    """

    org = models.ForeignKey(Org, verbose_name=_("Organization"), related_name="cases", on_delete=models.PROTECT)

    labels = models.ManyToManyField(Label, help_text=_("Labels assigned to this case"))

    assignee = models.ForeignKey(Partner, related_name="cases", on_delete=models.PROTECT)

    user_assignee = models.ForeignKey(
        User,
        null=True,
        on_delete=models.SET_NULL,
        related_name="cases",
        help_text="The (optional) user that this case is assigned to",
    )

    contact = models.ForeignKey(Contact, related_name="cases", on_delete=models.PROTECT)

    initial_message = models.OneToOneField(Message, null=True, related_name="initial_case", on_delete=models.PROTECT)

    summary = models.CharField(verbose_name=_("Summary"), max_length=255)

    opened_on = models.DateTimeField(auto_now_add=True, help_text="When this case was opened")

    closed_on = models.DateTimeField(null=True, help_text="When this case was closed")

    watchers = models.ManyToManyField(
        User, related_name="watched_cases", help_text="Users to be notified of case activity"
    )

    @classmethod
    def get_all(cls, org, user=None, label=None):
        queryset = cls.objects.filter(org=org)

        if user:
            # if user is not an org admin, we should only return cases with partner labels or assignment
            user_partner = user.get_partner(org)
            if user_partner and user_partner.is_restricted:
                queryset = queryset.filter(Q(labels__in=list(user_partner.get_labels())) | Q(assignee=user_partner))

        if label:
            queryset = queryset.filter(labels=label)

        return queryset.distinct()

    @classmethod
    def get_open(cls, org, user=None, label=None):
        return cls.get_all(org, user, label).filter(closed_on=None)

    @classmethod
    def get_closed(cls, org, user=None, label=None):
        return cls.get_all(org, user, label).exclude(closed_on=None)

    @classmethod
    def get_for_contact(cls, org, contact):
        return cls.get_all(org).filter(contact=contact)

    @classmethod
    def get_open_for_contact_on(cls, org, contact, dt):
        qs = cls.get_for_contact(org, contact)
        return qs.filter(opened_on__lt=dt).filter(Q(closed_on=None) | Q(closed_on__gt=dt)).first()

    @classmethod
    def search(cls, org, user, search):
        """
        Search for cases
        """
        folder = search.get("folder")
        assignee_id = search.get("assignee")
        after = search.get("after")
        before = search.get("before")

        if folder == CaseFolder.open:
            queryset = Case.get_open(org, user)
        elif folder == CaseFolder.closed:
            queryset = Case.get_closed(org, user)
        else:  # pragma: no cover
            raise ValueError("Invalid folder for cases")

        if assignee_id:
            queryset = queryset.filter(assignee__pk=assignee_id)

        if after:
            queryset = queryset.filter(opened_on__gte=after)
        if before:
            queryset = queryset.filter(opened_on__lte=before)

        queryset = queryset.select_related("contact", "assignee", "user_assignee")

        queryset = queryset.prefetch_related(Prefetch("labels", Label.objects.filter(is_active=True)))

        return queryset.order_by("-opened_on")

    @classmethod
    def get_or_open(cls, org, user, message, summary, assignee, user_assignee=None, contact=None):
        """
        Get an existing case, or open a new case if one doesn't exist. If message=None, then contact is required, and
        any open case for that contact will be returned. If no open cases exist for the contact, a new case will be
        created.
        """
        if not message and not contact:
            raise ValueError("Opening a case requires a message or contact")

        from casepro.profiles.models import Notification

        r = get_redis_connection()
        contact = message.contact if message else contact

        with r.lock(CASE_LOCK_KEY % (org.pk, contact.uuid)):
            if message:
                message.refresh_from_db()
                case = message.case
            else:
                message = None
                case = contact.cases.filter(closed_on=None).first()
            # if there is already an associated case, return that
            if case:
                case.is_new = False
                return case

            # suspend from groups, expire flows and archive messages
            contact.prepare_for_case()

            case = cls.objects.create(
                org=org,
                assignee=assignee,
                initial_message=message,
                contact=contact,
                summary=summary,
                user_assignee=user_assignee,
            )

            if message:
                case.labels.add(*list(message.labels.all()))  # copy labels from message to new case

                # attach message and subsequent messages to this case
                contact.incoming_messages.filter(case=None, created_on__gte=message.created_on).update(case=case)

            case.is_new = True
            case.watchers.add(user)
            action = CaseAction.create(case, user, CaseAction.OPEN, assignee=assignee, user_assignee=user_assignee)

            for assignee_user in assignee.get_users():
                if assignee_user != user:
                    Notification.new_case_assignment(org, assignee_user, action)