Repository: Cloud-CV/EvalAI

Issue:
Modify code in jobs app
**Current Behaviour:** The code in the function `change_submission_data_and_visibility` was according to the old convention and test cases are also missing.

**Expected Behaviour:** Modify the code to follow the new convention and also add the test cases.


Discussion:

Resolving patch:
diff --git a/apps/jobs/urls.py b/apps/jobs/urls.py
--- a/apps/jobs/urls.py
+++ b/apps/jobs/urls.py
@@ -3,9 +3,9 @@
 from . import views
 
 urlpatterns = [
-    url(r'challenge/(?P<challenge_id>[0-9]+)/'
-        r'challenge_phase/(?P<challenge_phase_id>[0-9]+)/submission/(?P<submission_id>[0-9]+)',
-        views.change_submission_visibility, name='change_submission_visibility'),
+    url(r'challenge/(?P<challenge_pk>[0-9]+)/'
+        r'challenge_phase/(?P<challenge_phase_pk>[0-9]+)/submission/(?P<submission_pk>[0-9]+)',
+        views.change_submission_data_and_visibility, name='change_submission_data_and_visibility'),
     url(r'challenge/(?P<challenge_id>[0-9]+)/'
         r'challenge_phase/(?P<challenge_phase_id>[0-9]+)/submission/',
         views.challenge_submission, name='challenge_submission'),
diff --git a/apps/jobs/views.py b/apps/jobs/views.py
--- a/apps/jobs/views.py
+++ b/apps/jobs/views.py
@@ -122,23 +122,17 @@ def challenge_submission(request, challenge_id, challenge_phase_id):
 @api_view(['PATCH'])
 @permission_classes((permissions.IsAuthenticated, HasVerifiedEmail))
 @authentication_classes((ExpiringTokenAuthentication,))
-def change_submission_visibility(request, challenge_id, challenge_phase_id, submission_id):
-    """API Endpoint for making a submission to a challenge"""
+def change_submission_data_and_visibility(request, challenge_pk, challenge_phase_pk, submission_pk):
+    """
+    API Endpoint for updating the submission meta data
+    and changing submission visibility.
+    """
 
     # check if the challenge exists or not
-    try:
-        challenge = Challenge.objects.get(pk=challenge_id)
-    except Challenge.DoesNotExist:
-        response_data = {'error': 'Challenge does not exist'}
-        return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
+    challenge = get_challenge_model(challenge_pk)
 
     # check if the challenge phase exists or not
-    try:
-        challenge_phase = ChallengePhase.objects.get(
-            pk=challenge_phase_id, challenge=challenge)
-    except ChallengePhase.DoesNotExist:
-        response_data = {'error': 'Challenge Phase does not exist'}
-        return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
+    challenge_phase = get_challenge_phase_model(challenge_phase_pk)
 
     if not challenge.is_active:
         response_data = {'error': 'Challenge is not active'}
@@ -150,18 +144,19 @@ def change_submission_visibility(request, challenge_id, challenge_phase_id, subm
             'error': 'Sorry, cannot accept submissions since challenge phase is not public'}
         return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE)
 
-    participant_team_id = get_participant_team_id_of_user_for_a_challenge(
-        request.user, challenge_id)
+    participant_team_pk = get_participant_team_id_of_user_for_a_challenge(
+        request.user, challenge_pk)
 
     try:
-        participant_team = ParticipantTeam.objects.get(pk=participant_team_id)
+        participant_team = ParticipantTeam.objects.get(pk=participant_team_pk)
     except ParticipantTeam.DoesNotExist:
         response_data = {'error': 'You haven\'t participated in the challenge'}
         return Response(response_data, status=status.HTTP_403_FORBIDDEN)
 
     try:
         submission = Submission.objects.get(participant_team=participant_team,
-                                            challenge_phase=challenge_phase, id=submission_id)
+                                            challenge_phase=challenge_phase,
+                                            id=submission_pk)
     except Submission.DoesNotExist:
         response_data = {'error': 'Submission does not exist'}
         return Response(response_data, status=status.HTTP_403_FORBIDDEN)


Test patch:
diff --git a/tests/unit/jobs/test_urls.py b/tests/unit/jobs/test_urls.py
--- a/tests/unit/jobs/test_urls.py
+++ b/tests/unit/jobs/test_urls.py
@@ -121,16 +121,16 @@ def tearDown(self):
 class TestJobsUrls(BaseAPITestClass):
 
     def test_change_submisson_visibility_url(self):
-        self.url = reverse_lazy('jobs:change_submission_visibility',
-                                kwargs={'challenge_id': self.challenge.pk,
-                                        'challenge_phase_id': self.challenge_phase.pk,
-                                        'submission_id': self.submission.pk})
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
         self.assertEqual(self.url,
                          '/api/jobs/challenge/{}/challenge_phase/{}/submission/{}'.format(self.challenge.pk,
                                                                                           self.challenge_phase.pk,
                                                                                           self.submission.pk))
         resolver = resolve(self.url)
-        self.assertEqual(resolver.view_name, 'jobs:change_submission_visibility')
+        self.assertEqual(resolver.view_name, 'jobs:change_submission_data_and_visibility')
 
     def test_challenge_submisson_url(self):
         self.url = reverse_lazy('jobs:challenge_submission',
diff --git a/tests/unit/jobs/test_views.py b/tests/unit/jobs/test_views.py
--- a/tests/unit/jobs/test_views.py
+++ b/tests/unit/jobs/test_views.py
@@ -477,3 +477,180 @@ def test_get_remaining_submission_time_when_limit_is_exhausted(self):
         response = self.client.get(self.url, {})
         self.assertEqual(response.data['message'], expected['message'])
         self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+
+class ChangeSubmissionDataAndVisibilityTest(BaseAPITestClass):
+
+    def setUp(self):
+        super(ChangeSubmissionDataAndVisibilityTest, self).setUp()
+
+        self.submission = Submission.objects.create(
+            participant_team=self.participant_team,
+            challenge_phase=self.challenge_phase,
+            created_by=self.challenge_host_team.created_by,
+            status='submitted',
+            input_file=self.challenge_phase.test_annotation,
+            method_name="Test Method",
+            method_description="Test Description",
+            project_url="http://testserver/",
+            publication_url="http://testserver/",
+            is_public=True,
+        )
+
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
+
+    def test_change_submission_data_and_visibility_when_challenge_does_not_exist(self):
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk+10,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
+
+        expected = {
+            'detail': 'Challenge {} does not exist'.format(self.challenge.pk+10)
+        }
+
+        response = self.client.patch(self.url, {})
+        self.assertEqual(response.data, expected)
+        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+    def test_change_submission_data_and_visibility_when_challenge_phase_does_not_exist(self):
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk+10,
+                                        'submission_pk': self.submission.pk})
+
+        expected = {
+            'detail': 'ChallengePhase {} does not exist'.format(self.challenge_phase.pk+10)
+        }
+
+        response = self.client.patch(self.url, {})
+        self.assertEqual(response.data, expected)
+        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+    def test_change_submission_data_and_visibility_when_challenge_is_not_active(self):
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
+        self.data = {
+            'method_name': 'Updated Method Name'
+        }
+        self.challenge.end_date = timezone.now() - timedelta(days=1)
+        self.challenge.save()
+
+        expected = {
+            'error': 'Challenge is not active'
+        }
+        response = self.client.patch(self.url, self.data)
+        self.assertEqual(response.data, expected)
+        self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE)
+
+    def test_change_submission_data_and_visibility_when_challenge_is_not_public(self):
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
+
+        self.challenge_phase.is_public = False
+        self.challenge_phase.save()
+        self.data = {
+            'method_name': 'Updated Method Name'
+        }
+
+        expected = {
+            'error': 'Sorry, cannot accept submissions since challenge phase is not public'
+        }
+
+        response = self.client.patch(self.url, self.data)
+        self.assertEqual(response.data, expected)
+        self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE)
+
+    def test_change_submission_data_and_visibility_when_participant_team_is_none(self):
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
+
+        self.participant_team.delete()
+
+        expected = {
+            'error': 'You haven\'t participated in the challenge'
+        }
+        self.data = {
+            'method_name': 'Updated Method Name'
+        }
+
+        response = self.client.patch(self.url, self.data)
+        self.assertEqual(response.data, expected)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_change_submission_data_and_visibility_when_participant_team_hasnt_participated_in_challenge(self):
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
+
+        # Note that we haven't added the self.participant_team to Challenge
+        expected = {
+            'error': 'You haven\'t participated in the challenge'
+        }
+        self.data = {
+            'method_name': 'Updated Method Name'
+        }
+
+        response = self.client.patch(self.url, self.data)
+        self.assertEqual(response.data, expected)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_change_submission_data_and_visibility_when_submission_exist(self):
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
+        self.data = {
+            'method_name': 'Updated Method Name'
+        }
+        expected = {
+                'id': self.submission.id,
+                'participant_team': self.submission.participant_team.pk,
+                'participant_team_name': self.submission.participant_team.team_name,
+                'execution_time': self.submission.execution_time,
+                'challenge_phase': self.submission.challenge_phase.pk,
+                'created_by': self.submission.created_by.pk,
+                'status': self.submission.status,
+                'input_file': "http://testserver%s" % (self.submission.input_file.url),
+                'method_name': self.data['method_name'],
+                'method_description': self.submission.method_description,
+                'project_url': self.submission.project_url,
+                'publication_url': self.submission.publication_url,
+                'stdout_file': None,
+                'stderr_file': None,
+                'submission_result_file': None,
+                "submitted_at": "{0}{1}".format(self.submission.submitted_at.isoformat(), 'Z').replace("+00:00", ""),
+                "is_public": self.submission.is_public,
+            }
+        self.challenge.participant_teams.add(self.participant_team)
+        response = self.client.patch(self.url, self.data)
+        self.assertEqual(response.data, expected)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+    def test_change_submission_data_and_visibility_when_submission_doesnt_exist(self):
+        self.url = reverse_lazy('jobs:change_submission_data_and_visibility',
+                                kwargs={'challenge_pk': self.challenge.pk,
+                                        'challenge_phase_pk': self.challenge_phase.pk,
+                                        'submission_pk': self.submission.pk})
+
+        expected = {
+            'error': 'Submission does not exist'
+        }
+        self.data = {
+            'method_name': 'Updated Method Name'
+        }
+        self.submission.delete()
+        self.challenge.participant_teams.add(self.participant_team)
+        response = self.client.patch(self.url, self.data)
+        self.assertEqual(response.data, expected)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)