Repository: Cloud-CV/EvalAI

Issue:
Add a serializer for challenge phase creation.
**Issue:** The` get` and `post` request for challenge phase are validating from the same serializer which exposes the `test_annotation` field.
**Solution:** Create a new serializer for post request in `challenges/serializers.py` with all the fields.


Discussion:

Resolving patch:
diff --git a/apps/challenges/serializers.py b/apps/challenges/serializers.py
--- a/apps/challenges/serializers.py
+++ b/apps/challenges/serializers.py
@@ -129,3 +129,25 @@ class ZipChallengePhaseSplitSerializer(serializers.ModelSerializer):
     class Meta:
         model = ChallengePhaseSplit
         fields = '__all__'
+
+
+class ChallengePhaseCreateSerializer(serializers.ModelSerializer):
+
+    is_active = serializers.ReadOnlyField()
+
+    def __init__(self, *args, **kwargs):
+        super(ChallengePhaseCreateSerializer, self).__init__(*args, **kwargs)
+        context = kwargs.get('context')
+        if context:
+            challenge = context.get('challenge')
+            if challenge:
+                kwargs['data']['challenge'] = challenge.pk
+            test_annotation = context.get('test_annotation')
+            if test_annotation:
+                kwargs['data']['test_annotation'] = test_annotation
+
+    class Meta:
+        model = ChallengePhase
+        fields = ('id', 'name', 'description', 'leaderboard_public', 'start_date',
+                  'end_date', 'challenge', 'max_submissions_per_day', 'max_submissions',
+                  'is_public', 'is_active', 'codename', 'test_annotation')
diff --git a/apps/challenges/views.py b/apps/challenges/views.py
--- a/apps/challenges/views.py
+++ b/apps/challenges/views.py
@@ -40,6 +40,7 @@
 from .permissions import IsChallengeCreator
 from .serializers import (ChallengeConfigSerializer,
                           ChallengePhaseSerializer,
+                          ChallengePhaseCreateSerializer,
                           ChallengePhaseSplitSerializer,
                           ChallengeSerializer,
                           DatasetSplitSerializer,
@@ -611,9 +612,9 @@ def create_challenge_using_zip_file(request, challenge_host_team_pk):
                     with open(test_annotation_file_path, 'rb') as test_annotation_file:
                         challenge_test_annotation_file = ContentFile(test_annotation_file.read(),
                                                                      test_annotation_file_path)
-                serializer = ChallengePhaseSerializer(data=data,
-                                                      context={'challenge': challenge,
-                                                               'test_annotation': challenge_test_annotation_file})
+                serializer = ChallengePhaseCreateSerializer(data=data,
+                                                            context={'challenge': challenge,
+                                                                     'test_annotation': challenge_test_annotation_file})
                 if serializer.is_valid():
                     serializer.save()
                     challenge_phase_ids[str(data['id'])] = serializer.instance.pk


Test patch:
diff --git a/tests/unit/challenges/test_serializers.py b/tests/unit/challenges/test_serializers.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/challenges/test_serializers.py
@@ -0,0 +1,133 @@
+import os
+
+from datetime import timedelta
+
+from django.core.files.uploadedfile import SimpleUploadedFile
+from django.contrib.auth.models import User
+from django.utils import timezone
+
+from allauth.account.models import EmailAddress
+from rest_framework.test import APITestCase, APIClient
+
+from challenges.models import (Challenge,
+                               ChallengePhase)
+from challenges.serializers import ChallengePhaseCreateSerializer
+from participants.models import ParticipantTeam
+from hosts.models import ChallengeHost, ChallengeHostTeam
+
+
+class BaseTestCase(APITestCase):
+
+    def setUp(self):
+        self.client = APIClient(enforce_csrf_checks=True)
+
+        self.user = User.objects.create(
+            username='someuser',
+            email="user@test.com",
+            password='secret_password')
+
+        EmailAddress.objects.create(
+            user=self.user,
+            email='user@test.com',
+            primary=True,
+            verified=True)
+
+        self.challenge_host_team = ChallengeHostTeam.objects.create(
+            team_name='Test Challenge Host Team',
+            created_by=self.user)
+
+        self.challenge = Challenge.objects.create(
+            title='Test Challenge',
+            short_description='Short description for test challenge',
+            description='Description for test challenge',
+            terms_and_conditions='Terms and conditions for test challenge',
+            submission_guidelines='Submission guidelines for test challenge',
+            creator=self.challenge_host_team,
+            published=False,
+            enable_forum=True,
+            anonymous_leaderboard=False,
+            start_date=timezone.now() - timedelta(days=2),
+            end_date=timezone.now() + timedelta(days=1),
+        )
+
+        self.challenge_host = ChallengeHost.objects.create(
+            user=self.user,
+            team_name=self.challenge_host_team,
+            status=ChallengeHost.ACCEPTED,
+            permissions=ChallengeHost.ADMIN)
+
+        self.participant_team = ParticipantTeam.objects.create(
+            team_name='Participant Team for Challenge',
+            created_by=self.user)
+
+        self.client.force_authenticate(user=self.user)
+
+
+class ChallengePhaseCreateSerializerTest(BaseTestCase):
+
+    def setUp(self):
+        super(ChallengePhaseCreateSerializerTest, self).setUp()
+
+        try:
+            os.makedirs('/tmp/evalai')
+        except OSError:
+            pass
+
+        with self.settings(MEDIA_ROOT='/tmp/evalai'):
+            self.challenge_phase = ChallengePhase.objects.create(
+                name='Challenge Phase',
+                description='Description for Challenge Phase',
+                leaderboard_public=False,
+                is_public=False,
+                start_date=timezone.now() - timedelta(days=2),
+                end_date=timezone.now() + timedelta(days=1),
+                challenge=self.challenge,
+                test_annotation=SimpleUploadedFile('test_sample_file.txt',
+                                                   'Dummy file content', content_type='text/plain'),
+                max_submissions_per_day=100000,
+                max_submissions=100000,
+            )
+
+            self.serializer_data = {
+                'id': self.challenge_phase.pk,
+                'name': 'Challenge Phase',
+                'description': 'Description for Challenge Phase',
+                'leaderboard_public': False,
+                'is_public': False,
+                'start_date': "{0}{1}".format(self.challenge_phase.start_date.isoformat(), 'Z').replace("+00:00", ""),
+                'end_date': "{0}{1}".format(self.challenge_phase.end_date.isoformat(), 'Z').replace("+00:00", ""),
+                'challenge': self.challenge.pk,
+                'test_annotation': self.challenge_phase.test_annotation.url,
+                'max_submissions_per_day': 100000,
+                'max_submissions': 100000,
+                'codename': self.challenge_phase.codename,
+                'is_active': self.challenge_phase.is_active,
+            }
+            self.challenge_phase_create_serializer = ChallengePhaseCreateSerializer(instance=self.challenge_phase)
+
+    def test_challenge_phase_create_serializer(self):
+
+        data = self.challenge_phase_create_serializer.data
+
+        self.assertItemsEqual(data.keys(), ['id', 'name', 'description', 'leaderboard_public', 'start_date',
+                                            'end_date', 'challenge', 'max_submissions_per_day', 'max_submissions',
+                                            'is_public', 'is_active', 'codename', 'test_annotation'])
+        self.assertEqual(data['id'], self.serializer_data['id'])
+        self.assertEqual(data['name'], self.serializer_data['name'])
+        self.assertEqual(data['description'], self.serializer_data['description'])
+        self.assertEqual(data['leaderboard_public'], self.serializer_data['leaderboard_public'])
+        self.assertEqual(data['start_date'], self.serializer_data['start_date'])
+        self.assertEqual(data['end_date'], self.serializer_data['end_date'])
+        self.assertEqual(data['challenge'], self.serializer_data['challenge'])
+        self.assertEqual(data['max_submissions_per_day'], self.serializer_data['max_submissions_per_day'])
+        self.assertEqual(data['max_submissions'], self.serializer_data['max_submissions'])
+        self.assertEqual(data['is_public'], self.serializer_data['is_public'])
+        self.assertEqual(data['codename'], self.serializer_data['codename'])
+        self.assertEqual(data['test_annotation'], self.serializer_data['test_annotation'])
+        self.assertEqual(data['is_active'], self.serializer_data['is_active'])
+
+    def test_challenge_phase_create_serializer_with_invalid_data(self):
+
+        serializer = ChallengePhaseCreateSerializer(data=self.serializer_data)
+        self.assertFalse(serializer.is_valid())
+        self.assertEqual(set(serializer.errors), set(['test_annotation']))