Beispiel #1
0
def send_messages(sender, instance, created, **kwargs):
    """When there is a message in a conversation we need to send it to any subscribed participants."""
    message = instance
    conversation = message.conversation

    topic = 'conversations:message'

    for subscription in ChannelSubscription.objects.recent().filter(
            user__in=conversation.participants.all()).distinct():

        payload = ConversationMessageSerializer(
            message, context={
                'request': MockRequest(user=subscription.user)
            }).data
        send_in_channel(subscription.reply_channel, topic, payload)

        if created and message.is_thread_reply(
        ) and subscription.user != message.author:
            payload = ConversationMessageSerializer(
                message.thread,
                context={
                    'request': MockRequest(user=subscription.user)
                }).data
            send_in_channel(subscription.reply_channel, topic, payload)

    # Send push notification and conversation updates when a message is created, but not when it is modified
    if not created:
        return

    tasks.notify_message_push_subscribers(message)

    # Send conversations object to participants after sending a message
    # (important for unread_message_count)
    # Exclude the author because their seen_up_to status gets updated,
    # so they will receive the `send_conversation_update` message
    topic = 'conversations:conversation'

    # Can be skipped for thread replies, as they don't alter the conversations object
    if message.is_thread_reply():
        return

    for subscription in ChannelSubscription.objects.recent()\
            .filter(user__in=conversation.participants.all())\
            .exclude(user=message.author).distinct():
        payload = ConversationSerializer(
            conversation,
            context={
                'request': MockRequest(user=subscription.user)
            }).data
        send_in_channel(subscription.reply_channel, topic, payload)
Beispiel #2
0
def send_messages(sender, instance, created, **kwargs):
    """When there is a message in a conversation we need to send it to any subscribed participants."""

    message = instance
    conversation = message.conversation

    topic = 'conversations:message'

    push_exclude_users = []

    for subscription in ChannelSubscription.objects.recent().filter(
            user__in=conversation.participants.all()):
        if not subscription.away_at:
            push_exclude_users.append(subscription.user)

        payload = ConversationMessageSerializer(
            message, context={
                'request': MockRequest(user=subscription.user)
            }).data
        send_in_channel(subscription.reply_channel, topic, payload)

    # Send push notifications when a message is created, but not when it is modified
    if created:
        tokens = [
            item.token for item in PushSubscription.objects.filter(
                Q(user__in=conversation.participants.all())
                & ~Q(user__in=push_exclude_users) & ~Q(user=message.author))
        ]

        if len(tokens) > 0:
            message_title = message.author.display_name
            if isinstance(conversation.target, Group):
                message_title = '{} / {}'.format(conversation.target.name,
                                                 message_title)

            notify_multiple_devices(
                registration_ids=tokens,
                message_title=message_title,
                message_body=message.content,
                # this causes each notification for a given conversation to replace previous notifications
                # fancier would be to make the new notifications show a summary not just the latest message
                tag='conversation:{}'.format(conversation.id))

    # Send conversations object to participants after sending a message
    # (important for unread_message_count)
    # Exclude the author because their seen_up_to status gets updated,
    # so they will receive the `send_conversation_update` message
    topic = 'conversations:conversation'

    for subscription in ChannelSubscription.objects.recent()\
            .filter(user__in=conversation.participants.all())\
            .exclude(user=message.author):
        payload = ConversationSerializer(
            conversation,
            context={
                'request': MockRequest(user=subscription.user)
            }).data
        send_in_channel(subscription.reply_channel, topic, payload)
Beispiel #3
0
def send_reaction_update(sender, instance, **kwargs):
    reaction = instance
    message = reaction.message
    conversation = message.conversation

    topic = 'conversations:message'

    for subscription in ChannelSubscription.objects.recent() \
            .filter(user__in=conversation.participants.all()) \
            .exclude(user=reaction.user).distinct():
        payload = ConversationMessageSerializer(
            message, context={
                'request': MockRequest(user=subscription.user)
            }).data
        send_in_channel(subscription.reply_channel, topic, payload)
Beispiel #4
0
def send_messages(sender, instance, **kwargs):
    """When there is a message in a conversation we need to send it to any subscribed participants."""

    message = instance
    conversation = message.conversation

    topic = 'conversations:message'
    payload = ConversationMessageSerializer(message).data

    push_exclude_users = []

    for subscription in ChannelSubscription.objects.recent().filter(user__in=conversation.participants.all()):
        # TODO: add back in once https://github.com/yunity/karrot-frontend/issues/770 is implemented
        # if not subscription.away_at:
        #     push_exclude_users.append(subscription.user)

        Channel(subscription.reply_channel).send({
            "text": json.dumps({
                'topic': topic,
                'payload': payload
            })
        })

    tokens = [item.token for item in
              PushSubscription.objects.filter(
                  Q(user__in=conversation.participants.all()) & ~Q(user__in=push_exclude_users) & ~Q(
                      user=message.author))]

    if len(tokens) > 0:

        message_title = message.author.display_name
        if isinstance(conversation.target, Group):
            message_title = '{} / {}'.format(conversation.target.name, message_title)

        notify_multiple_devices(
            registration_ids=tokens,
            message_title=message_title,
            message_body=message.content,
            # this causes each notification for a given conversation to replace previous notifications
            # fancier would be to make the new notifications show a summary not just the latest message
            tag='conversation:{}'.format(conversation.id)
        )
Beispiel #5
0
def send_thread_update(sender, instance, created, **kwargs):
    # Update thread object for user after updating their participation
    # (important for seen_up_to and unread_message_count)

    # Saves a few unnecessary messages if we only send on modify
    if created:
        return

    thread = instance.thread

    topic = 'conversations:message'
    payload = ConversationMessageSerializer(thread,
                                            context={
                                                'request':
                                                MockRequest(user=instance.user)
                                            }).data

    for subscription in ChannelSubscription.objects.recent().filter(
            user=instance.user):
        send_in_channel(subscription.reply_channel, topic, payload)
Beispiel #6
0
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset() \
            .exclude(latest_message_id=None) \
            .annotate_unread_message_count_for(self.request.user) \
            .select_related(
                'latest_message',
                'target_type',
             ) \
            .prefetch_related(
                'latest_message__reactions',
                'participants',
                'conversationparticipant_set',
             )
        queryset = self.filter_queryset(queryset)

        conversations = self.paginate_queryset(queryset)
        messages = [
            c.latest_message for c in conversations
            if c.latest_message is not None
        ]

        # Prefetch related objects per target type
        pickup_ct = ContentType.objects.get_for_model(PickupDate)
        pickup_conversations = [
            item for item in conversations if item.target_type == pickup_ct
        ]
        pickups = PickupDate.objects. \
            filter(id__in=[c.target_id for c in pickup_conversations]). \
            prefetch_related('collectors')

        applications_ct = ContentType.objects.get_for_model(GroupApplication)
        application_conversations = [
            item for item in conversations
            if item.target_type == applications_ct
        ]
        applications = GroupApplication.objects. \
            filter(id__in=[c.target_id for c in application_conversations]). \
            select_related('user')

        # Applicant does not have access to group member profiles, so we sideload reduced user profiles
        my_applications = [a for a in applications if a.user == request.user]

        def get_conversation(application):
            return next(c for c in application_conversations
                        if c.target_id == application.id)

        users = get_user_model().objects. \
            filter(conversationparticipant__conversation__in=[get_conversation(a) for a in my_applications]). \
            exclude(id=request.user.id)

        context = self.get_serializer_context()
        serializer = self.get_serializer(conversations, many=True)
        message_serializer = ConversationMessageSerializer(messages,
                                                           many=True,
                                                           context=context)
        pickups_serializer = PickupDateSerializer(pickups,
                                                  many=True,
                                                  context=context)
        application_serializer = GroupApplicationSerializer(applications,
                                                            many=True,
                                                            context=context)
        user_serializer = UserInfoSerializer(users, many=True, context=context)

        return self.get_paginated_response({
            'conversations':
            serializer.data,
            'messages':
            message_serializer.data,
            'pickups':
            pickups_serializer.data,
            'applications':
            application_serializer.data,
            'users_info':
            user_serializer.data,
        })
def send_messages(sender, instance, created, **kwargs):
    """When there is a message in a conversation we need to send it to any subscribed participants."""
    message = instance
    conversation = message.conversation

    topic = 'conversations:message'

    push_exclude_users = []

    for subscription in ChannelSubscription.objects.recent().filter(
            user__in=conversation.participants.all()):
        if not subscription.away_at:
            push_exclude_users.append(subscription.user)

        payload = ConversationMessageSerializer(
            message, context={
                'request': MockRequest(user=subscription.user)
            }).data
        send_in_channel(subscription.reply_channel, topic, payload)

        if created and message.is_thread_reply(
        ) and subscription.user != message.author:
            payload = ConversationMessageSerializer(
                message.thread,
                context={
                    'request': MockRequest(user=subscription.user)
                }).data
            send_in_channel(subscription.reply_channel, topic, payload)

    # Send push notification and conversation updates when a message is created, but not when it is modified
    if not created:
        return

    subscriptions = PushSubscription.objects.filter(
        Q(user__in=conversation.participants.all())
        & ~Q(user__in=push_exclude_users) & ~Q(user=message.author))

    message_title = message.author.display_name
    if isinstance(conversation.target, Group):
        message_title = '{} / {}'.format(conversation.target.name,
                                         message_title)

    click_action = None
    if message.is_thread_reply():
        click_action = frontend_urls.thread_url(message.thread)
    else:
        click_action = frontend_urls.conversation_url(conversation,
                                                      message.author)

    notify_subscribers(
        subscriptions=subscriptions,
        fcm_options={
            'message_title': message_title,
            'message_body': message.content,
            'click_action': click_action,
            'message_icon': logo_url(),
            # this causes each notification for a given conversation to replace previous notifications
            # fancier would be to make the new notifications show a summary not just the latest message
            'tag': 'conversation:{}'.format(conversation.id)
        })

    # Send conversations object to participants after sending a message
    # (important for unread_message_count)
    # Exclude the author because their seen_up_to status gets updated,
    # so they will receive the `send_conversation_update` message
    topic = 'conversations:conversation'

    # Can be skipped for thread replies, as they don't alter the conversations object
    if message.is_thread_reply():
        return

    for subscription in ChannelSubscription.objects.recent()\
            .filter(user__in=conversation.participants.all())\
            .exclude(user=message.author):
        payload = ConversationSerializer(
            conversation,
            context={
                'request': MockRequest(user=subscription.user)
            }).data
        send_in_channel(subscription.reply_channel, topic, payload)