diff --git a/zerver/lib/actions.py b/zerver/lib/actions.py index 2aef9dfe54..826d9c4808 100644 --- a/zerver/lib/actions.py +++ b/zerver/lib/actions.py @@ -58,6 +58,7 @@ from zerver.lib.stream_topic import StreamTopicTarget from zerver.lib.topic import ( filter_by_exact_message_topic, filter_by_topic_name_via_message, + update_messages_for_topic_edit, ORIG_TOPIC, PREV_TOPIC, TOPIC_LINKS, @@ -3969,27 +3970,12 @@ def do_update_message(user_profile: UserProfile, message: Message, topic_name: O edit_history_event[PREV_TOPIC] = orig_topic_name if propagate_mode in ["change_later", "change_all"]: - propagate_query = Q(recipient = message.recipient, subject = orig_topic_name) - # We only change messages up to 2 days in the past, to avoid hammering our - # DB by changing an unbounded amount of messages - if propagate_mode == 'change_all': - before_bound = timezone_now() - datetime.timedelta(days=2) - - propagate_query = (propagate_query & ~Q(id = message.id) & - Q(pub_date__range=(before_bound, timezone_now()))) - if propagate_mode == 'change_later': - propagate_query = propagate_query & Q(id__gt = message.id) - - messages = Message.objects.filter(propagate_query).select_related() - - # Evaluate the query before running the update - messages_list = list(messages) - messages.update(subject=topic_name) - - for m in messages_list: - # The cached ORM object is not changed by messages.update() - # and the remote cache update requires the new value - m.set_topic_name(topic_name) + messages_list = update_messages_for_topic_edit( + message=message, + propagate_mode=propagate_mode, + orig_topic_name=orig_topic_name, + topic_name=topic_name, + ) changed_messages += messages_list diff --git a/zerver/lib/topic.py b/zerver/lib/topic.py index 18be776952..1b4ca0b482 100644 --- a/zerver/lib/topic.py +++ b/zerver/lib/topic.py @@ -1,5 +1,8 @@ +import datetime + from django.db import connection -from django.db.models.query import QuerySet +from django.db.models.query import QuerySet, Q +from django.utils.timezone import now as timezone_now from zerver.models import ( Message, @@ -22,6 +25,34 @@ def filter_by_exact_message_topic(query: QuerySet, message: Message) -> QuerySet def filter_by_topic_name_via_message(query: QuerySet, topic_name: str) -> QuerySet: return query.filter(message__subject__iexact=topic_name) +def update_messages_for_topic_edit(message: Message, + propagate_mode: str, + orig_topic_name: str, + topic_name: str) -> List[Message]: + propagate_query = Q(recipient = message.recipient, subject = orig_topic_name) + # We only change messages up to 2 days in the past, to avoid hammering our + # DB by changing an unbounded amount of messages + if propagate_mode == 'change_all': + before_bound = timezone_now() - datetime.timedelta(days=2) + + propagate_query = (propagate_query & ~Q(id = message.id) & + Q(pub_date__range=(before_bound, timezone_now()))) + if propagate_mode == 'change_later': + propagate_query = propagate_query & Q(id__gt = message.id) + + messages = Message.objects.filter(propagate_query).select_related() + + # Evaluate the query before running the update + messages_list = list(messages) + messages.update(subject=topic_name) + + for m in messages_list: + # The cached ORM object is not changed by messages.update() + # and the remote cache update requires the new value + m.set_topic_name(topic_name) + + return messages_list + def generate_topic_history_from_db_rows(rows: List[Tuple[str, int]]) -> List[Dict[str, Any]]: canonical_topic_names = {} # type: Dict[str, Tuple[int, str]]