access_message: Allow selecting message row FOR UPDATE.

This is a prep change to start using `SELECT FOR UPDATE` queries
when there is a chance of race conditions.
This commit is contained in:
Abhijeet Prasad Bodas 2021-06-03 10:34:25 +05:30 committed by Tim Abbott
parent 51f5bbcd57
commit 1a9f385e17
1 changed files with 16 additions and 2 deletions

View File

@ -655,7 +655,9 @@ class ReactionDict:
def access_message(
user_profile: UserProfile, message_id: int
user_profile: UserProfile,
message_id: int,
lock_message: bool = False,
) -> Tuple[Message, Optional[UserMessage]]:
"""You can access a message by ID in our APIs that either:
(1) You received or have previously accessed via starring
@ -664,9 +666,21 @@ def access_message(
We produce consistent, boring error messages to avoid leaking any
information from a security perspective.
The lock_message parameter should be passed by callers that are
planning to modify the Message object. This will use the SQL
`SELECT FOR UPDATE` feature to ensure that other processes cannot
delete the message during the current transaction, which is
important to prevent rare race conditions. Callers must only
pass lock_message when inside a @transaction.atomic block.
"""
try:
message = Message.objects.select_related().get(id=message_id)
base_query = Message.objects.select_related()
if lock_message: # nocoverage
# We want to lock only the `Message` row, and not the related fields
# because the `Message` row only has a possibility of races.
base_query = base_query.select_for_update(of=("self",))
message = base_query.get(id=message_id)
except Message.DoesNotExist:
raise JsonableError(_("Invalid message(s)"))