-
Notifications
You must be signed in to change notification settings - Fork 5
feat: Implement atomic transaction for activating broadcast messages … #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
| from rest_framework.decorators import action, api_view, permission_classes | ||
| from rest_framework.response import Response | ||
| from rest_framework.permissions import IsAuthenticated, AllowAny | ||
| from django.db import transaction | ||
| from .models import BroadcastMessage | ||
| from .serializers import BroadcastMessageSerializer | ||
| from dashboard.models import UserDetails | ||
|
|
@@ -46,8 +47,17 @@ def set_active(self, request, pk=None): | |
| if message.user != request.user and not request.user.is_staff: | ||
| return Response({'error': 'Permission denied'}, status=status.HTTP_403_FORBIDDEN) | ||
|
|
||
| message.active = True | ||
| message.save() | ||
| # Use atomic transaction with row locking to prevent race conditions | ||
| with transaction.atomic(): | ||
| # Lock and deactivate all user's messages | ||
| BroadcastMessage.objects.select_for_update().filter( | ||
| user=request.user, active=True | ||
| ).update(active=False) | ||
|
|
||
| # Activate the selected message | ||
| message.active = True | ||
| message.save() | ||
|
Comment on lines
+50
to
+58
|
||
|
|
||
| return Response({'message': 'Message set as active'}) | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,4 @@ | ||||||||||||||
| from django.db import models | ||||||||||||||
| from django.db import models, transaction | ||||||||||||||
| from django.conf import settings | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
|
|
@@ -10,8 +10,16 @@ class BroadcastMessage(models.Model): | |||||||||||||
|
|
||||||||||||||
| def save(self, *args, **kwargs): | ||||||||||||||
| if self.active: | ||||||||||||||
| BroadcastMessage.objects.filter(user=self.user, active=True).update(active=False) | ||||||||||||||
| super().save(*args, **kwargs) | ||||||||||||||
| # Use atomic transaction with row locking to prevent race conditions | ||||||||||||||
| with transaction.atomic(): | ||||||||||||||
| # Lock and deactivate all user's active messages | ||||||||||||||
| BroadcastMessage.objects.select_for_update().filter( | ||||||||||||||
| user=self.user, active=True | ||||||||||||||
|
||||||||||||||
| # Lock and deactivate all user's active messages | |
| BroadcastMessage.objects.select_for_update().filter( | |
| user=self.user, active=True | |
| # Lock and deactivate all user's messages to ensure only one remains active | |
| BroadcastMessage.objects.select_for_update().filter( | |
| user=self.user |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an inconsistency in which user's messages are being deactivated. The permission check on line 47 validates that message.user matches request.user (or user is staff), but line 54 deactivates messages for request.user. If a staff user is activating another user's message, this will deactivate the staff user's messages instead of the message owner's messages.
The filter should use message.user instead of request.user to ensure the correct user's messages are deactivated.