def get_challenge_phase_submission_analysis(request, challenge_pk, challenge_phase_pk): """ API to fetch 1. The submissions count for challenge phase. 2. The participated team count for challenge phase. """ challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) submissions = Submission.objects.filter( challenge_phase=challenge_phase, challenge_phase__challenge=challenge) submission_count = submissions.count() participant_team_count = submissions.values_list( 'participant_team', flat=True).distinct().count() challenge_phase_submission_count = ChallengePhaseSubmissionCount( submission_count, participant_team_count, challenge_phase.pk) try: serializer = ChallengePhaseSubmissionCountSerializer(challenge_phase_submission_count) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) except: response_data = {'error': "Bad request. Please try again later!"} return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def get_last_submission_datetime_analysis(request, challenge_pk, challenge_phase_pk): """ API to fetch 1. To get the last submission time in a challenge phase. 2. To get the last submission time in a challenge. """ challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) submissions = Submission.objects.filter( challenge_phase__challenge=challenge) last_submission_timestamp_in_challenge = submissions.order_by( '-submitted_at')[0].created_at last_submission_timestamp_in_challenge_phase = submissions.filter( challenge_phase=challenge_phase).order_by( '-submitted_at')[0].created_at last_submission_timestamp = LastSubmissionTimestamp( last_submission_timestamp_in_challenge, last_submission_timestamp_in_challenge_phase, challenge_phase.pk) try: serializer = LastSubmissionTimestampSerializer( last_submission_timestamp) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) except: response_data = {'error': 'Bad request. Please try again later!'} return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def get_submissions_for_challenge(request, challenge_pk): challenge = get_challenge_model(challenge_pk) if not is_user_a_host_of_challenge(request.user, challenge.id): response_data = { "error": "Sorry, you are not authorized to make this request!" } return Response(response_data, status=status.HTTP_400_BAD_REQUEST) submission_status = request.query_params.get("status", None) valid_submission_status = [ Submission.SUBMITTED, Submission.RUNNING, Submission.FAILED, Submission.CANCELLED, Submission.FINISHED, Submission.SUBMITTING, ] if submission_status not in valid_submission_status: response_data = { "error": "Invalid submission status {}".format(submission_status) } return Response(response_data, status=status.HTTP_400_BAD_REQUEST) submissions_done_in_challenge = Submission.objects.filter( challenge_phase__challenge=challenge.id, status=submission_status) serializer = SubmissionSerializer(submissions_done_in_challenge, many=True, context={"request": request}) return Response(serializer.data, status=status.HTTP_200_OK)
def get_challenge_phase_submission_analysis(request, challenge_pk, challenge_phase_pk): """ Returns 1. Total number of submissions in a challenge phase 2. Number of teams which made submissions in a challenge phase 3. Number of submissions with status a)Submitting, b)Submitted, c)Running, d)Failed, e)Cancelled, f)Finished status 4. Number of flagged & public submissions in challenge phase """ challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) # Get the total submissions in a challenge phase submissions = Submission.objects.filter( challenge_phase=challenge_phase, challenge_phase__challenge=challenge) total_submissions = submissions.count() # Get the total participant teams in a challenge phase participant_team_count = submissions.values( 'participant_team').distinct().count() # Get flagged submission count flagged_submissions_count = submissions.filter(is_flagged=True).count() # Get public submission count public_submissions_count = submissions.filter(is_public=True).count() challenge_phase_submission_count = ChallengePhaseSubmissionAnalytics( total_submissions, participant_team_count, flagged_submissions_count, public_submissions_count, challenge_phase.pk) try: serializer = ChallengePhaseSubmissionAnalyticsSerializer( challenge_phase_submission_count) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) except ValueError: response_data = {'error': 'Bad request. Please try again later!'} return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def download_all_participants(request, challenge_pk): """ Returns the List of Participant Teams and its details in csv format """ if is_user_a_host_of_challenge(user=request.user, challenge_pk=challenge_pk): challenge = get_challenge_model(challenge_pk) participant_teams = challenge.participant_teams.all().order_by( "-team_name") teams = ChallengeParticipantSerializer(participant_teams, many=True, context={"request": request}) response = HttpResponse(content_type="text/csv") response[ "Content-Disposition"] = "attachment; filename=participant_teams_{0}.csv".format( challenge_pk) writer = csv.writer(response) writer.writerow([ "Team Name", "Team Members", "Email Id", ]) for team in teams.data: writer.writerow([ team["team_name"], ",".join(team["team_members"]), ",".join(team["team_members_email_ids"]), ]) return response else: response_data = { "error": "Sorry, you are not authorized to make this request" } return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def get_challenge_phase_submission_count_by_team(request, challenge_pk, challenge_phase_pk): """ Returns number of submissions done by a participant team in a challenge phase """ challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) participant_team = get_participant_team_id_of_user_for_a_challenge( request.user, challenge.pk) submissions = Submission.objects.filter( challenge_phase=challenge_phase, challenge_phase__challenge=challenge, participant_team=participant_team) participant_team_submissions = submissions.count() challenge_phase_submission_count = ChallengePhaseSubmissionCount( participant_team_submissions, challenge_phase.pk) try: serializer = ChallengePhaseSubmissionCountSerializer( challenge_phase_submission_count) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) except: response_data = {'error': "Bad request. Please try again later!"} return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def challenge_list(request, challenge_host_team_pk): try: challenge_host_team = ChallengeHostTeam.objects.get(pk=challenge_host_team_pk) except ChallengeHostTeam.DoesNotExist: response_data = {'error': 'ChallengeHostTeam does not exist'} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) if request.method == 'GET': challenge = Challenge.objects.filter(creator=challenge_host_team) paginator, result_page = paginated_queryset(challenge, request) serializer = ChallengeSerializer(result_page, many=True, context={'request': request}) response_data = serializer.data return paginator.get_paginated_response(response_data) elif request.method == 'POST': if not ChallengeHost.objects.filter(user=request.user, team_name_id=challenge_host_team_pk).exists(): response_data = { 'error': 'Sorry, you do not belong to this Host Team!'} return Response(response_data, status=status.HTTP_401_UNAUTHORIZED) serializer = ZipChallengeSerializer(data=request.data, context={'challenge_host_team': challenge_host_team, 'request': request}) if serializer.is_valid(): serializer.save() challenge = get_challenge_model(serializer.instance.pk) serializer = ChallengeSerializer(challenge) response_data = serializer.data return Response(response_data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_submission_count(request, challenge_pk, duration): """ Returns submission count for a challenge according to the duration Valid values for duration are all, daily, weekly and monthly. """ # make sure that a valid url is requested. if duration.lower() not in ('all', 'daily', 'weekly', 'monthly'): response_data = {'error': 'Wrong URL pattern!'} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) challenge = get_challenge_model(challenge_pk) challenge_phase_ids = challenge.challengephase_set.all().values_list( 'id', flat=True) q_params = {'challenge_phase__id__in': challenge_phase_ids} since_date = None if duration.lower() == 'daily': since_date = timezone.now().date() elif duration.lower() == 'weekly': since_date = (timezone.now() - timedelta(days=7)).date() elif duration.lower() == 'monthly': since_date = (timezone.now() - timedelta(days=30)).date() # for `all` we dont need any condition in `q_params` if since_date: q_params['submitted_at__gte'] = since_date submission_count = Submission.objects.filter(**q_params).count() submission_count = SubmissionCount(submission_count) serializer = SubmissionCountSerializer(submission_count) return Response(serializer.data, status=status.HTTP_200_OK)
def get_last_submission_time( request, challenge_pk, challenge_phase_pk, submission_by ): """ Returns the last submission time for a particular challenge phase """ challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) # To get the last submission time by a user in a challenge phase. if submission_by == "user": last_submitted_at = Submission.objects.filter( created_by=request.user.pk, challenge_phase=challenge_phase, challenge_phase__challenge=challenge, ) last_submitted_at = last_submitted_at.order_by("-submitted_at")[ 0 ].created_at last_submitted_at = LastSubmissionDateTime(last_submitted_at) serializer = LastSubmissionDateTimeSerializer(last_submitted_at) return Response(serializer.data, status=status.HTTP_200_OK) else: response_data = {"error": "Page not found!"} return Response(response_data, status=status.HTTP_404_NOT_FOUND)
def get_remaining_submissions(request, challenge_pk): ''' API to get the number of remaining submission for all phases. Below is the sample response returned by the API { "participant_team": "Sample_Participant_Team", "participant_team_id": 2, "phases": [ { "id": 1, "name": "Megan Phase", "start_date": "2018-10-28T14:22:53.022639Z", "end_date": "2020-06-19T14:22:53.022660Z", "limits": { "remaining_submissions_this_month_count": 9, "remaining_submissions_today_count": 5, "remaining_submissions_count": 29 } }, { "id": 2, "name": "Molly Phase", "start_date": "2018-10-28T14:22:53Z", "end_date": "2020-06-19T14:22:53Z", "limits": { "message": "You have exhausted this month's submission limit!", "remaining_time": "1481076.929224" // remaining_time is in seconds } } ] } ''' phases_data = {} challenge = get_challenge_model(challenge_pk) challenge_phases = ChallengePhase.objects.filter( challenge=challenge).order_by('pk') if not is_user_a_host_of_challenge(request.user, challenge_pk): challenge_phases = challenge_phases.filter( challenge=challenge, is_public=True).order_by('pk') phase_data_list = list() for phase in challenge_phases: remaining_submission_message, response_status = get_remaining_submission_for_a_phase( request.user, phase.id, challenge_pk) if response_status != status.HTTP_200_OK: return Response(remaining_submission_message, status=response_status) phase_data_list.append( RemainingSubmissionDataSerializer(phase, context={ 'limits': remaining_submission_message }).data) phases_data["phases"] = phase_data_list participant_team = get_participant_team_of_user_for_a_challenge( request.user, challenge_pk) phases_data['participant_team'] = participant_team.team_name phases_data['participant_team_id'] = participant_team.id return Response(phases_data, status=status.HTTP_200_OK)
def get_participant_count(request, challenge_pk): challenge = get_challenge_model(challenge_pk) participant_teams = challenge.participant_teams.all() participant_count = Participant.objects.filter( team__in=participant_teams).count() participant_count = ParticipantCount(participant_count) serializer = ParticipantCountSerializer(participant_count) return Response(serializer.data, status=status.HTTP_200_OK)
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 challenge = get_challenge_model(challenge_pk) # check if the challenge phase exists or not challenge_phase = get_challenge_phase_model(challenge_phase_pk) if not challenge.is_active: response_data = {'error': 'Challenge is not active'} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) # check if challenge phase is public and accepting solutions if not challenge_phase.is_public: response_data = { 'error': 'Sorry, cannot accept submissions since challenge phase is not public' } return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) 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_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_pk) except Submission.DoesNotExist: response_data = {'error': 'Submission does not exist'} return Response(response_data, status=status.HTTP_403_FORBIDDEN) serializer = SubmissionSerializer(submission, data=request.data, context={ 'participant_team': participant_team, 'challenge_phase': challenge_phase, 'request': request }, partial=True) if serializer.is_valid(): serializer.save() response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_participant_team_count(request, challenge_pk): """ Returns the number of participant teams in a challenge """ challenge = get_challenge_model(challenge_pk) participant_team_count = challenge.participant_teams.count() participant_team_count = ParticipantTeamCount(participant_team_count) serializer = ParticipantTeamCountSerializer(participant_team_count) return Response(serializer.data, status=status.HTTP_200_OK)
def get_last_submission_datetime_analysis( request, challenge_pk, challenge_phase_pk ): """ API to fetch 1. To get the last submission time in a challenge phase. 2. To get the last submission time in a challenge. """ challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) submissions = Submission.objects.filter( challenge_phase__challenge=challenge ) if not submissions: response_data = { "message": "You dont have any submissions in this challenge!" } return Response(response_data, status.HTTP_200_OK) last_submission_timestamp_in_challenge = submissions.order_by( "-submitted_at" )[0].created_at submissions_in_a_phase = submissions.filter( challenge_phase=challenge_phase ) if not submissions_in_a_phase: last_submission_timestamp_in_challenge_phase = ( "You dont have any submissions in this challenge phase!" ) else: last_submission_timestamp_in_challenge_phase = submissions_in_a_phase.order_by( "-submitted_at" )[ 0 ].created_at last_submission_timestamp = LastSubmissionTimestamp( last_submission_timestamp_in_challenge, last_submission_timestamp_in_challenge_phase, challenge_phase.pk, ) try: serializer = LastSubmissionTimestampSerializer( last_submission_timestamp ) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) except: # noqa: E722 response_data = {"error": "Bad request. Please try again later!"} return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def download_all_submissions_file(request, challenge_pk, file_type): # To check for the corresponding challenge from challenge_pk. challenge = get_challenge_model(challenge_pk) if file_type == 'csv': if is_user_a_host_of_challenge(user=request.user, challenge_pk=challenge_pk): submissions = Submission.objects.filter( challenge_phase__challenge=challenge).order_by('-submitted_at') response = HttpResponse(content_type='text/csv') response[ 'Content-Disposition'] = 'attachment; filename=all_submissions.csv' writer = csv.writer(response) writer.writerow([ 'id', 'Team Name', 'Challenge Phase', 'Status', 'Created By', 'Execution Time(sec.)', 'Submission Number', 'Submitted File', 'Stdout File', 'Stderr File', 'Submitted At', 'Submission Result File', 'Submission Metadata File', ]) for submission in submissions: writer.writerow([ submission.id, submission.participant_team, submission.challenge_phase, submission.status, submission.created_by, submission.execution_time, submission.submission_number, submission.input_file, submission.stdout_file, submission.stderr_file, submission.created_at, submission.submission_result_file, submission.submission_metadata_file, ]) return response else: response_data = { 'error': 'Only Challenge Hosts can use the export feature!' } return Response(response_data, status=status.HTTP_400_BAD_REQUEST) else: response_data = {'error': 'The file type requested is not valid!'} return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def get_all_submissions_of_challenge(request, challenge_pk, challenge_phase_pk): """ Returns all the submissions for a particular challenge """ # To check for the corresponding challenge from challenge_pk. challenge = get_challenge_model(challenge_pk) # To check for the corresponding challenge phase from the challenge_phase_pk and challenge. try: challenge_phase = ChallengePhase.objects.get(pk=challenge_phase_pk, challenge=challenge) except ChallengePhase.DoesNotExist: response_data = {'error': 'Challenge Phase {} does not exist'.format(challenge_phase_pk)} return Response(response_data, status=status.HTTP_404_NOT_FOUND) # To check for the user as a host of the challenge from the request and challenge_pk. if is_user_a_host_of_challenge(user=request.user, challenge_pk=challenge_pk): # Filter submissions on the basis of challenge for host for now. Later on, the support for query # parameters like challenge phase, date is to be added. submissions = Submission.objects.filter(challenge_phase__challenge=challenge).order_by('-submitted_at') paginator, result_page = paginated_queryset(submissions, request) try: serializer = ChallengeSubmissionManagementSerializer(result_page, many=True, context={'request': request}) response_data = serializer.data return paginator.get_paginated_response(response_data) except: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # To check for the user as a participant of the challenge from the request and challenge_pk. elif has_user_participated_in_challenge(user=request.user, challenge_id=challenge_pk): # get participant team object for the user for a particular challenge. participant_team_pk = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_pk) # Filter submissions on the basis of challenge phase for a participant. submissions = Submission.objects.filter(participant_team=participant_team_pk, challenge_phase=challenge_phase).order_by('-submitted_at') paginator, result_page = paginated_queryset(submissions, request) try: serializer = SubmissionSerializer(result_page, many=True, context={'request': request}) response_data = serializer.data return paginator.get_paginated_response(response_data) except: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # when user is neither host not participant of the challenge. else: response_data = {'error': 'You are neither host nor participant of the challenge!'} return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def challenge_detail(request, challenge_host_team_pk, challenge_pk): try: challenge_host_team = ChallengeHostTeam.objects.get( pk=challenge_host_team_pk) except ChallengeHostTeam.DoesNotExist: response_data = {'error': 'ChallengeHostTeam does not exist'} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) try: challenge = Challenge.objects.get(pk=challenge_pk) except Challenge.DoesNotExist: response_data = {'error': 'Challenge does not exist'} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) if request.method == 'GET': serializer = ChallengeSerializer(challenge, context={'request': request}) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) elif request.method in ['PUT', 'PATCH']: if request.method == 'PATCH': serializer = ZipChallengeSerializer(challenge, data=request.data, context={ 'challenge_host_team': challenge_host_team, 'request': request }, partial=True) else: serializer = ZipChallengeSerializer(challenge, data=request.data, context={ 'challenge_host_team': challenge_host_team, 'request': request }) if serializer.is_valid(): serializer.save() challenge = get_challenge_model(serializer.instance.pk) serializer = ChallengeSerializer(challenge) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) elif request.method == 'DELETE': challenge.delete() return Response(status=status.HTTP_204_NO_CONTENT)
def star_challenge(request, challenge_pk): """ API endpoint for starring and unstarring a challenge. """ challenge = get_challenge_model(challenge_pk) if request.method == 'POST': try: starred_challenge = StarChallenge.objects.get(user=request.user, challenge=challenge) starred_challenge.is_starred = not starred_challenge.is_starred starred_challenge.save() serializer = StarChallengeSerializer(starred_challenge) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) except: serializer = StarChallengeSerializer(data=request.data, context={ 'request': request, 'challenge': challenge, 'is_starred': True }) if serializer.is_valid(): serializer.save() response_data = serializer.data return Response(response_data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) if request.method == 'GET': try: starred_challenge = StarChallenge.objects.get(user=request.user, challenge=challenge) serializer = StarChallengeSerializer(starred_challenge) response_data = serializer.data return Response(response_data, status=status.HTTP_200_OK) except: starred_challenge = StarChallenge.objects.filter( challenge=challenge) if not starred_challenge: response_data = {'is_starred': False, 'count': 0} return Response(response_data, status=status.HTTP_200_OK) serializer = StarChallengeSerializer(starred_challenge, many=True) response_data = { 'is_starred': False, 'count': serializer.data[0]['count'] } return Response(response_data, status=status.HTTP_200_OK)
def remove_participant_team_from_challenge( request, challenge_pk, participant_team_pk ): """ API to remove the participant team from a challenge Arguments: request {HttpRequest} -- The request object challenge_pk {[int]} -- Challenge primary key participant_team_pk {[int]} -- Participant team primary key Returns: Response Object -- An object containing api response """ challenge = get_challenge_model(challenge_pk) participant_team = get_participant_model(participant_team_pk) if participant_team.created_by == request.user: if participant_team.challenge_set.filter(id=challenge_pk).exists(): challenge_phases = ChallengePhase.objects.filter( challenge=challenge ) for challenge_phase in challenge_phases: submissions = Submission.objects.filter( participant_team=participant_team_pk, challenge_phase=challenge_phase, ) if submissions.count() > 0: response_data = { "error": "Unable to remove team as you have already made submission to the challenge" } return Response( response_data, status=status.HTTP_400_BAD_REQUEST ) challenge.participant_teams.remove(participant_team) return Response(status=status.HTTP_200_OK) else: response_data = { "error": "Team has not participated in the challenge" } return Response(response_data, status=status.HTTP_400_BAD_REQUEST) else: response_data = { "error": "Sorry, you do not have permissions to remove this participant team" } return Response(response_data, status=status.HTTP_401_UNAUTHORIZED)
def get_submissions_for_challenge(request, challenge_pk): challenge = get_challenge_model(challenge_pk) if not is_user_a_host_of_challenge(request.user, challenge.id): response_data = { "error": "Sorry, you are not authorized to make this request!" } return Response(response_data, status=status.HTTP_400_BAD_REQUEST) submissions_done_in_challenge = SubmissionFilter( request.GET, queryset=Submission.objects.filter( challenge_phase__challenge=challenge.id)) serializer = SubmissionSerializer(submissions_done_in_challenge.qs, many=True, context={'request': request}) return Response(serializer.data, status=status.HTTP_200_OK)
def test_host_downloads_participant_team(self): expected = io.StringIO() expected_participant_teams = csv.writer(expected) expected_participant_teams.writerow( ["Team Name", "Team Members", "Email Id"]) challenge = get_challenge_model(self.challenge.pk) participant_team = challenge.participant_teams.all().order_by( "-team_name") participant_teams = ChallengeParticipantSerializer(participant_team, many=True) for team in participant_teams.data: expected_participant_teams.writerow([ team["team_name"], ",".join(team["team_members"]), ",".join(team["team_members_email_ids"]), ]) self.client.force_authenticate(user=self.user) response = self.client.get(self.url, {}) self.assertEqual(response.content.decode("utf-8"), expected.getvalue()) self.assertEqual(response.status_code, status.HTTP_200_OK)
def get_submission_count(request, challenge_pk, duration): """ Returns submission count for a challenge according to the duration Valid values for duration are all, daily, weekly and monthly. """ # make sure that a valid url is requested. if duration.lower() not in ("all", "daily", "weekly", "monthly"): response_data = {"error": "Wrong URL pattern!"} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) challenge = get_challenge_model(challenge_pk) challenge_phase_ids = challenge.challengephase_set.all().values_list( "id", flat=True ) q_params = {"challenge_phase__id__in": challenge_phase_ids} since_date = None if duration.lower() == "daily": # Get the midnight time of the day since_date = timezone.now().replace( hour=0, minute=0, second=0, microsecond=0 ) elif duration.lower() == "weekly": since_date = (timezone.now() - timedelta(days=7)).replace( hour=0, minute=0, second=0, microsecond=0 ) elif duration.lower() == "monthly": since_date = (timezone.now() - timedelta(days=30)).replace( hour=0, minute=0, second=0, microsecond=0 ) # for `all` we dont need any condition in `q_params` if since_date: q_params["submitted_at__gte"] = since_date submission_count = Submission.objects.filter(**q_params).count() submission_count = SubmissionCount(submission_count) serializer = SubmissionCountSerializer(submission_count) return Response(serializer.data, status=status.HTTP_200_OK)
def get_last_submission_time(request, challenge_pk, challenge_phase_pk, submission_by): challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) # To get the last submission time by a user in a challenge phase. if submission_by == 'user': last_submitted_at = Submission.objects.filter( created_by=request.user.pk, challenge_phase=challenge_phase, challenge_phase__challenge=challenge) last_submitted_at = last_submitted_at.order_by( '-submitted_at')[0].created_at last_submitted_at = LastSubmissionDateTime(last_submitted_at) serializer = LastSubmissionDateTimeSerializer(last_submitted_at) return Response(serializer.data, status=status.HTTP_200_OK) else: response_data = {'error': 'Page not found!'} return Response(response_data, status=status.HTTP_404_NOT_FOUND)
def get_challenge_phase_submission_analysis(request, challenge_pk, challenge_phase_pk): """ API to fetch 1. The submissions count for challenge phase. 2. The participated team count for challenge phase. """ challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) submissions = Submission.objects.filter( challenge_phase__challenge=challenge, challenge_phase=challenge_phase) try: serializer = ChallengePhaseSubmissionAnalysisSerializer(submissions, many=True) if serializer.data: response_data = serializer.data[0] return Response(response_data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK) except: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_last_submission_datetime_analysis(request, challenge_pk, challenge_phase_pk): """ API to fetch 1. To get the last submission time in a challenge phase. 2. To get the last submission time in a challenge. """ challenge = get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) submissions = Submission.objects.filter( challenge_phase__challenge=challenge, challenge_phase=challenge_phase) try: serializer = LastSubmissionDateTimeAnalysisSerializer(submissions, many=True) if serializer.data: response_data = serializer.data[0] return Response(response_data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK) except: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_participant_team_details_for_challenge(request, challenge_pk): """ API to get the participant team detail Arguments: request {HttpRequest} -- The request object challenge_pk {[int]} -- Challenge primary key Returns: {dict} -- Participant team detail that has participated in the challenge """ challenge = get_challenge_model(challenge_pk) if has_user_participated_in_challenge(request.user, challenge_pk): participant_team = get_participant_team_of_user_for_a_challenge( request.user, challenge_pk) serializer = ParticipantTeamSerializer(participant_team) return Response(serializer.data, status=status.HTTP_200_OK) else: response_data = { "error": f"The user {request.user.username} has not participanted in {challenge.title}" } return Response(response_data, status=status.HTTP_404_NOT_FOUND)
def get_remaining_submissions(request, challenge_phase_pk, challenge_pk): ''' Returns the number of remaining submissions that a participant can do per day and in total to a particular challenge phase of a challenge. ''' # significance of get_challenge_model() here to check # if the challenge exists or not get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) participant_team_pk = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_pk) # Conditional check for the existence of participant team of the user. if not participant_team_pk: response_data = {'error': 'You haven\'t participated in the challenge'} return Response(response_data, status=status.HTTP_403_FORBIDDEN) max_submissions_per_day_count = challenge_phase.max_submissions_per_day max_submissions_count = challenge_phase.max_submissions submissions_done = Submission.objects.filter( challenge_phase__challenge=challenge_pk, challenge_phase=challenge_phase_pk, participant_team=participant_team_pk) failed_submissions = submissions_done.filter( status=Submission.FAILED) submissions_done_today = submissions_done.filter( submitted_at__gte=timezone.now().date()) failed_submissions_done_today = submissions_done_today.filter( status=Submission.FAILED) submissions_done_count = submissions_done.count() failed_submissions_count = failed_submissions.count() submissions_done_today_count = submissions_done_today.count() failed_submissions_done_today_count = failed_submissions_done_today.count() # Checks if #today's successful submission is greater than or equal to max submission per day if ((submissions_done_today_count - failed_submissions_done_today_count) >= max_submissions_per_day_count or (max_submissions_per_day_count == 0)): # Get the UTC time of the instant when the above condition is true. date_time_now = timezone.now() # Calculate the next day's date. date_time_tomorrow = date_time_now.date() + datetime.timedelta(1) utc = timezone.utc # Get the midnight time of the day i.e. 12:00 AM of next day. midnight = utc.localize(datetime.datetime.combine( date_time_tomorrow, datetime.time())) # Subtract the current time from the midnight time to get the remaining time for the next day's submissions. remaining_time = midnight - date_time_now # Return the remaining time with a message. response_data = {'message': 'You have exhausted today\'s submission limit', 'remaining_time': remaining_time } return Response(response_data, status=status.HTTP_200_OK) else: # Calculate the remaining submissions for today. remaining_submissions_today_count = (max_submissions_per_day_count - (submissions_done_today_count - failed_submissions_done_today_count) ) # calculate the remaining submissions from total submissions. remaining_submission_count = max_submissions_count - \ (submissions_done_count - failed_submissions_count) if remaining_submissions_today_count > remaining_submission_count: remaining_submissions_today_count = remaining_submission_count # Return the above calculated data. response_data = {'remaining_submissions_today_count': remaining_submissions_today_count, 'remaining_submissions': remaining_submission_count } return Response(response_data, status=status.HTTP_200_OK)
def download_all_submissions(request, challenge_pk, challenge_phase_pk, file_type): # To check for the corresponding challenge from challenge_pk. challenge = get_challenge_model(challenge_pk) # To check for the corresponding challenge phase from the challenge_phase_pk and challenge. try: challenge_phase = ChallengePhase.objects.get(pk=challenge_phase_pk, challenge=challenge) except ChallengePhase.DoesNotExist: response_data = { 'error': 'Challenge Phase {} does not exist'.format(challenge_phase_pk) } return Response(response_data, status=status.HTTP_404_NOT_FOUND) if file_type == 'csv': if is_user_a_host_of_challenge(user=request.user, challenge_pk=challenge_pk): submissions = Submission.objects.filter( challenge_phase__challenge=challenge).order_by('-submitted_at') submissions = ChallengeSubmissionManagementSerializer( submissions, many=True, context={'request': request}) response = HttpResponse(content_type='text/csv') response[ 'Content-Disposition'] = 'attachment; filename=all_submissions.csv' writer = csv.writer(response) writer.writerow([ 'id', 'Team Name', 'Team Members', 'Team Members Email Id', 'Challenge Phase', 'Status', 'Created By', 'Execution Time(sec.)', 'Submission Number', 'Submitted File', 'Stdout File', 'Stderr File', 'Submitted At', 'Submission Result File', 'Submission Metadata File', ]) for submission in submissions.data: writer.writerow([ submission['id'], submission['participant_team'], ",".join(username['username'] for username in submission['participant_team_members']), ",".join( email['email'] for email in submission['participant_team_members']), submission['challenge_phase'], submission['status'], submission['created_by'], submission['execution_time'], submission['submission_number'], submission['input_file'], submission['stdout_file'], submission['stderr_file'], submission['created_at'], submission['submission_result_file'], submission['submission_metadata_file'], ]) return response elif has_user_participated_in_challenge(user=request.user, challenge_id=challenge_pk): # get participant team object for the user for a particular challenge. participant_team_pk = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_pk) # Filter submissions on the basis of challenge phase for a participant. submissions = Submission.objects.filter( participant_team=participant_team_pk, challenge_phase=challenge_phase).order_by('-submitted_at') submissions = ChallengeSubmissionManagementSerializer( submissions, many=True, context={'request': request}) response = HttpResponse(content_type='text/csv') response[ 'Content-Disposition'] = 'attachment; filename=all_submissions.csv' writer = csv.writer(response) writer.writerow([ 'Team Name', 'Method Name', 'Status', 'Execution Time(sec.)', 'Submitted File', 'Result File', 'Stdout File', 'Stderr File', 'Submitted At', ]) for submission in submissions.data: writer.writerow([ submission['participant_team'], submission['method_name'], submission['status'], submission['execution_time'], submission['input_file'], submission['submission_result_file'], submission['stdout_file'], submission['stderr_file'], submission['created_at'], ]) return response else: response_data = { 'error': 'You are neither host nor participant of the challenge!' } return Response(response_data, status=status.HTTP_400_BAD_REQUEST) else: response_data = {'error': 'The file type requested is not valid!'} return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
def get_remaining_submission_for_a_phase(user, challenge_phase_pk, challenge_pk): """ Returns the number of remaining submissions that a participant can do daily, monthly and in total to a particular challenge phase of a challenge. """ get_challenge_model(challenge_pk) challenge_phase = get_challenge_phase_model(challenge_phase_pk) participant_team_pk = get_participant_team_id_of_user_for_a_challenge( user, challenge_pk) # Conditional check for the existence of participant team of the user. if not participant_team_pk: response_data = {"error": "You haven't participated in the challenge"} return response_data, status.HTTP_403_FORBIDDEN max_submissions_count = challenge_phase.max_submissions max_submissions_per_month_count = challenge_phase.max_submissions_per_month max_submissions_per_day_count = challenge_phase.max_submissions_per_day submissions_done = Submission.objects.filter( challenge_phase__challenge=challenge_pk, challenge_phase=challenge_phase_pk, participant_team=participant_team_pk, ).exclude(status__in=submission_status_to_exclude) submissions_done_this_month = submissions_done.filter( submitted_at__gte=timezone.now().replace( day=1, hour=0, minute=0, second=0, microsecond=0)) # Get the submissions_done_today by midnight time of the day submissions_done_today = submissions_done.filter( submitted_at__gte=timezone.now().replace( hour=0, minute=0, second=0, microsecond=0)) submissions_done_count = submissions_done.count() submissions_done_this_month_count = submissions_done_this_month.count() submissions_done_today_count = submissions_done_today.count() # Check for maximum submission limit if submissions_done_count >= max_submissions_count: response_data = { "message": "You have exhausted maximum submission limit!", "submission_limit_exceeded": True, } return response_data, status.HTTP_200_OK # Check for monthy submission limit elif submissions_done_this_month_count >= max_submissions_per_month_count: date_time_now = timezone.now() next_month_start_date_time = date_time_now + datetime.timedelta( days=+30) next_month_start_date_time = next_month_start_date_time.replace( day=1, hour=0, minute=0, second=0, microsecond=0) remaining_time = next_month_start_date_time - date_time_now if submissions_done_today_count >= max_submissions_per_day_count: response_data = { "message": "Both daily and monthly submission limits are exhausted!", "remaining_time": remaining_time, } else: response_data = { "message": "You have exhausted this month's submission limit!", "remaining_time": remaining_time, } return response_data, status.HTTP_200_OK # Checks if #today's successful submission is greater than or equal to max submission per day elif submissions_done_today_count >= max_submissions_per_day_count: date_time_now = timezone.now() date_time_tomorrow = date_time_now + datetime.timedelta(1) # Get the midnight time of the day i.e. 12:00 AM of next day. midnight = date_time_tomorrow.replace(hour=0, minute=0, second=0) remaining_time = midnight - date_time_now response_data = { "message": "You have exhausted today's submission limit!", "remaining_time": remaining_time, } return response_data, status.HTTP_200_OK else: # calculate the remaining submissions from total submissions. remaining_submission_count = (max_submissions_count - submissions_done_count) # Calculate the remaining submissions for current month. remaining_submissions_this_month_count = ( max_submissions_per_month_count - submissions_done_this_month_count) # Calculate the remaining submissions for today. remaining_submissions_today_count = (max_submissions_per_day_count - submissions_done_today_count) remaining_submissions_this_month_count = min( remaining_submission_count, remaining_submissions_this_month_count) remaining_submissions_today_count = min( remaining_submissions_this_month_count, remaining_submissions_today_count, ) response_data = { "remaining_submissions_this_month_count": remaining_submissions_this_month_count, "remaining_submissions_today_count": remaining_submissions_today_count, "remaining_submissions_count": remaining_submission_count, } return response_data, status.HTTP_200_OK
def invite_participant_to_team(request, pk): try: participant_team = ParticipantTeam.objects.get(pk=pk) except ParticipantTeam.DoesNotExist: response_data = {"error": "Participant Team does not exist"} return Response(response_data, status=status.HTTP_404_NOT_FOUND) if not is_user_part_of_participant_team(request.user, participant_team): response_data = {"error": "You are not a member of this team!"} return Response(response_data, status=status.HTTP_400_BAD_REQUEST) email = request.data.get("email") try: user = User.objects.get(email=email) except User.DoesNotExist: response_data = { "error": "User does not exist with this email address!" } return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) participant = Participant.objects.filter(team=participant_team, user=user) if participant.exists(): response_data = {"error": "User is already part of the team!"} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) invited_user_participated_challenges = get_list_of_challenges_participated_by_a_user( user).values_list("id", flat=True) team_participated_challenges = get_list_of_challenges_for_participant_team( [participant_team]).values_list("id", flat=True) if set(invited_user_participated_challenges) & set( team_participated_challenges): """ Check if the user has already participated in challenges where the inviting participant has participated. If this is the case, then the user cannot be invited since he cannot participate in a challenge via two teams. """ response_data = { "error": "Sorry, the invited user has already participated" " in atleast one of the challenges which you are already a" " part of. Please try creating a new team and then invite." } return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) if len(team_participated_challenges) > 0: for challenge_pk in team_participated_challenges: challenge = get_challenge_model(challenge_pk) if len(challenge.banned_email_ids) > 0: # Check if team participants emails are banned for (participant_email ) in participant_team.get_all_participants_email(): if participant_email in challenge.banned_email_ids: message = "You cannot invite as you're a part of {} team and it has been banned " "from this challenge. Please contact the challenge host." response_data = { "error": message.format(participant_team.team_name) } return Response( response_data, status=status.HTTP_406_NOT_ACCEPTABLE, ) # Check if invited user is banned if email in challenge.banned_email_ids: message = "You cannot invite as the invited user has been banned " "from this challenge. Please contact the challenge host." response_data = {"error": message} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) # Check if user is in allowed list. if len(challenge.allowed_email_domains) > 0: if not is_user_in_allowed_email_domains(email, challenge_pk): message = "Sorry, users with {} email domain(s) are only allowed to participate in this challenge." domains = "" for domain in challenge.allowed_email_domains: domains = "{}{}{}".format(domains, "/", domain) domains = domains[1:] response_data = {"error": message.format(domains)} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) # Check if user is in blocked list. if is_user_in_blocked_email_domains(email, challenge_pk): message = "Sorry, users with {} email domain(s) are not allowed to participate in this challenge." domains = "" for domain in challenge.blocked_email_domains: domains = "{}{}{}".format(domains, "/", domain) domains = domains[1:] response_data = {"error": message.format(domains)} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) serializer = InviteParticipantToTeamSerializer( data=request.data, context={ "participant_team": participant_team, "request": request }, ) if serializer.is_valid(): serializer.save() response_data = { "message": "User has been successfully added to the team!" } return Response(response_data, status=status.HTTP_202_ACCEPTED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)