mirror of
https://github.com/zulip/zulip.git
synced 2025-11-09 08:26:11 +00:00
mute user: Mark as read old messages immediately.
When a user is muted, in the same request, we mark any existing unreads from that user as read. This is done for all types of messages (PM/huddle/stream) and regardless of whether the user was mentioned in them. This will not break the unread count logic of the web frontend, because that algorithm decides which messages to mark as read based only on the pointer location and the whitespace at the bottom, not on what messages have already been marked as read.
This commit is contained in:
committed by
Tim Abbott
parent
2f56f8d0ed
commit
8b098b95bb
@@ -5051,6 +5051,46 @@ def do_mark_stream_messages_as_read(
|
||||
return count
|
||||
|
||||
|
||||
def do_mark_muted_user_messages_as_read(
|
||||
user_profile: UserProfile,
|
||||
muted_user: UserProfile,
|
||||
) -> int:
|
||||
messages = UserMessage.objects.filter(
|
||||
user_profile=user_profile, message__sender=muted_user
|
||||
).extra(where=[UserMessage.where_unread()])
|
||||
|
||||
message_ids = list(messages.values_list("message__id", flat=True))
|
||||
|
||||
count = messages.update(
|
||||
flags=F("flags").bitor(UserMessage.flags.read),
|
||||
)
|
||||
|
||||
event = dict(
|
||||
type="update_message_flags",
|
||||
op="add",
|
||||
operation="add",
|
||||
flag="read",
|
||||
messages=message_ids,
|
||||
all=False,
|
||||
)
|
||||
event_time = timezone_now()
|
||||
|
||||
send_event(user_profile.realm, event, [user_profile.id])
|
||||
do_clear_mobile_push_notifications_for_ids([user_profile.id], message_ids)
|
||||
|
||||
do_increment_logging_stat(
|
||||
user_profile, COUNT_STATS["messages_read::hour"], None, event_time, increment=count
|
||||
)
|
||||
do_increment_logging_stat(
|
||||
user_profile,
|
||||
COUNT_STATS["messages_read_interactions::hour"],
|
||||
None,
|
||||
event_time,
|
||||
increment=min(1, count),
|
||||
)
|
||||
return count
|
||||
|
||||
|
||||
def do_update_mobile_push_notification(
|
||||
message: Message, prior_mention_user_ids: Set[int], stream_push_user_ids: Set[int]
|
||||
) -> None:
|
||||
@@ -6515,6 +6555,7 @@ def do_mute_user(
|
||||
if date_muted is None:
|
||||
date_muted = timezone_now()
|
||||
add_user_mute(user_profile, muted_user, date_muted)
|
||||
do_mark_muted_user_messages_as_read(user_profile, muted_user)
|
||||
event = dict(type="muted_users", muted_users=get_user_mutes(user_profile))
|
||||
send_event(user_profile.realm, event, [user_profile.id])
|
||||
|
||||
|
||||
@@ -1011,8 +1011,11 @@ class NormalActionsTest(BaseAction):
|
||||
|
||||
def test_muted_users_events(self) -> None:
|
||||
muted_user = self.example_user("othello")
|
||||
events = self.verify_action(lambda: do_mute_user(self.user_profile, muted_user))
|
||||
check_muted_users("events[0]", events[0])
|
||||
events = self.verify_action(
|
||||
lambda: do_mute_user(self.user_profile, muted_user), num_events=2
|
||||
)
|
||||
check_update_message_flags_add("events[0]", events[0])
|
||||
check_muted_users("events[1]", events[1])
|
||||
|
||||
mute_object = get_mute_object(self.user_profile, muted_user)
|
||||
assert mute_object is not None
|
||||
|
||||
@@ -224,3 +224,44 @@ class MutedUsersTests(ZulipTestCase):
|
||||
self.assert_usermessage_read_flag(othello, stream_message, False)
|
||||
self.assert_usermessage_read_flag(othello, huddle_message, False)
|
||||
self.assert_usermessage_read_flag(othello, pm_to_othello, False)
|
||||
|
||||
def test_existing_messages_from_muted_user_marked_as_read(self) -> None:
|
||||
hamlet = self.example_user("hamlet")
|
||||
self.login_user(hamlet)
|
||||
cordelia = self.example_user("cordelia")
|
||||
othello = self.example_user("othello")
|
||||
|
||||
self.make_stream("general")
|
||||
self.subscribe(hamlet, "general")
|
||||
self.subscribe(cordelia, "general")
|
||||
self.subscribe(othello, "general")
|
||||
|
||||
# Have Cordelia send messages to Hamlet and Othello.
|
||||
stream_message = self.send_stream_message(cordelia, "general", "Spam in stream")
|
||||
huddle_message = self.send_huddle_message(cordelia, [hamlet, othello], "Spam in huddle")
|
||||
pm_to_hamlet = self.send_personal_message(cordelia, hamlet, "Spam in PM")
|
||||
pm_to_othello = self.send_personal_message(cordelia, othello, "Spam in PM")
|
||||
|
||||
# These messages are unreads for both Hamlet and Othello right now.
|
||||
self.assert_usermessage_read_flag(hamlet, stream_message, False)
|
||||
self.assert_usermessage_read_flag(hamlet, huddle_message, False)
|
||||
self.assert_usermessage_read_flag(hamlet, pm_to_hamlet, False)
|
||||
|
||||
self.assert_usermessage_read_flag(othello, stream_message, False)
|
||||
self.assert_usermessage_read_flag(othello, huddle_message, False)
|
||||
self.assert_usermessage_read_flag(othello, pm_to_othello, False)
|
||||
|
||||
# Hamlet mutes Cordelia.
|
||||
url = "/api/v1/users/me/muted_users/{}".format(cordelia.id)
|
||||
result = self.api_post(hamlet, url)
|
||||
self.assert_json_success(result)
|
||||
|
||||
# The messages sent earlier should be marked as read for Hamlet.
|
||||
self.assert_usermessage_read_flag(hamlet, stream_message, True)
|
||||
self.assert_usermessage_read_flag(hamlet, huddle_message, True)
|
||||
self.assert_usermessage_read_flag(hamlet, pm_to_hamlet, True)
|
||||
|
||||
# These messages are still unreads for Othello, since he did not mute Cordelia.
|
||||
self.assert_usermessage_read_flag(othello, stream_message, False)
|
||||
self.assert_usermessage_read_flag(othello, huddle_message, False)
|
||||
self.assert_usermessage_read_flag(othello, pm_to_othello, False)
|
||||
|
||||
Reference in New Issue
Block a user