def setUp(self): faculty_test_data.Command().handle() self.p = Person.objects.get(userid='ggbaker') self.u = Unit.objects.get(id=1) self.date = datetime.date(2014, 1, 1) self.e = CareerEvent(person=self.p, unit=self.u, event_type="APPOINT", start_date=self.date) self.e.get_handler().save(self.p)
class CareerEventTest(TestCase): def setUp(self): faculty_test_data.Command().handle() self.p = Person.objects.get(userid='ggbaker') self.u = Unit.objects.get(id=1) self.date = datetime.date(2014, 1, 1) self.e = CareerEvent(person=self.p, unit=self.u, event_type="APPOINT", start_date=self.date) self.e.get_handler().save(self.p) def test_get_effective_date(self): events = CareerEvent.objects.effective_date(self.date) for e in events: assert e.start_date <= self.date assert e.end_date == None or e.end_date >= self.date def test_get_effective_semester(self): semester = Semester.objects.get(name='1141') events = CareerEvent.objects.effective_semester(semester) start, end = semester.start_end_dates(semester) for e in events: assert e.start_date >= start assert e.end_date == None or (e.end_date <= end and e.end_date >= start) def test_flag_logic(self): """ Check the event.flags setting logic: flags set only if there's a real effect. """ e = CareerEvent(person=self.p, unit=self.u, event_type="FELLOW", start_date=self.date) e.config = {'add_salary': 0, 'add_pay': 0, 'teaching_credit': 0} h = e.get_handler() h.save(self.p) self.assertFalse(e.flags.affects_salary) self.assertFalse(e.flags.affects_teaching) e.config['add_salary'] = 5 h.save(self.p) self.assertTrue(e.flags.affects_salary) self.assertFalse(e.flags.affects_teaching) e.config['add_salary'] = 0 e.config['teaching_credit'] = 1 h.save(self.p) self.assertFalse(e.flags.affects_salary) self.assertTrue(e.flags.affects_teaching)
def run(self): sems = Semester.objects.filter(name__gte='1001', name__lte=Semester.next_starting().name) u = Unit.objects.get(label='ENSC') courses = CourseOffering.objects.prefetch_related('meeting_time').filter(semester__in=sems, owner=u, graded=True).exclude( flags=CourseOffering.flags.combined).exclude(subject='DDP').order_by('semester', 'subject', 'number') course_history = Table() course_history.append_column('Semester') course_history.append_column('Course') course_history.append_column('Instructor') course_history.append_column('Enrolment') course_history.append_column('Campus') course_history.append_column('Joint With') course_history.append_column('Lecture Times') course_history.append_column('Instructor(s) Rank(s)') for course in courses: semester = course.semester.label() label = course.name() instr = course.instructors_printing_str() enrl = '%i/%i' % (course.enrl_tot, course.enrl_cap) if course.campus in CAMPUSES_SHORT: campus = CAMPUSES_SHORT[course.campus] else: campus = 'Unknown' if course.config.get('joint_with'): joint = str(', '.join(course.config.get('joint_with'))) else: joint = '' meeting_times = '' mt = [t for t in course.meeting_time.all() if t.meeting_type == 'LEC'] if mt: meeting_times = ', '.join(str("%s %s-%s" % (WEEKDAYS[t.weekday], t.start_time, t.end_time)) for t in mt) ranks = "; ".join(CareerEvent.ranks_as_of_semester(p.id, course.semester) for p in course.instructors()) course_history.append_row([semester, label, instr, enrl, campus, joint, meeting_times, ranks]) self.artifacts.append(course_history)
def test_event_types(self): """ Basic tests of each event handler """ fac_member = Person.objects.get(userid='ggbaker') fac_role = Role.objects.filter(person=fac_member)[0] editor = Person.objects.get(userid='dixon') units = Unit.objects.all() start_date = datetime.date(2014, 1, 1) for Handler in HANDLERS: # Make sure all required abstract methods at least overrided # XXX: should output the missing method on fail try: # If a handler is missing any required methods (like teaching, salary, etc), # then instantiation will raise an Exception. This means that there is no need # to explicitly check if a handler with a flag has overriden a specific base # mixin method. handler = Handler( CareerEvent(person=fac_member, unit=fac_role.unit, start_date=start_date)) handler.set_handler_specific_data() if 'affects_salary' in Handler.FLAGS: self.assertTrue(issubclass(Handler, SalaryCareerEvent)) self.assertIsInstance(handler, SalaryCareerEvent) self.assertIsInstance(handler.salary_adjust_annually(), SalaryAdjust) else: self.assertFalse(handler.event.flags.affects_salary) if 'affects_teaching' in Handler.FLAGS: self.assertTrue(issubclass(Handler, TeachingCareerEvent)) self.assertIsInstance(handler, TeachingCareerEvent) self.assertIsInstance( handler.teaching_adjust_per_semester(), TeachingAdjust) else: self.assertFalse(handler.event.flags.affects_teaching) # test form creation Handler.get_entry_form(editor=editor, units=units) # display methods that each handler must implement shortsummary = handler.short_summary() self.assertIsInstance(shortsummary, basestring) self.assertNotIn( '%s', shortsummary) # find these cases that shouldn't exist html = handler.to_html() self.assertIsInstance( html, (safestring.SafeString, safestring.SafeText, safestring.SafeUnicode)) except: print "failure with Handler==%s" % (Handler) raise
def create_for(cls, person, form=None): """ Given a person, create a new instance of the handler for them. """ from faculty.models import CareerEvent event = CareerEvent(person=person, event_type=cls.EVENT_TYPE) ret = cls(event) if form: ret.load(form) return ret
def event_get_or_create(**kwargs): """ CareerEvent.objects.get_or_create, but doesn't save and returns a Handler """ try: e = CareerEvent.objects.get(**kwargs) except CareerEvent.DoesNotExist: e = CareerEvent(**kwargs) h = EVENT_TYPES[e.event_type](event=e) return e, h
def test_is_exclusive_close_previous(self): self.Handler.IS_EXCLUSIVE = True handler1 = self.Handler(CareerEvent(person=self.person, unit=self.unit)) handler1.event.title = 'hello world' handler1.event.start_date = date.today() handler1.save(self.person) handler2 = self.Handler(CareerEvent(person=self.person, unit=self.unit)) handler2.event.title = 'Foobar' handler2.event.start_date = date.today() + timedelta(days=1) handler2.save(self.person) # XXX: handler1's event won't be automatically refreshed after we've 'closed' it # so we must grab a fresh copy to verify. handler1_modified_event = CareerEvent.objects.get(id=handler1.event.id) self.assertEqual( handler1_modified_event.end_date, handler2.event.start_date - datetime.timedelta(days=1))
def run(self): sems = Semester.objects.filter(name__gte='1001', name__lte=Semester.next_starting().name) u = Unit.objects.filter(label__in=['CMPT', 'ENSC', 'MSE']) courses = CourseOffering.objects.prefetch_related( 'meeting_time').filter( semester__in=sems, owner__in=u, graded=True).exclude( flags=CourseOffering.flags.combined).exclude( subject='DDP').exclude(component='CAN').order_by( 'semester', 'subject', 'number') course_history = Table() course_history.append_column('Semester') course_history.append_column('Course') course_history.append_column('Units') course_history.append_column('Instructor') course_history.append_column('Enrolment') course_history.append_column('Campus') course_history.append_column('Joint With') course_history.append_column('Lecture Times') course_history.append_column('Instructor(s) Rank(s)') for course in courses: semester = course.semester.label() label = course.name() units = course.units instr = course.instructors_printing_str() enrl = '%i/%i' % (course.enrl_tot, course.enrl_cap) if course.campus in CAMPUSES_SHORT: campus = CAMPUSES_SHORT[course.campus] else: campus = 'Unknown' if course.config.get('joint_with'): joint = str(', '.join(course.config.get('joint_with'))) else: joint = '' meeting_times = '' mt = [ t for t in course.meeting_time.all() if t.meeting_type == 'LEC' ] if mt: meeting_times = ', '.join( str("%s %s-%s" % (WEEKDAYS[t.weekday], t.start_time, t.end_time)) for t in mt) ranks = "; ".join( CareerEvent.ranks_as_of_semester(p.id, course.semester) for p in course.instructors()) course_history.append_row([ semester, label, units, instr, enrl, campus, joint, meeting_times, ranks ]) self.artifacts.append(course_history)
def test_is_instant(self): handler = self.HandlerInstant( CareerEvent(person=self.person, unit=self.unit)) # Ensure the 'end_date' field is successfully removed form = handler.get_entry_form(self.person, []) self.assertNotIn('end_date', form.fields) # 'end_date' should be None before saving handler.event.start_date = date.today() self.assertIsNone(handler.event.end_date) # 'start_date' should be equal to 'end_date' after saving handler.save(self.person) self.assertEqual(handler.event.start_date, handler.event.end_date)
def run(self): sems = Semester.objects.filter(name__gte='1094', name__lte=Semester.current().offset(2).name) u = Unit.objects.filter(label__in=['CMPT', 'MSE', 'ENSC']) courses = CourseOffering.objects.prefetch_related('meeting_time').filter(semester__in=sems, owner__in=u, graded=True).exclude( flags=CourseOffering.flags.combined).exclude(subject='DDP').order_by('semester', 'subject', 'number') courses = list(courses) courses.sort(key=lambda x: (x.instructors_printing_str(), x.semester)) course_history = Table() course_history.append_column('Instructor') course_history.append_column('Instructor(s) Rank(s)') course_history.append_column('School') course_history.append_column('Grad Students') course_history.append_column('Semester') course_history.append_column('Course') course_history.append_column('Enrolment') course_history.append_column('Campus') course_history.append_column('Joint With') course_history.append_column('Lecture Times') course_history.append_column('Credits') for course in courses: semester = course.semester.label() label = course.name() instr = course.instructors_printing_str() enrl = '%i/%i' % (course.enrl_tot, course.enrl_cap) unit = course.owner credits = course.units if course.campus in CAMPUSES_SHORT: campus = CAMPUSES_SHORT[course.campus] else: campus = 'Unknown' if course.config.get('joint_with'): joint = str(', '.join(course.config.get('joint_with'))) else: joint = '' meeting_times = '' mt = [t for t in course.meeting_time.all() if t.meeting_type == 'LEC'] if mt: meeting_times = ', '.join(str("%s %s-%s" % (WEEKDAYS[t.weekday], t.start_time, t.end_time)) for t in mt) grads = "; ".join(str(Supervisor.objects.filter(supervisor__userid=p.userid, supervisor_type='SEN', removed=False).count()) for p in course.instructors()) ranks = "; ".join(CareerEvent.ranks_as_of_semester(p.id, course.semester) for p in course.instructors()) course_history.append_row([instr, ranks, unit, grads, semester, label, enrl, campus, joint, meeting_times, credits]) self.artifacts.append(course_history)
def test_management_permissions(self): """ Check that permission methods are returning as expected """ fac_member = Person.objects.get(userid='ggbaker') dept_admin = Person.objects.get(userid='dixon') dean_admin = Person.objects.get(userid='dzhao') fac_role = Role.objects.filter(person=fac_member)[0] handler = SalaryModificationEventHandler( CareerEvent(person=fac_member, unit=fac_role.unit)) # tests below assume these permission settings for this event type self.assertEqual(handler.VIEWABLE_BY, 'MEMB') self.assertEqual(handler.EDITABLE_BY, 'DEPT') self.assertEqual(handler.APPROVAL_BY, 'FAC') self.assertFalse(handler.can_edit(fac_member)) self.assertTrue(handler.can_edit(dept_admin)) self.assertTrue(handler.can_edit(dean_admin)) self.assertFalse(handler.can_approve(fac_member)) self.assertFalse(handler.can_approve(dept_admin)) self.assertTrue(handler.can_approve(dean_admin))
def test_flag_logic(self): """ Check the event.flags setting logic: flags set only if there's a real effect. """ e = CareerEvent(person=self.p, unit=self.u, event_type="FELLOW", start_date=self.date) e.config = {'add_salary': 0, 'add_pay': 0, 'teaching_credit': 0} h = e.get_handler() h.save(self.p) self.assertFalse(e.flags.affects_salary) self.assertFalse(e.flags.affects_teaching) e.config['add_salary'] = 5 h.save(self.p) self.assertTrue(e.flags.affects_salary) self.assertFalse(e.flags.affects_teaching) e.config['add_salary'] = 0 e.config['teaching_credit'] = 1 h.save(self.p) self.assertFalse(e.flags.affects_salary) self.assertTrue(e.flags.affects_teaching)
def run(self): sems = Semester.objects.filter(name__gte='1101', name__lte=Semester.current().name) u = Unit.objects.filter(label__in=['CMPT', 'MSE', 'ENSC']) courses = CourseOffering.objects.prefetch_related( 'meeting_time').filter( semester__in=sems, owner__in=u, graded=True).exclude( flags=CourseOffering.flags.combined).exclude( subject='DDP').order_by('semester', 'subject', 'number') instructors = Member.objects.filter(role='INST', added_reason='AUTO', offering__in=courses) \ .exclude(offering__component='CAN') \ .order_by('person__last_name', 'person__first_name', 'offering__semester__name') course_history = Table() course_history.append_column('Instructor') course_history.append_column('First Teaching Semester (>=1101)') course_history.append_column('Last Teaching Semester') course_history.append_column('Current Rank') course_history.append_column('School') course_history.append_column('Teaching Credits') course_history.append_column('Mean Headcount') course_history.append_column('Crs per Year') course_history.append_column('Unique Crs') course_history.append_column('Crs Levels') for i, memberships in itertools.groupby(instructors, key=lambda i: i.person): memberships = [m for m in memberships if m.teaching_credit() > 0] if i is None or not memberships: continue instr = i.sortname() first_semester = memberships[0].offering.semester last_semester = memberships[-1].offering.semester rank = CareerEvent.current_ranks(i.id) roles = Role.objects.filter(person=i, role='FAC').select_related('unit') unit = ', '.join(r.unit.label for r in roles) if rank == 'unknown': rank = 'non-faculty' if unit == '': unit = ', '.join(set(m.offering.subject for m in memberships)) offerings = [m.offering for m in memberships] num_offerings = float(sum(m.teaching_credit() for m in memberships)) headcount = sum(o.enrl_tot for o in offerings) duration = last_semester - first_semester + 1 levels = sorted(list(set(str(o.number)[0] for o in offerings))) unique = len(set(o.course_id for o in offerings)) course_history.append_row([ instr, first_semester.name, last_semester.name, rank, unit, round(num_offerings, 2), round(headcount / num_offerings, 1), round(num_offerings / duration * 3, 1), unique, ','.join(levels) ]) self.artifacts.append(course_history)