def has_object_permission(self, request, view, obj): try: fdbk_category = ag_models.FeedbackCategory( request.query_params.get('feedback_category')) except KeyError: raise exceptions.ValidationError( {'feedback_category': 'Missing required query param: feedback_category'}) except ValueError: raise exceptions.ValidationError( {'feedback_category': 'Invalid feedback category requested: {}'.format( request.query_params.get('feedback_category'))}) submission = get_submission_fn(obj) group = submission.group project = group.project course = project.course deadline_past = _deadline_is_past(submission) in_group = group.members.filter(pk=request.user.pk).exists() if course.is_staff(request.user): # Staff can always request any feedback category for # their own submissions. if in_group: return True # Staff can always request staff_viewer feedback # for other groups' submissions. if fdbk_category == ag_models.FeedbackCategory.staff_viewer: return True # Staff can only request staff_viewer or max feedback # for other groups' submissions. if fdbk_category != ag_models.FeedbackCategory.max: return False # Staff can only request max feedback for other groups' # ultimate submissions if the project deadline and group's # extension have passed. group_ultimate_submission = get_ultimate_submission(group) return deadline_past and group_ultimate_submission == submission # Non-staff users cannot view other groups' submissions if not group.members.filter(pk=request.user.pk).exists(): return False if fdbk_category == ag_models.FeedbackCategory.normal: return not submission.is_past_daily_limit if fdbk_category == ag_models.FeedbackCategory.past_limit_submission: return submission.is_past_daily_limit if fdbk_category == ag_models.FeedbackCategory.ultimate_submission: user_ultimate_submission = get_ultimate_submission(group, request.user) return (not project.hide_ultimate_submission_fdbk and user_ultimate_submission == submission and deadline_past) return False
def test_two_best_dont_count_for_user(self): self.project.validate_and_update( ultimate_submission_policy=ag_models.UltimateSubmissionPolicy.best) suite = ag_models.StudentTestSuite.objects.validate_and_create( name='suite', project=self.project, buggy_impl_names=[f'bug{i}' for i in range(3)], points_per_exposed_bug=1) best_submission = obj_build.make_finished_submission( self.group, does_not_count_for=[self.does_not_count_for_user.username]) ag_models.StudentTestSuiteResult.objects.validate_and_create( student_test_suite=suite, submission=best_submission, bugs_exposed=suite.buggy_impl_names) self.assertEqual( 3, get_submission_fdbk(best_submission, ag_models.FeedbackCategory.max).total_points) second_best_submission = obj_build.make_finished_submission( self.group, does_not_count_for=[self.does_not_count_for_user.username]) ag_models.StudentTestSuiteResult.objects.validate_and_create( student_test_suite=suite, submission=second_best_submission, bugs_exposed=suite.buggy_impl_names[:-1]) self.assertEqual( 2, get_submission_fdbk(second_best_submission, ag_models.FeedbackCategory.max).total_points) other_submission = obj_build.make_finished_submission(self.group) self.assertEqual( 0, get_submission_fdbk(other_submission, ag_models.FeedbackCategory.max).total_points) counts_for_user_ultimate_submission = get_ultimate_submission( self.group, user=self.counts_for_user) self.assertEqual(best_submission, counts_for_user_ultimate_submission) does_not_count_for_user_ultimate_submission = get_ultimate_submission( self.group, user=self.does_not_count_for_user) self.assertEqual(other_submission, does_not_count_for_user_ultimate_submission)
def create(self, *args, **kwargs): """ Creates a new HandgradingResult for the specified Group, or returns an already existing one. """ group = self.get_object() try: handgrading_rubric = group.project.handgrading_rubric except ObjectDoesNotExist: raise exceptions.ValidationError( {'handgrading_rubric': 'Project {} has not enabled handgrading'.format(group.project.pk)}) ultimate_submission = get_ultimate_submission(group) if not ultimate_submission: raise exceptions.ValidationError( {'num_submissions': 'Group {} has no submissions'.format(group.pk)}) handgrading_result, created = handgrading_models.HandgradingResult.objects.get_or_create( defaults={'submission': ultimate_submission}, handgrading_rubric=handgrading_rubric, group=group) for criterion in handgrading_rubric.criteria.all(): handgrading_models.CriterionResult.objects.get_or_create( defaults={'selected': False}, criterion=criterion, handgrading_result=handgrading_result, ) serializer = self.get_serializer(handgrading_result) return response.Response( serializer.data, status=status.HTTP_201_CREATED if created else status.HTTP_200_OK)
def test_no_submissions_count_for_user(self): oldest_submission = obj_build.make_finished_submission( self.group, does_not_count_for=[self.does_not_count_for_user.username]) most_recent_submission = obj_build.make_finished_submission( self.group, does_not_count_for=[self.does_not_count_for_user.username]) counts_for_user_ultimate_submission = get_ultimate_submission( self.group, user=self.counts_for_user) self.assertEqual(most_recent_submission, counts_for_user_ultimate_submission) does_not_count_for_user_ultimate_submission = get_ultimate_submission( self.group, user=self.does_not_count_for_user) self.assertIsNone(does_not_count_for_user_ultimate_submission)
def test_most_recent_does_not_count_for_user(self): self.project.validate_and_update(ultimate_submission_policy=ag_models. UltimateSubmissionPolicy.most_recent) oldest_submission = obj_build.make_finished_submission(self.group) most_recent_submission = obj_build.make_finished_submission( self.group, does_not_count_for=[self.does_not_count_for_user.username]) counts_for_user_ultimate_submission = get_ultimate_submission( self.group, user=self.counts_for_user) self.assertEqual(most_recent_submission, counts_for_user_ultimate_submission) does_not_count_for_user_ultimate_submission = get_ultimate_submission( self.group, user=self.does_not_count_for_user) self.assertEqual(oldest_submission, does_not_count_for_user_ultimate_submission)
def test_get_ultimate_submission(self): data = self.prepare_data(self.project) group = data[0].group best_sub = data[0].best_submission most_recent = data[0].most_recent_submission print(group.submissions.count()) print(group.submissions.all()) self.assertEqual(ag_models.UltimateSubmissionPolicy.most_recent, self.project.ultimate_submission_policy) ultimate_most_recent = get_ultimate_submission(group) self.assertEqual(most_recent, ultimate_most_recent) self.project.validate_and_update( ultimate_submission_policy=ag_models.UltimateSubmissionPolicy.best) ultimate_best = get_ultimate_submission(group) self.assertEqual(best_sub, ultimate_best)
def test_get_ultimate_submission_no_finished_submissions(self): for policy in ag_models.UltimateSubmissionPolicy: self.project.validate_and_update(ultimate_submission_policy=policy) group = obj_build.make_group(project=self.project) submission = obj_build.make_submission(group=group) self.assertEqual(1, group.submissions.count()) self.assertNotEqual( ag_models.Submission.GradingStatus.finished_grading, submission.status) ultimate_submission = get_ultimate_submission(group) self.assertIsNone(ultimate_submission)
def test_get_ultimate_submission_group_has_no_submissions(self): group_with_submissions_data = self.prepare_data(self.project)[0] self.project.validate_and_update(ultimate_submission_policy=ag_models. UltimateSubmissionPolicy.most_recent) group_with_no_submissions = obj_build.make_group(project=self.project) self.assertEqual(0, group_with_no_submissions.submissions.count()) ultimate_submission = get_ultimate_submission( group_with_no_submissions) self.assertIsNone(ultimate_submission) ultimate_submissions = [ fdbk.submission for fdbk in get_ultimate_submissions( self.project, filter_groups=None, ag_test_preloader=AGTestPreLoader(self.project)) ] self.assertSequenceEqual( [group_with_submissions_data.most_recent_submission], ultimate_submissions) self.project.validate_and_update( ultimate_submission_policy=ag_models.UltimateSubmissionPolicy.best) self.assertEqual(0, group_with_no_submissions.submissions.count()) ultimate_submission = get_ultimate_submission( group_with_no_submissions) self.assertIsNone(ultimate_submission) ultimate_submissions = [ fdbk.submission for fdbk in get_ultimate_submissions( self.project, filter_groups=None, ag_test_preloader=AGTestPreLoader(self.project)) ] self.assertSequenceEqual([group_with_submissions_data.best_submission], ultimate_submissions)
def test_get_ultimate_submission_group_has_no_submissions(self): for policy in ag_models.UltimateSubmissionPolicy: self.project.validate_and_update(ultimate_submission_policy=policy) group = obj_build.make_group(project=self.project) self.assertEqual(0, group.submissions.count()) ultimate_submission = get_ultimate_submission(group) self.assertIsNone(ultimate_submission) ultimate_submissions = list( get_ultimate_submissions(self.project, filter_groups=[group], ag_test_preloader=AGTestPreLoader( self.project))) self.assertSequenceEqual([], ultimate_submissions)
def ultimate_submission(self, request, *args, **kwargs): """ Permissions details: - The normal group and submission viewing permissions apply first. - Staff members can always view their own ultimate submission. - Staff members can only view student and other staff ultimate submissions if the project closing time has passed. - If the project closing time has passed, staff can view student and other staff ultimate submissions regardless of whether ultimate submissions are marked as hidden. - Students can view their ultimate submissions as long as the closing time has passed and ultimate submissions are not overridden as being hidden. """ group = self.get_object() ultimate_submission = get_ultimate_submission(group, user=request.user) if ultimate_submission is None: return response.Response(status=status.HTTP_404_NOT_FOUND) return response.Response( ag_serializers.SubmissionSerializer(ultimate_submission).data)
def serialize_ultimate_submission_results(ultimate_submissions: Iterable[SubmissionResultFeedback], *, full_results: bool, include_handgrading: bool = False) -> List[dict]: """ Returns serialized ultimate submission data for each user in the groups linked to ultimate_submissions. This function also accounts for submissions that don't count for a partecular user due to late day usage. :param ultimate_submissions: :param full_results: Whether to include information about individual test cases. :param include_handgrading: :return: [ { "username": <username>, "group": <group>, "ultimate_submission": { "results": { "total_points": <int>, "total_points_possible": <int>, // Only present if full_points is True "ag_test_suite_results": [<ag test suite result details>], "student_test_suite_results": [<student test suite result details>], // Only present if include_handgrading is True "handgrading_total_points": <int>, "handgrading_total_points_possible": <int> }, <submission data> } }, ... ] """ results = [] for submission_fdbk in ultimate_submissions: submission = submission_fdbk.submission group = submission.group if group.extended_due_date is not None and group.extended_due_date > timezone.now(): submission_data = None else: submission_data = _get_submission_data_with_results(submission_fdbk, full_results, include_handgrading) group_data = group.to_dict() for username in group.member_names: user_data = { 'username': username, 'group': group_data, } if username in submission.does_not_count_for: user_ultimate_submission = get_ultimate_submission( group, group.members.get(username=username)) # NOTE: Do NOT overwrite submission_data user_submission_data = _get_submission_data_with_results( SubmissionResultFeedback( user_ultimate_submission, ag_models.FeedbackCategory.max, submission_fdbk.ag_test_preloader), full_results, include_handgrading ) user_data['ultimate_submission'] = user_submission_data else: user_data['ultimate_submission'] = submission_data results.append(user_data) return results