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 change_submission_visibility(request, challenge_id, challenge_phase_id, submission_id): """API Endpoint for making a submission to a challenge""" # 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) # 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) 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_id = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_id) try: participant_team = ParticipantTeam.objects.get(pk=participant_team_id) 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) except Submission.DoesNotExist: response_data = {'error': 'Submission does not exist'} return Response(response_data, status=status.HTTP_403_FORBIDDEN) print request.data 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_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) 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) submission_count = submissions.count() submissions = Submission.objects.filter( challenge_phase=challenge_phase, challenge_phase__challenge=challenge) 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 download_file_and_publish_submission_message(request_data, user_pk, request_method, challenge_phase_id): """ Download submission file from url and send it for the evaluation """ user = User.objects.get(pk=user_pk) challenge_phase = ChallengePhase.objects.get(pk=challenge_phase_id) participant_team_id = get_participant_team_id_of_user_for_a_challenge( user, challenge_phase.challenge.pk) participant_team = ParticipantTeam.objects.get(pk=participant_team_id) request = HttpRequest() request.method = request_method request.user = user try: downloaded_file = get_file_from_url(request_data["file_url"]) file_path = os.path.join(downloaded_file["temp_dir_path"], downloaded_file["name"]) with open(file_path, 'rb') as f: input_file = SimpleUploadedFile(downloaded_file["name"], f.read(), content_type="multipart/form-data") data = { "input_file": input_file, "method_name": request_data["method_name"], "method_description": request_data["method_description"], "project_url": request_data["project_url"], "publication_url": request_data["publication_url"], "status": Submission.SUBMITTED } serializer = SubmissionSerializer(data=data, context={ 'participant_team': participant_team, 'challenge_phase': challenge_phase, 'request': request }) if serializer.is_valid(): serializer.save() submission = serializer.instance # publish messages in the submission worker queue publish_submission_message({ "challenge_pk": challenge_phase.challenge.pk, "phase_pk": challenge_phase.pk, "submission_pk": submission.pk }) logger.info("Message published to submission worker successfully!") shutil.rmtree(downloaded_file['temp_dir_path']) except Exception as e: logger.exception( "Exception while downloading and sending submission for evaluation {}" .format(e))
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_submission(request, challenge_id, challenge_phase_id): """API Endpoint for making a submission to a challenge""" # 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) # 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) if request.method == 'GET': # getting participant team object for the user for a particular challenge. participant_team_id = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_id) # check if participant team exists or not. try: ParticipantTeam.objects.get(pk=participant_team_id) except ParticipantTeam.DoesNotExist: response_data = {'error': 'You haven\'t participated in the challenge'} return Response(response_data, status=status.HTTP_403_FORBIDDEN) submission = Submission.objects.filter(participant_team=participant_team_id, challenge_phase=challenge_phase).order_by('-submitted_at') paginator, result_page = paginated_queryset(submission, 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) elif request.method == 'POST': # check if the challenge is active or not 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 active if not challenge_phase.is_active: response_data = { 'error': 'Sorry, cannot accept submissions since challenge phase is not active'} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) # check if user is a challenge host or a participant if not is_user_a_host_of_challenge(request.user, challenge_id): # 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_403_FORBIDDEN) participant_team_id = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_id) try: participant_team = ParticipantTeam.objects.get(pk=participant_team_id) except ParticipantTeam.DoesNotExist: response_data = {'error': 'You haven\'t participated in the challenge'} return Response(response_data, status=status.HTTP_403_FORBIDDEN) # Fetch the number of submissions under progress. submissions_in_progress_status = [Submission.SUBMITTED, Submission.SUBMITTING, Submission.RUNNING] submissions_in_progress = Submission.objects.filter( participant_team=participant_team_id, challenge_phase=challenge_phase, status__in=submissions_in_progress_status).count() if submissions_in_progress >= challenge_phase.max_concurrent_submissions_allowed: message = 'You have {} submissions that are being processed. \ Please wait for them to finish and then try again.' response_data = {'error': message.format(submissions_in_progress)} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) serializer = SubmissionSerializer(data=request.data, context={'participant_team': participant_team, 'challenge_phase': challenge_phase, 'request': request }) if serializer.is_valid(): serializer.save() response_data = serializer.data submission = serializer.instance # publish message in the queue publish_submission_message(challenge_id, challenge_phase_id, submission.id) return Response(response_data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE)
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 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_403_FORBIDDEN) # check if challenge phase is public and accepting solutions if not is_user_a_host_of_challenge(request.user, challenge_pk): 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_403_FORBIDDEN) 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) try: is_public = request.data['is_public'] if is_public is True: when_made_public = datetime.datetime.now() request.data['when_made_public'] = when_made_public except KeyError: pass 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 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 challenge_submission(request, challenge_id, challenge_phase_id): """API Endpoint for making a submission to a challenge""" # 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) # 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) if request.method == 'GET': # getting participant team object for the user for a particular challenge. participant_team_id = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_id) # check if participant team exists or not. try: ParticipantTeam.objects.get(pk=participant_team_id) except ParticipantTeam.DoesNotExist: response_data = { 'error': 'You haven\'t participated in the challenge' } return Response(response_data, status=status.HTTP_403_FORBIDDEN) submission = Submission.objects.filter( participant_team=participant_team_id, challenge_phase=challenge_phase).order_by('-submitted_at') paginator, result_page = paginated_queryset(submission, 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) elif request.method == 'POST': # check if the challenge is active or not 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 active if not challenge_phase.is_active: response_data = { 'error': 'Sorry, cannot accept submissions since challenge phase 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_id = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_id) try: participant_team = ParticipantTeam.objects.get( pk=participant_team_id) except ParticipantTeam.DoesNotExist: response_data = { 'error': 'You haven\'t participated in the challenge' } return Response(response_data, status=status.HTTP_403_FORBIDDEN) serializer = SubmissionSerializer(data=request.data, context={ 'participant_team': participant_team, 'challenge_phase': challenge_phase, 'request': request }) if serializer.is_valid(): serializer.save() response_data = serializer.data submission = serializer.instance # publish message in the queue publish_submission_message(challenge_id, challenge_phase_id, submission.id) return Response(response_data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
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_403_FORBIDDEN) # check if challenge phase is public and accepting solutions if not is_user_a_host_of_challenge(request.user, challenge_pk): 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_403_FORBIDDEN) elif request.data.get("is_baseline"): response_data = { "error": "Sorry, you are not authorized to make this request" } return Response(response_data, status=status.HTTP_400_BAD_REQUEST) 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) try: is_public = request.data["is_public"] if is_public is True: when_made_public = datetime.datetime.now() request.data["when_made_public"] = when_made_public except KeyError: pass 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_remaining_submissions(request, 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. ''' # 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_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=Submission.FAILED) 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!', 'max_submission_exceeded': True } return Response(response_data, status=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(response_data, status=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(response_data, status=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': remaining_submission_count } return Response(response_data, status=status.HTTP_200_OK)
def challenge_submission(request, challenge_id, challenge_phase_id): """API Endpoint for making a submission to a challenge""" # 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) # 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) if request.method == "GET": # getting participant team object for the user for a particular challenge. participant_team_id = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_id) # check if participant team exists or not. try: ParticipantTeam.objects.get(pk=participant_team_id) except ParticipantTeam.DoesNotExist: response_data = { "error": "You haven't participated in the challenge" } return Response(response_data, status=status.HTTP_403_FORBIDDEN) submission = Submission.objects.filter( participant_team=participant_team_id, challenge_phase=challenge_phase, ).order_by("-submitted_at") filtered_submissions = SubmissionFilter(request.GET, queryset=submission) paginator, result_page = paginated_queryset(filtered_submissions.qs, request) serializer = SubmissionSerializer(result_page, many=True, context={"request": request}) response_data = serializer.data return paginator.get_paginated_response(response_data) elif request.method == "POST": # check if the challenge is active or not 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 active if not challenge_phase.is_active: response_data = { "error": "Sorry, cannot accept submissions since challenge phase is not active" } return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) # check if user is a challenge host or a participant if not is_user_a_host_of_challenge(request.user, challenge_id): # 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_403_FORBIDDEN) # if allowed email ids list exist, check if the user exist in that list or not if challenge_phase.allowed_email_ids: if request.user.email not in challenge_phase.allowed_email_ids: response_data = { "error": "Sorry, you are not allowed to participate in this challenge phase" } return Response(response_data, status=status.HTTP_403_FORBIDDEN) participant_team_id = get_participant_team_id_of_user_for_a_challenge( request.user, challenge_id) try: participant_team = ParticipantTeam.objects.get( pk=participant_team_id) except ParticipantTeam.DoesNotExist: response_data = { "error": "You haven't participated in the challenge" } return Response(response_data, status=status.HTTP_403_FORBIDDEN) all_participants_email = participant_team.get_all_participants_email() for participant_email in all_participants_email: if participant_email in challenge.banned_email_ids: message = "You're a part of {} team and it has been banned from this challenge. \ Please contact the challenge host.".format( participant_team.team_name) response_data = {"error": message} return Response(response_data, status=status.HTTP_403_FORBIDDEN) # Fetch the number of submissions under progress. submissions_in_progress_status = [ Submission.SUBMITTED, Submission.SUBMITTING, Submission.RUNNING, ] submissions_in_progress = Submission.objects.filter( participant_team=participant_team_id, challenge_phase=challenge_phase, status__in=submissions_in_progress_status, ).count() if (submissions_in_progress >= challenge_phase.max_concurrent_submissions_allowed): message = "You have {} submissions that are being processed. \ Please wait for them to finish and then try again." response_data = {"error": message.format(submissions_in_progress)} return Response(response_data, status=status.HTTP_406_NOT_ACCEPTABLE) if not request.FILES: if not is_url_valid(request.data['file_url']): response_data = {'error': 'The file URL does not exists!'} return Response(response_data, status=status.HTTP_400_BAD_REQUEST) download_file_and_publish_submission_message.delay( request.data, request.user.id, request.method, challenge_phase_id) response_data = { 'message': 'Please wait while your submission being evaluated!' } return Response(response_data, status=status.HTTP_200_OK) serializer = SubmissionSerializer( data=request.data, context={ "participant_team": participant_team, "challenge_phase": challenge_phase, "request": request, }, ) if serializer.is_valid(): serializer.save() response_data = serializer.data submission = serializer.instance # publish message in the queue publish_submission_message(challenge_id, challenge_phase_id, submission.id) return Response(response_data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE)