Skip to content
Open
Show file tree
Hide file tree
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
55 changes: 50 additions & 5 deletions src/apps/api/tests/test_submissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,16 @@ def test_no_one_can_see_detailed_result_when_visualization_is_false(self):
resp = self.client.get(url)
assert resp.status_code == 404

def test_who_can_see_detailed_result_when_visualization_is_true(self):
def test_who_can_see_detailed_result_when_visualization_is_true_and_competition_is_private(self):
self.comp.enable_detailed_results = True
self.comp.published = False
self.comp.save()
url = reverse('submission-get-detail-result', args=(self.existing_submission.pk,))

url = reverse("submission-get-detail-result", args=(self.existing_submission.pk,))

# Anonymous user cannot see submission detail result
resp = self.client.get(url)
assert resp.status_code == 403

# Competition creator can see detail result
self.client.force_login(self.creator)
Expand All @@ -263,17 +269,17 @@ def test_who_can_see_detailed_result_when_visualization_is_true(self):
resp = self.client.get(url)
assert resp.status_code == 200

# approved user can see submission detail result
# Approved user can see submission detail result
self.client.force_login(self.participant)
resp = self.client.get(url)
assert resp.status_code == 200

# pending user cannot see submission detail result
# Pending user cannot see submission detail result
self.client.force_login(self.pending_participant)
resp = self.client.get(url)
assert resp.status_code == 403

# denied user cannot see submission detail result
# Denied user cannot see submission detail result
self.client.force_login(self.denied_participant)
resp = self.client.get(url)
assert resp.status_code == 403
Expand All @@ -283,6 +289,45 @@ def test_who_can_see_detailed_result_when_visualization_is_true(self):
resp = self.client.get(url)
assert resp.status_code == 403

def test_who_can_see_detailed_result_when_visualization_is_true_and_competition_is_public(self):
self.comp.enable_detailed_results = True
self.comp.published = True
self.comp.save()

url = reverse("submission-get-detail-result", args=(self.existing_submission.pk,))

# Detailed results are publicly available
resp = self.client.get(url)
assert resp.status_code == 200

self.client.force_login(self.creator)
resp = self.client.get(url)
assert resp.status_code == 200

self.client.force_login(self.collaborator)
resp = self.client.get(url)
assert resp.status_code == 200

self.client.force_login(self.superuser)
resp = self.client.get(url)
assert resp.status_code == 200

self.client.force_login(self.participant)
resp = self.client.get(url)
assert resp.status_code == 200

self.client.force_login(self.pending_participant)
resp = self.client.get(url)
assert resp.status_code == 200

self.client.force_login(self.denied_participant)
resp = self.client.get(url)
assert resp.status_code == 200

self.client.force_login(self.other_user)
resp = self.client.get(url)
assert resp.status_code == 200


class SubmissionUpdateTest(APITestCase):
def setUp(self):
Expand Down
66 changes: 38 additions & 28 deletions src/apps/api/views/submissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,37 +443,47 @@ def get_details(self, request, pk):

@action(detail=True, methods=('GET',))
def get_detail_result(self, request, pk):
submission = Submission.objects.get(pk=pk)
# Check if competition show visualization is true
if submission.phase.competition.enable_detailed_results:
# get submission's competition approved participants
approved_participants = submission.phase.competition.participants.filter(status=CompetitionParticipant.APPROVED)
participant_usernames = [participant.user.username for participant in approved_participants]

# check if in this competition
# user is collaborator
# or
# user is approved participant
# or
# user is creator
# or
# user is super user
if request.user in submission.phase.competition.collaborators.all() or\
request.user.username in participant_usernames or\
request.user == submission.phase.competition.created_by or\
request.user.is_superuser:

data = SubmissionFilesSerializer(submission, context=self.get_serializer_context()).data
return Response(data["detailed_result"], status=status.HTTP_200_OK)
submission = get_object_or_404(Submission, pk=pk)
competition = submission.phase.competition

# Helper to avoid repeating serialization/Response code
def _allowed():
data = SubmissionFilesSerializer(submission, context=self.get_serializer_context()).data
return Response(data.get("detailed_result"), status=status.HTTP_200_OK)

# Check if competition show visualization is true
if competition.enable_detailed_results:
if competition.published:
# Detailed results are publicly available
return _allowed()
else:
return Response({
"error_msg": "You do not have permission to see the detailed result. Participate in this competition to view result."},
status=status.HTTP_403_FORBIDDEN
)
# Competition is private
user = request.user
if not user.is_authenticated:
return Response(
{"error_msg": "You do not have permission to see the detailed result. Participate in this competition to view result."},
status=status.HTTP_403_FORBIDDEN,
)
# Give access if user is collaborator, approved participant,
# competition creator or super user
is_collaborator = competition.collaborators.filter(pk=user.pk).exists()
is_creator = (user == competition.created_by)
is_superuser = user.is_superuser
is_approved_participant = CompetitionParticipant.objects.filter(
competition=competition,
user=user,
status=CompetitionParticipant.APPROVED,
).exists()
if is_collaborator or is_approved_participant or is_creator or is_superuser:
# Allow access
return _allowed()
return Response(
{"error_msg": "You do not have permission to see the detailed result."},
status=status.HTTP_403_FORBIDDEN,
)
else:
return Response({
"error_msg": "Detailed results are disable for this competition!"},
return Response(
{"error_msg": "Detailed results are disabled for this competition!"},
status=status.HTTP_404_NOT_FOUND
)

Expand Down
2 changes: 1 addition & 1 deletion src/apps/competitions/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,5 @@ def get_context_data(self, **kwargs):
return context


class CompetitionDetailedResults(LoginRequiredMixin, TemplateView):
class CompetitionDetailedResults(TemplateView):
template_name = 'competitions/detailed_results.html'