mirror of
https://github.com/zulip/zulip.git
synced 2025-11-10 00:46:03 +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.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.lib.user_groups import create_user_group, access_user_group_by_id
|
||||||
from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity, \
|
from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity, \
|
||||||
RealmDomain, Service, \
|
RealmDomain, Service, SubMessage, \
|
||||||
Subscription, Recipient, Message, Attachment, UserMessage, RealmAuditLog, \
|
Subscription, Recipient, Message, Attachment, UserMessage, RealmAuditLog, \
|
||||||
UserHotspot, MultiuseInvite, ScheduledMessage, \
|
UserHotspot, MultiuseInvite, ScheduledMessage, \
|
||||||
Client, DefaultStream, DefaultStreamGroup, UserPresence, PushDeviceToken, \
|
Client, DefaultStream, DefaultStreamGroup, UserPresence, PushDeviceToken, \
|
||||||
@@ -1424,6 +1424,32 @@ def bulk_insert_ums(ums: List[UserMessageLite]) -> None:
|
|||||||
with connection.cursor() as cursor:
|
with connection.cursor() as cursor:
|
||||||
cursor.execute(query)
|
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,
|
def notify_reaction_update(user_profile: UserProfile, message: Message,
|
||||||
reaction: Reaction, op: str) -> None:
|
reaction: Reaction, op: str) -> None:
|
||||||
user_dict = {'user_id': user_profile.id,
|
user_dict = {'user_id': user_profile.id,
|
||||||
|
|||||||
@@ -560,6 +560,9 @@ def apply_event(state: Dict[str, Any],
|
|||||||
elif event['type'] == "reaction":
|
elif event['type'] == "reaction":
|
||||||
# The client will get the message with the reactions directly
|
# The client will get the message with the reactions directly
|
||||||
pass
|
pass
|
||||||
|
elif event['type'] == "submessage":
|
||||||
|
# The client will get submessages with their messages
|
||||||
|
pass
|
||||||
elif event['type'] == 'typing':
|
elif event['type'] == 'typing':
|
||||||
# Typing notification events are transient and thus ignored
|
# Typing notification events are transient and thus ignored
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ from zerver.lib.actions import (
|
|||||||
do_add_realm_domain,
|
do_add_realm_domain,
|
||||||
do_add_realm_filter,
|
do_add_realm_filter,
|
||||||
do_add_streams_to_default_stream_group,
|
do_add_streams_to_default_stream_group,
|
||||||
|
do_add_submessage,
|
||||||
do_change_avatar_fields,
|
do_change_avatar_fields,
|
||||||
do_change_bot_owner,
|
do_change_bot_owner,
|
||||||
do_change_default_all_public_streams,
|
do_change_default_all_public_streams,
|
||||||
@@ -867,6 +868,34 @@ class EventsRegisterTest(ZulipTestCase):
|
|||||||
error = schema_checker('events[0]', events[0])
|
error = schema_checker('events[0]', events[0])
|
||||||
self.assert_on_error(error)
|
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:
|
def test_remove_reaction(self) -> None:
|
||||||
schema_checker = self.check_events_dict([
|
schema_checker = self.check_events_dict([
|
||||||
('type', equals('reaction')),
|
('type', equals('reaction')),
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import mock
|
||||||
|
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
|
|
||||||
from zerver.lib.message import (
|
from zerver.lib.message import (
|
||||||
@@ -73,3 +75,83 @@ class TestBasics(ZulipTestCase):
|
|||||||
rows = msg_rows[0]['submessages']
|
rows = msg_rows[0]['submessages']
|
||||||
rows.sort(key=lambda r: r['id'])
|
rows.sort(key=lambda r: r['id'])
|
||||||
self.assertEqual(rows, expected_data)
|
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,
|
url(r'users/me/subscriptions/(?P<stream_id>\d+)$', rest_dispatch,
|
||||||
{'PATCH': 'zerver.views.streams.update_subscriptions_property'}),
|
{'PATCH': 'zerver.views.streams.update_subscriptions_property'}),
|
||||||
|
|
||||||
|
url(r'^submessage$',
|
||||||
|
rest_dispatch,
|
||||||
|
{'POST': 'zerver.views.submessage.process_submessage'}),
|
||||||
|
|
||||||
# New endpoint for handling reactions.
|
# New endpoint for handling reactions.
|
||||||
url(r'^messages/(?P<message_id>[0-9]+)/reactions$',
|
url(r'^messages/(?P<message_id>[0-9]+)/reactions$',
|
||||||
rest_dispatch,
|
rest_dispatch,
|
||||||
|
|||||||
Reference in New Issue
Block a user