mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	Add /submessage endpoint.
This commit is contained in:
		@@ -64,7 +64,7 @@ from zerver.lib.topic_mutes import (
 | 
			
		||||
from zerver.lib.users import bulk_get_users, check_full_name, user_ids_to_users
 | 
			
		||||
from zerver.lib.user_groups import create_user_group, access_user_group_by_id
 | 
			
		||||
from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity, \
 | 
			
		||||
    RealmDomain, Service, \
 | 
			
		||||
    RealmDomain, Service, SubMessage, \
 | 
			
		||||
    Subscription, Recipient, Message, Attachment, UserMessage, RealmAuditLog, \
 | 
			
		||||
    UserHotspot, MultiuseInvite, ScheduledMessage, \
 | 
			
		||||
    Client, DefaultStream, DefaultStreamGroup, UserPresence, PushDeviceToken, \
 | 
			
		||||
@@ -1424,6 +1424,32 @@ def bulk_insert_ums(ums: List[UserMessageLite]) -> None:
 | 
			
		||||
    with connection.cursor() as cursor:
 | 
			
		||||
        cursor.execute(query)
 | 
			
		||||
 | 
			
		||||
def do_add_submessage(sender_id: int,
 | 
			
		||||
                      message_id: int,
 | 
			
		||||
                      msg_type: str,
 | 
			
		||||
                      content: str,
 | 
			
		||||
                      data: Any,
 | 
			
		||||
                      ) -> None:
 | 
			
		||||
    submessage = SubMessage(
 | 
			
		||||
        sender_id=sender_id,
 | 
			
		||||
        message_id=message_id,
 | 
			
		||||
        msg_type=msg_type,
 | 
			
		||||
        content=content,
 | 
			
		||||
    )
 | 
			
		||||
    submessage.save()
 | 
			
		||||
 | 
			
		||||
    event = dict(
 | 
			
		||||
        type="submessage",
 | 
			
		||||
        msg_type=msg_type,
 | 
			
		||||
        message_id=message_id,
 | 
			
		||||
        sender_id=sender_id,
 | 
			
		||||
        data=data,
 | 
			
		||||
    )
 | 
			
		||||
    ums = UserMessage.objects.filter(message_id=message_id)
 | 
			
		||||
    target_user_ids = [um.user_profile_id for um in ums]
 | 
			
		||||
 | 
			
		||||
    send_event(event, target_user_ids)
 | 
			
		||||
 | 
			
		||||
def notify_reaction_update(user_profile: UserProfile, message: Message,
 | 
			
		||||
                           reaction: Reaction, op: str) -> None:
 | 
			
		||||
    user_dict = {'user_id': user_profile.id,
 | 
			
		||||
 
 | 
			
		||||
@@ -560,6 +560,9 @@ def apply_event(state: Dict[str, Any],
 | 
			
		||||
    elif event['type'] == "reaction":
 | 
			
		||||
        # The client will get the message with the reactions directly
 | 
			
		||||
        pass
 | 
			
		||||
    elif event['type'] == "submessage":
 | 
			
		||||
        # The client will get submessages with their messages
 | 
			
		||||
        pass
 | 
			
		||||
    elif event['type'] == 'typing':
 | 
			
		||||
        # Typing notification events are transient and thus ignored
 | 
			
		||||
        pass
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ from zerver.lib.actions import (
 | 
			
		||||
    do_add_realm_domain,
 | 
			
		||||
    do_add_realm_filter,
 | 
			
		||||
    do_add_streams_to_default_stream_group,
 | 
			
		||||
    do_add_submessage,
 | 
			
		||||
    do_change_avatar_fields,
 | 
			
		||||
    do_change_bot_owner,
 | 
			
		||||
    do_change_default_all_public_streams,
 | 
			
		||||
@@ -867,6 +868,34 @@ class EventsRegisterTest(ZulipTestCase):
 | 
			
		||||
        error = schema_checker('events[0]', events[0])
 | 
			
		||||
        self.assert_on_error(error)
 | 
			
		||||
 | 
			
		||||
    def test_add_submessage(self) -> None:
 | 
			
		||||
        schema_checker = self.check_events_dict([
 | 
			
		||||
            ('type', equals('submessage')),
 | 
			
		||||
            ('message_id', check_int),
 | 
			
		||||
            ('sender_id', check_int),
 | 
			
		||||
            ('msg_type', check_string),
 | 
			
		||||
            ('data', check_string),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        cordelia = self.example_user('cordelia')
 | 
			
		||||
        stream_name = 'Verona'
 | 
			
		||||
        message_id = self.send_stream_message(
 | 
			
		||||
            sender_email=cordelia.email,
 | 
			
		||||
            stream_name=stream_name,
 | 
			
		||||
        )
 | 
			
		||||
        events = self.do_test(
 | 
			
		||||
            lambda: do_add_submessage(
 | 
			
		||||
                sender_id=cordelia.id,
 | 
			
		||||
                message_id=message_id,
 | 
			
		||||
                msg_type='whatever',
 | 
			
		||||
                content='"stuff"',
 | 
			
		||||
                data='stuff',
 | 
			
		||||
            ),
 | 
			
		||||
            state_change_expected=False,
 | 
			
		||||
        )
 | 
			
		||||
        error = schema_checker('events[0]', events[0])
 | 
			
		||||
        self.assert_on_error(error)
 | 
			
		||||
 | 
			
		||||
    def test_remove_reaction(self) -> None:
 | 
			
		||||
        schema_checker = self.check_events_dict([
 | 
			
		||||
            ('type', equals('reaction')),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
import mock
 | 
			
		||||
 | 
			
		||||
from zerver.lib.test_classes import ZulipTestCase
 | 
			
		||||
 | 
			
		||||
from zerver.lib.message import (
 | 
			
		||||
@@ -73,3 +75,83 @@ class TestBasics(ZulipTestCase):
 | 
			
		||||
        rows = msg_rows[0]['submessages']
 | 
			
		||||
        rows.sort(key=lambda r: r['id'])
 | 
			
		||||
        self.assertEqual(rows, expected_data)
 | 
			
		||||
 | 
			
		||||
    def test_endpoint_errors(self) -> None:
 | 
			
		||||
        cordelia = self.example_user('cordelia')
 | 
			
		||||
        stream_name = 'Verona'
 | 
			
		||||
        message_id = self.send_stream_message(
 | 
			
		||||
            sender_email=cordelia.email,
 | 
			
		||||
            stream_name=stream_name,
 | 
			
		||||
        )
 | 
			
		||||
        self.login(cordelia.email)
 | 
			
		||||
 | 
			
		||||
        payload = dict(
 | 
			
		||||
            message_id=message_id,
 | 
			
		||||
            msg_type='whatever',
 | 
			
		||||
            content='not json',
 | 
			
		||||
        )
 | 
			
		||||
        result = self.client_post('/json/submessage', payload)
 | 
			
		||||
        self.assert_json_error(result, 'Invalid json for submessage')
 | 
			
		||||
 | 
			
		||||
        hamlet = self.example_user('hamlet')
 | 
			
		||||
        bad_message_id = self.send_personal_message(
 | 
			
		||||
            from_email=hamlet.email,
 | 
			
		||||
            to_email=hamlet.email,
 | 
			
		||||
        )
 | 
			
		||||
        payload = dict(
 | 
			
		||||
            message_id=bad_message_id,
 | 
			
		||||
            msg_type='whatever',
 | 
			
		||||
            content='does not matter',
 | 
			
		||||
        )
 | 
			
		||||
        result = self.client_post('/json/submessage', payload)
 | 
			
		||||
        self.assert_json_error(result, 'Invalid message(s)')
 | 
			
		||||
 | 
			
		||||
    def test_endpoint_success(self) -> None:
 | 
			
		||||
        cordelia = self.example_user('cordelia')
 | 
			
		||||
        hamlet = self.example_user('hamlet')
 | 
			
		||||
        stream_name = 'Verona'
 | 
			
		||||
        message_id = self.send_stream_message(
 | 
			
		||||
            sender_email=cordelia.email,
 | 
			
		||||
            stream_name=stream_name,
 | 
			
		||||
        )
 | 
			
		||||
        self.login(cordelia.email)
 | 
			
		||||
 | 
			
		||||
        payload = dict(
 | 
			
		||||
            message_id=message_id,
 | 
			
		||||
            msg_type='whatever',
 | 
			
		||||
            content='{"name": "alice", "salary": 20}'
 | 
			
		||||
        )
 | 
			
		||||
        with mock.patch('zerver.lib.actions.send_event') as m:
 | 
			
		||||
            result = self.client_post('/json/submessage', payload)
 | 
			
		||||
        self.assert_json_success(result)
 | 
			
		||||
 | 
			
		||||
        expected_data = dict(
 | 
			
		||||
            message_id=message_id,
 | 
			
		||||
            data=dict(
 | 
			
		||||
                name='alice',
 | 
			
		||||
                salary=20,
 | 
			
		||||
            ),
 | 
			
		||||
            msg_type='whatever',
 | 
			
		||||
            sender_id=cordelia.id,
 | 
			
		||||
            type='submessage',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(m.call_count, 1)
 | 
			
		||||
        data = m.call_args[0][0]
 | 
			
		||||
        self.assertEqual(data, expected_data)
 | 
			
		||||
        users = m.call_args[0][1]
 | 
			
		||||
        self.assertIn(cordelia.id, users)
 | 
			
		||||
        self.assertIn(hamlet.id, users)
 | 
			
		||||
 | 
			
		||||
        rows = SubMessage.get_raw_db_rows([message_id])
 | 
			
		||||
        self.assertEqual(len(rows), 1)
 | 
			
		||||
        row = rows[0]
 | 
			
		||||
 | 
			
		||||
        expected_data = dict(
 | 
			
		||||
            id=row['id'],
 | 
			
		||||
            message_id=message_id,
 | 
			
		||||
            content='{"name": "alice", "salary": 20}',
 | 
			
		||||
            msg_type='whatever',
 | 
			
		||||
            sender_id=cordelia.id,
 | 
			
		||||
        )
 | 
			
		||||
        self.assertEqual(row, expected_data)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								zerver/views/submessage.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								zerver/views/submessage.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
import logging
 | 
			
		||||
import ujson
 | 
			
		||||
 | 
			
		||||
from django.http import HttpRequest, HttpResponse
 | 
			
		||||
from django.utils.translation import ugettext as _
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
 | 
			
		||||
from zerver.decorator import (
 | 
			
		||||
    has_request_variables,
 | 
			
		||||
    REQ,
 | 
			
		||||
)
 | 
			
		||||
from zerver.lib.actions import do_add_submessage
 | 
			
		||||
from zerver.lib.message import access_message
 | 
			
		||||
from zerver.lib.validator import check_int
 | 
			
		||||
from zerver.lib.response import (
 | 
			
		||||
    json_error,
 | 
			
		||||
    json_success
 | 
			
		||||
)
 | 
			
		||||
from zerver.models import UserProfile
 | 
			
		||||
 | 
			
		||||
@has_request_variables
 | 
			
		||||
def process_submessage(request: HttpRequest,
 | 
			
		||||
                       user_profile: UserProfile,
 | 
			
		||||
                       message_id: int=REQ(validator=check_int),
 | 
			
		||||
                       msg_type: str=REQ(),
 | 
			
		||||
                       content: str=REQ(),
 | 
			
		||||
                       ) -> HttpResponse:
 | 
			
		||||
    message, user_message = access_message(user_profile, message_id)
 | 
			
		||||
 | 
			
		||||
    if not settings.ALLOW_SUB_MESSAGES:  # nocoverage
 | 
			
		||||
        msg = 'Feature not enabled'
 | 
			
		||||
        return json_error(msg)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        data = ujson.loads(content)
 | 
			
		||||
    except Exception:
 | 
			
		||||
        return json_error(_("Invalid json for submessage"))
 | 
			
		||||
 | 
			
		||||
    do_add_submessage(
 | 
			
		||||
        sender_id=user_profile.id,
 | 
			
		||||
        message_id=message.id,
 | 
			
		||||
        msg_type=msg_type,
 | 
			
		||||
        content=content,
 | 
			
		||||
        data=data,
 | 
			
		||||
    )
 | 
			
		||||
    return json_success()
 | 
			
		||||
@@ -187,6 +187,10 @@ v1_api_and_json_patterns = [
 | 
			
		||||
    url(r'users/me/subscriptions/(?P<stream_id>\d+)$', rest_dispatch,
 | 
			
		||||
        {'PATCH': 'zerver.views.streams.update_subscriptions_property'}),
 | 
			
		||||
 | 
			
		||||
    url(r'^submessage$',
 | 
			
		||||
        rest_dispatch,
 | 
			
		||||
        {'POST': 'zerver.views.submessage.process_submessage'}),
 | 
			
		||||
 | 
			
		||||
    # New endpoint for handling reactions.
 | 
			
		||||
    url(r'^messages/(?P<message_id>[0-9]+)/reactions$',
 | 
			
		||||
        rest_dispatch,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user