Skip to content
Open
Changes from all 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
71 changes: 40 additions & 31 deletions apps/jobs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
import os
import uuid

from django.db import transaction
import botocore
from accounts.permissions import HasVerifiedEmail
from base.utils import (
Expand Down Expand Up @@ -298,7 +298,7 @@ def challenge_submission(request, challenge_id, challenge_phase_id):
response_data, status=status.HTTP_406_NOT_ACCEPTABLE
)

if not request.FILES:
if not request.FILES:
if request.data.get("file_url") is None:
response_data = {"error": "The file URL is missing!"}
return Response(
Expand All @@ -321,49 +321,46 @@ def challenge_submission(request, challenge_id, challenge_phase_id):
return Response(response_data, status=status.HTTP_200_OK)

if request.data.get("submission_meta_attributes"):
submission_meta_attributes = json.load(
submission_meta_attributes = json.loads(
request.data.get("submission_meta_attributes")
)
request.data["submission_meta_attributes"] = (
submission_meta_attributes
)

# Determine is_public flag
if request.data.get("is_public") is None:
request.data["is_public"] = (
True if challenge_phase.is_submission_public else False
)
else:
request.data["is_public"] = json.loads(request.data["is_public"])
if (
request.data.get("is_public")
and challenge_phase.is_restricted_to_select_one_submission
):
# Handle corner case for restrict one public lb submission
submissions_already_public = Submission.objects.filter(
is_public=True,
participant_team=participant_team,
challenge_phase=challenge_phase,
)
# Make the existing public submission private before making the
# new submission public
if submissions_already_public.count() == 1:
# Case when the phase is restricted to make only one
# submission as public
submission_serializer = SubmissionSerializer(
submissions_already_public[0],
data={"is_public": False},
context={
"participant_team": participant_team,
"challenge_phase": challenge_phase,
"request": request,
},
partial=True,

# Enforce "only one public submission" rule with atomic DB locking
if (
request.data.get("is_public")
and challenge_phase.is_restricted_to_select_one_submission
):
# Atomic block ensures no race between concurrent requests
with transaction.atomic():
# Lock existing public submissions in this phase for this team
submissions_already_public = (
Submission.objects
.select_for_update()
.filter(
is_public=True,
participant_team=participant_team,
challenge_phase=challenge_phase,
)
if submission_serializer.is_valid():
submission_serializer.save()
)

# If one exists, make it private before marking the new one
if submissions_already_public.exists():
existing_public = submissions_already_public.first()
existing_public.is_public = False
existing_public.save(update_fields=["is_public"])

# Override submission visibility if leaderboard_public = False for a
# challenge phase
# Override submission visibility if leaderboard_public = False
if not challenge_phase.leaderboard_public:
request.data["is_public"] = challenge_phase.is_submission_public

Expand Down Expand Up @@ -410,6 +407,18 @@ def challenge_submission(request, challenge_id, challenge_phase_id):
serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE
)

if serializer.is_valid():
serializer.save()
response_data = serializer.data
submission = serializer.instance
message["submission_pk"] = submission.id
# publish message in the queue
publish_submission_message(message)
return Response(response_data, status=status.HTTP_201_CREATED)
return Response(
serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE
)


@api_view(["PATCH"])
@throttle_classes([UserRateThrottle])
Expand Down