Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 40 additions & 13 deletions care/emr/api/viewsets/scheduling/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,25 +93,52 @@ def validate_data(self, instance, model_obj=None):
if existing_current:
raise ValidationError("Sub Queue already has a current token")

if (
instance.sub_queue
and instance.status == TokenStatusOptions.IN_PROGRESS.value
):
new_current = get_object_or_404(
TokenSubQueue,
external_id=instance.sub_queue,
)
if new_current.current_token and new_current.current_token != model_obj:
raise ValidationError("Sub Queue already has a current token")

return super().validate_data(instance, model_obj)
Comment on lines 83 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 IN_PROGRESS guard bypassed when sub_queue is null

The new validation at lines 94–98 that blocks direct IN_PROGRESS updates lives inside if model_obj and instance.sub_queue:. A caller that sends {"status": "in_progress", "sub_queue": null} satisfies pydantic (since TokenUpdateSpec.sub_queue: UUID4 | None accepts null) but makes instance.sub_queue falsy, so the entire guard is skipped. The token then transitions to IN_PROGRESS with sub_queue = null in perform_update — the old sub-queue's current_token gets cleared, but nothing sets a new current_token, leaving the queue in an inconsistent state.

The IN_PROGRESS status check should be guarded on model_obj alone, independent of whether a sub-queue is being provided in the same request.


def perform_update(self, instance):
obj = self.get_object()
if (
instance.sub_queue
and obj.sub_queue != instance.sub_queue
and instance.status == TokenStatusOptions.IN_PROGRESS.value
):
raise ValidationError(
"Use set_next endpoint to change the sub queue of a token"
)
if instance.sub_queue and instance.sub_queue.facility != instance.facility:
raise ValidationError("Sub Queue and Queue are not in the same facility")
with transaction.atomic():
obj = self.get_object()
if obj.sub_queue and obj.sub_queue != instance.sub_queue:
if (
instance.sub_queue
and obj.sub_queue.resource != instance.sub_queue.resource
):
raise ValidationError(
"Sub Queue and Queue are not in the same resource"
)
# Clear current token if the sub queue is changed
if obj.sub_queue.current_token == obj:
obj.sub_queue.current_token = None
obj.sub_queue.save(update_fields=["current_token", "modified_date"])
if (
obj.sub_queue
and obj.sub_queue != instance.sub_queue
and instance.sub_queue
and obj.sub_queue.resource != instance.sub_queue.resource
):
raise ValidationError(
"Sub Queue and Queue are not in the same resource"
)
# Clear current token if the sub queue is changed
if (
obj.sub_queue
and obj.sub_queue.current_token == obj
and (
obj.sub_queue != instance.sub_queue
or instance.status != TokenStatusOptions.IN_PROGRESS.value
)
):
obj.sub_queue.current_token = None
obj.sub_queue.save(update_fields=["current_token", "modified_date"])
Comment thread
nandkishorr marked this conversation as resolved.
super().perform_update(instance)

def perform_destroy(self, instance):
Expand Down
8 changes: 6 additions & 2 deletions care/emr/api/viewsets/scheduling/token_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,12 @@ def set_next_token_to_subqueue(self, request, *args, **kwargs):
).order_by("created_date")
if category:
tokens_qs = tokens_qs.filter(category=category)
if tokens_qs.exists():
next_token = tokens_qs.first()
tokens_in_waiting_qs = tokens_qs.filter(sub_queue__isnull=True)
tokens_in_calling_qs = tokens_qs.filter(sub_queue=sub_queue)
if tokens_in_calling_qs.exists():
next_token = tokens_in_calling_qs.first()
elif tokens_in_waiting_qs.exists():
next_token = tokens_in_waiting_qs.first()
else:
raise ValidationError("No tokens found")
Comment thread
nandkishorr marked this conversation as resolved.
sub_queue.current_token = next_token
Expand Down
Loading