mirror of https://github.com/zulip/zulip.git
events: Send `delete_message` event to user who deleted the message.
Fixes #29826. Co-authored-by: Mukul Goyal <goyal.mukul7689@gmail.com> Co-authored-by: Aman Agrawal <amanagr@zulip.com>
This commit is contained in:
parent
34d3b2302e
commit
7a80fcf042
|
@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 9.0
|
## Changes in Zulip 9.0
|
||||||
|
|
||||||
|
**Feature level 274**
|
||||||
|
|
||||||
|
* [`GET /events`](/api/get-events): `delete_message` events are now
|
||||||
|
always sent to the user who deletes the message, even if the message
|
||||||
|
was in a channel that the user was not subscribed to.
|
||||||
|
|
||||||
**Feature level 273**
|
**Feature level 273**
|
||||||
|
|
||||||
* [`POST /register`](/api/register-queue): Added `server_thumbnail_formats`
|
* [`POST /register`](/api/register-queue): Added `server_thumbnail_formats`
|
||||||
|
|
|
@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
||||||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||||
|
|
||||||
API_FEATURE_LEVEL = 273 # Last bumped for server_thumbnail_formats
|
API_FEATURE_LEVEL = 274 # Last bumped for `delete_message` event.
|
||||||
|
|
||||||
|
|
||||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||||
|
|
|
@ -45,7 +45,9 @@ def check_update_first_message_id(
|
||||||
send_event_on_commit(realm, stream_event, users_to_notify)
|
send_event_on_commit(realm, stream_event, users_to_notify)
|
||||||
|
|
||||||
|
|
||||||
def do_delete_messages(realm: Realm, messages: Iterable[Message]) -> None:
|
def do_delete_messages(
|
||||||
|
realm: Realm, messages: Iterable[Message], *, acting_user: UserProfile | None
|
||||||
|
) -> None:
|
||||||
# messages in delete_message event belong to the same topic
|
# messages in delete_message event belong to the same topic
|
||||||
# or is a single direct message, as any other behaviour is not possible with
|
# or is a single direct message, as any other behaviour is not possible with
|
||||||
# the current callers to this method.
|
# the current callers to this method.
|
||||||
|
@ -61,12 +63,12 @@ def do_delete_messages(realm: Realm, messages: Iterable[Message]) -> None:
|
||||||
|
|
||||||
sample_message = messages[0]
|
sample_message = messages[0]
|
||||||
message_type = "stream"
|
message_type = "stream"
|
||||||
users_to_notify = []
|
users_to_notify = set()
|
||||||
if not sample_message.is_stream_message():
|
if not sample_message.is_stream_message():
|
||||||
assert len(messages) == 1
|
assert len(messages) == 1
|
||||||
message_type = "private"
|
message_type = "private"
|
||||||
ums = UserMessage.objects.filter(message_id__in=message_ids)
|
ums = UserMessage.objects.filter(message_id__in=message_ids)
|
||||||
users_to_notify = [um.user_profile_id for um in ums]
|
users_to_notify = set(ums.values_list("user_profile_id", flat=True))
|
||||||
archiving_chunk_size = retention.MESSAGE_BATCH_SIZE
|
archiving_chunk_size = retention.MESSAGE_BATCH_SIZE
|
||||||
|
|
||||||
if message_type == "stream":
|
if message_type == "stream":
|
||||||
|
@ -78,9 +80,13 @@ def do_delete_messages(realm: Realm, messages: Iterable[Message]) -> None:
|
||||||
)
|
)
|
||||||
# We exclude long-term idle users, since they by definition have no active clients.
|
# We exclude long-term idle users, since they by definition have no active clients.
|
||||||
subscriptions = subscriptions.exclude(user_profile__long_term_idle=True)
|
subscriptions = subscriptions.exclude(user_profile__long_term_idle=True)
|
||||||
users_to_notify = list(subscriptions.values_list("user_profile_id", flat=True))
|
users_to_notify = set(subscriptions.values_list("user_profile_id", flat=True))
|
||||||
archiving_chunk_size = retention.STREAM_MESSAGE_BATCH_SIZE
|
archiving_chunk_size = retention.STREAM_MESSAGE_BATCH_SIZE
|
||||||
|
|
||||||
|
if acting_user is not None:
|
||||||
|
# Always send event to the user who deleted the message.
|
||||||
|
users_to_notify.add(acting_user.id)
|
||||||
|
|
||||||
move_messages_to_archive(message_ids, realm=realm, chunk_size=archiving_chunk_size)
|
move_messages_to_archive(message_ids, realm=realm, chunk_size=archiving_chunk_size)
|
||||||
if message_type == "stream":
|
if message_type == "stream":
|
||||||
stream = Stream.objects.get(id=sample_message.recipient.type_id)
|
stream = Stream.objects.get(id=sample_message.recipient.type_id)
|
||||||
|
|
|
@ -187,7 +187,7 @@ def maybe_send_resolve_topic_notifications(
|
||||||
# For that reason, we apply a short grace period during which
|
# For that reason, we apply a short grace period during which
|
||||||
# such an undo action will just delete the previous notification
|
# such an undo action will just delete the previous notification
|
||||||
# message instead.
|
# message instead.
|
||||||
if maybe_delete_previous_resolve_topic_notification(stream, new_topic_name):
|
if maybe_delete_previous_resolve_topic_notification(user_profile, stream, new_topic_name):
|
||||||
return None, True
|
return None, True
|
||||||
|
|
||||||
# Compute the users who either sent or reacted to messages that
|
# Compute the users who either sent or reacted to messages that
|
||||||
|
@ -222,7 +222,9 @@ def maybe_send_resolve_topic_notifications(
|
||||||
return resolved_topic_message_id, False
|
return resolved_topic_message_id, False
|
||||||
|
|
||||||
|
|
||||||
def maybe_delete_previous_resolve_topic_notification(stream: Stream, topic: str) -> bool:
|
def maybe_delete_previous_resolve_topic_notification(
|
||||||
|
user_profile: UserProfile, stream: Stream, topic: str
|
||||||
|
) -> bool:
|
||||||
assert stream.recipient_id is not None
|
assert stream.recipient_id is not None
|
||||||
last_message = messages_for_topic(stream.realm_id, stream.recipient_id, topic).last()
|
last_message = messages_for_topic(stream.realm_id, stream.recipient_id, topic).last()
|
||||||
|
|
||||||
|
@ -238,7 +240,7 @@ def maybe_delete_previous_resolve_topic_notification(stream: Stream, topic: str)
|
||||||
if time_difference > settings.RESOLVE_TOPIC_UNDO_GRACE_PERIOD_SECONDS:
|
if time_difference > settings.RESOLVE_TOPIC_UNDO_GRACE_PERIOD_SECONDS:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
do_delete_messages(stream.realm, [last_message])
|
do_delete_messages(stream.realm, [last_message], acting_user=user_profile)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2071,13 +2071,25 @@ paths:
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
description: |
|
description: |
|
||||||
Event sent when a message has been deleted.
|
Event sent when a message has been deleted.
|
||||||
Sent to all users who received the message.
|
|
||||||
|
Sent to all users who currently are subscribed to the
|
||||||
|
messages' recipient. May also be sent to additional users
|
||||||
|
who had access to it, including, in particular, an
|
||||||
|
administrator user deleting messages in a stream that they
|
||||||
|
are not subscribed to.
|
||||||
|
|
||||||
|
This means that clients can assume that they will always
|
||||||
|
receive an event of this type for deletions that the
|
||||||
|
client itself initiated.
|
||||||
|
|
||||||
This event is also sent when the user loses access to a message,
|
This event is also sent when the user loses access to a message,
|
||||||
such as when it is [moved to a channel][message-move-channel] that
|
such as when it is [moved to a channel][message-move-channel] that
|
||||||
the user does not [have permission to access][channel-access].
|
the user does not [have permission to access][channel-access].
|
||||||
|
|
||||||
**Changes**: Before Zulip 5.0 (feature level 77), events
|
**Changes**: Before Zulip 9.0 (feature level 274), this
|
||||||
|
event was only sent to subscribers of the message's recipient.
|
||||||
|
|
||||||
|
Before Zulip 5.0 (feature level 77), events
|
||||||
for direct messages contained additional `sender_id` and
|
for direct messages contained additional `sender_id` and
|
||||||
`recipient_id` fields.
|
`recipient_id` fields.
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ class UnclaimedAttachmentTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
message_id = self.send_stream_message(hamlet, "Denmark", body, "test")
|
message_id = self.send_stream_message(hamlet, "Denmark", body, "test")
|
||||||
|
|
||||||
# Delete that message; this moves it to ArchivedAttachment but leaves the file on disk
|
# Delete that message; this moves it to ArchivedAttachment but leaves the file on disk
|
||||||
do_delete_messages(hamlet.realm, [Message.objects.get(id=message_id)])
|
do_delete_messages(hamlet.realm, [Message.objects.get(id=message_id)], acting_user=None)
|
||||||
self.assert_exists(
|
self.assert_exists(
|
||||||
attachment, has_file=True, has_attachment=False, has_archived_attachment=True
|
attachment, has_file=True, has_attachment=False, has_archived_attachment=True
|
||||||
)
|
)
|
||||||
|
@ -190,7 +190,9 @@ class UnclaimedAttachmentTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
|
|
||||||
# Delete the second message; this leaves an Attachment and an
|
# Delete the second message; this leaves an Attachment and an
|
||||||
# ArchivedAttachment, both associated with a message
|
# ArchivedAttachment, both associated with a message
|
||||||
do_delete_messages(hamlet.realm, [Message.objects.get(id=first_message_id)])
|
do_delete_messages(
|
||||||
|
hamlet.realm, [Message.objects.get(id=first_message_id)], acting_user=None
|
||||||
|
)
|
||||||
self.assert_exists(
|
self.assert_exists(
|
||||||
attachment, has_file=True, has_attachment=True, has_archived_attachment=True
|
attachment, has_file=True, has_attachment=True, has_archived_attachment=True
|
||||||
)
|
)
|
||||||
|
@ -220,7 +222,9 @@ class UnclaimedAttachmentTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Deleting the other message now leaves just an ArchivedAttachment
|
# Deleting the other message now leaves just an ArchivedAttachment
|
||||||
do_delete_messages(hamlet.realm, [Message.objects.get(id=second_message_id)])
|
do_delete_messages(
|
||||||
|
hamlet.realm, [Message.objects.get(id=second_message_id)], acting_user=None
|
||||||
|
)
|
||||||
self.assert_exists(
|
self.assert_exists(
|
||||||
attachment, has_file=True, has_attachment=False, has_archived_attachment=True
|
attachment, has_file=True, has_attachment=False, has_archived_attachment=True
|
||||||
)
|
)
|
||||||
|
@ -298,7 +302,9 @@ class UnclaimedAttachmentTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
# Deleting the sent message leaves us with an Attachment
|
# Deleting the sent message leaves us with an Attachment
|
||||||
# attached to the scheduled message, and an archived
|
# attached to the scheduled message, and an archived
|
||||||
# attachment with an archived message
|
# attachment with an archived message
|
||||||
do_delete_messages(hamlet.realm, [Message.objects.get(id=sent_message_id)])
|
do_delete_messages(
|
||||||
|
hamlet.realm, [Message.objects.get(id=sent_message_id)], acting_user=None
|
||||||
|
)
|
||||||
self.assert_exists(
|
self.assert_exists(
|
||||||
attachment, has_file=True, has_attachment=True, has_archived_attachment=True
|
attachment, has_file=True, has_attachment=True, has_archived_attachment=True
|
||||||
)
|
)
|
||||||
|
@ -361,7 +367,9 @@ class UnclaimedAttachmentTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
|
|
||||||
# Delete the message and then unschedule the scheduled message
|
# Delete the message and then unschedule the scheduled message
|
||||||
# before expiring the ArchivedMessages.
|
# before expiring the ArchivedMessages.
|
||||||
do_delete_messages(hamlet.realm, [Message.objects.get(id=sent_message_id)])
|
do_delete_messages(
|
||||||
|
hamlet.realm, [Message.objects.get(id=sent_message_id)], acting_user=None
|
||||||
|
)
|
||||||
delete_scheduled_message(hamlet, scheduled_message_id)
|
delete_scheduled_message(hamlet, scheduled_message_id)
|
||||||
self.assert_exists(
|
self.assert_exists(
|
||||||
attachment, has_file=True, has_attachment=True, has_archived_attachment=True
|
attachment, has_file=True, has_attachment=True, has_archived_attachment=True
|
||||||
|
@ -425,7 +433,7 @@ class UnclaimedAttachmentTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
message_id = self.send_stream_message(hamlet, "Denmark", body, "test")
|
message_id = self.send_stream_message(hamlet, "Denmark", body, "test")
|
||||||
|
|
||||||
# Delete and purge the message, leaving both the ArchivedAttachments dangling
|
# Delete and purge the message, leaving both the ArchivedAttachments dangling
|
||||||
do_delete_messages(hamlet.realm, [Message.objects.get(id=message_id)])
|
do_delete_messages(hamlet.realm, [Message.objects.get(id=message_id)], acting_user=None)
|
||||||
with self.settings(ARCHIVED_DATA_VACUUMING_DELAY_DAYS=0):
|
with self.settings(ARCHIVED_DATA_VACUUMING_DELAY_DAYS=0):
|
||||||
clean_archived_data()
|
clean_archived_data()
|
||||||
|
|
||||||
|
|
|
@ -3117,7 +3117,7 @@ class NormalActionsTest(BaseAction):
|
||||||
msg_id_2 = self.send_stream_message(hamlet, "Verona")
|
msg_id_2 = self.send_stream_message(hamlet, "Verona")
|
||||||
messages = [Message.objects.get(id=msg_id), Message.objects.get(id=msg_id_2)]
|
messages = [Message.objects.get(id=msg_id), Message.objects.get(id=msg_id_2)]
|
||||||
with self.verify_action(state_change_expected=True) as events:
|
with self.verify_action(state_change_expected=True) as events:
|
||||||
do_delete_messages(self.user_profile.realm, messages)
|
do_delete_messages(self.user_profile.realm, messages, acting_user=None)
|
||||||
check_delete_message(
|
check_delete_message(
|
||||||
"events[0]",
|
"events[0]",
|
||||||
events[0],
|
events[0],
|
||||||
|
@ -3138,7 +3138,7 @@ class NormalActionsTest(BaseAction):
|
||||||
with self.verify_action(
|
with self.verify_action(
|
||||||
state_change_expected=True, bulk_message_deletion=False, num_events=2
|
state_change_expected=True, bulk_message_deletion=False, num_events=2
|
||||||
) as events:
|
) as events:
|
||||||
do_delete_messages(self.user_profile.realm, messages)
|
do_delete_messages(self.user_profile.realm, messages, acting_user=None)
|
||||||
check_delete_message(
|
check_delete_message(
|
||||||
"events[0]",
|
"events[0]",
|
||||||
events[0],
|
events[0],
|
||||||
|
@ -3154,7 +3154,7 @@ class NormalActionsTest(BaseAction):
|
||||||
msg_id_2 = self.send_stream_message(hamlet, "test_stream1")
|
msg_id_2 = self.send_stream_message(hamlet, "test_stream1")
|
||||||
message = Message.objects.get(id=msg_id)
|
message = Message.objects.get(id=msg_id)
|
||||||
with self.verify_action(state_change_expected=True, num_events=2) as events:
|
with self.verify_action(state_change_expected=True, num_events=2) as events:
|
||||||
do_delete_messages(self.user_profile.realm, [message])
|
do_delete_messages(self.user_profile.realm, [message], acting_user=None)
|
||||||
|
|
||||||
check_stream_update("events[0]", events[0])
|
check_stream_update("events[0]", events[0])
|
||||||
self.assertEqual(events[0]["property"], "first_message_id")
|
self.assertEqual(events[0]["property"], "first_message_id")
|
||||||
|
@ -3176,7 +3176,7 @@ class NormalActionsTest(BaseAction):
|
||||||
)
|
)
|
||||||
message = Message.objects.get(id=msg_id)
|
message = Message.objects.get(id=msg_id)
|
||||||
with self.verify_action(state_change_expected=True) as events:
|
with self.verify_action(state_change_expected=True) as events:
|
||||||
do_delete_messages(self.user_profile.realm, [message])
|
do_delete_messages(self.user_profile.realm, [message], acting_user=None)
|
||||||
check_delete_message(
|
check_delete_message(
|
||||||
"events[0]",
|
"events[0]",
|
||||||
events[0],
|
events[0],
|
||||||
|
@ -3193,7 +3193,7 @@ class NormalActionsTest(BaseAction):
|
||||||
)
|
)
|
||||||
message = Message.objects.get(id=msg_id)
|
message = Message.objects.get(id=msg_id)
|
||||||
with self.verify_action(state_change_expected=True, bulk_message_deletion=False) as events:
|
with self.verify_action(state_change_expected=True, bulk_message_deletion=False) as events:
|
||||||
do_delete_messages(self.user_profile.realm, [message])
|
do_delete_messages(self.user_profile.realm, [message], acting_user=None)
|
||||||
check_delete_message(
|
check_delete_message(
|
||||||
"events[0]",
|
"events[0]",
|
||||||
events[0],
|
events[0],
|
||||||
|
@ -3210,13 +3210,13 @@ class NormalActionsTest(BaseAction):
|
||||||
msg_id = self.send_stream_message(user_profile, "Verona")
|
msg_id = self.send_stream_message(user_profile, "Verona")
|
||||||
message = Message.objects.get(id=msg_id)
|
message = Message.objects.get(id=msg_id)
|
||||||
with self.verify_action(state_change_expected=True):
|
with self.verify_action(state_change_expected=True):
|
||||||
do_delete_messages(self.user_profile.realm, [message])
|
do_delete_messages(self.user_profile.realm, [message], acting_user=None)
|
||||||
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
||||||
self.assertEqual(result["max_message_id"], -1)
|
self.assertEqual(result["max_message_id"], -1)
|
||||||
|
|
||||||
def test_do_delete_message_with_no_messages(self) -> None:
|
def test_do_delete_message_with_no_messages(self) -> None:
|
||||||
with self.verify_action(num_events=0, state_change_expected=False) as events:
|
with self.verify_action(num_events=0, state_change_expected=False) as events:
|
||||||
do_delete_messages(self.user_profile.realm, [])
|
do_delete_messages(self.user_profile.realm, [], acting_user=None)
|
||||||
self.assertEqual(events, [])
|
self.assertEqual(events, [])
|
||||||
|
|
||||||
def test_add_attachment(self) -> None:
|
def test_add_attachment(self) -> None:
|
||||||
|
|
|
@ -496,7 +496,7 @@ class PreviewTestCase(ZulipTestCase):
|
||||||
event = patched.call_args[0][1]
|
event = patched.call_args[0][1]
|
||||||
|
|
||||||
msg = Message.objects.select_related("sender").get(id=msg_id)
|
msg = Message.objects.select_related("sender").get(id=msg_id)
|
||||||
do_delete_messages(msg.realm, [msg])
|
do_delete_messages(msg.realm, [msg], acting_user=None)
|
||||||
|
|
||||||
# We do still fetch the URL, as we don't want to incur the
|
# We do still fetch the URL, as we don't want to incur the
|
||||||
# cost of locking the row while we do the HTTP fetches.
|
# cost of locking the row while we do the HTTP fetches.
|
||||||
|
|
|
@ -308,7 +308,7 @@ class DeleteMessageTest(ZulipTestCase):
|
||||||
m.side_effect = AssertionError(
|
m.side_effect = AssertionError(
|
||||||
"Events should be sent only after the transaction commits."
|
"Events should be sent only after the transaction commits."
|
||||||
)
|
)
|
||||||
do_delete_messages(hamlet.realm, [message])
|
do_delete_messages(hamlet.realm, [message], acting_user=None)
|
||||||
|
|
||||||
def test_delete_message_in_unsubscribed_private_stream(self) -> None:
|
def test_delete_message_in_unsubscribed_private_stream(self) -> None:
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
|
@ -347,17 +347,17 @@ class DeleteMessageTest(ZulipTestCase):
|
||||||
first_message_id = message_ids[0]
|
first_message_id = message_ids[0]
|
||||||
|
|
||||||
message = Message.objects.get(id=message_ids[3])
|
message = Message.objects.get(id=message_ids[3])
|
||||||
do_delete_messages(realm, [message])
|
do_delete_messages(realm, [message], acting_user=None)
|
||||||
stream = get_stream(stream_name, realm)
|
stream = get_stream(stream_name, realm)
|
||||||
self.assertEqual(stream.first_message_id, first_message_id)
|
self.assertEqual(stream.first_message_id, first_message_id)
|
||||||
|
|
||||||
first_message = Message.objects.get(id=first_message_id)
|
first_message = Message.objects.get(id=first_message_id)
|
||||||
do_delete_messages(realm, [first_message])
|
do_delete_messages(realm, [first_message], acting_user=None)
|
||||||
stream = get_stream(stream_name, realm)
|
stream = get_stream(stream_name, realm)
|
||||||
self.assertEqual(stream.first_message_id, message_ids[1])
|
self.assertEqual(stream.first_message_id, message_ids[1])
|
||||||
|
|
||||||
all_messages = Message.objects.filter(id__in=message_ids)
|
all_messages = Message.objects.filter(id__in=message_ids)
|
||||||
with self.assert_database_query_count(24):
|
with self.assert_database_query_count(24):
|
||||||
do_delete_messages(realm, all_messages)
|
do_delete_messages(realm, all_messages, acting_user=None)
|
||||||
stream = get_stream(stream_name, realm)
|
stream = get_stream(stream_name, realm)
|
||||||
self.assertEqual(stream.first_message_id, None)
|
self.assertEqual(stream.first_message_id, None)
|
||||||
|
|
|
@ -1733,7 +1733,7 @@ class MessageMoveTopicTest(ZulipTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
message = Message.objects.get(id=message_id)
|
message = Message.objects.get(id=message_id)
|
||||||
do_delete_messages(admin_user.realm, [message])
|
do_delete_messages(admin_user.realm, [message], acting_user=None)
|
||||||
|
|
||||||
assert stream.recipient_id is not None
|
assert stream.recipient_id is not None
|
||||||
changed_messages = messages_for_topic(stream.realm_id, stream.recipient_id, original_topic)
|
changed_messages = messages_for_topic(stream.realm_id, stream.recipient_id, original_topic)
|
||||||
|
|
|
@ -3263,7 +3263,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
||||||
"trigger": NotificationTriggers.DIRECT_MESSAGE,
|
"trigger": NotificationTriggers.DIRECT_MESSAGE,
|
||||||
}
|
}
|
||||||
# Now, delete the message the normal way
|
# Now, delete the message the normal way
|
||||||
do_delete_messages(user_profile.realm, [message])
|
do_delete_messages(user_profile.realm, [message], acting_user=None)
|
||||||
|
|
||||||
# This mock.patch() should be assertNoLogs once that feature
|
# This mock.patch() should be assertNoLogs once that feature
|
||||||
# is added to Python.
|
# is added to Python.
|
||||||
|
|
|
@ -1146,7 +1146,7 @@ class TestDoDeleteMessages(ZulipTestCase):
|
||||||
messages = Message.objects.filter(id__in=message_ids)
|
messages = Message.objects.filter(id__in=message_ids)
|
||||||
|
|
||||||
with self.assert_database_query_count(22):
|
with self.assert_database_query_count(22):
|
||||||
do_delete_messages(realm, messages)
|
do_delete_messages(realm, messages, acting_user=None)
|
||||||
self.assertFalse(Message.objects.filter(id__in=message_ids).exists())
|
self.assertFalse(Message.objects.filter(id__in=message_ids).exists())
|
||||||
|
|
||||||
archived_messages = ArchivedMessage.objects.filter(id__in=message_ids)
|
archived_messages = ArchivedMessage.objects.filter(id__in=message_ids)
|
||||||
|
|
|
@ -183,7 +183,7 @@ def delete_message_backend(
|
||||||
message = access_message(user_profile, message_id, lock_message=True)
|
message = access_message(user_profile, message_id, lock_message=True)
|
||||||
validate_can_delete_message(user_profile, message)
|
validate_can_delete_message(user_profile, message)
|
||||||
try:
|
try:
|
||||||
do_delete_messages(user_profile.realm, [message])
|
do_delete_messages(user_profile.realm, [message], acting_user=user_profile)
|
||||||
except (Message.DoesNotExist, IntegrityError):
|
except (Message.DoesNotExist, IntegrityError):
|
||||||
raise JsonableError(_("Message already deleted"))
|
raise JsonableError(_("Message already deleted"))
|
||||||
return json_success(request)
|
return json_success(request)
|
||||||
|
|
|
@ -938,7 +938,7 @@ def delete_in_topic(
|
||||||
)
|
)
|
||||||
if not messages_to_delete:
|
if not messages_to_delete:
|
||||||
break
|
break
|
||||||
do_delete_messages(user_profile.realm, messages_to_delete)
|
do_delete_messages(user_profile.realm, messages_to_delete, acting_user=user_profile)
|
||||||
|
|
||||||
return json_success(request, data={"complete": True})
|
return json_success(request, data={"complete": True})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue