def candidate_submission_upload_view(request: HttpRequest, submission_type: str) -> HttpResponse: submission_type_ = getattr(SubmissionTypes, submission_type) file = request.FILES["file"] now_str = datetime.now().strftime("%m_%d_%Y__%H_%M_%S") upload_key = f"{submission_type_.uname}/{request.user.uuid}/{file.name}@{now_str}" interface.storage_client.save(upload_key, file) submission_result = interface.grader_client.grade( assignment_id=submission_type_.uname, user_uuid=request.user.uuid, submission_s3_bucket=settings.STORAGE_BUCKET, submission_s3_key=upload_key, ) application = Application.objects.get(user=request.user) sub = Submission(file_location=upload_key, score=submission_result.score, feedback_location=submission_result.feedback_s3_key) Domain.add_submission(application, submission_type_, sub) if submission_type == SubmissionTypes.coding_test.uname: return HttpResponseRedirect("/candidate/coding-test") return HttpResponseRedirect(f"/candidate/slu/{submission_type}")
def test_add_submission_error_close_applications(self) -> None: interface.feature_flag_client.set_applications_opening_date( datetime.now() - timedelta(hours=5)) interface.feature_flag_client.set_applications_closing_date( datetime.now() - timedelta(hours=2)) a = Application.objects.create(user=User.objects.create( email="*****@*****.**")) with self.assertRaises(DomainException): Domain.add_submission(a, SubmissionTypes.coding_test, Submission()) with self.assertRaises(DomainException): Domain.add_submission(a, SubmissionTypes.slu01, Submission())
def handle(self, *args, **options) -> None: bucket = options["bucket"] directory = options["dir"] if bucket is None and directory is None: raise CommandError("you need to specify --bucket or --dir") expected_keys = { # "key": "description", "public-assets/ldssa_logo.png": "this is LDSA Logo, displayed in the login/signup pages", Domain.get_candidate_release_zip("coding_test"): "this is the candidate nbgrader `coding_test` release, the one candidates can donwload", Domain.get_candidate_release_zip("slu01"): "this is the candidate nbgrader `slu01` release, the one candidates can donwload", Domain.get_candidate_release_zip("slu02"): "this is the candidate nbgrader `slu02` release, the one candidates can donwload", Domain.get_candidate_release_zip("slu03"): "this is the candidate nbgrader `slu03` release, the one candidates can donwload", } fail = False if bucket is not None: s3 = boto3.client("s3") for k, d in expected_keys.items(): try: s3.head_object(Bucket=bucket, Key=k) self.stdout.write(f"{k} -> " + self.style.SUCCESS("found.")) except ClientError: self.stdout.write(f"{k} -> " + self.style.ERROR("not found.")) fail = True elif directory is not None: for k, d in expected_keys.items(): if os.path.isfile(os.path.join(directory, k)): self.stdout.write(f"{k} -> " + self.style.SUCCESS("found.")) else: self.stdout.write(f"{k} -> " + self.style.ERROR("not found.")) self.stdout.write(self.style.WARNING(d)) fail = True else: raise Exception if fail: raise CommandError("At least one key is missing...") else: self.stdout.write(self.style.SUCCESS("All Good!"))
def test_add_submission_error_not_started_coding_test(self) -> None: interface.feature_flag_client.set_applications_opening_date( datetime.now() - timedelta(minutes=30)) interface.feature_flag_client.set_applications_closing_date( datetime.now() + timedelta(minutes=30)) a = Application.objects.create(user=User.objects.create( email="*****@*****.**")) a.coding_test_started_at = None a.save() with self.assertRaises(DomainException): Domain.add_submission(a, SubmissionTypes.coding_test, Submission()) self.assertEqual(a.submissions.count(), 0)
def test_add_submission_error_max_submissions(self) -> None: interface.feature_flag_client.set_applications_opening_date( datetime.now() - timedelta(minutes=30)) interface.feature_flag_client.set_applications_closing_date( datetime.now() + timedelta(minutes=30)) a = Application.objects.create(user=User.objects.create( email="*****@*****.**")) for _ in range(0, 251): Submission.objects.create( application=a, submission_type=SubmissionTypes.coding_test.uname) Submission.objects.create( application=a, submission_type=SubmissionTypes.slu01.uname) Submission.objects.create( application=a, submission_type=SubmissionTypes.slu02.uname) Submission.objects.create( application=a, submission_type=SubmissionTypes.slu03.uname) a.coding_test_started_at = datetime.now() a.save() with self.assertRaises(DomainException): Domain.add_submission(a, SubmissionTypes.coding_test, Submission()) with self.assertRaises(DomainException): Domain.add_submission(a, SubmissionTypes.slu01, Submission()) with self.assertRaises(DomainException): Domain.add_submission(a, SubmissionTypes.slu02, Submission()) with self.assertRaises(DomainException): Domain.add_submission(a, SubmissionTypes.slu03, Submission()) self.assertEqual(a.submissions.count(), 251 * 4)
def get_candidate_state(candidate: User) -> CandidateState: state = {} state["confirmed_email"] = candidate.email_confirmed state["accepted_coc"] = candidate.code_of_conduct_accepted state[ "decided_scholarship"] = candidate.applying_for_scholarship is not None state["applying_for_scholarship"] = candidate.applying_for_scholarship try: _ = candidate.profile state["created_profile"] = True except Profile.DoesNotExist: state["created_profile"] = False application, _ = Application.objects.get_or_create(user=candidate) status = ApplicationsDomain.get_application_detailed_status( application) state["application_status"] = status["application"] state["coding_test_status"] = status[SubmissionTypes.coding_test.uname] state["slu01_status"] = status[SubmissionTypes.slu01.uname] state["slu02_status"] = status[SubmissionTypes.slu02.uname] state["slu03_status"] = status[SubmissionTypes.slu03.uname] try: state["selection_status"] = SelectionDomain.get_status( candidate.selection) except Selection.DoesNotExist: state["selection_status"] = None return CandidateState(**state)
def test_get_close_date(self) -> None: a = Application.objects.create(user=User.objects.create( email="*****@*****.**")) expected_domain_buffer_delta = timedelta(minutes=2) self.assertEqual(Domain.get_end_date(a, SubmissionTypes.coding_test), self.acd) self.assertEqual( Domain.get_end_date(a, SubmissionTypes.coding_test, apply_buffer=True), self.acd + expected_domain_buffer_delta, ) self.assertEqual(Domain.get_end_date(a, SubmissionTypes.slu01), self.acd) self.assertEqual( Domain.get_end_date(a, SubmissionTypes.slu01, apply_buffer=True), self.acd + expected_domain_buffer_delta) self.assertEqual(Domain.get_end_date(a, SubmissionTypes.slu02), self.acd) self.assertEqual( Domain.get_end_date(a, SubmissionTypes.slu02, apply_buffer=True), self.acd + expected_domain_buffer_delta) self.assertEqual(Domain.get_end_date(a, SubmissionTypes.slu03), self.acd) self.assertEqual( Domain.get_end_date(a, SubmissionTypes.slu03, apply_buffer=True), self.acd + expected_domain_buffer_delta) coding_test_delta = timedelta( minutes=interface.feature_flag_client.get_coding_test_duration()) dt_now = datetime.now() a.coding_test_started_at = dt_now a.save() self.assertEqual(Domain.get_end_date(a, SubmissionTypes.coding_test), dt_now + coding_test_delta) self.assertEqual( Domain.get_end_date(a, SubmissionTypes.coding_test, apply_buffer=True), dt_now + coding_test_delta + expected_domain_buffer_delta, )
def test_get_start_date(self) -> None: a = Application.objects.create(user=User.objects.create( email="*****@*****.**")) self.assertEqual(Domain.get_start_date(a, SubmissionTypes.coding_test), None) self.assertEqual(Domain.get_start_date(a, SubmissionTypes.slu01), self.aod) self.assertEqual(Domain.get_start_date(a, SubmissionTypes.slu02), self.aod) self.assertEqual(Domain.get_start_date(a, SubmissionTypes.slu03), self.aod) dt_now = datetime.now() a.coding_test_started_at = dt_now a.save() self.assertEqual(Domain.get_start_date(a, SubmissionTypes.coding_test), dt_now)
def trigger_applications_are_over() -> None: if datetime.now() < interface.feature_flag_client.get_applications_closing_date(): logger.error("trying to trigger `applications over` event but applications are still open") raise EventsException("Can't trigger `applications over` event") sent_count = 0 q = ApplicationDomainQueries.all() for a in q: try: ApplicationDomain.application_over(a) sent_count += 1 except ApplicationDomainException: pass # means that email was already sent a.refresh_from_db() if a.application_over_email_sent == "passed": SelectionDomain.create(a.user) logger.info(f"sent {sent_count} `application_over` emails")
def test_add_submission(self) -> None: interface.feature_flag_client.set_applications_opening_date( datetime.now() - timedelta(minutes=30)) interface.feature_flag_client.set_applications_closing_date( datetime.now() + timedelta(minutes=30)) a = Application.objects.create(user=User.objects.create( email="*****@*****.**")) a.coding_test_started_at = datetime.now() a.save() Domain.add_submission(a, SubmissionTypes.coding_test, Submission()) Domain.add_submission(a, SubmissionTypes.slu01, Submission()) Domain.add_submission(a, SubmissionTypes.slu02, Submission()) Domain.add_submission(a, SubmissionTypes.slu03, Submission()) self.assertEqual(a.submissions.count(), 4) interface.feature_flag_client.set_applications_closing_date( datetime.now() - timedelta(minutes=30)) # will work because end-date will be based on start_end + duration, not on the ff.closing_date Domain.add_submission(a, SubmissionTypes.coding_test, Submission()) self.assertEqual(a.submissions.count(), 5)
def test_has_positive_score(self) -> None: target_app = Application.objects.create(user=User.objects.create( email="*****@*****.**")) other_app = Application.objects.create(user=User.objects.create( email="*****@*****.**")) Submission.objects.create( application=target_app, score=10, submission_type=SubmissionTypes.coding_test.uname) Submission.objects.create( application=target_app, score=89, submission_type=SubmissionTypes.coding_test.uname) Submission.objects.create(application=target_app, score=15, submission_type=SubmissionTypes.slu01.uname) Submission.objects.create(application=target_app, score=14, submission_type=SubmissionTypes.slu03.uname) Submission.objects.create(application=target_app, score=5, submission_type=SubmissionTypes.slu03.uname) Submission.objects.create(application=target_app, score=19, submission_type=SubmissionTypes.slu03.uname) self.assertEqual( Domain.has_positive_score(target_app, SubmissionTypes.coding_test), True) self.assertEqual( Domain.has_positive_score(target_app, SubmissionTypes.slu01), False) self.assertEqual( Domain.has_positive_score(target_app, SubmissionTypes.slu02), False) self.assertEqual( Domain.has_positive_score(target_app, SubmissionTypes.slu03), True) self.assertEqual( Domain.has_positive_score(other_app, SubmissionTypes.coding_test), False) self.assertEqual( Domain.has_positive_score(other_app, SubmissionTypes.slu01), False) self.assertEqual( Domain.has_positive_score(other_app, SubmissionTypes.slu02), False) self.assertEqual( Domain.has_positive_score(other_app, SubmissionTypes.slu03), False)
def candidate_assignment_download_view(request: HttpRequest) -> HttpResponse: try: assignment_id = request.GET["assignment_id"] except Exception: raise Http404 application = Application.objects.get(user=request.user) if assignment_id == SubmissionTypes.coding_test.uname and application.coding_test_started_at is None: raise Http404 key = Domain.get_candidate_release_zip(assignment_id) url = interface.storage_client.get_attachment_url( key, content_type="application/zip") return HttpResponseRedirect(url)
def test_get_best_score(self) -> None: target_app = Application.objects.create(user=User.objects.create( email="*****@*****.**")) other_app = Application.objects.create(user=User.objects.create( email="*****@*****.**")) Submission.objects.create( application=target_app, score=10, submission_type=SubmissionTypes.coding_test.uname) Submission.objects.create( application=target_app, score=89, submission_type=SubmissionTypes.coding_test.uname) Submission.objects.create(application=target_app, score=73, submission_type=SubmissionTypes.slu01.uname) Submission.objects.create(application=target_app, score=71, submission_type=SubmissionTypes.slu03.uname) Submission.objects.create(application=target_app, score=21, submission_type=SubmissionTypes.slu03.uname) Submission.objects.create(application=target_app, score=92, submission_type=SubmissionTypes.slu03.uname) self.assertEqual( Domain.get_best_score(target_app, SubmissionTypes.coding_test), 89) self.assertEqual( Domain.get_best_score(target_app, SubmissionTypes.slu01), 73) self.assertEqual( Domain.get_best_score(target_app, SubmissionTypes.slu02), None) self.assertEqual( Domain.get_best_score(target_app, SubmissionTypes.slu03), 92) self.assertEqual( Domain.get_best_score(other_app, SubmissionTypes.coding_test), None) self.assertEqual( Domain.get_best_score(other_app, SubmissionTypes.slu01), None) self.assertEqual( Domain.get_best_score(other_app, SubmissionTypes.slu02), None) self.assertEqual( Domain.get_best_score(other_app, SubmissionTypes.slu03), None)
def submission_view_ctx(application: Application, submission_type: SubmissionType) -> Dict[str, Any]: return { "submission_type": submission_type, "status": Domain.get_sub_type_status(application, submission_type).name, "submissions_closes_at": Domain.get_end_date(application, submission_type).strftime("%Y-%m-%d %H:%M"), "best_score": Domain.get_best_score(application, submission_type), "download_enabled": Domain.can_add_submission(application, submission_type), "upload_enabled": Domain.can_add_submission(application, submission_type), "submissions": Submission.objects.filter( application=application, submission_type=submission_type.uname).order_by("-updated_at"), "coding_test_started_at_ms": int(application.coding_test_started_at.timestamp() * 1000) if application.coding_test_started_at is not None else None, }
def staff_candidate_view(request: HttpRequest, user_id: int) -> HttpResponse: try: user = User.objects.filter(is_staff=False).filter(is_admin=False).get( id=user_id) except User.DoesNotExist: raise Http404 try: application = user.application total_submissions = Submission.objects.filter( application=application).count() application_best_scores = { SubmissionTypes.coding_test.uname: ApplicationDomain.get_best_score(application, SubmissionTypes.coding_test), SubmissionTypes.slu01.uname: ApplicationDomain.get_best_score(application, SubmissionTypes.slu01), SubmissionTypes.slu02.uname: ApplicationDomain.get_best_score(application, SubmissionTypes.slu02), SubmissionTypes.slu03.uname: ApplicationDomain.get_best_score(application, SubmissionTypes.slu03), } except Application.DoesNotExist: total_submissions = 0 application_best_scores = {} ctx = { "user": user, "total_submissions": total_submissions, "application_best_scores": application_best_scores } template = loader.get_template("./staff_templates/candidate.html") return HttpResponse(template.render(ctx, request))
def test_get_status(self) -> None: a = Application.objects.create(user=User.objects.create( email="*****@*****.**")) interface.feature_flag_client.set_applications_opening_date( datetime.now() + timedelta(minutes=5)) self.assertEqual( Domain.get_sub_type_status(a, SubmissionTypes.coding_test), SubmissionStatus.not_started) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu01), SubmissionStatus.not_started) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu02), SubmissionStatus.not_started) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu03), SubmissionStatus.not_started) self.assertEqual(Domain.get_application_status(a), ApplicationStatus.not_started) interface.feature_flag_client.set_applications_opening_date( datetime.now() - timedelta(minutes=5)) interface.feature_flag_client.set_applications_closing_date( datetime.now() + timedelta(minutes=5)) self.assertEqual( Domain.get_sub_type_status(a, SubmissionTypes.coding_test), SubmissionStatus.not_started) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu01), SubmissionStatus.ongoing) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu02), SubmissionStatus.ongoing) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu03), SubmissionStatus.ongoing) self.assertEqual(Domain.get_application_status(a), ApplicationStatus.ongoing) Submission.objects.create(application=a, score=99, submission_type=SubmissionTypes.slu01.uname) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu01), SubmissionStatus.passed) self.assertEqual(Domain.get_application_status(a), ApplicationStatus.ongoing) Submission.objects.create( application=a, score=99, submission_type=SubmissionTypes.coding_test.uname) Submission.objects.create(application=a, score=99, submission_type=SubmissionTypes.slu01.uname) slu02_sub = Submission.objects.create( application=a, score=99, submission_type=SubmissionTypes.slu02.uname) Submission.objects.create(application=a, score=99, submission_type=SubmissionTypes.slu03.uname) self.assertEqual( Domain.get_sub_type_status(a, SubmissionTypes.coding_test), SubmissionStatus.passed) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu01), SubmissionStatus.passed) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu02), SubmissionStatus.passed) self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu02), SubmissionStatus.passed) self.assertEqual(Domain.get_application_status(a), ApplicationStatus.passed) slu02_sub.delete() interface.feature_flag_client.set_applications_closing_date( datetime.now() - timedelta(minutes=5)) a.save() self.assertEqual(Domain.get_sub_type_status(a, SubmissionTypes.slu02), SubmissionStatus.failed) self.assertEqual(Domain.get_application_status(a), ApplicationStatus.failed)
def staff_applications_view(request: HttpRequest) -> HttpResponse: query = Application.objects.all().order_by("user__email") filter_by_application_status = request.GET.get("application_status") applications = [] count_by_type: Dict[Any, Any] = { "application": { s: 0 for s in [ Status.not_started.name, Status.ongoing.name, Status.passed.name, Status.failed.name ] }, SubmissionTypes.coding_test.uname: { s: 0 for s in [ Status.not_started.name, Status.ongoing.name, Status.passed.name, Status.failed.name ] }, SubmissionTypes.slu01.uname: { s: 0 for s in [ Status.not_started.name, Status.ongoing.name, Status.passed.name, Status.failed.name ] }, SubmissionTypes.slu02.uname: { s: 0 for s in [ Status.not_started.name, Status.ongoing.name, Status.passed.name, Status.failed.name ] }, SubmissionTypes.slu03.uname: { s: 0 for s in [ Status.not_started.name, Status.ongoing.name, Status.passed.name, Status.failed.name ] }, } for a in query: application_det_status = Domain.get_application_detailed_status(a) for sub_type, sub_status in application_det_status.items(): count_by_type[sub_type][sub_status.name] += 1 if (filter_by_application_status is not None and application_det_status["application"].name != filter_by_application_status): continue applications.append({ "ref": a, "status_list": [ application_det_status["application"], *[ Domain.get_sub_type_status(a, sub_type) for sub_type in SubmissionTypes.all ], ], }) status_enum = { s.name: { "name": s.name, "value": s.value, "count": count_by_type["application"][s.name] } for s in Status } ctx = { "status_enum": status_enum, "applications": applications, "summary": count_by_type } template = loader.get_template("./staff_templates/applications.html") return HttpResponse(template.render(ctx, request))