Esempio n. 1
0
def calculate_letter_grade(course, activity):
    """
    Calculate all the student's grade in the course's CalletterActivity.
    If student param is specified, this student's grade is calculated instead
    of the whole class, please also make sure this student is in the course
    before passing the student param.
    """
    if not isinstance(course, CourseOffering):
        raise TypeError('CourseOffering type is required')
    if not isinstance(activity, CalLetterActivity):
        raise TypeError('CalLetterActivity type is required')

    # calculate for all student
    student_list = Member.objects.filter(offering=course, role='STUD')
    letter_grade_list = LetterGrade.objects.filter(
        activity=activity).select_related('member')

    ignored = 0
    for s in student_list:
        # calculate grade

        result = generate_lettergrades(s, activity)

        # save grade
        member_found = False
        for letter_grade in letter_grade_list:
            if letter_grade.member == s:
                member_found = True
                if letter_grade.flag != "CALC":
                    ignored += 1
                elif result != letter_grade.letter_grade or letter_grade.flag != "CALC":
                    # ignore manually-set grades; only save when the value changes
                    letter_grade.letter_grade = result
                    letter_grade.flag = "CALC"
                    letter_grade.save(newsitem=False, entered_by=None)
                break
        if not member_found:
            letter_grade = LetterGrade(activity=activity,
                                       member=s,
                                       letter_grade=result,
                                       flag='CALC')
            letter_grade.save(newsitem=False, entered_by=None)
    return ignored
Esempio n. 2
0
def calculate_letter_grade(course, activity):
    """
    Calculate all the student's grade in the course's CalletterActivity.
    If student param is specified, this student's grade is calculated instead
    of the whole class, please also make sure this student is in the course
    before passing the student param.
    """
    if not isinstance(course, CourseOffering):
        raise TypeError('CourseOffering type is required')
    if not isinstance(activity, CalLetterActivity):
        raise TypeError('CalLetterActivity type is required')

    # calculate for all student
    student_list = Member.objects.filter(offering=course, role='STUD')
    letter_grade_list = LetterGrade.objects.filter(activity = activity).select_related('member') 
   
    ignored = 0
    for s in student_list:
        # calculate grade

        result = generate_lettergrades(s,activity)

        # save grade
        member_found = False
        for letter_grade in letter_grade_list:
            if letter_grade.member == s:
                member_found = True     
                if letter_grade.flag != "CALC":
                    ignored += 1
                elif result != letter_grade.letter_grade or letter_grade.flag != "CALC":
                    # ignore manually-set grades; only save when the value changes
                    letter_grade.letter_grade = result
                    letter_grade.flag = "CALC"
                    letter_grade.save(newsitem=False, entered_by=None)
                break
        if not member_found:
            letter_grade = LetterGrade(activity=activity, member=s,
                                         letter_grade=result, flag='CALC')
            letter_grade.save(newsitem=False, entered_by=None)
    return ignored
Esempio n. 3
0
 def setMark(self, grade, entered_by):
     """         
     Set the mark of the group members
     """
     super(GroupActivityMark_LetterGrade, self).setMark(grade)
     #assign mark for each member in the group
     group_members = GroupMember.objects.filter(group=self.group, activity=self.letter_activity, confirmed=True)
     for g_member in group_members:
         try:            
             lgrade = LetterGrade.objects.get(activity=self.letter_activity, member=g_member.student)
         except LetterGrade.DoesNotExist: 
             lgrade = LetterGrade(activity=self.letter_activity, member=g_member.student)
         lgrade.letter_grade = grade
         lgrade.flag = 'GRAD'
         lgrade.save(entered_by=entered_by, group=self.group)
Esempio n. 4
0
    def test_api_permissions(self):
        """
        Make sure the API views display activity/grade info at the right moments
        """
        client = Client()
        client.login_user("0aaa0")
        grades_url = reverse('api.OfferingGrades', kwargs={'course_slug': TEST_COURSE_SLUG})
        stats_url = reverse('api.OfferingStats', kwargs={'course_slug': TEST_COURSE_SLUG})

        o = CourseOffering.objects.get(slug=TEST_COURSE_SLUG)
        na = NumericActivity.objects.get(slug='a1')
        la = LetterActivity.objects.get(slug='rep')
        instr = Member.objects.get(person__userid='ggbaker', offering=o, role='INST')
        student = Member.objects.get(person__userid='0aaa0', offering=o, role='STUD')

        # mock out the cache so we get fresh results for each request
        with self.settings(CACHES={ 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache' } }):

            # below uses assertFalse to test for None, '', [], {}, all of which are fine. Just no real grade info.

            # invisible activities shouldn't appear
            na.status = 'INVI'
            na.save(entered_by=instr.person)
            la.status = 'INVI'
            la.save(entered_by=instr.person)
            resp = client.get(grades_url)
            data = json.loads(resp.content)
            self.assertIsNone(self._get_by_slug(data, 'a1'))
            self.assertIsNone(self._get_by_slug(data, 'rep'))

            # no grades: shouldn't see
            na.status = 'URLS'
            na.save(entered_by=instr.person)
            la.status = 'URLS'
            la.save(entered_by=instr.person)
            resp = client.get(grades_url)
            data = json.loads(resp.content)
            self.assertFalse(self._get_by_slug(data, 'a1')['grade'])
            self.assertFalse(self._get_by_slug(data, 'rep')['grade'])
            self.assertFalse(self._get_by_slug(data, 'a1')['details'])
            self.assertFalse(self._get_by_slug(data, 'rep')['details'])

            resp = client.get(stats_url)
            data = json.loads(resp.content)
            self.assertIn('unreleased activities', self._get_by_slug(data, 'a1')['missing_reason'])
            self.assertIn('unreleased activities', self._get_by_slug(data, 'rep')['missing_reason'])
            self.assertIsNone(self._get_by_slug(data, 'a1')['count'])
            self.assertIsNone(self._get_by_slug(data, 'rep')['count'])

            # grades but unreleased: shouldn't see
            ng = NumericGrade(activity=na, member=student, value=1, flag='GRAD', comment='Foo')
            ng.save(entered_by=instr.person)
            from marking.models import StudentActivityMark, ActivityComponentMark, ActivityComponent
            am = StudentActivityMark(numeric_grade=ng, mark=2, created_by='ggbaker', overall_comment='thecomment')
            am.save()
            comp = ActivityComponent.objects.filter(numeric_activity=na)[0]
            cm = ActivityComponentMark(activity_mark=am, value=2, comment='foo',
                                       activity_component=comp)
            cm.save()
            am.setMark(2, entered_by=instr.person)

            lg = LetterGrade(activity=la, member=student, letter_grade='A', flag='GRAD', comment='Foo')
            lg.save(entered_by=instr.person)
            resp = client.get(grades_url)
            data = json.loads(resp.content)
            self.assertFalse(self._get_by_slug(data, 'a1')['grade'])
            self.assertFalse(self._get_by_slug(data, 'rep')['grade'])
            self.assertFalse(self._get_by_slug(data, 'a1')['details'])
            self.assertFalse(self._get_by_slug(data, 'rep')['details'])

            # release and they should appear
            na.status = 'RLS'
            na.save(entered_by=instr.person)
            la.status = 'RLS'
            la.save(entered_by=instr.person)
            resp = client.get(grades_url)
            data = json.loads(resp.content)
            self.assertEqual(self._get_by_slug(data, 'a1')['grade'], '2')
            self.assertEqual(self._get_by_slug(data, 'rep')['grade'], 'A')
            self.assertEqual(self._get_by_slug(data, 'a1')['details']['overall_comment'], 'thecomment')
            self.assertIsNone(self._get_by_slug(data, 'rep')['details']) # letter grades have no marking

            resp = client.get(stats_url)
            data = json.loads(resp.content)
            self.assertIn('small classes', self._get_by_slug(data, 'a1')['missing_reason'])
            self.assertIn('small classes', self._get_by_slug(data, 'rep')['missing_reason'])
Esempio n. 5
0
    def test_get_grade(self):
        """
        Make sure activity.get_grade() keeps the right things hidden
        """
        o = CourseOffering.objects.get(slug=self.course_slug)
        na = NumericActivity.objects.get(slug='a1')
        la = LetterActivity.objects.get(slug='rep')
        instr = Person.objects.get(userid='ggbaker')

        student = Member.objects.get(person__userid='0aaa0', offering=o)

        na.status = 'RLS'
        na.save(entered_by=instr)
        la.status = 'RLS'
        la.save(entered_by=instr)

        # no grades yet
        self.assertEqual(na.get_grade(student.person, 'STUD'), None)
        self.assertEqual(la.get_grade(student.person, 'STUD'), None)
        self.assertEqual(na.get_grade(student.person, 'INST'), None)
        self.assertEqual(la.get_grade(student.person, 'INST'), None)

        # grades should be visible
        ng = NumericGrade(activity=na, member=student, value=1, flag='GRAD', comment='Foo')
        ng.save(entered_by=instr)
        lg = LetterGrade(activity=la, member=student, letter_grade='A', flag='GRAD', comment='Foo')
        lg.save(entered_by=instr)
        self.assertEqual(na.get_grade(student.person, 'STUD').grade, 1)
        self.assertEqual(la.get_grade(student.person, 'STUD').grade, 'A')
        self.assertEqual(na.get_grade(student.person, 'INST').grade, 1)
        self.assertEqual(la.get_grade(student.person, 'INST').grade, 'A')

        # unreleased: grades visible only to staff
        na.status = 'URLS'
        na.save(entered_by=instr)
        la.status = 'URLS'
        la.save(entered_by=instr)
        self.assertEqual(na.get_grade(student.person, 'STUD'), None)
        self.assertEqual(la.get_grade(student.person, 'STUD'), None)
        self.assertEqual(na.get_grade(student.person, 'INST').grade, 1)
        self.assertEqual(la.get_grade(student.person, 'INST').grade, 'A')

        # student shouldn't ever see invisible grade
        na.status = 'INVI'
        na.save(entered_by=instr)
        la.status = 'INVI'
        la.save(entered_by=instr)
        with self.assertRaises(RuntimeError):
            na.get_grade(student.person, 'STUD')
        with self.assertRaises(RuntimeError):
            la.get_grade(student.person, 'STUD')
        self.assertEqual(na.get_grade(student.person, 'INST').grade, 1)
        self.assertEqual(la.get_grade(student.person, 'INST').grade, 'A')

        # flag==NOGR handling
        ng.flag = 'NOGR'
        ng.save(entered_by=instr)
        lg.flag = 'NOGR'
        lg.save(entered_by=instr)
        na.status = 'RLS'
        na.save(entered_by=instr)
        la.status = 'RLS'
        la.save(entered_by=instr)
        self.assertEqual(na.get_grade(student.person, 'STUD'), None)
        self.assertEqual(la.get_grade(student.person, 'STUD'), None)
        self.assertEqual(na.get_grade(student.person, 'INST'), None)
        self.assertEqual(la.get_grade(student.person, 'INST'), None)
Esempio n. 6
0
    def test_sort_letter(self):
        """
        Test sorting letter grades
        """
        s, c = create_offering()
        
        a = LetterActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, due_date=None, group=False)
        a.save()

        ms = []
        for i in range(10):
            p = Person.objects.get(userid="0aaa%i"%i)
            m = Member(person=p, offering=c, role="STUD", added_reason="UNK")
            m.save()
            ms.append(m)
        
        g = LetterGrade(activity=a, member=ms[0], letter_grade="B+", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[1], letter_grade="A", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[2], letter_grade="D", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[3], letter_grade="B-", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[4], letter_grade="P", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[5], letter_grade="GN", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[6], letter_grade="F", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[7], letter_grade="DE", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[8], letter_grade="C-", flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a, member=ms[9], letter_grade="N", flag="GRAD")
        g.save(entered_by='ggbaker')
        
        g_objs = LetterGrade.objects.filter(activity=a)
        gs = [g.letter_grade for g in g_objs]
        gs_sort = sorted_letters(gs)
        self.assertEquals(gs_sort, ['A', 'B+', 'B-', 'C-', 'D', 'P', 'F', 'DE', 'N', 'GN'])
        
        # pre-sort by userid for median testing (so we know which subsets we're grabbing)
        gs = [(int(g.member.person.userid[4:]), g.letter_grade) for g in g_objs]
        gs.sort()
        gs = [g for u,g in gs]

        # odd-length case
        self.assertEquals(median_letters(sorted_letters(gs[0:5])), "B-")
        # even length with median at boundary
        self.assertEquals(median_letters(sorted_letters(gs[0:6])), "B-/D")
        # empty list
        self.assertEquals(median_letters([]), u"\u2014")
Esempio n. 7
0
    def test_api_permissions(self):
        """
        Make sure the API views display activity/grade info at the right moments
        """
        client = Client()
        client.login_user("0aaa0")
        grades_url = reverse('api:OfferingGrades',
                             kwargs={'course_slug': TEST_COURSE_SLUG})
        stats_url = reverse('api:OfferingStats',
                            kwargs={'course_slug': TEST_COURSE_SLUG})

        o = CourseOffering.objects.get(slug=TEST_COURSE_SLUG)
        na = NumericActivity.objects.get(slug='a1')
        la = LetterActivity.objects.get(slug='rep')
        instr = Member.objects.get(person__userid='ggbaker',
                                   offering=o,
                                   role='INST')
        student = Member.objects.get(person__userid='0aaa0',
                                     offering=o,
                                     role='STUD')

        # mock out the cache so we get fresh results for each request
        with self.settings(CACHES={
                'default': {
                    'BACKEND': 'django.core.cache.backends.dummy.DummyCache'
                }
        }):

            # below uses assertFalse to test for None, '', [], {}, all of which are fine. Just no real grade info.

            # invisible activities shouldn't appear
            na.status = 'INVI'
            na.save(entered_by=instr.person)
            la.status = 'INVI'
            la.save(entered_by=instr.person)
            resp = client.get(grades_url)
            data = json.loads(resp.content.decode('utf8'))
            self.assertIsNone(self._get_by_slug(data, 'a1'))
            self.assertIsNone(self._get_by_slug(data, 'rep'))

            # no grades: shouldn't see
            na.status = 'URLS'
            na.save(entered_by=instr.person)
            la.status = 'URLS'
            la.save(entered_by=instr.person)
            resp = client.get(grades_url)
            data = json.loads(resp.content.decode('utf8'))
            self.assertFalse(self._get_by_slug(data, 'a1')['grade'])
            self.assertFalse(self._get_by_slug(data, 'rep')['grade'])
            self.assertFalse(self._get_by_slug(data, 'a1')['details'])
            self.assertFalse(self._get_by_slug(data, 'rep')['details'])

            resp = client.get(stats_url)
            data = json.loads(resp.content.decode('utf8'))
            self.assertIn('unreleased activities',
                          self._get_by_slug(data, 'a1')['missing_reason'])
            self.assertIn('unreleased activities',
                          self._get_by_slug(data, 'rep')['missing_reason'])
            self.assertIsNone(self._get_by_slug(data, 'a1')['count'])
            self.assertIsNone(self._get_by_slug(data, 'rep')['count'])

            # grades but unreleased: shouldn't see
            ng = NumericGrade(activity=na,
                              member=student,
                              value=1,
                              flag='GRAD',
                              comment='Foo')
            ng.save(entered_by=instr.person)
            from marking.models import StudentActivityMark, ActivityComponentMark, ActivityComponent
            am = StudentActivityMark(numeric_grade=ng,
                                     mark=2,
                                     created_by='ggbaker',
                                     overall_comment='thecomment')
            am.save()
            comp = ActivityComponent.objects.filter(numeric_activity=na)[0]
            cm = ActivityComponentMark(activity_mark=am,
                                       value=2,
                                       comment='foo',
                                       activity_component=comp)
            cm.save()
            am.setMark(2, entered_by=instr.person)

            lg = LetterGrade(activity=la,
                             member=student,
                             letter_grade='A',
                             flag='GRAD',
                             comment='Foo')
            lg.save(entered_by=instr.person)
            resp = client.get(grades_url)
            data = json.loads(resp.content.decode('utf8'))
            self.assertFalse(self._get_by_slug(data, 'a1')['grade'])
            self.assertFalse(self._get_by_slug(data, 'rep')['grade'])
            self.assertFalse(self._get_by_slug(data, 'a1')['details'])
            self.assertFalse(self._get_by_slug(data, 'rep')['details'])

            # release and they should appear
            na.status = 'RLS'
            na.save(entered_by=instr.person)
            la.status = 'RLS'
            la.save(entered_by=instr.person)
            resp = client.get(grades_url)
            data = json.loads(resp.content.decode('utf8'))
            self.assertEqual(self._get_by_slug(data, 'a1')['grade'], '2.00')
            self.assertEqual(self._get_by_slug(data, 'rep')['grade'], 'A')
            self.assertEqual(
                self._get_by_slug(data, 'a1')['details']['overall_comment'],
                'thecomment')
            self.assertIsNone(self._get_by_slug(
                data, 'rep')['details'])  # letter grades have no marking

            resp = client.get(stats_url)
            data = json.loads(resp.content.decode('utf8'))
            self.assertIn('small classes',
                          self._get_by_slug(data, 'a1')['missing_reason'])
            self.assertIn('small classes',
                          self._get_by_slug(data, 'rep')['missing_reason'])
Esempio n. 8
0
    def test_get_grade(self):
        """
        Make sure activity.get_grade() keeps the right things hidden
        """
        o = CourseOffering.objects.get(slug=self.course_slug)
        na = NumericActivity.objects.get(slug='a1')
        la = LetterActivity.objects.get(slug='rep')
        instr = Person.objects.get(userid='ggbaker')

        student = Member.objects.get(person__userid='0aaa0', offering=o)

        na.status = 'RLS'
        na.save(entered_by=instr)
        la.status = 'RLS'
        la.save(entered_by=instr)

        # no grades yet
        self.assertEqual(na.get_grade(student.person, 'STUD'), None)
        self.assertEqual(la.get_grade(student.person, 'STUD'), None)
        self.assertEqual(na.get_grade(student.person, 'INST'), None)
        self.assertEqual(la.get_grade(student.person, 'INST'), None)

        # grades should be visible
        ng = NumericGrade(activity=na,
                          member=student,
                          value=1,
                          flag='GRAD',
                          comment='Foo')
        ng.save(entered_by=instr)
        lg = LetterGrade(activity=la,
                         member=student,
                         letter_grade='A',
                         flag='GRAD',
                         comment='Foo')
        lg.save(entered_by=instr)
        self.assertEqual(na.get_grade(student.person, 'STUD').grade, 1)
        self.assertEqual(la.get_grade(student.person, 'STUD').grade, 'A')
        self.assertEqual(na.get_grade(student.person, 'INST').grade, 1)
        self.assertEqual(la.get_grade(student.person, 'INST').grade, 'A')

        # unreleased: grades visible only to staff
        na.status = 'URLS'
        na.save(entered_by=instr)
        la.status = 'URLS'
        la.save(entered_by=instr)
        self.assertEqual(na.get_grade(student.person, 'STUD'), None)
        self.assertEqual(la.get_grade(student.person, 'STUD'), None)
        self.assertEqual(na.get_grade(student.person, 'INST').grade, 1)
        self.assertEqual(la.get_grade(student.person, 'INST').grade, 'A')

        # student shouldn't ever see invisible grade
        na.status = 'INVI'
        na.save(entered_by=instr)
        la.status = 'INVI'
        la.save(entered_by=instr)
        with self.assertRaises(RuntimeError):
            na.get_grade(student.person, 'STUD')
        with self.assertRaises(RuntimeError):
            la.get_grade(student.person, 'STUD')
        self.assertEqual(na.get_grade(student.person, 'INST').grade, 1)
        self.assertEqual(la.get_grade(student.person, 'INST').grade, 'A')

        # flag==NOGR handling
        ng.flag = 'NOGR'
        ng.save(entered_by=instr)
        lg.flag = 'NOGR'
        lg.save(entered_by=instr)
        na.status = 'RLS'
        na.save(entered_by=instr)
        la.status = 'RLS'
        la.save(entered_by=instr)
        self.assertEqual(na.get_grade(student.person, 'STUD'), None)
        self.assertEqual(la.get_grade(student.person, 'STUD'), None)
        self.assertEqual(na.get_grade(student.person, 'INST'), None)
        self.assertEqual(la.get_grade(student.person, 'INST'), None)
Esempio n. 9
0
    def test_sort_letter(self):
        """
        Test sorting letter grades
        """
        s, c = create_offering()

        a = LetterActivity(name="Assignment 1",
                           short_name="A1",
                           status="RLS",
                           offering=c,
                           position=2,
                           due_date=None,
                           group=False)
        a.save()

        ms = []
        for i in range(10):
            p = Person.objects.get(userid="0aaa%i" % i)
            m = Member(person=p, offering=c, role="STUD", added_reason="UNK")
            m.save()
            ms.append(m)

        g = LetterGrade(activity=a,
                        member=ms[0],
                        letter_grade="B+",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[1],
                        letter_grade="A",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[2],
                        letter_grade="D",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[3],
                        letter_grade="B-",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[4],
                        letter_grade="P",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[5],
                        letter_grade="GN",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[6],
                        letter_grade="F",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[7],
                        letter_grade="DE",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[8],
                        letter_grade="C-",
                        flag="GRAD")
        g.save(entered_by='ggbaker')
        g = LetterGrade(activity=a,
                        member=ms[9],
                        letter_grade="N",
                        flag="GRAD")
        g.save(entered_by='ggbaker')

        g_objs = LetterGrade.objects.filter(activity=a)
        gs = [g.letter_grade for g in g_objs]
        gs_sort = sorted_letters(gs)
        self.assertEqual(
            gs_sort, ['A', 'B+', 'B-', 'C-', 'D', 'P', 'F', 'DE', 'N', 'GN'])

        # pre-sort by userid for median testing (so we know which subsets we're grabbing)
        gs = [(int(g.member.person.userid[4:]), g.letter_grade)
              for g in g_objs]
        gs.sort()
        gs = [g for u, g in gs]

        # odd-length case
        self.assertEqual(median_letters(sorted_letters(gs[0:5])), "B-")
        # even length with median at boundary
        self.assertEqual(median_letters(sorted_letters(gs[0:6])), "B-/D")
        # empty list
        self.assertEqual(median_letters([]), "\u2014")