Пример #1
0
    def test_course_offering(self):
        """
        Create and test a course offering
        """
        s, c = create_offering()
        
        # should have a get_absolute_url
        url = c.get_absolute_url()
        self.assertEquals(url, str(url))
        self.assertEquals(url[0], '/')
        self.assertEquals(str(c), "CMPT 120 D100 (Fall 2007)")
        self.assertEquals(c.name(), "CMPT 120 D1")

        # check uniqueness criteria
        c2 = CourseOffering(subject="CMPT", number="120", section="D100", semester=s, component="LAB",
                graded=True, crse_id=11112, class_nbr=22223, campus='SURRY',
                enrl_cap=101, enrl_tot=100, wait_tot=3)
        # south doesn't seem to create the constraints in SQLite for testing
        #self.assertRaises(IntegrityError, c2.save)

        c2 = CourseOffering(subject="CMPT", number="121", section="D100", semester=s, component="LAB",
                graded=True, crse_id=11111, class_nbr=22223, campus='SURRY',
                enrl_cap=101, enrl_tot=100, wait_tot=3)
        # south doesn't seem to create the constraints in SQLite for testing
        #self.assertRaises(IntegrityError, c2.save)

        c2 = CourseOffering(subject="MACM", number="121", section="D102", semester=s, component="LAB",
                graded=True, crse_id=11112, class_nbr=22222, campus='SURRY',
                enrl_cap=101, enrl_tot=100, wait_tot=3)
        # south doesn't seem to create the constraints in SQLite for testing
        #self.assertRaises(IntegrityError, c2.save)

        # test some course memberships
        p1 = Person(emplid=210012345, userid="test1",
                last_name="Lname", first_name="Fname", pref_first_name="Fn", middle_name="M")
        p1.save()
        m = Member(person=p1, offering=c, role="INST", credits=0, career="NONS", added_reason="AUTO")
        m.save()
        
        self.assertEqual( str(list(c.instructors())), "[<Person: Lname, Fname>]")
        self.assertEqual( str(list(c.tas())), "[]")
        self.assertEqual( c.student_count(), 0)

        m.role = "TA"
        m.save()
        self.assertEqual( str(list(c.instructors())), "[]")
        self.assertEqual( str(list(c.tas())), "[<Person: Lname, Fname>]")
        self.assertEqual( c.student_count(), 0)

        m.role = "STUD"
        m.save()
        self.assertEqual( str(list(c.instructors())), "[]")
        self.assertEqual( str(list(c.tas())), "[]")
        self.assertEqual( c.student_count(), 1)
        
        self.assertEqual( str(m), "test1 (210012345) in CMPT 120 D100 (Fall 2007)")
Пример #2
0
    def test_course_page(self):
        """
        Check out a course front-page
        """
        _, c = create_offering()
        
        client = Client()
        # not logged in: should be redirected to login page
        response = client.get(c.get_absolute_url())
        self.assertEqual(response.status_code, 302)

        # log in as student "0aaa0"
        client.login_user("0aaa0")
        p = Person.objects.get(userid="0aaa0")

        # not in the course: should get 403 Forbidden
        response = client.get(c.get_absolute_url())
        self.assertEqual(response.status_code, 403)
        
        # add to course and try again
        m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK")
        m.save()
        response = client.get(c.get_absolute_url())
        self.assertEqual(response.status_code, 200)
        validate_content(self, response.content, c.get_absolute_url())

        # dropped students should be forbidden
        m.role="DROP"
        m.save()
        response = client.get(c.get_absolute_url())
        self.assertEqual(response.status_code, 403)
Пример #3
0
    def test_course_page(self):
        """
        Check out a course front-page
        """
        _, c = create_offering()
        
        client = Client()
        # not logged in: should be redirected to login page
        response = client.get(c.get_absolute_url())
        self.assertEqual(response.status_code, 302)

        # log in as student "0aaa0"
        client.login_user("0aaa0")
        p = Person.objects.get(userid="0aaa0")

        # not in the course: should get 403 Forbidden
        response = client.get(c.get_absolute_url())
        self.assertEqual(response.status_code, 403)
        
        # add to course and try again
        m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK")
        m.save()
        response = client.get(c.get_absolute_url())
        self.assertEqual(response.status_code, 200)
        validate_content(self, response.content, c.get_absolute_url())

        # dropped students should be forbidden
        m.role="DROP"
        m.save()
        response = client.get(c.get_absolute_url())
        self.assertEqual(response.status_code, 403)
Пример #4
0
def ensure_member(person,
                  offering,
                  role,
                  cred,
                  added_reason,
                  career,
                  labtut_section=None,
                  grade=None,
                  sched_print_instr=None):
    """
    Make sure this member exists with the right properties.
    """
    if person.emplid in [200133427, 200133425, 200133426]:
        # these are: ["Faculty", "Tba", "Sessional"]. Ignore them: they're ugly.
        return

    m_old = Member.objects.filter(person=person, offering=offering)

    if len(m_old) > 1:
        # may be other manually-created dropped entries: that's okay.
        m_old = Member.objects.filter(person=person,
                                      offering=offering).exclude(role="DROP")
        if len(m_old) > 1:
            raise KeyError("Already duplicate entries: %r" % (m_old))
        elif len(m_old) == 0:
            m_old = Member.objects.filter(person=person, offering=offering)

    if len(m_old) >= 1:
        m = m_old[0]
    else:
        m = Member(person=person, offering=offering)

    m.role = role
    m.labtut_section = labtut_section
    m.credits = cred
    m.added_reason = added_reason
    m.career = career

    # record official grade if we have it (and might need it)
    if has_letter_activities(m.offering):
        m.official_grade = grade or None
    else:
        m.official_grade = None

    # record sched_print_instr status for instructors
    if role == 'INST' and sched_print_instr:
        m.config['sched_print_instr'] = sched_print_instr == 'Y'

    # if offering is being given lab/tutorial sections, flag it as having them
    # there must be some way to detect this in ps_class_tbl, but I can't see it.
    if labtut_section and not offering.labtut():
        offering.set_labtut(True)
        offering.save_if_dirty()

    m.save_if_dirty()
    return m
Пример #5
0
def ensure_member(person, offering, role, cred, added_reason, career, labtut_section=None, grade=None, sched_print_instr=None):
    """
    Make sure this member exists with the right properties.
    """
    if person.emplid in [200133427, 200133425, 200133426]:
        # these are: ["Faculty", "Tba", "Sessional"]. Ignore them: they're ugly.
        return
    
    m_old = Member.objects.filter(person=person, offering=offering)

    if len(m_old)>1:
        # may be other manually-created dropped entries: that's okay.
        m_old = Member.objects.filter(person=person, offering=offering).exclude(role="DROP")
        if len(m_old)>1:
            raise KeyError("Already duplicate entries: %r" % (m_old))
        elif len(m_old)==0:
            m_old = Member.objects.filter(person=person, offering=offering)
        
    if len(m_old)>=1:
        m = m_old[0]
    else:
        m = Member(person=person, offering=offering)

    m.role = role
    m.labtut_section = labtut_section
    m.credits = cred
    m.added_reason = added_reason
    m.career = career

    # record official grade if we have it (and might need it)
    if has_letter_activities(m.offering):
        m.official_grade = grade or None
    else:
        m.official_grade = None

    # record sched_print_instr status for instructors
    if role=='INST' and sched_print_instr:
        m.config['sched_print_instr'] = sched_print_instr == 'Y'

    # if offering is being given lab/tutorial sections, flag it as having them
    # there must be some way to detect this in ps_class_tbl, but I can't see it.
    if labtut_section and not offering.labtut():
        offering.set_labtut(True)
        offering.save_if_dirty()
    
    m.save_if_dirty()
    return m
Пример #6
0
    def test_search_updates(self):
        """
        Make sure indexing in Haystack is working as we expect.
        """
        fname = 'TestStudentUnusualName'
        s, c = create_offering()

        # clear the search index and query: we shouldn't find anything.
        haystack_clear_index()
        results = SearchQuerySet().models(Member).filter(text__fuzzy=fname)
        self.assertEqual(results.count(), 0)

        # add something searchable and query: we don't expect it to appear in real-time
        p = Person(last_name='Test',
                   first_name=fname,
                   userid='0aaa99999',
                   emplid=123456)
        p.save()
        m = Member(person=p, offering=c, role='STUD')
        m.save()

        results = SearchQuerySet().models(Member).filter(text__fuzzy=fname)
        self.assertEqual(results.count(), 0)

        # ... but after update_index.we do.
        haystack_update_index()
        results = SearchQuerySet().models(Member).filter(text__fuzzy=fname)
        self.assertEqual(results.count(), 1)

        # same for removing from the index.
        m.role = 'DROP'
        m.save()
        results = SearchQuerySet().models(Member).filter(text__fuzzy=fname)
        self.assertEqual(results.count(), 1)

        # update_index doesn't detect a data change that excludes the object from the index_queryset
        haystack_update_index()
        results = SearchQuerySet().models(Member).filter(text__fuzzy=fname)
        self.assertEqual(results.count(), 1)

        # but rebuild_index will fix that up.
        haystack_rebuild_index()
        results = SearchQuerySet().models(Member).filter(text__fuzzy=fname)
        self.assertEqual(results.count(), 0)
Пример #7
0
        def add_membership_for(tacrs, reason, memberships):
            if not tacrs.contract.should_be_added_to_the_course or tacrs.total_bu <= 0:
                return

            # Find existing membership for this person+offering if it exists
            # (Behaviour here implies you can't be both TA and other role in one offering: I'm okay with that.)
            for m in memberships:
                if m.person == person and m.offering == tacrs.course:
                    break
            else:
                # there was no membership: create
                m = Member(person=person, offering=tacrs.course)
                memberships.append(m)

            m.role = 'TA'
            m.credits = 0
            m.career = 'NONS'
            m.added_reason = reason
            m.config['bu'] = str(tacrs.total_bu)
Пример #8
0
        def add_membership_for(tacrs, reason, memberships):
            if not tacrs.contract.should_be_added_to_the_course or tacrs.total_bu <= 0:
                return

            # Find existing membership for this person+offering if it exists
            # (Behaviour here implies you can't be both TA and other role in one offering: I'm okay with that.)
            for m in memberships:
                if m.person == person and m.offering == tacrs.course:
                    break
            else:
                # there was no membership: create
                m = Member(person=person, offering=tacrs.course)
                memberships.append(m)

            m.role = 'TA'
            m.credits = 0
            m.career = 'NONS'
            m.added_reason = reason
            m.config['bu'] = str(tacrs.total_bu)
Пример #9
0
def manage_tas(request, course_slug):
    course = get_object_or_404(CourseOffering, slug=course_slug)
    longform = False
    if not Member.objects.filter(offering=course,
                                 person__userid=request.user.username,
                                 role="INST"):
        # only instructors can manage TAs
        return ForbiddenResponse(request, "Only instructors can manage TAs")

    if request.method == 'POST' and 'action' in request.POST and request.POST[
            'action'] == 'add':
        form = TAForm(offering=course, data=request.POST)
        if form.non_field_errors():
            # have an unknown userid
            longform = True
        elif form.is_valid():
            userid = form.cleaned_data['userid']
            if not Person.objects.filter(userid=userid) \
                    and form.cleaned_data['fname'] and form.cleaned_data['lname']:
                # adding a new person: handle that.
                eid = 1
                # search for an unused temp emplid
                while True:
                    emplid = "%09i" % (eid)
                    if not Person.objects.filter(emplid=emplid):
                        break
                    eid += 1
                p = Person(first_name=form.cleaned_data['fname'],
                           pref_first_name=form.cleaned_data['fname'],
                           last_name=form.cleaned_data['lname'],
                           middle_name='',
                           userid=userid,
                           emplid=emplid)
                p.save()

            else:
                p = Person.objects.get(userid=userid)

            m = Member(person=p,
                       offering=course,
                       role="TA",
                       credits=0,
                       career="NONS",
                       added_reason="TAIN")
            m.save()

            #LOG EVENT#
            l = LogEntry(userid=request.user.username,
                         description=("TA added by instructor: %s for %s") %
                         (userid, course),
                         related_object=m)
            l.save()
            messages.success(request, 'Added %s as a TA.' % (p.name()))
            return HttpResponseRedirect(
                reverse(manage_tas, kwargs={'course_slug': course.slug}))

    elif request.method == 'POST' and 'action' in request.POST and request.POST[
            'action'] == 'del':
        userid = request.POST['userid']
        ms = Member.objects.filter(person__userid=userid,
                                   offering=course,
                                   role="TA",
                                   added_reason="TAIN")
        if ms:
            m = ms[0]
            m.role = "DROP"
            m.save()
            #LOG EVENT#
            l = LogEntry(userid=request.user.username,
                         description=("TA removed by instructor: %s for %s") %
                         (userid, course),
                         related_object=m)
            l.save()
            messages.success(request,
                             'Removed %s as a TA.' % (m.person.name()))
        return HttpResponseRedirect(
            reverse(manage_tas, kwargs={'course_slug': course.slug}))

    else:
        form = TAForm(offering=course)

    tas = Member.objects.filter(role="TA", offering=course)
    context = {
        'course': course,
        'form': form,
        'tas': tas,
        'longform': longform
    }
    return render(request, 'coredata/manage_tas.html', context)
Пример #10
0
def manage_tas(request, course_slug):
    course = get_object_or_404(CourseOffering, slug=course_slug)
    longform = False
    if not Member.objects.filter(offering=course, person__userid=request.user.username, role="INST"):
        # only instructors can manage TAs
        return ForbiddenResponse(request, "Only instructors can manage TAs")
    
    if request.method == 'POST' and 'action' in request.POST and request.POST['action']=='add':
        form = TAForm(offering=course, data=request.POST)
        if form.non_field_errors():
            # have an unknown userid
            longform = True
        elif form.is_valid():
            userid = form.cleaned_data['userid']
            if not Person.objects.filter(userid=userid) \
                    and form.cleaned_data['fname'] and form.cleaned_data['lname']:
                # adding a new person: handle that.
                eid = 1
                # search for an unused temp emplid
                while True:
                    emplid = "%09i" % (eid)
                    if not Person.objects.filter(emplid=emplid):
                        break
                    eid += 1
                p = Person(first_name=form.cleaned_data['fname'], pref_first_name=form.cleaned_data['fname'], last_name=form.cleaned_data['lname'], middle_name='', userid=userid, emplid=emplid)
                p.save()

            else:
                p = Person.objects.get(userid=userid)

            m = Member(person=p, offering=course, role="TA", credits=0, career="NONS", added_reason="TAIN")
            m.save()
                
            #LOG EVENT#
            l = LogEntry(userid=request.user.username,
                  description=("TA added by instructor: %s for %s") % (userid, course),
                  related_object=m)
            l.save()
            messages.success(request, 'Added %s as a TA.' % (p.name()))
            return HttpResponseRedirect(reverse(manage_tas, kwargs={'course_slug': course.slug}))
            

    elif request.method == 'POST' and 'action' in request.POST and request.POST['action']=='del':
        userid = request.POST['userid']
        ms = Member.objects.filter(person__userid=userid, offering=course, role="TA", added_reason="TAIN")
        if ms:
            m = ms[0]
            m.role = "DROP"
            m.save()
            #LOG EVENT#
            l = LogEntry(userid=request.user.username,
                  description=("TA removed by instructor: %s for %s") % (userid, course),
                  related_object=m)
            l.save()
            messages.success(request, 'Removed %s as a TA.' % (m.person.name()))
        return HttpResponseRedirect(reverse(manage_tas, kwargs={'course_slug': course.slug}))

    else:
        form = TAForm(offering=course)

    tas = Member.objects.filter(role="TA", offering=course)
    context = {'course': course, 'form': form, 'tas': tas, 'longform': longform}
    return render(request, 'coredata/manage_tas.html', context)
Пример #11
0
    def test_group_staff(self):
        """
        Check out group pages for an instructor: go through the group-creation process from the instructor side.
        """
        s, c = create_offering()
        a = NumericActivity(name="Assignment 1",
                            short_name="A1",
                            status="URLS",
                            offering=c,
                            position=3,
                            max_grade=20,
                            group=True)
        a.save()
        a = NumericActivity(name="Assignment 2",
                            short_name="A2",
                            status="URLS",
                            offering=c,
                            position=6,
                            max_grade=20,
                            group=True)
        a.save()

        userid1 = "0aaa6"
        userid2 = "0aaa0"
        userid3 = "0aaa1"
        userid4 = "ggbaker"
        for u in [userid1, userid2, userid3, userid4]:
            p = Person.objects.get(userid=u)
            m = Member(person=p,
                       offering=c,
                       role="STUD",
                       credits=3,
                       career="UGRD",
                       added_reason="UNK")
            m.save()
        m.role = "INST"
        m.save()

        client = Client()
        client.login_user("ggbaker")

        # group management screen
        url = reverse('groups.views.groupmanage',
                      kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        self.assertContains(response,
                            "There are currently no groups in this course")
        url = reverse('groups.views.create', kwargs={'course_slug': c.slug})
        self.assertContains(response, 'href="%s"' % (url))

        # group creation form
        response = basic_page_tests(self, client, url)

        # submit group create
        url = reverse('groups.views.submit', kwargs={'course_slug': c.slug})
        response = client.post(
            url, {
                "GroupName": "Test Group",
                "a1-selected": True,
                "a2-selected": False,
                '0aaa6-selected': False,
                '0aaa0-selected': True,
                '0aaa1-selected': True
            })
        self.assertEquals(response.status_code, 302)

        gs = Group.objects.filter(courseoffering=c)
        self.assertEquals(len(gs), 1)
        self.assertEquals(gs[0].name, "Test Group")
        self.assertEquals(gs[0].slug, "g-test-group")

        gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0])
        self.assertEquals(len(gms), 2)
        self.assertEquals(gms[0].confirmed, True)
        self.assertEquals(gms[1].confirmed, True)
        self.assertEquals(set(gm.student.person.userid for gm in gms),
                          set([userid2, userid3]))

        # check group management screen again
        url = reverse('groups.views.groupmanage',
                      kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)

        # add membership form
        url = reverse('groups.views.assign_student',
                      kwargs={
                          'course_slug': c.slug,
                          'group_slug': "g-test-group"
                      })
        response = basic_page_tests(self, client, url)

        # submit add membership
        response = client.post(
            url, {
                "a1-selected": True,
                "a2-selected": True,
                '0aaa6-selected': False,
                '0aaa0-selected': False,
                '0aaa1-selected': True
            })
        self.assertEquals(response.status_code, 302)
        # both still in for A1
        gms = GroupMember.objects.filter(group__courseoffering=c,
                                         group=gs[0],
                                         activity__slug="a1")
        self.assertEquals(set(gm.student.person.userid for gm in gms),
                          set([userid2, userid3]))
        # 0aaa1 added for A2
        gms = GroupMember.objects.filter(group__courseoffering=c,
                                         group=gs[0],
                                         activity__slug="a2")
        self.assertEquals(set(gm.student.person.userid for gm in gms),
                          set([userid3]))

        # remove member form
        url = reverse('groups.views.remove_student',
                      kwargs={
                          'course_slug': c.slug,
                          'group_slug': "g-test-group"
                      })
        response = basic_page_tests(self, client, url)

        # submit remove member
        response = client.post(
            url, {
                '0aaa6_a1-selected': True,
                '0aaa0_a1-selected': False,
                '0aaa1_a1-selected': True
            })
        self.assertEquals(response.status_code, 302)
        # 0aaa1 gone for A1
        gms = GroupMember.objects.filter(group__courseoffering=c,
                                         group=gs[0],
                                         activity__slug="a1")
        self.assertEquals(set(gm.student.person.userid for gm in gms),
                          set([userid2]))
        # 0aaa1 still there for A2
        gms = GroupMember.objects.filter(group__courseoffering=c,
                                         group=gs[0],
                                         activity__slug="a2")
        self.assertEquals(set(gm.student.person.userid for gm in gms),
                          set([userid3]))

        # rename group form
        url = reverse('groups.views.change_name',
                      kwargs={
                          'course_slug': c.slug,
                          'group_slug': "g-test-group"
                      })
        response = basic_page_tests(self, client, url)

        # submit change name
        response = client.post(url, {'name': 'otherName'})
        self.assertEquals(response.status_code, 302)
        g = Group.objects.get(courseoffering=c)
        self.assertEquals(g.name, 'otherName')
        self.assertEquals(g.slug, 'g-test-group')

        # recheck basic view with more data
        url = reverse('groups.views.groupmanage',
                      kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)

        url = reverse('groups.views.view_group',
                      kwargs={
                          'course_slug': c.slug,
                          'group_slug': "g-test-group"
                      })
        response = basic_page_tests(self, client, url)
Пример #12
0
    def save(self, *args, **kwargs):
        super(TAContract, self).save(*args, **kwargs)

        # set SIN field on any GradStudent objects for this person
        from grad.models import GradStudent
        for gs in GradStudent.objects.filter(person=self.application.person):
            dummy_sins = ['999999999', '000000000', '123456789']
            if (('sin' not in gs.config 
                or ('sin' in gs.config and gs.config['sin'] in dummy_sins)) 
                and not self.sin in dummy_sins ):
                gs.person.set_sin(self.sin)
                gs.person.save()

        # if signed, create the Member objects so they have access to the courses.
        courses = TACourse.objects.filter(contract=self)
        for crs in courses:
            members = Member.objects.filter(person=self.application.person, offering=crs.course).exclude(role='DROP')
            # assert( len(members) <= 1 )
            dropped_members = Member.objects.filter(person=self.application.person, offering=crs.course, role='DROP')
            # Should Member just have an optional FK to TACourse rather than getting a copy of the BU? 
            if (self.status in ['SGN', 'ACC'] and crs.bu > 0) and not members:
                if dropped_members:
                    m = dropped_members[0]
                    # if this student was added/dropped by the prof, then added_reason might not be CTA
                    m.added_reason='CTA'
                    m.role = "TA"
                else:
                    # signed, but not a member: create
                    m = Member(person=self.application.person, offering=crs.course, role='TA',
                           added_reason='CTA', credits=0, career='NONS')
                m.config['bu'] = crs.total_bu
                m.save()
            elif (self.status in ['SGN', 'ACC'] and crs.bu > 0 ) and members:
                # change in BU -> change in BU for Member
                m = members[0]
                if not 'bu' in m.config or m.config['bu'] != crs.total_bu:
                    # if this student was added by the prof, then added_reason might not be CTA
                    m.config['bu'] = crs.total_bu
                    m.added_reason='CTA'
                    m.save()
            elif ( (not self.status in ['SGN', 'ACC']) or crs.bu == 0) and members:
                # already in course, but status isn't signed: remove
                m = members[0]
                if m.role == 'TA' and m.added_reason == 'CTA':
                    m.role = 'DROP'
                    m.save()
            else: 
                # (self.status not in ['SGN', 'ACC'] or crs.bu == 0) and not members
                # there is no contract and this student doesn't exist as a Member in the course
                pass
            
            if self.status in ('CAN', 'REJ'):
                # These students should be removed from their courses. 
                crs.bu = 0
                crs.save()

            # If this course has 0 BUs and a course Member record, clear that record. 
            if crs.bu == 0 and members:
                m = members[0]
                if m.role == 'TA' and m.added_reason == 'CTA':
                    m.role = 'DROP'
                    m.save()

        # If they are CTA-added members of any other course this semester, they probably shouldn't be
        members = Member.objects.filter(person=self.application.person, role='TA', added_reason='CTA', offering__semester=self.posting.semester )
        courseofferings = [crs.course for crs in courses if crs.bu > 0]
        for member in members:
            if member.offering not in courseofferings:
                member.role = 'DROP'
                member.save()
Пример #13
0
    def sync_course_member(self):
        """
        Once a contract is Signed, we should create a Member object for them.
        If a contract is Cancelled, we should DROP the Member object. 

        This operation should be idempotent - run it as many times as you
        want, the result should always be the same. 
        """
        # if signed, create the Member objects so they have access to the courses.
        courses = self.course.all()
        for crs in courses:
            members = Member.objects.filter(person=self.person, 
                                            role='TA',
                                            offering=crs.course)
            # the student should either be in the course (1) or not (0)
            # any other number of responses is unacceptable. 
            assert( len(members) == 1 or len(members) == 0 )


            dropped_members = Member.objects.filter(person=self.person, 
                                                    offering=crs.course, 
                                                    role='DROP')
            
            assert( len(dropped_members) == 1 or len(dropped_members) == 0)

            # this shouldn't be. 
            if members and dropped_members:
                d = dropped_members[0]
                d.delete()
                dropped_members = []
           
            # the student must be in one of these three states
            exists_and_is_in_the_course = len(members) > 0
            exists_and_is_dropped = len(dropped_members) > 0
            does_not_exist = len(members) == 0 and len(dropped_members) == 0
            
            assert(exists_and_is_in_the_course or exists_and_is_dropped or does_not_exist)            
            assert(not(exists_and_is_in_the_course and exists_and_is_dropped))
            assert(not(exists_and_is_dropped and does_not_exist))
            assert(not(exists_and_is_in_the_course and does_not_exist))
            assert(len(dropped_members) < 2)
            assert(len(members) < 2)

            if self.should_be_added_to_the_course:
                if exists_and_is_dropped:
                    m = dropped_members[0]
                elif exists_and_is_in_the_course:
                    m = members[0]
                elif does_not_exist:
                    m = Member(person=self.person, 
                               offering=crs.course, 
                               role='TA',
                               added_reason='TAC',
                               credits=0, 
                               career='NONS')
                else:
                    assert(False)
                m.added_reason='TAC'
                m.role = 'TA'
                m.config['bu'] = crs.total_bu
                m.save()
                crs.member = m
                crs.save(always_allow=True)
            else:
                if exists_and_is_dropped:
                    pass
                elif exists_and_is_in_the_course:
                    m = members[0]
                    if m.added_reason == 'TAC':
                        m.role = 'DROP'
                        m.save()
                    crs.member = None
                    crs.save(always_allow=True)
                elif does_not_exist:
                    pass

        # If they are TAC-added members of any other course this semester,
        #    they probably shouldn't be.
        members = Member.objects.filter(person=self.person, 
                                        role='TA', 
                                        added_reason='TAC',
                                        offering__semester=self.category.hiring_semester.semester)
        
        courseofferings = [crs.course for crs in courses]
        for member in members:
            if member.offering not in courseofferings:
                member.role = 'DROP'
                member.save()
Пример #14
0
    def sync_course_member(self):
        """
        Once a contract is Signed, we should create a Member object for them.
        If a contract is Cancelled, we should DROP the Member object. 

        This operation should be idempotent - run it as many times as you
        want, the result should always be the same. 
        """
        # if signed, create the Member objects so they have access to the courses.
        courses = self.course.all()
        for crs in courses:
            members = Member.objects.filter(person=self.person,
                                            role='TA',
                                            offering=crs.course)
            # the student should either be in the course (1) or not (0)
            # any other number of responses is unacceptable.
            assert (len(members) == 1 or len(members) == 0)

            dropped_members = Member.objects.filter(person=self.person,
                                                    offering=crs.course,
                                                    role='DROP')

            assert (len(dropped_members) == 1 or len(dropped_members) == 0)

            # this shouldn't be.
            if members and dropped_members:
                d = dropped_members[0]
                d.delete()
                dropped_members = []

            # the student must be in one of these three states
            exists_and_is_in_the_course = len(members) > 0
            exists_and_is_dropped = len(dropped_members) > 0
            does_not_exist = len(members) == 0 and len(dropped_members) == 0

            assert (exists_and_is_in_the_course or exists_and_is_dropped
                    or does_not_exist)
            assert (not (exists_and_is_in_the_course
                         and exists_and_is_dropped))
            assert (not (exists_and_is_dropped and does_not_exist))
            assert (not (exists_and_is_in_the_course and does_not_exist))
            assert (len(dropped_members) < 2)
            assert (len(members) < 2)

            if self.should_be_added_to_the_course:
                if exists_and_is_dropped:
                    m = dropped_members[0]
                elif exists_and_is_in_the_course:
                    m = members[0]
                elif does_not_exist:
                    m = Member(person=self.person,
                               offering=crs.course,
                               role='TA',
                               added_reason='TAC',
                               credits=0,
                               career='NONS')
                else:
                    assert (False)
                m.added_reason = 'TAC'
                m.role = 'TA'
                m.config['bu'] = crs.total_bu
                m.save()
                crs.member = m
                crs.save(always_allow=True)
            else:
                if exists_and_is_dropped:
                    pass
                elif exists_and_is_in_the_course:
                    m = members[0]
                    if m.added_reason == 'TAC':
                        m.role = 'DROP'
                        m.save()
                    crs.member = None
                    crs.save(always_allow=True)
                elif does_not_exist:
                    pass

        # If they are TAC-added members of any other course this semester,
        #    they probably shouldn't be.
        members = Member.objects.filter(
            person=self.person,
            role='TA',
            added_reason='TAC',
            offering__semester=self.category.hiring_semester.semester)

        courseofferings = [crs.course for crs in courses]
        for member in members:
            if member.offering not in courseofferings:
                member.role = 'DROP'
                member.save()
Пример #15
0
    def test_instructor_workflow(self):
        """
        Work through the site as an instructor
        """
        s, c = create_offering()
        userid1 = "0aaa0"
        userid2 = "0aaa1"
        userid3 = "0aaa2"
        userid4 = "ggbaker"
        for u in [userid1, userid2, userid3, userid4]:
            p = Person.objects.get(userid=u)
            m = Member(person=p,
                       offering=c,
                       role="STUD",
                       credits=3,
                       career="UGRD",
                       added_reason="UNK")
            m.save()
        m.role = "INST"
        m.save()

        client = Client()
        client.login_user("ggbaker")

        # course main screen
        url = reverse('offering:course_info', kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        url = reverse('offering:activity_choice',
                      kwargs={'course_slug': c.slug})
        self.assertContains(response, 'href="' + url + '"')
        url = reverse('offering:add_numeric_activity',
                      kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)

        # add activity
        import datetime
        now = datetime.datetime.now()
        due = now + datetime.timedelta(days=7)
        response = client.post(
            url, {
                'name': 'Assignment 1',
                'short_name': 'A1',
                'status': 'URLS',
                'due_date_0': due.strftime('%Y-%m-%d'),
                'due_date_1': due.strftime('%H:%M:%S'),
                'percent': '10',
                'group': '1',
                'max_grade': 25,
                'extend_group': 'None'
            })
        self.assertEqual(response.status_code, 302)

        acts = NumericActivity.objects.filter(offering=c)
        self.assertEqual(len(acts), 1)
        a = acts[0]
        self.assertEqual(a.name, "Assignment 1")
        self.assertEqual(a.slug, "a1")
        self.assertEqual(a.max_grade, 25)
        self.assertEqual(a.group, False)
        self.assertEqual(a.deleted, False)

        # add calculated numeric activity
        url = reverse('offering:add_cal_numeric_activity',
                      kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        response = client.post(
            url, {
                'name': 'Total',
                'short_name': 'Total',
                'status': 'URLS',
                'group': '1',
                'max_grade': 30,
                'formula': '[A1]+5'
            })
        self.assertEqual(response.status_code, 302)

        acts = CalNumericActivity.objects.filter(offering=c)
        self.assertEqual(len(acts), 1)
        a = acts[0]
        self.assertEqual(a.slug, "total")
        self.assertEqual(a.max_grade, 30)
        self.assertEqual(a.group, False)
        self.assertEqual(a.deleted, False)
        self.assertEqual(a.formula, '[A1]+5')

        # formula tester
        url = reverse('offering:formula_tester',
                      kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        response = client.get(
            url, {
                'formula': '[A1]+5',
                'a1-status': 'RLS',
                'a1-value': '6',
                'total-status': 'URLS'
            })
        self.assertContains(response, '<div id="formula_result">11.0</div>')
        validate_content(self, response.content, url)
Пример #16
0
    def test_instructor_workflow(self):
        """
        Work through the site as an instructor
        """
        s, c = create_offering()
        userid1 = "0aaa0"
        userid2 = "0aaa1"
        userid3 = "0aaa2"
        userid4 = "ggbaker"
        for u in [userid1, userid2, userid3, userid4]:
            p = Person.objects.get(userid=u)
            m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK")
            m.save()
        m.role="INST"
        m.save()
        
        client = Client()
        client.login_user("ggbaker")
        
        # course main screen
        url = reverse('grades.views.course_info', kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        url = reverse('grades.views.activity_choice', kwargs={'course_slug': c.slug})
        self.assertContains(response, 'href="' + url +'"')
        url = reverse('grades.views.add_numeric_activity', kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        
        # add activity
        import datetime
        now = datetime.datetime.now()
        due = now + datetime.timedelta(days=7)
        response = client.post(url, {'name':'Assignment 1', 'short_name':'A1', 'status':'URLS', 'due_date_0':due.strftime('%Y-%m-%d'), 'due_date_1':due.strftime('%H:%M:%S'), 'percent': '10', 'group': '1', 'max_grade': 25, 'extend_group': 'None'})
        self.assertEquals(response.status_code, 302)
        
        acts = NumericActivity.objects.filter(offering=c)
        self.assertEquals(len(acts), 1)
        a = acts[0]
        self.assertEquals(a.name, "Assignment 1")
        self.assertEquals(a.slug, "a1")
        self.assertEquals(a.max_grade, 25)
        self.assertEquals(a.group, False)
        self.assertEquals(a.deleted, False)
        
        # add calculated numeric activity
        url = reverse('grades.views.add_cal_numeric_activity', kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        response = client.post(url, {'name':'Total', 'short_name':'Total', 'status':'URLS', 'group': '1', 'max_grade': 30, 'formula': '[A1]+5'})
        self.assertEquals(response.status_code, 302)

        acts = CalNumericActivity.objects.filter(offering=c)
        self.assertEquals(len(acts), 1)
        a = acts[0]
        self.assertEquals(a.slug, "total")
        self.assertEquals(a.max_grade, 30)
        self.assertEquals(a.group, False)
        self.assertEquals(a.deleted, False)
        self.assertEquals(a.formula, '[A1]+5')
        
        # formula tester
        url = reverse('grades.views.formula_tester', kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        response = client.get(url, {'formula': '[A1]+5', 'a1-status': 'RLS', 'a1-value': '6', 'total-status': 'URLS'})
        self.assertContains(response, '<div id="formula_result">11.0</div>')
        validate_content(self, response.content, url)
Пример #17
0
    def test_group_staff(self):
        """
        Check out group pages for an instructor: go through the group-creation process from the instructor side.
        """
        s, c = create_offering()
        a = NumericActivity(name="Assignment 1", short_name="A1", status="URLS", offering=c, position=3, max_grade=20, group=True)
        a.save()
        a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True)
        a.save()
        
        userid1 = "0aaa6"
        userid2 = "0aaa0"
        userid3 = "0aaa1"
        userid4 = "ggbaker"
        for u in [userid1, userid2, userid3, userid4]:
            p = Person.objects.get(userid=u)
            m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK")
            m.save()
        m.role="INST"
        m.save()
        
        client = Client()
        client.login_user("ggbaker")
        
        # group management screen
        url = reverse('groups.views.groupmanage', kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)
        self.assertContains(response, "There are currently no groups in this course")
        url = reverse('groups.views.create', kwargs={'course_slug': c.slug})
        self.assertContains(response, 'href="%s"'%(url))
        
        # group creation form
        response = basic_page_tests(self, client, url)

        # submit group create
        url = reverse('groups.views.submit', kwargs={'course_slug': c.slug})
        response = client.post(url, {"GroupName": "Test Group", "a1-selected": True, "a2-selected": False, 
                '0aaa6-selected': False, '0aaa0-selected': True, '0aaa1-selected': True})
        self.assertEquals(response.status_code, 302)

        gs =  Group.objects.filter(courseoffering=c)
        self.assertEquals(len(gs), 1)
        self.assertEquals(gs[0].name, "Test Group")
        self.assertEquals(gs[0].slug, "g-test-group")

        gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0])
        self.assertEquals(len(gms), 2)
        self.assertEquals(gms[0].confirmed, True)
        self.assertEquals(gms[1].confirmed, True)
        self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid2,userid3]))
        
        # check group management screen again
        url = reverse('groups.views.groupmanage', kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)

        # add membership form
        url = reverse('groups.views.assign_student', kwargs={'course_slug': c.slug, 'group_slug': "g-test-group"})
        response = basic_page_tests(self, client, url)
        
        # submit add membership
        response = client.post(url, {"a1-selected": True, "a2-selected": True, 
                '0aaa6-selected': False, '0aaa0-selected': False, '0aaa1-selected': True})
        self.assertEquals(response.status_code, 302)
        # both still in for A1
        gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a1")
        self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid2,userid3]))
        # 0aaa1 added for A2
        gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a2")
        self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid3]))
        
        # remove member form
        url = reverse('groups.views.remove_student', kwargs={'course_slug': c.slug, 'group_slug': "g-test-group"})
        response = basic_page_tests(self, client, url)
        
        # submit remove member
        response = client.post(url, {'0aaa6_a1-selected': True, '0aaa0_a1-selected': False, '0aaa1_a1-selected': True})
        self.assertEquals(response.status_code, 302)
        # 0aaa1 gone for A1
        gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a1")
        self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid2]))
        # 0aaa1 still there for A2
        gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a2")
        self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid3]))

        # rename group form
        url = reverse('groups.views.change_name', kwargs={'course_slug': c.slug, 'group_slug': "g-test-group"})
        response = basic_page_tests(self, client, url)
        
        # submit change name
        response = client.post(url, {'name': 'otherName'})
        self.assertEquals(response.status_code, 302)
        g = Group.objects.get(courseoffering=c)
        self.assertEquals(g.name, 'otherName')
        self.assertEquals(g.slug, 'g-test-group')

        # recheck basic view with more data        
        url = reverse('groups.views.groupmanage', kwargs={'course_slug': c.slug})
        response = basic_page_tests(self, client, url)

        url = reverse('groups.views.view_group', kwargs={'course_slug': c.slug, 'group_slug': "g-test-group"})
        response = basic_page_tests(self, client, url)