def test_view_all_submissions_does_not_show_code_for_submissions(self): second_submission = Submission(language=self.python_language, challenge=self.challenge, author=self.auth_user, code="time") second_submission.save() response = self.client.get(path='/challenges/{}/submissions/all'.format(self.challenge.id), HTTP_AUTHORIZATION=self.auth_token) self.assertEqual(response.status_code, 200) for submission in response.data: self.assertNotIn('code', submission.keys())
def test_view_all_submissions(self): second_submission = Submission(language=self.python_language, challenge=self.challenge, author=self.auth_user, code="") second_submission.save() response = self.client.get(path='/challenges/{}/submissions/all'.format(self.challenge.id), HTTP_AUTHORIZATION=self.auth_token) self.assertEqual(response.status_code, 200) # Should order them by creation date descending self.assertEqual(LimitedSubmissionSerializer([second_submission, self.submission], many=True).data, response.data)
def test_can_save_duplicate_submission(self): s = Submission(language=self.python_language, challenge=self.challenge, author=self.auth_user, code="") s.save() s = Submission(language=self.python_language, challenge=self.challenge, author=self.auth_user, code="") s.save() self.assertEqual(Submission.objects.count(), 2)
def create_challenge_completion_post(self, submission: Submission): """ Creates a NewsfeedItem of type ChallengeCompletion ex: Stanislav has completed challenge Firefox with 100/100 score after 30 attempts """ challenge = submission.challenge author: User = submission.author if not submission.has_solved_challenge(): raise Exception(f'Submission has not solved the challenge!') return self.create( author_id=author.id, type=NW_ITEM_CHALLENGE_COMPLETION_POST, content={ 'challenge_id': challenge.id, 'challenge_name': challenge.name, 'submission_id': submission.id, 'challenge_score': challenge.score, 'attempts_count': author.fetch_unsuccessful_challenge_attempts_count(challenge) })
def to_representation(self, instance: Submission): """ Modification to add four variables to the serialized data - user_has_voted - Boolean indicating if the user has voted at all for this - user_has_upvoted - Boolean indicating if the user has upvoted the submission (user_has_voted must be true) - upvote_count - int showing the amount of upvotes this submission has - downvote_count - int showing the amount of downvotes this submission has """ from accounts.models import User result = super().to_representation(instance) user: User = getattr(self.context.get('request', None), 'user', None) # TODO: Move to helper # TODO: Make user be passed in __init__ if user is None: result['user_has_voted'] = False result['user_has_upvoted'] = False else: user_vote = user.get_vote_for_submission(submission_id=instance.id) if user_vote is None: result['user_has_voted'] = False result['user_has_upvoted'] = False else: result['user_has_voted'] = True result['user_has_upvoted'] = user_vote.is_upvote upvote_count, downvote_count = instance.get_votes_count() result['upvote_count'] = upvote_count result['downvote_count'] = downvote_count return result
def test_fetch_top_submission_for_challenge_and_user_ignores_pending_submissions(self): SubmissionFactory(author=self.auth_user, challenge=self.challenge, result_score=50, pending=True) SubmissionFactory(author=self.auth_user, challenge=self.challenge, result_score=66, pending=True) received_submission = Submission.fetch_top_submission_for_challenge_and_user(self.challenge.id, self.auth_user.id) # should return None as there is no top submission self.assertIsNone(received_submission)
def fetch_max_score_for_challenge(self, challenge_id): """ Fetches the maximum score this user has scored for the given challenge """ from challenges.models import Submission top_submission = Submission.fetch_top_submission_for_challenge_and_user( challenge_id, self.id) max_score = top_submission.maxscore if top_submission else 0 return max_score
def test_fetch_top_submission_for_challenge_and_user_returns_bigger_score(self): SubmissionFactory(author=self.auth_user, challenge=self.challenge, result_score=50, pending=False) SubmissionFactory(author=self.auth_user, challenge=self.challenge, result_score=66, pending=False) # IS PENDING! SubmissionFactory(author=self.auth_user, challenge=self.challenge, result_score=1000, pending=True) SubmissionFactory(author=self.auth_user, challenge=self.challenge, result_score=100, pending=False) received_submission = Submission.fetch_top_submission_for_challenge_and_user(self.challenge.id, self.auth_user.id) self.assertIsNotNone(received_submission) self.assertEqual(received_submission.maxscore, 100)
def list(self, request, *args, **kwargs): latest_submissions = Submission.fetch_last_10_submissions_for_unique_challenges_by_user( user_id=request.user.id) latest_challenges = [ submission.challenge for submission in latest_submissions ] return Response(data=LimitedChallengeSerializer( latest_challenges, many=True, context={ 'request': request }).data)
def archive_submission(submission, form, link_form, phase): """Archive the old ``Submisssion`` and create a new entry for the currrent ``Phase`` ``PhaseRound`` combination""" previous_submission = submission new_submission = Submission(created_by=previous_submission.created_by, category=previous_submission.category, phase=phase) # ``Submission`` enters to tne open ``PhaseRound`` if phase.current_round: new_submission.phase_round = phase.current_round # Reuse the existing image if one hasn't been provided if not form.cleaned_data.get('sketh_note'): new_submission.sketh_note = submission.sketh_note # Create a new instance of the ``ModelForm`` since we want to duplicate # and call whatever mechanisms might be triggered through the form new_form = form.__class__(form.data, form.files, instance=new_submission) new_submission = new_form.save() submission.parent.update_version(new_submission) # Duplicate the links sent for this ``Submission`` create_link = lambda link: ExternalLink.objects.create( url=link['url'], name=link['name'], submission=new_submission) link_form = [create_link(link) for link in link_form.cleaned_data if link] return new_submission
def list(self, request, *args, **kwargs): challenge_pk = kwargs.get('challenge_pk', '') try: Challenge.objects.get(pk=challenge_pk) except Challenge.DoesNotExist: return Response( data={'error': f'Invalid challenge id {challenge_pk}!'}, status=400) top_submissions = Submission.fetch_top_submissions_for_challenge( challenge_id=challenge_pk) return Response( data=LimitedSubmissionSerializer(top_submissions, many=True).data)
def archive_submission(submission, form, link_form, phase): """Archive the old ``Submisssion`` and create a new entry for the currrent ``Phase`` ``PhaseRound`` combination""" previous_submission = submission new_submission = Submission(created_by=previous_submission.created_by, category=previous_submission.category, phase=phase) # ``Submission`` enters to tne open ``PhaseRound`` if phase.current_round: new_submission.phase_round = phase.current_round # Reuse the existing image if one hasn't been provided if not form.cleaned_data.get('sketh_note'): new_submission.sketh_note = submission.sketh_note # Create a new instance of the ``ModelForm`` since we want to duplicate # and call whatever mechanisms might be triggered through the form new_form = form.__class__(form.data, form.files, instance=new_submission) new_submission = new_form.save() submission.parent.update_version(new_submission) # Duplicate the links sent for this ``Submission`` create_link = lambda link: ExternalLink.objects.create( url=link['url'], name=link['name'], submission=new_submission) link_form = [create_link(link) for link in link_form.cleaned_data if link] return new_submission
def retrieve(self, request, *args, **kwargs): challenge_pk = kwargs.get('challenge_pk', '') try: Challenge.objects.get(pk=challenge_pk) except Challenge.DoesNotExist: return Response( data={'error': f'Invalid challenge id {challenge_pk}!'}, status=400) top_submission = Submission.fetch_top_submission_for_challenge_and_user( challenge_id=challenge_pk, user_id=request.user.id) if top_submission is None: return Response(status=404) # doesnt exist return Response(data=LimitedSubmissionSerializer(top_submission).data)
def test_fetch_last_10_submissions_for_unique_challenges_by_author(self): """ The method should return the last 10 submissions for unique challenges by the author """ for _ in range(20): # Create 20 submissions SubmissionFactory(author=self.auth_user) for _ in range(10): # Create last 10 submissions for one challenge SubmissionFactory(author=self.auth_user, challenge=self.challenge) latest_unique_submissions = Submission.fetch_last_10_submissions_for_unique_challenges_by_user(user_id=self.auth_user.id) # the first one should be for self.challenge, since we made it last self.assertEqual(latest_unique_submissions[0].challenge, self.challenge) # they should all be for unique challenges unique_challenge_ids = set([s.challenge.id for s in latest_unique_submissions]) self.assertEqual(10, len(unique_challenge_ids))
def test_fetch_top_submissions(self): """ The method should return the top submissions for a given challenge, selecting the top submission for each user """ """ Arrange """ f_submission = SubmissionFactory(author=self.auth_user, challenge=self.challenge, result_score=50) # Second user with submissions s_user = UserFactory() SubmissionFactory(author=s_user, challenge=self.challenge) # should get ignored top_submission = SubmissionFactory(author=s_user, challenge=self.challenge, result_score=51) # Third user with equal to first submission t_user = UserFactory() tr_sub = SubmissionFactory(challenge=self.challenge, author=t_user, result_score=50) expected_submissions = [top_submission, f_submission, tr_sub] # ordered by score, then by date (oldest first) received_submissions = list(Submission.fetch_top_submissions_for_challenge(self.challenge.id)) self.assertEqual(expected_submissions, received_submissions)
def create(self, request, *args, **kwargs): challenge_pk = kwargs.get('challenge_pk') code_given = request.data.get('code') language_given = request.data.get('language') challenge, language, is_valid, response = self.validate_data( challenge_pk, code_given, language_given, request.user) if not is_valid: return response # invalid data submission = Submission(code=code_given, author=request.user, challenge=challenge, task_id=1, language=language) submission.save() celery_task = run_grader_task.delay( test_case_count=challenge.test_case_count, test_folder_name=challenge.test_file_name, code=code_given, lang=language.name, submission_id=submission.id) request.user.last_submit_at = timezone.now() request.user.save() submission.task_id = celery_task submission.save() # Create the test cases TestCase.objects.bulk_create([ TestCase(submission=submission) for _ in range(challenge.test_case_count) ]) return Response(data=SubmissionSerializer(submission).data, status=201)
def grade_result(submission: Submission, timed_out_percentage: int, elapsed_seconds: float): """ Given a tested submission and the percentage of test cases that have timed out, update its score in accordance to the number of test cases passed and if more than 40% of the test cases have timed out, set the Submission's timed_out field as true """ challenge: Challenge = submission.challenge num_successful_tests = len([ True for ts_cs in submission.testcase_set.all() if not ts_cs.pending and ts_cs.success ]) result_per_test = challenge.score / challenge.test_case_count submission.result_score = num_successful_tests * result_per_test submission.pending = False submission.elapsed_seconds = elapsed_seconds if timed_out_percentage >= SUBMISSION_MINIMUM_TIMED_OUT_PERCENTAGE: submission.timed_out = True submission.save()
def test_fetch_top_submission_for_challenge_and_user_no_submissions_should_be_empty(self): received_submission = Submission.fetch_top_submission_for_challenge_and_user(self.challenge.id, self.auth_user.id) self.assertIsNone(received_submission)
def test_fetch_top_submissions_no_submissions_should_be_empty(self): received_submissions = list(Submission.fetch_top_submissions_for_challenge(self.challenge.id)) self.assertEqual([], received_submissions)
def test_cannot_save_blank_submission(self): s = Submission(language=self.python_language, challenge=self.challenge, author=self.auth_user, code='') with self.assertRaises(Exception): s.full_clean()
def test_absolute_url(self): s = Submission(language=self.python_language, challenge=self.challenge, author=self.auth_user, code="") s.save() self.assertEqual(s.get_absolute_url(), '/challenges/{}/submissions/{}'.format(s.challenge_id, s.id))