mirror of https://github.com/zulip/zulip.git
models: Always search Messages with a realm_id or id limit.
Unless there is a limit on `id`, always provide a `realm_id` limit as well. We also notate which index is expected to be used in each query.
This commit is contained in:
parent
f9dd2549eb
commit
b94402152d
|
@ -447,7 +447,13 @@ def count_message_by_user_query(realm: Optional[Realm]) -> QueryFn:
|
||||||
if realm is None:
|
if realm is None:
|
||||||
realm_clause: Composable = SQL("")
|
realm_clause: Composable = SQL("")
|
||||||
else:
|
else:
|
||||||
realm_clause = SQL("zerver_userprofile.realm_id = {} AND").format(Literal(realm.id))
|
# We limit both userprofile and message so that we only see
|
||||||
|
# users from this realm, but also get the performance speedup
|
||||||
|
# of limiting messages by realm.
|
||||||
|
realm_clause = SQL(
|
||||||
|
"zerver_userprofile.realm_id = {} AND zerver_message.realm_id = {} AND"
|
||||||
|
).format(Literal(realm.id), Literal(realm.id))
|
||||||
|
# Uses index: zerver_message_realm_date_sent (or the only-date index)
|
||||||
return lambda kwargs: SQL(
|
return lambda kwargs: SQL(
|
||||||
"""
|
"""
|
||||||
INSERT INTO analytics_usercount
|
INSERT INTO analytics_usercount
|
||||||
|
@ -474,7 +480,13 @@ def count_message_type_by_user_query(realm: Optional[Realm]) -> QueryFn:
|
||||||
if realm is None:
|
if realm is None:
|
||||||
realm_clause: Composable = SQL("")
|
realm_clause: Composable = SQL("")
|
||||||
else:
|
else:
|
||||||
realm_clause = SQL("zerver_userprofile.realm_id = {} AND").format(Literal(realm.id))
|
# We limit both userprofile and message so that we only see
|
||||||
|
# users from this realm, but also get the performance speedup
|
||||||
|
# of limiting messages by realm.
|
||||||
|
realm_clause = SQL(
|
||||||
|
"zerver_userprofile.realm_id = {} AND zerver_message.realm_id = {} AND"
|
||||||
|
).format(Literal(realm.id), Literal(realm.id))
|
||||||
|
# Uses index: zerver_message_realm_date_sent (or the only-date index)
|
||||||
return lambda kwargs: SQL(
|
return lambda kwargs: SQL(
|
||||||
"""
|
"""
|
||||||
INSERT INTO analytics_usercount
|
INSERT INTO analytics_usercount
|
||||||
|
@ -523,7 +535,10 @@ def count_message_by_stream_query(realm: Optional[Realm]) -> QueryFn:
|
||||||
if realm is None:
|
if realm is None:
|
||||||
realm_clause: Composable = SQL("")
|
realm_clause: Composable = SQL("")
|
||||||
else:
|
else:
|
||||||
realm_clause = SQL("zerver_stream.realm_id = {} AND").format(Literal(realm.id))
|
realm_clause = SQL(
|
||||||
|
"zerver_stream.realm_id = {} AND zerver_message.realm_id = {} AND"
|
||||||
|
).format(Literal(realm.id), Literal(realm.id))
|
||||||
|
# Uses index: zerver_message_realm_date_sent (or the only-date index)
|
||||||
return lambda kwargs: SQL(
|
return lambda kwargs: SQL(
|
||||||
"""
|
"""
|
||||||
INSERT INTO analytics_streamcount
|
INSERT INTO analytics_streamcount
|
||||||
|
|
|
@ -39,6 +39,7 @@ if settings.BILLING_ENABLED:
|
||||||
|
|
||||||
|
|
||||||
def get_realm_day_counts() -> Dict[str, Dict[str, Markup]]:
|
def get_realm_day_counts() -> Dict[str, Dict[str, Markup]]:
|
||||||
|
# Uses index: zerver_message_date_sent_3b5b05d8
|
||||||
query = SQL(
|
query = SQL(
|
||||||
"""
|
"""
|
||||||
select
|
select
|
||||||
|
|
|
@ -163,6 +163,7 @@ def sent_messages_report(realm: str) -> str:
|
||||||
"Bots",
|
"Bots",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Uses index: zerver_message_realm_date_sent
|
||||||
query = SQL(
|
query = SQL(
|
||||||
"""
|
"""
|
||||||
select
|
select
|
||||||
|
@ -188,6 +189,8 @@ def sent_messages_report(realm: str) -> str:
|
||||||
r.string_id = %s
|
r.string_id = %s
|
||||||
and
|
and
|
||||||
date_sent > now() - interval '2 week'
|
date_sent > now() - interval '2 week'
|
||||||
|
and
|
||||||
|
m.realm_id = r.id
|
||||||
group by
|
group by
|
||||||
date_sent::date
|
date_sent::date
|
||||||
order by
|
order by
|
||||||
|
|
|
@ -2550,7 +2550,7 @@ class StripeTest(StripeTestCase):
|
||||||
)
|
)
|
||||||
sender = get_system_bot(settings.NOTIFICATION_BOT, user.realm_id)
|
sender = get_system_bot(settings.NOTIFICATION_BOT, user.realm_id)
|
||||||
recipient_id = self.example_user("desdemona").recipient_id
|
recipient_id = self.example_user("desdemona").recipient_id
|
||||||
message = Message.objects.filter(sender=sender.id).first()
|
message = Message.objects.filter(realm_id=realm.id, sender=sender.id).first()
|
||||||
assert message is not None
|
assert message is not None
|
||||||
self.assertEqual(message.content, expected_message)
|
self.assertEqual(message.content, expected_message)
|
||||||
self.assertEqual(message.recipient.type, Recipient.PERSONAL)
|
self.assertEqual(message.recipient.type, Recipient.PERSONAL)
|
||||||
|
|
|
@ -139,7 +139,7 @@ def send_bot_mock_message(
|
||||||
bot: UserProfile, integration: Integration, fixture_path: str, config: BaseScreenshotConfig
|
bot: UserProfile, integration: Integration, fixture_path: str, config: BaseScreenshotConfig
|
||||||
) -> None:
|
) -> None:
|
||||||
# Delete all messages, so new message is the only one it's message group
|
# Delete all messages, so new message is the only one it's message group
|
||||||
Message.objects.filter(sender=bot).delete()
|
Message.objects.filter(realm_id=bot.realm_id, sender=bot).delete()
|
||||||
data, _, _ = get_fixture_info(fixture_path)
|
data, _, _ = get_fixture_info(fixture_path)
|
||||||
|
|
||||||
assert bot.bot_owner is not None
|
assert bot.bot_owner is not None
|
||||||
|
@ -166,7 +166,7 @@ def send_bot_payload_message(
|
||||||
bot: UserProfile, integration: WebhookIntegration, fixture_path: str, config: ScreenshotConfig
|
bot: UserProfile, integration: WebhookIntegration, fixture_path: str, config: ScreenshotConfig
|
||||||
) -> bool:
|
) -> bool:
|
||||||
# Delete all messages, so new message is the only one it's message group
|
# Delete all messages, so new message is the only one it's message group
|
||||||
Message.objects.filter(sender=bot).delete()
|
Message.objects.filter(realm_id=bot.realm_id, sender=bot).delete()
|
||||||
data, json_fixture, fixture_name = get_fixture_info(fixture_path)
|
data, json_fixture, fixture_name = get_fixture_info(fixture_path)
|
||||||
|
|
||||||
headers = get_requests_headers(integration.name, fixture_name)
|
headers = get_requests_headers(integration.name, fixture_name)
|
||||||
|
@ -217,7 +217,7 @@ def send_bot_payload_message(
|
||||||
|
|
||||||
|
|
||||||
def capture_last_message_screenshot(bot: UserProfile, image_path: str) -> None:
|
def capture_last_message_screenshot(bot: UserProfile, image_path: str) -> None:
|
||||||
message = Message.objects.filter(sender=bot).last()
|
message = Message.objects.filter(realm_id=bot.realm_id, sender=bot).last()
|
||||||
realm = get_realm("zulip")
|
realm = get_realm("zulip")
|
||||||
if message is None:
|
if message is None:
|
||||||
print(f"No message found for {bot.full_name}")
|
print(f"No message found for {bot.full_name}")
|
||||||
|
|
|
@ -17,6 +17,23 @@ rules:
|
||||||
include:
|
include:
|
||||||
- zerver/views/
|
- zerver/views/
|
||||||
|
|
||||||
|
- id: limit-message-filter
|
||||||
|
patterns:
|
||||||
|
- pattern: Message.objects.filter(...)
|
||||||
|
- pattern-not: Message.objects.filter(..., realm=..., ...)
|
||||||
|
- pattern-not: Message.objects.filter(..., realm_id=..., ...)
|
||||||
|
- pattern-not: Message.objects.filter(..., realm_id__in=..., ...)
|
||||||
|
- pattern-not: Message.objects.filter(..., id=..., ...)
|
||||||
|
- pattern-not: Message.objects.filter(..., id__in=..., ...)
|
||||||
|
- pattern-not: Message.objects.filter(..., id__lt=..., ...)
|
||||||
|
- pattern-not: Message.objects.filter(..., id__gt=..., ...)
|
||||||
|
message: "Set either a realm limit or an id limit on Message queries"
|
||||||
|
languages: [python]
|
||||||
|
severity: ERROR
|
||||||
|
paths:
|
||||||
|
exclude:
|
||||||
|
- "**/migrations/"
|
||||||
|
|
||||||
- id: dont-import-models-in-migrations
|
- id: dont-import-models-in-migrations
|
||||||
patterns:
|
patterns:
|
||||||
- pattern-not: from zerver.lib.redis_utils import get_redis_client
|
- pattern-not: from zerver.lib.redis_utils import get_redis_client
|
||||||
|
|
|
@ -181,7 +181,12 @@ def add_new_user_history(user_profile: UserProfile, streams: Iterable[Stream]) -
|
||||||
# Start by finding recent messages matching those recipients.
|
# Start by finding recent messages matching those recipients.
|
||||||
cutoff_date = timezone_now() - ONBOARDING_RECENT_TIMEDELTA
|
cutoff_date = timezone_now() - ONBOARDING_RECENT_TIMEDELTA
|
||||||
recent_message_ids = set(
|
recent_message_ids = set(
|
||||||
Message.objects.filter(recipient_id__in=recipient_ids, date_sent__gt=cutoff_date)
|
Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_id
|
||||||
|
realm_id=user_profile.realm_id,
|
||||||
|
recipient_id__in=recipient_ids,
|
||||||
|
date_sent__gt=cutoff_date,
|
||||||
|
)
|
||||||
.order_by("-id")
|
.order_by("-id")
|
||||||
.values_list("id", flat=True)[0:MAX_NUM_ONBOARDING_MESSAGES]
|
.values_list("id", flat=True)[0:MAX_NUM_ONBOARDING_MESSAGES]
|
||||||
)
|
)
|
||||||
|
|
|
@ -134,7 +134,11 @@ def too_many_recent_realm_invites(realm: Realm, num_invitees: int) -> bool:
|
||||||
not estimated_sent["messages"]
|
not estimated_sent["messages"]
|
||||||
# Only after we've done the rough-estimate check, take the
|
# Only after we've done the rough-estimate check, take the
|
||||||
# time to do the exact check:
|
# time to do the exact check:
|
||||||
and not Message.objects.filter(realm=realm, sender__is_bot=False).exists()
|
and not Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_sender_recipient (prefix)
|
||||||
|
realm=realm,
|
||||||
|
sender__is_bot=False,
|
||||||
|
).exists()
|
||||||
):
|
):
|
||||||
warning_flags.append("no-messages-sent")
|
warning_flags.append("no-messages-sent")
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,10 @@ def do_delete_messages(realm: Realm, messages: Iterable[Message]) -> None:
|
||||||
|
|
||||||
def do_delete_messages_by_sender(user: UserProfile) -> None:
|
def do_delete_messages_by_sender(user: UserProfile) -> None:
|
||||||
message_ids = list(
|
message_ids = list(
|
||||||
Message.objects.filter(sender=user).values_list("id", flat=True).order_by("id")
|
# Uses index: zerver_message_realm_sender_recipient (prefix)
|
||||||
|
Message.objects.filter(realm_id=user.realm_id, sender=user)
|
||||||
|
.values_list("id", flat=True)
|
||||||
|
.order_by("id")
|
||||||
)
|
)
|
||||||
if message_ids:
|
if message_ids:
|
||||||
move_messages_to_archive(message_ids, chunk_size=retention.STREAM_MESSAGE_BATCH_SIZE)
|
move_messages_to_archive(message_ids, chunk_size=retention.STREAM_MESSAGE_BATCH_SIZE)
|
||||||
|
|
|
@ -611,7 +611,7 @@ def do_update_message(
|
||||||
|
|
||||||
assert target_stream.recipient_id is not None
|
assert target_stream.recipient_id is not None
|
||||||
target_topic_has_messages = messages_for_topic(
|
target_topic_has_messages = messages_for_topic(
|
||||||
target_stream.recipient_id, target_topic
|
realm.id, target_stream.recipient_id, target_topic
|
||||||
).exists()
|
).exists()
|
||||||
|
|
||||||
if propagate_mode in ["change_later", "change_all"]:
|
if propagate_mode in ["change_later", "change_all"]:
|
||||||
|
@ -804,6 +804,7 @@ def do_update_message(
|
||||||
# unless the topic has thousands of messages of history.
|
# unless the topic has thousands of messages of history.
|
||||||
assert stream_being_edited.recipient_id is not None
|
assert stream_being_edited.recipient_id is not None
|
||||||
unmoved_messages = messages_for_topic(
|
unmoved_messages = messages_for_topic(
|
||||||
|
realm.id,
|
||||||
stream_being_edited.recipient_id,
|
stream_being_edited.recipient_id,
|
||||||
orig_topic_name,
|
orig_topic_name,
|
||||||
)
|
)
|
||||||
|
@ -1041,7 +1042,7 @@ def do_update_message(
|
||||||
# it reuses existing logic, which is good for keeping it
|
# it reuses existing logic, which is good for keeping it
|
||||||
# correct as we maintain the codebase.
|
# correct as we maintain the codebase.
|
||||||
preexisting_topic_messages = messages_for_topic(
|
preexisting_topic_messages = messages_for_topic(
|
||||||
stream_for_new_topic.recipient_id, new_topic
|
realm.id, stream_for_new_topic.recipient_id, new_topic
|
||||||
).exclude(id__in=[*changed_message_ids, resolved_topic_message_id])
|
).exclude(id__in=[*changed_message_ids, resolved_topic_message_id])
|
||||||
|
|
||||||
visible_preexisting_messages = bulk_access_messages(
|
visible_preexisting_messages = bulk_access_messages(
|
||||||
|
@ -1136,6 +1137,7 @@ def check_time_limit_for_change_all_propagate_mode(
|
||||||
).values_list("message_id", flat=True)
|
).values_list("message_id", flat=True)
|
||||||
messages_allowed_to_move: List[int] = list(
|
messages_allowed_to_move: List[int] = list(
|
||||||
Message.objects.filter(
|
Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_pkey
|
||||||
id__in=accessible_messages_in_topic,
|
id__in=accessible_messages_in_topic,
|
||||||
date_sent__gt=timezone_now()
|
date_sent__gt=timezone_now()
|
||||||
- datetime.timedelta(seconds=message_move_deadline_seconds),
|
- datetime.timedelta(seconds=message_move_deadline_seconds),
|
||||||
|
@ -1146,7 +1148,7 @@ def check_time_limit_for_change_all_propagate_mode(
|
||||||
total_messages_requested_to_move = len(accessible_messages_in_topic)
|
total_messages_requested_to_move = len(accessible_messages_in_topic)
|
||||||
else:
|
else:
|
||||||
all_messages_in_topic = (
|
all_messages_in_topic = (
|
||||||
messages_for_topic(message.recipient_id, message.topic_name())
|
messages_for_topic(message.realm_id, message.recipient_id, message.topic_name())
|
||||||
.order_by("id")
|
.order_by("id")
|
||||||
.values_list("id", "date_sent")
|
.values_list("id", "date_sent")
|
||||||
)
|
)
|
||||||
|
|
|
@ -276,6 +276,7 @@ def do_update_message_flags(
|
||||||
subscribed_recipient_ids = get_subscribed_stream_recipient_ids_for_user(user_profile)
|
subscribed_recipient_ids = get_subscribed_stream_recipient_ids_for_user(user_profile)
|
||||||
|
|
||||||
message_ids_in_unsubscribed_streams = set(
|
message_ids_in_unsubscribed_streams = set(
|
||||||
|
# Uses index: zerver_message_pkey
|
||||||
Message.objects.select_related("recipient")
|
Message.objects.select_related("recipient")
|
||||||
.filter(id__in=messages, recipient__type=Recipient.STREAM)
|
.filter(id__in=messages, recipient__type=Recipient.STREAM)
|
||||||
.exclude(recipient_id__in=subscribed_recipient_ids)
|
.exclude(recipient_id__in=subscribed_recipient_ids)
|
||||||
|
@ -326,6 +327,7 @@ def do_update_message_flags(
|
||||||
historical_messages = bulk_access_messages(
|
historical_messages = bulk_access_messages(
|
||||||
user_profile,
|
user_profile,
|
||||||
list(
|
list(
|
||||||
|
# Uses index: zerver_message_pkey
|
||||||
Message.objects.filter(id__in=historical_message_ids).prefetch_related(
|
Message.objects.filter(id__in=historical_message_ids).prefetch_related(
|
||||||
"recipient"
|
"recipient"
|
||||||
)
|
)
|
||||||
|
|
|
@ -232,7 +232,7 @@ def get_recipient_info(
|
||||||
# has syntax that might be a @topic mention without having confirmed the syntax isn't, say,
|
# has syntax that might be a @topic mention without having confirmed the syntax isn't, say,
|
||||||
# in a code block.
|
# in a code block.
|
||||||
topic_participant_user_ids = participants_for_topic(
|
topic_participant_user_ids = participants_for_topic(
|
||||||
recipient.id, stream_topic.topic_name
|
realm_id, recipient.id, stream_topic.topic_name
|
||||||
)
|
)
|
||||||
subscription_rows = (
|
subscription_rows = (
|
||||||
get_subscriptions_for_send_message(
|
get_subscriptions_for_send_message(
|
||||||
|
@ -1085,6 +1085,8 @@ def already_sent_mirrored_message_id(message: Message) -> Optional[int]:
|
||||||
time_window = datetime.timedelta(seconds=0)
|
time_window = datetime.timedelta(seconds=0)
|
||||||
|
|
||||||
messages = Message.objects.filter(
|
messages = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_subject
|
||||||
|
realm_id=message.realm_id,
|
||||||
sender=message.sender,
|
sender=message.sender,
|
||||||
recipient=message.recipient,
|
recipient=message.recipient,
|
||||||
subject=message.topic_name(),
|
subject=message.topic_name(),
|
||||||
|
|
|
@ -420,8 +420,11 @@ def do_scrub_realm(realm: Realm, *, acting_user: Optional[UserProfile]) -> None:
|
||||||
)
|
)
|
||||||
cross_realm_bot_message_ids = list(
|
cross_realm_bot_message_ids = list(
|
||||||
Message.objects.filter(
|
Message.objects.filter(
|
||||||
# Filtering by both message.recipient and message.realm is more robust for ensuring
|
# Filtering by both message.recipient and message.realm is
|
||||||
# no messages belonging to another realm will be deleted due to some bugs.
|
# more robust for ensuring no messages belonging to
|
||||||
|
# another realm will be deleted due to some bugs.
|
||||||
|
#
|
||||||
|
# Uses index: zerver_message_realm_sender_recipient
|
||||||
sender__realm=internal_realm,
|
sender__realm=internal_realm,
|
||||||
recipient_id__in=all_recipient_ids_in_realm,
|
recipient_id__in=all_recipient_ids_in_realm,
|
||||||
realm=realm,
|
realm=realm,
|
||||||
|
|
|
@ -193,7 +193,11 @@ def do_reactivate_stream(
|
||||||
|
|
||||||
# Update caches
|
# Update caches
|
||||||
cache_set(display_recipient_cache_key(stream.recipient_id), new_name)
|
cache_set(display_recipient_cache_key(stream.recipient_id), new_name)
|
||||||
messages = Message.objects.filter(recipient_id=stream.recipient_id).only("id")
|
messages = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_id
|
||||||
|
realm_id=realm.id,
|
||||||
|
recipient_id=stream.recipient_id,
|
||||||
|
).only("id")
|
||||||
cache_delete_many(to_dict_cache_key_id(message.id) for message in messages)
|
cache_delete_many(to_dict_cache_key_id(message.id) for message in messages)
|
||||||
|
|
||||||
# Unset the is_web_public cache on attachments, since the stream is now private.
|
# Unset the is_web_public cache on attachments, since the stream is now private.
|
||||||
|
@ -284,11 +288,17 @@ def merge_streams(
|
||||||
# this before removing the subscription objects, to avoid messages
|
# this before removing the subscription objects, to avoid messages
|
||||||
# "disappearing" if an error interrupts this function.
|
# "disappearing" if an error interrupts this function.
|
||||||
message_ids_to_clear = list(
|
message_ids_to_clear = list(
|
||||||
Message.objects.filter(recipient=recipient_to_destroy).values_list("id", flat=True)
|
Message.objects.filter(
|
||||||
)
|
# Uses index: zerver_message_realm_recipient_id
|
||||||
count = Message.objects.filter(recipient=recipient_to_destroy).update(
|
realm_id=realm.id,
|
||||||
recipient=recipient_to_keep
|
recipient=recipient_to_destroy,
|
||||||
|
).values_list("id", flat=True)
|
||||||
)
|
)
|
||||||
|
count = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_id (prefix)
|
||||||
|
realm_id=realm.id,
|
||||||
|
recipient=recipient_to_destroy,
|
||||||
|
).update(recipient=recipient_to_keep)
|
||||||
bulk_delete_cache_keys(message_ids_to_clear)
|
bulk_delete_cache_keys(message_ids_to_clear)
|
||||||
|
|
||||||
# Remove subscriptions to the old stream.
|
# Remove subscriptions to the old stream.
|
||||||
|
@ -1185,7 +1195,11 @@ def do_rename_stream(stream: Stream, new_name: str, user_profile: UserProfile) -
|
||||||
|
|
||||||
assert stream.recipient_id is not None
|
assert stream.recipient_id is not None
|
||||||
recipient_id: int = stream.recipient_id
|
recipient_id: int = stream.recipient_id
|
||||||
messages = Message.objects.filter(recipient_id=recipient_id).only("id")
|
messages = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_id
|
||||||
|
realm_id=stream.realm_id,
|
||||||
|
recipient_id=recipient_id,
|
||||||
|
).only("id")
|
||||||
|
|
||||||
cache_set(display_recipient_cache_key(recipient_id), stream.name)
|
cache_set(display_recipient_cache_key(recipient_id), stream.name)
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,10 @@ def do_delete_user_preserving_messages(user_profile: UserProfile) -> None:
|
||||||
force_date_joined=date_joined,
|
force_date_joined=date_joined,
|
||||||
create_personal_recipient=False,
|
create_personal_recipient=False,
|
||||||
)
|
)
|
||||||
Message.objects.filter(sender=user_profile).update(sender=temp_replacement_user)
|
# Uses index: zerver_message_realm_sender_recipient (prefix)
|
||||||
|
Message.objects.filter(realm_id=realm.id, sender=user_profile).update(
|
||||||
|
sender=temp_replacement_user
|
||||||
|
)
|
||||||
Subscription.objects.filter(
|
Subscription.objects.filter(
|
||||||
user_profile=user_profile, recipient__type=Recipient.HUDDLE
|
user_profile=user_profile, recipient__type=Recipient.HUDDLE
|
||||||
).update(user_profile=temp_replacement_user)
|
).update(user_profile=temp_replacement_user)
|
||||||
|
@ -212,7 +215,10 @@ def do_delete_user_preserving_messages(user_profile: UserProfile) -> None:
|
||||||
replacement_user.recipient = personal_recipient
|
replacement_user.recipient = personal_recipient
|
||||||
replacement_user.save(update_fields=["recipient"])
|
replacement_user.save(update_fields=["recipient"])
|
||||||
|
|
||||||
Message.objects.filter(sender=temp_replacement_user).update(sender=replacement_user)
|
# Uses index: zerver_message_realm_sender_recipient (prefix)
|
||||||
|
Message.objects.filter(realm_id=realm.id, sender=temp_replacement_user).update(
|
||||||
|
sender=replacement_user
|
||||||
|
)
|
||||||
Subscription.objects.filter(
|
Subscription.objects.filter(
|
||||||
user_profile=temp_replacement_user, recipient__type=Recipient.HUDDLE
|
user_profile=temp_replacement_user, recipient__type=Recipient.HUDDLE
|
||||||
).update(user_profile=replacement_user, is_user_active=replacement_user.is_active)
|
).update(user_profile=replacement_user, is_user_active=replacement_user.is_active)
|
||||||
|
|
|
@ -162,6 +162,7 @@ def _enqueue_emails_for_realm(realm: Realm, cutoff: datetime.datetime) -> None:
|
||||||
|
|
||||||
|
|
||||||
def get_recent_topics(
|
def get_recent_topics(
|
||||||
|
realm_id: int,
|
||||||
stream_ids: List[int],
|
stream_ids: List[int],
|
||||||
cutoff_date: datetime.datetime,
|
cutoff_date: datetime.datetime,
|
||||||
) -> List[DigestTopic]:
|
) -> List[DigestTopic]:
|
||||||
|
@ -171,7 +172,9 @@ def get_recent_topics(
|
||||||
# * number of senders
|
# * number of senders
|
||||||
|
|
||||||
messages = (
|
messages = (
|
||||||
|
# Uses index: zerver_message_realm_recipient_date_sent
|
||||||
Message.objects.filter(
|
Message.objects.filter(
|
||||||
|
realm_id=realm_id,
|
||||||
recipient__type=Recipient.STREAM,
|
recipient__type=Recipient.STREAM,
|
||||||
recipient__type_id__in=stream_ids,
|
recipient__type_id__in=stream_ids,
|
||||||
date_sent__gt=cutoff_date,
|
date_sent__gt=cutoff_date,
|
||||||
|
@ -307,7 +310,7 @@ def bulk_get_digest_context(
|
||||||
# Get all the recent topics for all the users. This does the heavy
|
# Get all the recent topics for all the users. This does the heavy
|
||||||
# lifting of making an expensive query to the Message table. Then
|
# lifting of making an expensive query to the Message table. Then
|
||||||
# for each user, we filter to just the streams they care about.
|
# for each user, we filter to just the streams they care about.
|
||||||
recent_topics = get_recent_topics(sorted(all_stream_ids), cutoff_date)
|
recent_topics = get_recent_topics(realm.id, sorted(all_stream_ids), cutoff_date)
|
||||||
|
|
||||||
stream_map = get_slim_stream_map(all_stream_ids)
|
stream_map = get_slim_stream_map(all_stream_ids)
|
||||||
|
|
||||||
|
|
|
@ -629,6 +629,7 @@ def handle_missedmessage_emails(
|
||||||
# messages that were permanently deleted, since those would now be
|
# messages that were permanently deleted, since those would now be
|
||||||
# in the ArchivedMessage table, not the Message table.
|
# in the ArchivedMessage table, not the Message table.
|
||||||
messages = Message.objects.filter(
|
messages = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_pkey
|
||||||
usermessage__user_profile_id=user_profile,
|
usermessage__user_profile_id=user_profile,
|
||||||
id__in=message_ids,
|
id__in=message_ids,
|
||||||
usermessage__flags=~UserMessage.flags.read,
|
usermessage__flags=~UserMessage.flags.read,
|
||||||
|
|
|
@ -1314,6 +1314,8 @@ def export_partial_message_files(
|
||||||
|
|
||||||
if public_only:
|
if public_only:
|
||||||
messages_we_received = Message.objects.filter(
|
messages_we_received = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_sender_recipient
|
||||||
|
realm_id=realm.id,
|
||||||
sender__in=ids_of_our_possible_senders,
|
sender__in=ids_of_our_possible_senders,
|
||||||
recipient__in=recipient_ids_for_us,
|
recipient__in=recipient_ids_for_us,
|
||||||
)
|
)
|
||||||
|
@ -1329,6 +1331,8 @@ def export_partial_message_files(
|
||||||
# anyone in the export and received by any of the users who we
|
# anyone in the export and received by any of the users who we
|
||||||
# have consent to export.
|
# have consent to export.
|
||||||
messages_we_received = Message.objects.filter(
|
messages_we_received = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_sender_recipient
|
||||||
|
realm_id=realm.id,
|
||||||
sender__in=ids_of_our_possible_senders,
|
sender__in=ids_of_our_possible_senders,
|
||||||
recipient__in=recipient_ids_for_us,
|
recipient__in=recipient_ids_for_us,
|
||||||
)
|
)
|
||||||
|
@ -1345,6 +1349,8 @@ def export_partial_message_files(
|
||||||
messages_we_received_in_protected_history_streams = Message.objects.annotate(
|
messages_we_received_in_protected_history_streams = Message.objects.annotate(
|
||||||
has_usermessage=has_usermessage_expression
|
has_usermessage=has_usermessage_expression
|
||||||
).filter(
|
).filter(
|
||||||
|
# Uses index: zerver_message_realm_sender_recipient
|
||||||
|
realm_id=realm.id,
|
||||||
sender__in=ids_of_our_possible_senders,
|
sender__in=ids_of_our_possible_senders,
|
||||||
recipient_id__in=(
|
recipient_id__in=(
|
||||||
set(consented_recipient_ids) & set(streams_with_protected_history_recipient_ids)
|
set(consented_recipient_ids) & set(streams_with_protected_history_recipient_ids)
|
||||||
|
@ -1370,6 +1376,8 @@ def export_partial_message_files(
|
||||||
recipient_ids_for_them = get_ids(recipients_for_them)
|
recipient_ids_for_them = get_ids(recipients_for_them)
|
||||||
|
|
||||||
messages_we_sent_to_them = Message.objects.filter(
|
messages_we_sent_to_them = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_sender_recipient
|
||||||
|
realm_id=realm.id,
|
||||||
sender__in=consented_user_ids,
|
sender__in=consented_user_ids,
|
||||||
recipient__in=recipient_ids_for_them,
|
recipient__in=recipient_ids_for_them,
|
||||||
)
|
)
|
||||||
|
@ -1410,6 +1418,7 @@ def write_message_partials(
|
||||||
dump_file_id = 1
|
dump_file_id = 1
|
||||||
|
|
||||||
for message_id_chunk in message_id_chunks:
|
for message_id_chunk in message_id_chunks:
|
||||||
|
# Uses index: zerver_message_pkey
|
||||||
actual_query = Message.objects.filter(id__in=message_id_chunk).order_by("id")
|
actual_query = Message.objects.filter(id__in=message_id_chunk).order_by("id")
|
||||||
message_chunk = make_raw(actual_query)
|
message_chunk = make_raw(actual_query)
|
||||||
|
|
||||||
|
@ -2253,13 +2262,21 @@ def export_messages_single_user(
|
||||||
|
|
||||||
return ", ".join(user_names)
|
return ", ".join(user_names)
|
||||||
|
|
||||||
messages_from_me = Message.objects.filter(sender=user_profile)
|
messages_from_me = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_sender_recipient (prefix)
|
||||||
|
realm_id=user_profile.realm_id,
|
||||||
|
sender=user_profile,
|
||||||
|
)
|
||||||
|
|
||||||
my_subscriptions = Subscription.objects.filter(
|
my_subscriptions = Subscription.objects.filter(
|
||||||
user_profile=user_profile, recipient__type__in=[Recipient.PERSONAL, Recipient.HUDDLE]
|
user_profile=user_profile, recipient__type__in=[Recipient.PERSONAL, Recipient.HUDDLE]
|
||||||
)
|
)
|
||||||
my_recipient_ids = [sub.recipient_id for sub in my_subscriptions]
|
my_recipient_ids = [sub.recipient_id for sub in my_subscriptions]
|
||||||
messages_to_me = Message.objects.filter(recipient_id__in=my_recipient_ids)
|
messages_to_me = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_id (prefix)
|
||||||
|
realm_id=user_profile.realm_id,
|
||||||
|
recipient_id__in=my_recipient_ids,
|
||||||
|
)
|
||||||
|
|
||||||
# Find all message ids that pertain to us.
|
# Find all message ids that pertain to us.
|
||||||
all_message_ids: Set[int] = set()
|
all_message_ids: Set[int] = set()
|
||||||
|
|
|
@ -228,7 +228,13 @@ def build_page_params_for_home_page_load(
|
||||||
# In narrow_stream context, initial pointer is just latest message
|
# In narrow_stream context, initial pointer is just latest message
|
||||||
recipient = narrow_stream.recipient
|
recipient = narrow_stream.recipient
|
||||||
page_params["max_message_id"] = -1
|
page_params["max_message_id"] = -1
|
||||||
max_message = Message.objects.filter(recipient=recipient).order_by("-id").only("id").first()
|
max_message = (
|
||||||
|
# Uses index: zerver_message_realm_recipient_id
|
||||||
|
Message.objects.filter(realm_id=realm.id, recipient=recipient)
|
||||||
|
.order_by("-id")
|
||||||
|
.only("id")
|
||||||
|
.first()
|
||||||
|
)
|
||||||
if max_message:
|
if max_message:
|
||||||
page_params["max_message_id"] = max_message.id
|
page_params["max_message_id"] = max_message.id
|
||||||
page_params["narrow_stream"] = narrow_stream.name
|
page_params["narrow_stream"] = narrow_stream.name
|
||||||
|
|
|
@ -511,6 +511,7 @@ class MessageDict:
|
||||||
"sending_client__name",
|
"sending_client__name",
|
||||||
"sender__realm_id",
|
"sender__realm_id",
|
||||||
]
|
]
|
||||||
|
# Uses index: zerver_message_pkey
|
||||||
messages = Message.objects.filter(id__in=needed_ids).values(*fields)
|
messages = Message.objects.filter(id__in=needed_ids).values(*fields)
|
||||||
return MessageDict.sew_submessages_and_reactions_to_msgs(messages)
|
return MessageDict.sew_submessages_and_reactions_to_msgs(messages)
|
||||||
|
|
||||||
|
@ -1476,6 +1477,7 @@ def update_first_visible_message_id(realm: Realm) -> None:
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
first_visible_message_id = (
|
first_visible_message_id = (
|
||||||
|
# Uses index: zerver_message_realm_id
|
||||||
Message.objects.filter(realm=realm)
|
Message.objects.filter(realm=realm)
|
||||||
.values("id")
|
.values("id")
|
||||||
.order_by("-id")[realm.message_visibility_limit - 1]["id"]
|
.order_by("-id")[realm.message_visibility_limit - 1]["id"]
|
||||||
|
|
|
@ -189,12 +189,14 @@ def move_expired_messages_to_archive_by_recipient(
|
||||||
) -> int:
|
) -> int:
|
||||||
assert message_retention_days != -1
|
assert message_retention_days != -1
|
||||||
|
|
||||||
|
# Uses index: zerver_message_realm_recipient_date_sent
|
||||||
query = SQL(
|
query = SQL(
|
||||||
"""
|
"""
|
||||||
INSERT INTO zerver_archivedmessage ({dst_fields}, archive_transaction_id)
|
INSERT INTO zerver_archivedmessage ({dst_fields}, archive_transaction_id)
|
||||||
SELECT {src_fields}, {archive_transaction_id}
|
SELECT {src_fields}, {archive_transaction_id}
|
||||||
FROM zerver_message
|
FROM zerver_message
|
||||||
WHERE zerver_message.recipient_id = {recipient_id}
|
WHERE zerver_message.realm_id = {realm_id}
|
||||||
|
AND zerver_message.recipient_id = {recipient_id}
|
||||||
AND zerver_message.date_sent < {check_date}
|
AND zerver_message.date_sent < {check_date}
|
||||||
LIMIT {chunk_size}
|
LIMIT {chunk_size}
|
||||||
ON CONFLICT (id) DO UPDATE SET archive_transaction_id = {archive_transaction_id}
|
ON CONFLICT (id) DO UPDATE SET archive_transaction_id = {archive_transaction_id}
|
||||||
|
@ -207,6 +209,7 @@ def move_expired_messages_to_archive_by_recipient(
|
||||||
query,
|
query,
|
||||||
type=ArchiveTransaction.RETENTION_POLICY_BASED,
|
type=ArchiveTransaction.RETENTION_POLICY_BASED,
|
||||||
realm=realm,
|
realm=realm,
|
||||||
|
realm_id=Literal(realm.id),
|
||||||
recipient_id=Literal(recipient.id),
|
recipient_id=Literal(recipient.id),
|
||||||
check_date=Literal(check_date.isoformat()),
|
check_date=Literal(check_date.isoformat()),
|
||||||
chunk_size=chunk_size,
|
chunk_size=chunk_size,
|
||||||
|
@ -224,6 +227,7 @@ def move_expired_personal_and_huddle_messages_to_archive(
|
||||||
recipient_types = (Recipient.PERSONAL, Recipient.HUDDLE)
|
recipient_types = (Recipient.PERSONAL, Recipient.HUDDLE)
|
||||||
|
|
||||||
# Archive expired personal and huddle Messages in the realm, including cross-realm messages.
|
# Archive expired personal and huddle Messages in the realm, including cross-realm messages.
|
||||||
|
# Uses index: zerver_message_realm_recipient_date_sent
|
||||||
query = SQL(
|
query = SQL(
|
||||||
"""
|
"""
|
||||||
INSERT INTO zerver_archivedmessage ({dst_fields}, archive_transaction_id)
|
INSERT INTO zerver_archivedmessage ({dst_fields}, archive_transaction_id)
|
||||||
|
@ -318,6 +322,8 @@ def delete_messages(msg_ids: List[int]) -> None:
|
||||||
# key to Message (due to `on_delete=CASCADE` in our models
|
# key to Message (due to `on_delete=CASCADE` in our models
|
||||||
# configuration), so we need to be sure we've taken care of
|
# configuration), so we need to be sure we've taken care of
|
||||||
# archiving the messages before doing this step.
|
# archiving the messages before doing this step.
|
||||||
|
#
|
||||||
|
# Uses index: zerver_message_pkey
|
||||||
Message.objects.filter(id__in=msg_ids).delete()
|
Message.objects.filter(id__in=msg_ids).delete()
|
||||||
|
|
||||||
|
|
||||||
|
@ -453,6 +459,7 @@ def get_realms_and_streams_for_archiving() -> List[Tuple[Realm, List[Stream]]]:
|
||||||
def move_messages_to_archive(
|
def move_messages_to_archive(
|
||||||
message_ids: List[int], realm: Optional[Realm] = None, chunk_size: int = MESSAGE_BATCH_SIZE
|
message_ids: List[int], realm: Optional[Realm] = None, chunk_size: int = MESSAGE_BATCH_SIZE
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# Uses index: zerver_message_pkey
|
||||||
query = SQL(
|
query = SQL(
|
||||||
"""
|
"""
|
||||||
INSERT INTO zerver_archivedmessage ({dst_fields}, archive_transaction_id)
|
INSERT INTO zerver_archivedmessage ({dst_fields}, archive_transaction_id)
|
||||||
|
|
|
@ -24,6 +24,7 @@ def get_undelivered_scheduled_messages(
|
||||||
user_profile: UserProfile,
|
user_profile: UserProfile,
|
||||||
) -> List[Union[APIScheduledDirectMessageDict, APIScheduledStreamMessageDict]]:
|
) -> List[Union[APIScheduledDirectMessageDict, APIScheduledStreamMessageDict]]:
|
||||||
scheduled_messages = ScheduledMessage.objects.filter(
|
scheduled_messages = ScheduledMessage.objects.filter(
|
||||||
|
realm_id=user_profile.realm_id,
|
||||||
sender=user_profile,
|
sender=user_profile,
|
||||||
# Notably, we don't require failed=False, since we will want
|
# Notably, we don't require failed=False, since we will want
|
||||||
# to display those to users.
|
# to display those to users.
|
||||||
|
|
|
@ -210,7 +210,10 @@ def add_missing_messages(user_profile: UserProfile) -> None:
|
||||||
|
|
||||||
all_stream_msgs = list(
|
all_stream_msgs = list(
|
||||||
Message.objects.filter(
|
Message.objects.filter(
|
||||||
recipient_id__in=recipient_ids, id__gt=user_profile.last_active_message_id
|
# Uses index: zerver_message_realm_recipient_id
|
||||||
|
realm_id=user_profile.realm_id,
|
||||||
|
recipient_id__in=recipient_ids,
|
||||||
|
id__gt=user_profile.last_active_message_id,
|
||||||
)
|
)
|
||||||
.order_by("id")
|
.order_by("id")
|
||||||
.values("id", "recipient__type_id")
|
.values("id", "recipient__type_id")
|
||||||
|
|
|
@ -92,8 +92,12 @@ def filter_by_topic_name_via_message(
|
||||||
return query.filter(message__subject__iexact=topic_name)
|
return query.filter(message__subject__iexact=topic_name)
|
||||||
|
|
||||||
|
|
||||||
def messages_for_topic(stream_recipient_id: int, topic_name: str) -> QuerySet[Message]:
|
def messages_for_topic(
|
||||||
|
realm_id: int, stream_recipient_id: int, topic_name: str
|
||||||
|
) -> QuerySet[Message]:
|
||||||
return Message.objects.filter(
|
return Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_upper_subject
|
||||||
|
realm_id=realm_id,
|
||||||
recipient_id=stream_recipient_id,
|
recipient_id=stream_recipient_id,
|
||||||
subject__iexact=topic_name,
|
subject__iexact=topic_name,
|
||||||
)
|
)
|
||||||
|
@ -149,13 +153,17 @@ def update_messages_for_topic_edit(
|
||||||
edit_history_event: EditHistoryEvent,
|
edit_history_event: EditHistoryEvent,
|
||||||
last_edit_time: datetime,
|
last_edit_time: datetime,
|
||||||
) -> List[Message]:
|
) -> List[Message]:
|
||||||
propagate_query = Q(recipient_id=old_stream.recipient_id, subject__iexact=orig_topic_name)
|
propagate_query = Q(
|
||||||
|
recipient_id=old_stream.recipient_id,
|
||||||
|
subject__iexact=orig_topic_name,
|
||||||
|
)
|
||||||
if propagate_mode == "change_all":
|
if propagate_mode == "change_all":
|
||||||
propagate_query = propagate_query & ~Q(id=edited_message.id)
|
propagate_query = propagate_query & ~Q(id=edited_message.id)
|
||||||
if propagate_mode == "change_later":
|
if propagate_mode == "change_later":
|
||||||
propagate_query = propagate_query & Q(id__gt=edited_message.id)
|
propagate_query = propagate_query & Q(id__gt=edited_message.id)
|
||||||
|
|
||||||
messages = Message.objects.filter(propagate_query).select_related(
|
# Uses index: zerver_message_realm_recipient_upper_subject
|
||||||
|
messages = Message.objects.filter(propagate_query, realm_id=old_stream.realm_id).select_related(
|
||||||
*Message.DEFAULT_SELECT_RELATED
|
*Message.DEFAULT_SELECT_RELATED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -283,12 +291,17 @@ def get_topic_resolution_and_bare_name(stored_name: str) -> Tuple[bool, str]:
|
||||||
return (False, stored_name)
|
return (False, stored_name)
|
||||||
|
|
||||||
|
|
||||||
def participants_for_topic(recipient_id: int, topic_name: str) -> Set[int]:
|
def participants_for_topic(realm_id: int, recipient_id: int, topic_name: str) -> Set[int]:
|
||||||
"""
|
"""
|
||||||
Users who either sent or reacted to the messages in the topic.
|
Users who either sent or reacted to the messages in the topic.
|
||||||
The function is expensive for large numbers of messages in the topic.
|
The function is expensive for large numbers of messages in the topic.
|
||||||
"""
|
"""
|
||||||
messages = Message.objects.filter(recipient_id=recipient_id, subject__iexact=topic_name)
|
messages = Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_upper_subject
|
||||||
|
realm_id=realm_id,
|
||||||
|
recipient_id=recipient_id,
|
||||||
|
subject__iexact=topic_name,
|
||||||
|
)
|
||||||
participants = set(
|
participants = set(
|
||||||
UserProfile.objects.filter(
|
UserProfile.objects.filter(
|
||||||
Q(id__in=Subquery(messages.values("sender_id")))
|
Q(id__in=Subquery(messages.values("sender_id")))
|
||||||
|
|
|
@ -3189,6 +3189,8 @@ class Message(AbstractMessage):
|
||||||
|
|
||||||
def get_context_for_message(message: Message) -> QuerySet[Message]:
|
def get_context_for_message(message: Message) -> QuerySet[Message]:
|
||||||
return Message.objects.filter(
|
return Message.objects.filter(
|
||||||
|
# Uses index: zerver_message_realm_recipient_upper_subject
|
||||||
|
realm_id=message.realm_id,
|
||||||
recipient_id=message.recipient_id,
|
recipient_id=message.recipient_id,
|
||||||
subject__iexact=message.subject,
|
subject__iexact=message.subject,
|
||||||
id__lt=message.id,
|
id__lt=message.id,
|
||||||
|
@ -3676,6 +3678,8 @@ def validate_attachment_request_for_spectator_access(
|
||||||
Attachment.objects.filter(id=attachment.id, is_web_public__isnull=True).update(
|
Attachment.objects.filter(id=attachment.id, is_web_public__isnull=True).update(
|
||||||
is_web_public=Exists(
|
is_web_public=Exists(
|
||||||
Message.objects.filter(
|
Message.objects.filter(
|
||||||
|
# Uses index: zerver_attachment_messages_attachment_id_message_id_key
|
||||||
|
realm_id=realm.id,
|
||||||
attachment=OuterRef("id"),
|
attachment=OuterRef("id"),
|
||||||
recipient__stream__invite_only=False,
|
recipient__stream__invite_only=False,
|
||||||
recipient__stream__is_web_public=True,
|
recipient__stream__is_web_public=True,
|
||||||
|
@ -3723,6 +3727,8 @@ def validate_attachment_request(
|
||||||
Attachment.objects.filter(id=attachment.id, is_realm_public__isnull=True).update(
|
Attachment.objects.filter(id=attachment.id, is_realm_public__isnull=True).update(
|
||||||
is_realm_public=Exists(
|
is_realm_public=Exists(
|
||||||
Message.objects.filter(
|
Message.objects.filter(
|
||||||
|
# Uses index: zerver_attachment_messages_attachment_id_message_id_key
|
||||||
|
realm_id=user_profile.realm_id,
|
||||||
attachment=OuterRef("id"),
|
attachment=OuterRef("id"),
|
||||||
recipient__stream__invite_only=False,
|
recipient__stream__invite_only=False,
|
||||||
),
|
),
|
||||||
|
|
|
@ -131,7 +131,7 @@ class GitterImporter(ZulipTestCase):
|
||||||
|
|
||||||
# test rendered_messages
|
# test rendered_messages
|
||||||
realm_users = UserProfile.objects.filter(realm=realm)
|
realm_users = UserProfile.objects.filter(realm=realm)
|
||||||
messages = Message.objects.filter(sender__in=realm_users)
|
messages = Message.objects.filter(realm_id=realm.id, sender__in=realm_users)
|
||||||
for message in messages:
|
for message in messages:
|
||||||
self.assertIsNotNone(message.rendered_content, None)
|
self.assertIsNotNone(message.rendered_content, None)
|
||||||
|
|
||||||
|
|
|
@ -643,7 +643,7 @@ class RealmImportExportTest(ExportFile):
|
||||||
type_id__in=public_stream_ids, type=Recipient.STREAM
|
type_id__in=public_stream_ids, type=Recipient.STREAM
|
||||||
)
|
)
|
||||||
public_stream_message_ids = Message.objects.filter(
|
public_stream_message_ids = Message.objects.filter(
|
||||||
recipient__in=public_stream_recipients
|
realm_id=realm.id, recipient__in=public_stream_recipients
|
||||||
).values_list("id", flat=True)
|
).values_list("id", flat=True)
|
||||||
|
|
||||||
# Messages from Private stream C are not exported since no member gave consent
|
# Messages from Private stream C are not exported since no member gave consent
|
||||||
|
@ -656,7 +656,7 @@ class RealmImportExportTest(ExportFile):
|
||||||
type_id__in=private_stream_ids, type=Recipient.STREAM
|
type_id__in=private_stream_ids, type=Recipient.STREAM
|
||||||
)
|
)
|
||||||
private_stream_message_ids = Message.objects.filter(
|
private_stream_message_ids = Message.objects.filter(
|
||||||
recipient__in=private_stream_recipients
|
realm_id=realm.id, recipient__in=private_stream_recipients
|
||||||
).values_list("id", flat=True)
|
).values_list("id", flat=True)
|
||||||
|
|
||||||
pm_recipients = Recipient.objects.filter(
|
pm_recipients = Recipient.objects.filter(
|
||||||
|
@ -664,7 +664,7 @@ class RealmImportExportTest(ExportFile):
|
||||||
)
|
)
|
||||||
pm_query = Q(recipient__in=pm_recipients) | Q(sender__in=consented_user_ids)
|
pm_query = Q(recipient__in=pm_recipients) | Q(sender__in=consented_user_ids)
|
||||||
exported_pm_ids = (
|
exported_pm_ids = (
|
||||||
Message.objects.filter(pm_query)
|
Message.objects.filter(pm_query, realm=realm.id)
|
||||||
.values_list("id", flat=True)
|
.values_list("id", flat=True)
|
||||||
.values_list("id", flat=True)
|
.values_list("id", flat=True)
|
||||||
)
|
)
|
||||||
|
@ -676,7 +676,7 @@ class RealmImportExportTest(ExportFile):
|
||||||
)
|
)
|
||||||
pm_query = Q(recipient__in=huddle_recipients) | Q(sender__in=consented_user_ids)
|
pm_query = Q(recipient__in=huddle_recipients) | Q(sender__in=consented_user_ids)
|
||||||
exported_huddle_ids = (
|
exported_huddle_ids = (
|
||||||
Message.objects.filter(pm_query)
|
Message.objects.filter(pm_query, realm=realm.id)
|
||||||
.values_list("id", flat=True)
|
.values_list("id", flat=True)
|
||||||
.values_list("id", flat=True)
|
.values_list("id", flat=True)
|
||||||
)
|
)
|
||||||
|
@ -1260,7 +1260,7 @@ class RealmImportExportTest(ExportFile):
|
||||||
# test messages
|
# test messages
|
||||||
def get_stream_messages(r: Realm) -> QuerySet[Message]:
|
def get_stream_messages(r: Realm) -> QuerySet[Message]:
|
||||||
recipient = get_recipient_stream(r)
|
recipient = get_recipient_stream(r)
|
||||||
messages = Message.objects.filter(recipient=recipient)
|
messages = Message.objects.filter(realm_id=r.id, recipient=recipient)
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
@getter
|
@getter
|
||||||
|
|
|
@ -2289,7 +2289,7 @@ class GetOldMessagesTest(ZulipTestCase):
|
||||||
stream_names = ["Scotland", "Verona", "Venice"]
|
stream_names = ["Scotland", "Verona", "Venice"]
|
||||||
|
|
||||||
def send_messages_to_all_streams() -> None:
|
def send_messages_to_all_streams() -> None:
|
||||||
Message.objects.filter(recipient__type=Recipient.STREAM).delete()
|
Message.objects.filter(realm_id=realm.id, recipient__type=Recipient.STREAM).delete()
|
||||||
for stream_name in stream_names:
|
for stream_name in stream_names:
|
||||||
self.subscribe(hamlet, stream_name)
|
self.subscribe(hamlet, stream_name)
|
||||||
for i in range(num_messages_per_stream):
|
for i in range(num_messages_per_stream):
|
||||||
|
|
|
@ -1573,9 +1573,24 @@ class ScrubRealmTest(ZulipTestCase):
|
||||||
|
|
||||||
CustomProfileField.objects.create(realm=lear)
|
CustomProfileField.objects.create(realm=lear)
|
||||||
|
|
||||||
self.assertEqual(Message.objects.filter(sender__in=[iago, othello]).count(), 10)
|
self.assertEqual(
|
||||||
self.assertEqual(Message.objects.filter(sender__in=[cordelia, king]).count(), 10)
|
Message.objects.filter(
|
||||||
self.assertEqual(Message.objects.filter(sender=notification_bot).count(), 6)
|
realm_id__in=(zulip.id, lear.id), sender__in=[iago, othello]
|
||||||
|
).count(),
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
Message.objects.filter(
|
||||||
|
realm_id__in=(zulip.id, lear.id), sender__in=[cordelia, king]
|
||||||
|
).count(),
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
Message.objects.filter(
|
||||||
|
realm_id__in=(zulip.id, lear.id), sender=notification_bot
|
||||||
|
).count(),
|
||||||
|
6,
|
||||||
|
)
|
||||||
self.assertEqual(UserMessage.objects.filter(user_profile__in=[iago, othello]).count(), 25)
|
self.assertEqual(UserMessage.objects.filter(user_profile__in=[iago, othello]).count(), 25)
|
||||||
self.assertEqual(UserMessage.objects.filter(user_profile__in=[cordelia, king]).count(), 25)
|
self.assertEqual(UserMessage.objects.filter(user_profile__in=[cordelia, king]).count(), 25)
|
||||||
|
|
||||||
|
@ -1584,9 +1599,24 @@ class ScrubRealmTest(ZulipTestCase):
|
||||||
with self.assertLogs(level="WARNING"):
|
with self.assertLogs(level="WARNING"):
|
||||||
do_scrub_realm(zulip, acting_user=None)
|
do_scrub_realm(zulip, acting_user=None)
|
||||||
|
|
||||||
self.assertEqual(Message.objects.filter(sender__in=[iago, othello]).count(), 0)
|
self.assertEqual(
|
||||||
self.assertEqual(Message.objects.filter(sender__in=[cordelia, king]).count(), 10)
|
Message.objects.filter(
|
||||||
self.assertEqual(Message.objects.filter(sender=notification_bot).count(), 3)
|
realm_id__in=(zulip.id, lear.id), sender__in=[iago, othello]
|
||||||
|
).count(),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
Message.objects.filter(
|
||||||
|
realm_id__in=(zulip.id, lear.id), sender__in=[cordelia, king]
|
||||||
|
).count(),
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
Message.objects.filter(
|
||||||
|
realm_id__in=(zulip.id, lear.id), sender=notification_bot
|
||||||
|
).count(),
|
||||||
|
3,
|
||||||
|
)
|
||||||
self.assertEqual(UserMessage.objects.filter(user_profile__in=[iago, othello]).count(), 0)
|
self.assertEqual(UserMessage.objects.filter(user_profile__in=[iago, othello]).count(), 0)
|
||||||
self.assertEqual(UserMessage.objects.filter(user_profile__in=[cordelia, king]).count(), 25)
|
self.assertEqual(UserMessage.objects.filter(user_profile__in=[cordelia, king]).count(), 25)
|
||||||
|
|
||||||
|
|
|
@ -697,7 +697,9 @@ class MoveMessageToArchiveGeneral(MoveMessageToArchiveBase):
|
||||||
)
|
)
|
||||||
for attachment_id in attachment_ids:
|
for attachment_id in attachment_ids:
|
||||||
attachment_id_to_message_ids[attachment_id] = list(
|
attachment_id_to_message_ids[attachment_id] = list(
|
||||||
Message.objects.filter(attachment__id=attachment_id).values_list("id", flat=True),
|
Message.objects.filter(realm_id=realm_id, attachment__id=attachment_id).values_list(
|
||||||
|
"id", flat=True
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
usermsg_ids = self._get_usermessage_ids(msg_ids)
|
usermsg_ids = self._get_usermessage_ids(msg_ids)
|
||||||
|
@ -736,9 +738,9 @@ class MoveMessageToArchiveGeneral(MoveMessageToArchiveBase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set(attachment_id_to_message_ids[attachment_id]),
|
set(attachment_id_to_message_ids[attachment_id]),
|
||||||
set(
|
set(
|
||||||
Message.objects.filter(attachment__id=attachment_id).values_list(
|
Message.objects.filter(
|
||||||
"id", flat=True
|
realm_id=realm_id, attachment__id=attachment_id
|
||||||
)
|
).values_list("id", flat=True)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1306,13 +1306,17 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
]:
|
]:
|
||||||
stream = get_stream(stream_name, realm)
|
stream = get_stream(stream_name, realm)
|
||||||
recipient = stream.recipient
|
recipient = stream.recipient
|
||||||
messages = Message.objects.filter(recipient=recipient).order_by("date_sent")
|
messages = Message.objects.filter(realm_id=realm.id, recipient=recipient).order_by(
|
||||||
|
"date_sent"
|
||||||
|
)
|
||||||
self.assert_length(messages, message_count)
|
self.assert_length(messages, message_count)
|
||||||
self.assertIn(text, messages[0].content)
|
self.assertIn(text, messages[0].content)
|
||||||
|
|
||||||
# Check admin organization's signups stream messages
|
# Check admin organization's signups stream messages
|
||||||
recipient = signups_stream.recipient
|
recipient = signups_stream.recipient
|
||||||
messages = Message.objects.filter(recipient=recipient).order_by("id")
|
messages = Message.objects.filter(realm_id=internal_realm.id, recipient=recipient).order_by(
|
||||||
|
"id"
|
||||||
|
)
|
||||||
self.assert_length(messages, 1)
|
self.assert_length(messages, 1)
|
||||||
# Check organization name, subdomain and organization type are in message content
|
# Check organization name, subdomain and organization type are in message content
|
||||||
self.assertIn("Zulip Test", messages[0].content)
|
self.assertIn("Zulip Test", messages[0].content)
|
||||||
|
@ -1610,7 +1614,9 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
|
|
||||||
# Make sure the correct Welcome Bot direct message is sent.
|
# Make sure the correct Welcome Bot direct message is sent.
|
||||||
welcome_msg = Message.objects.filter(
|
welcome_msg = Message.objects.filter(
|
||||||
sender__email="welcome-bot@zulip.com", recipient__type=Recipient.PERSONAL
|
realm_id=get_realm(string_id).id,
|
||||||
|
sender__email="welcome-bot@zulip.com",
|
||||||
|
recipient__type=Recipient.PERSONAL,
|
||||||
).latest("id")
|
).latest("id")
|
||||||
self.assertTrue(welcome_msg.content.startswith("Hello, and welcome to Zulip!"))
|
self.assertTrue(welcome_msg.content.startswith("Hello, and welcome to Zulip!"))
|
||||||
|
|
||||||
|
@ -1661,7 +1667,9 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
|
|
||||||
# Make sure the correct Welcome Bot direct message is sent.
|
# Make sure the correct Welcome Bot direct message is sent.
|
||||||
welcome_msg = Message.objects.filter(
|
welcome_msg = Message.objects.filter(
|
||||||
sender__email="welcome-bot@zulip.com", recipient__type=Recipient.PERSONAL
|
realm_id=get_realm(string_id).id,
|
||||||
|
sender__email="welcome-bot@zulip.com",
|
||||||
|
recipient__type=Recipient.PERSONAL,
|
||||||
).latest("id")
|
).latest("id")
|
||||||
self.assertTrue(welcome_msg.content.startswith("Hello, and welcome to Zulip!"))
|
self.assertTrue(welcome_msg.content.startswith("Hello, and welcome to Zulip!"))
|
||||||
|
|
||||||
|
|
|
@ -2499,10 +2499,10 @@ class DeleteUserTest(ZulipTestCase):
|
||||||
self.send_personal_message(hamlet, cordelia)
|
self.send_personal_message(hamlet, cordelia)
|
||||||
|
|
||||||
personal_message_ids_to_hamlet = Message.objects.filter(
|
personal_message_ids_to_hamlet = Message.objects.filter(
|
||||||
recipient=hamlet_personal_recipient
|
realm_id=realm.id, recipient=hamlet_personal_recipient
|
||||||
).values_list("id", flat=True)
|
).values_list("id", flat=True)
|
||||||
self.assertGreater(len(personal_message_ids_to_hamlet), 0)
|
self.assertGreater(len(personal_message_ids_to_hamlet), 0)
|
||||||
self.assertTrue(Message.objects.filter(sender=hamlet).exists())
|
self.assertTrue(Message.objects.filter(realm_id=realm.id, sender=hamlet).exists())
|
||||||
|
|
||||||
huddle_message_ids_from_cordelia = [
|
huddle_message_ids_from_cordelia = [
|
||||||
self.send_huddle_message(cordelia, [hamlet, othello]) for i in range(3)
|
self.send_huddle_message(cordelia, [hamlet, othello]) for i in range(3)
|
||||||
|
@ -2535,7 +2535,9 @@ class DeleteUserTest(ZulipTestCase):
|
||||||
self.assertEqual(Message.objects.filter(id__in=huddle_message_ids_from_hamlet).count(), 0)
|
self.assertEqual(Message.objects.filter(id__in=huddle_message_ids_from_hamlet).count(), 0)
|
||||||
self.assertEqual(Message.objects.filter(id__in=huddle_message_ids_from_cordelia).count(), 3)
|
self.assertEqual(Message.objects.filter(id__in=huddle_message_ids_from_cordelia).count(), 3)
|
||||||
|
|
||||||
self.assertEqual(Message.objects.filter(sender_id=hamlet_user_id).count(), 0)
|
self.assertEqual(
|
||||||
|
Message.objects.filter(realm_id=realm.id, sender_id=hamlet_user_id).count(), 0
|
||||||
|
)
|
||||||
|
|
||||||
# Verify that the dummy user is subscribed to the deleted user's huddles, to keep huddle data
|
# Verify that the dummy user is subscribed to the deleted user's huddles, to keep huddle data
|
||||||
# in a correct state.
|
# in a correct state.
|
||||||
|
@ -2564,10 +2566,10 @@ class DeleteUserTest(ZulipTestCase):
|
||||||
self.send_personal_message(hamlet, cordelia)
|
self.send_personal_message(hamlet, cordelia)
|
||||||
|
|
||||||
personal_message_ids_to_hamlet = Message.objects.filter(
|
personal_message_ids_to_hamlet = Message.objects.filter(
|
||||||
recipient=hamlet_personal_recipient
|
realm_id=realm.id, recipient=hamlet_personal_recipient
|
||||||
).values_list("id", flat=True)
|
).values_list("id", flat=True)
|
||||||
self.assertGreater(len(personal_message_ids_to_hamlet), 0)
|
self.assertGreater(len(personal_message_ids_to_hamlet), 0)
|
||||||
self.assertTrue(Message.objects.filter(sender=hamlet).exists())
|
self.assertTrue(Message.objects.filter(realm_id=realm.id, sender=hamlet).exists())
|
||||||
|
|
||||||
huddle_message_ids_from_cordelia = [
|
huddle_message_ids_from_cordelia = [
|
||||||
self.send_huddle_message(cordelia, [hamlet, othello]) for i in range(3)
|
self.send_huddle_message(cordelia, [hamlet, othello]) for i in range(3)
|
||||||
|
@ -2584,7 +2586,7 @@ class DeleteUserTest(ZulipTestCase):
|
||||||
self.assertGreater(len(huddle_with_hamlet_recipient_ids), 0)
|
self.assertGreater(len(huddle_with_hamlet_recipient_ids), 0)
|
||||||
|
|
||||||
original_messages_from_hamlet_count = Message.objects.filter(
|
original_messages_from_hamlet_count = Message.objects.filter(
|
||||||
sender_id=hamlet_user_id
|
realm_id=realm.id, sender_id=hamlet_user_id
|
||||||
).count()
|
).count()
|
||||||
self.assertGreater(original_messages_from_hamlet_count, 0)
|
self.assertGreater(original_messages_from_hamlet_count, 0)
|
||||||
|
|
||||||
|
@ -2614,7 +2616,7 @@ class DeleteUserTest(ZulipTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
Message.objects.filter(sender_id=hamlet_user_id).count(),
|
Message.objects.filter(realm_id=realm.id, sender_id=hamlet_user_id).count(),
|
||||||
original_messages_from_hamlet_count,
|
original_messages_from_hamlet_count,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -923,7 +923,9 @@ def delete_in_topic(
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
stream, ignored_sub = access_stream_by_id(user_profile, stream_id)
|
stream, ignored_sub = access_stream_by_id(user_profile, stream_id)
|
||||||
|
|
||||||
messages = messages_for_topic(assert_is_not_none(stream.recipient_id), topic_name)
|
messages = messages_for_topic(
|
||||||
|
user_profile.realm_id, assert_is_not_none(stream.recipient_id), topic_name
|
||||||
|
)
|
||||||
# Note: It would be better to use bulk_access_messages here, which is our core function
|
# Note: It would be better to use bulk_access_messages here, which is our core function
|
||||||
# for obtaining the accessible messages - and it's good to use it wherever we can,
|
# for obtaining the accessible messages - and it's good to use it wherever we can,
|
||||||
# so that we have a central place to keep up to date with our security model for
|
# so that we have a central place to keep up to date with our security model for
|
||||||
|
|
|
@ -97,6 +97,7 @@ from zerver.models import (
|
||||||
Realm,
|
Realm,
|
||||||
RealmAuditLog,
|
RealmAuditLog,
|
||||||
ScheduledMessageNotificationEmail,
|
ScheduledMessageNotificationEmail,
|
||||||
|
Stream,
|
||||||
UserMessage,
|
UserMessage,
|
||||||
UserProfile,
|
UserProfile,
|
||||||
filter_to_valid_prereg_users,
|
filter_to_valid_prereg_users,
|
||||||
|
@ -1013,12 +1014,15 @@ class DeferredWorker(QueueProcessingWorker):
|
||||||
"Marking messages as read for all users, stream_recipient_id %s",
|
"Marking messages as read for all users, stream_recipient_id %s",
|
||||||
event["stream_recipient_id"],
|
event["stream_recipient_id"],
|
||||||
)
|
)
|
||||||
|
stream = Stream.objects.get(recipient_id=event["stream_recipient_id"])
|
||||||
# This event is generated by the stream deactivation code path.
|
# This event is generated by the stream deactivation code path.
|
||||||
batch_size = 100
|
batch_size = 100
|
||||||
offset = 0
|
offset = 0
|
||||||
while True:
|
while True:
|
||||||
messages = Message.objects.filter(
|
messages = Message.objects.filter(
|
||||||
recipient_id=event["stream_recipient_id"]
|
# Uses index: zerver_message_realm_recipient_id
|
||||||
|
realm_id=stream.realm_id,
|
||||||
|
recipient_id=event["stream_recipient_id"],
|
||||||
).order_by("id")[offset : offset + batch_size]
|
).order_by("id")[offset : offset + batch_size]
|
||||||
|
|
||||||
with transaction.atomic(savepoint=False):
|
with transaction.atomic(savepoint=False):
|
||||||
|
|
Loading…
Reference in New Issue