def setUp(self, *args, **kwargs): super(TeacherCheckinModuleTest, self).setUp(*args, **kwargs) self.add_user_profiles() self.schedule_randomly() # only scheduled classes used in module self.ccc = ClassCreationController(self.program) pm = ProgramModule.objects.get(handler='TeacherCheckinModule') self.module = ProgramModuleObj.getFromProgModule(self.program, pm) self.now = self.settings['start_time'] self.past = datetime.datetime(1970, 1, 1) self.future = datetime.datetime.max self.admin = self.admins[0] self.teacher = self.teachers[0] self.cls = self.teacher.getTaughtClasses()[0] self.event = 'teacher_checked_in' self.teacher2 = ESPUser.objects.create(username='******') self.teacher2.makeRole("Teacher")
def force_availability(self, request, tl, one, two, module, extra, prog): teacher_dict = prog.teachers(QObjects=True) unavailable_teachers = ESPUser.objects.filter( (teacher_dict['class_approved'] | teacher_dict['class_proposed']) & ~teacher_dict['availability']).distinct() if request.method == 'POST': if request.POST.has_key('sure') and request.POST['sure'] == 'True': # Use the ClassCreationController to send e-mail from esp.program.controllers.classreg import ClassCreationController ccc = ClassCreationController(prog) for teacher in unavailable_teachers: for ts in prog.getTimeSlots(): teacher.addAvailableTime(prog, ts) ccc.send_availability_email( teacher, note= 'Availability was overridden by the program directors in order to make your class schedule feasible. Please contact them for more information.' ) return self.scheduling(request, tl, one, two, module, 'refresh', prog) else: return self.scheduling(request, tl, one, two, module, '', prog) # Normally, though, return a page explaining the issue. context = {'prog': self.program} context['good_teacher_num'] = ESPUser.objects.filter( teacher_dict['class_approved'] & teacher_dict['availability']).distinct().count() context['total_teacher_num'] = ESPUser.objects.filter( teacher_dict['class_approved']).distinct().count() context['bad_teacher_num'] = unavailable_teachers.count() return render_to_response(self.baseDir() + 'force_prompt.html', request, (prog, tl), context)
def availabilityForm(self, request, tl, one, two, prog, teacher, isAdmin): time_options = self.program.getTimeSlots(types=[self.event_type()]) # Group contiguous blocks if not Tag.getBooleanTag('availability_group_timeslots', default=True): time_groups = [list(time_options)] else: time_groups = Event.group_contiguous(list(time_options)) blank = False available_slots = teacher.getAvailableTimes(self.program, True) # must set the ignore_classes=True parameter above, otherwise when a teacher tries to edit their # availability, it will show their scheduled times as unavailable. # Fetch the timeslots the teacher is scheduled in and grey them out. # If we found a timeslot that they are scheduled in but is not available, show a warning. taken_slots = [] avail_and_teaching = [] user_sections = teacher.getTaughtSections(self.program) conflict_found = False for section in user_sections: for timeslot in section.get_meeting_times(): taken_slots.append(timeslot) if timeslot not in available_slots: conflict_found = True else: avail_and_teaching.append(timeslot) if request.method == 'POST': # Process form post_vars = request.POST # Reset teacher's availability teacher.clearAvailableTimes(self.program) # But add back in the times they're teaching # because those aren't submitted with the form for timeslot in avail_and_teaching: teacher.addAvailableTime(self.program, timeslot) # Add in resources for the checked available times. timeslot_ids = map(int, post_vars.getlist('timeslots')) timeslots = Event.objects.filter( id__in=timeslot_ids).order_by('start') missing_tsids = set(timeslot_ids) - set(x.id for x in timeslots) if missing_tsids: raise ESPError( 'Received requests for the following timeslots that don\'t exist: %s' % str(list(sorted(missing_tsids))), log=False) blank = (not (bool(len(timeslot_ids) + len(avail_and_teaching)))) if not blank: for timeslot in timeslots: teacher.addAvailableTime(self.program, timeslot) # Send an e-mail showing availability to the teacher (and the archive) ccc = ClassCreationController(self.program) ccc.send_availability_email(teacher) if isAdmin: # Return to the relevant check_availability page return HttpResponseRedirect( '/manage/%s/%s/check_availability?user=%s' % (one, two, teacher.id)) else: # Return to the main registration page return self.goToCore(tl) # Show new form if not (len(available_slots) or blank): # I'm not sure whether or not we want the "or blank" # If they didn't enter anything, make everything checked by default. available_slots = self.program.getTimeSlots( types=[self.event_type()]) # The following 2 lines mark the teacher as always available. This # is sometimes helpful, but not usually the desired behavior. # for a in available_slots: # teacher.addAvailableTime(self.program, a) context = { 'groups': [{ 'selections': [{ 'checked': (t in available_slots), 'taken': (t in taken_slots), 'slot': t } for t in group] } for group in time_groups] } context['num_groups'] = len(context['groups']) context['prog'] = self.program context['is_overbooked'] = ( not self.isCompleted() and (teacher.getTaughtTime(self.program) > timedelta(0))) context['submitted_blank'] = blank context['conflict_found'] = conflict_found context['teacher_user'] = teacher return render_to_response(self.baseDir() + 'availability_form.html', request, context)
def makeaclass_logic(self, request, tl, one, two, module, extra, prog, newclass=None, action='create', populateonly=False): """ The logic for the teacher class registration form. A brief description of some of the key arguments: - newclass -- The class object from which to fill in the data - action -- What action is the form performing? Options are 'create', 'createopenclass', 'edit', 'editopenclass' - populateonly -- If True and newclass is specified, the form will only populate the fields, rather than keeping track of which class they came from and saving edits back to that. This is used for the class copying logic. """ context = {'module': self} if request.method == 'POST' and 'class_reg_page' in request.POST: if not self.deadline_met(): return self.goToCore(tl) ccc = ClassCreationController(self.program) try: if action == 'create': newclass = ccc.makeaclass(request.user, request.POST) elif action == 'createopenclass': newclass = ccc.makeaclass( request.user, request.POST, form_class=TeacherOpenClassRegForm) elif action == 'edit': newclass = ccc.editclass(request.user, request.POST, extra) elif action == 'editopenclass': newclass = ccc.editclass( request.user, request.POST, extra, form_class=TeacherOpenClassRegForm) do_question = bool( ProgramModule.objects.filter(handler="TeacherReviewApps", program=self.program)) if do_question: return HttpResponseRedirect( newclass.parent_program.get_teach_url() + "app_questions") if request.POST.get('manage') == 'manage': if request.POST['manage_submit'] == 'reload': return HttpResponseRedirect(request.get_full_path() + '?manage=manage') elif request.POST['manage_submit'] == 'manageclass': return HttpResponseRedirect( '/manage/%s/manageclass/%s' % (self.program.getUrlBase(), extra)) elif request.POST['manage_submit'] == 'dashboard': return HttpResponseRedirect('/manage/%s/dashboard' % self.program.getUrlBase()) elif request.POST['manage_submit'] == 'main': return HttpResponseRedirect('/manage/%s/main' % self.program.getUrlBase()) return self.goToCore(tl) except ClassCreationValidationError, e: reg_form = e.reg_form resource_formset = e.resource_formset
def coteachers(self, request, tl, one, two, module, extra, prog): if not 'clsid' in request.POST: return self.goToCore(tl) # just fails. if extra == 'nojs': ajax = False else: ajax = True classes = ClassSubject.objects.filter(id=request.POST['clsid']) if len(classes) != 1 or not request.user.canEdit(classes[0]): return render_to_response(self.baseDir() + 'cannoteditclass.html', request, {}) cls = classes[0] # set txtTeachers and coteachers.... if not 'coteachers' in request.POST: coteachers = cls.get_teachers() coteachers = [ user for user in coteachers if user.id != request.user.id ] txtTeachers = ",".join([str(user.id) for user in coteachers]) else: txtTeachers = request.POST['coteachers'] coteachers = txtTeachers.split(',') coteachers = [x for x in coteachers if x != ''] coteachers = [ ESPUser.objects.get(id=userid) for userid in coteachers ] add_list_members( "%s_%s-teachers" % (prog.program_type, prog.program_instance), coteachers) op = '' if 'op' in request.POST: op = request.POST['op'] conflictingusers = [] error = False if op == 'add': if len(request.POST['teacher_selected'].strip()) == 0: error = 'Error - Please click on the name when it drops down.' elif (request.POST['teacher_selected'] == str(request.user.id)): error = 'Error - You cannot select yourself as a coteacher!' elif request.POST['teacher_selected'] in txtTeachers.split(','): error = 'Error - You already added this teacher as a coteacher!' if error: return render_to_response( self.baseDir() + 'coteachers.html', request, { 'class': cls, 'ajax': ajax, 'txtTeachers': txtTeachers, 'coteachers': coteachers, 'error': error, 'conflicts': [] }) # add schedule conflict checking here... teacher = ESPUser.objects.get(id=request.POST['teacher_selected']) if cls.conflicts(teacher): conflictingusers.append(teacher.first_name + ' ' + teacher.last_name) else: coteachers.append(teacher) txtTeachers = ",".join( [str(coteacher.id) for coteacher in coteachers]) elif op == 'del': ids = request.POST.getlist('delete_coteachers') newcoteachers = [] for coteacher in coteachers: if str(coteacher.id) not in ids: newcoteachers.append(coteacher) coteachers = newcoteachers txtTeachers = ",".join( [str(coteacher.id) for coteacher in coteachers]) elif op == 'save': old_coteachers_set = set(cls.get_teachers()) new_coteachers_set = set(coteachers) to_be_added = new_coteachers_set - old_coteachers_set to_be_deleted = old_coteachers_set - new_coteachers_set # don't delete the current user if request.user in to_be_deleted: to_be_deleted.remove(request.user) for teacher in to_be_added: if cls.conflicts(teacher): conflictingusers.append(teacher.first_name + ' ' + teacher.last_name) if len(conflictingusers) == 0: # remove some old coteachers for teacher in to_be_deleted: cls.removeTeacher(teacher) # add bits for all new coteachers ccc = ClassCreationController(self.program) for teacher in to_be_added: ccc.associate_teacher_with_class(cls, teacher) ccc.send_class_mail_to_directors(cls) return self.goToCore(tl) return render_to_response( self.baseDir() + 'coteachers.html', request, { 'class': cls, 'ajax': ajax, 'txtTeachers': txtTeachers, 'coteachers': coteachers, 'conflicts': conflictingusers })
def coteachers(self, request, tl, one, two, module, extra, prog): from esp.users.models import ESPUser # Allow submitting class ID via either GET or POST. if request.GET.has_key('clsid'): clsid = request.GET['clsid'] elif request.POST.has_key('clsid'): clsid = request.POST['clsid'] else: return self.goToCore(tl) # just fails. if extra == 'nojs': ajax = False else: ajax = True classes = ClassSubject.objects.filter(id = clsid) if len(classes) != 1 or not request.user.canEdit(classes[0]): return render_to_response(self.baseDir()+'cannoteditclass.html', request, (prog, tl),{}) cls = classes[0] # set txtTeachers and coteachers.... if not request.POST.has_key('coteachers'): coteachers = cls.teachers() coteachers = [ ESPUser(user) for user in coteachers ] txtTeachers = ",".join([str(user.id) for user in coteachers ]) else: txtTeachers = request.POST['coteachers'] coteachers = txtTeachers.split(',') coteachers = [ x for x in coteachers if x != '' ] coteachers = [ ESPUser(User.objects.get(id=userid)) for userid in coteachers ] op = '' if request.POST.has_key('op'): op = request.POST['op'] conflictingusers = [] error = False if op == 'add': if len(request.POST['teacher_selected'].strip()) == 0: error = 'Error - Please click on the name when it drops down.' elif request.POST['teacher_selected'] in txtTeachers.split(','): error = 'Error - You already added this teacher as a coteacher!' if error: return render_to_response(self.baseDir()+'coteachers.html', request, (prog, tl),{'class':cls, 'ajax':ajax, 'txtTeachers': txtTeachers, 'coteachers': coteachers, 'error': error}) # add schedule conflict checking here... teacher = ESPUser.objects.get(id = request.POST['teacher_selected']) if cls.conflicts(teacher): conflictingusers.append(teacher.first_name+' '+teacher.last_name) else: coteachers.append(teacher) txtTeachers = ",".join([str(coteacher.id) for coteacher in coteachers ]) elif op == 'del': ids = request.POST.getlist('delete_coteachers') newcoteachers = [] for coteacher in coteachers: if str(coteacher.id) not in ids: newcoteachers.append(coteacher) coteachers = newcoteachers txtTeachers = ",".join([str(coteacher.id) for coteacher in coteachers ]) elif op == 'save': # if for teacher in coteachers: if cls.conflicts(teacher): conflictingusers.append(teacher.first_name+' '+teacher.last_name) if len(conflictingusers) == 0: for teacher in cls.teachers(): cls.removeTeacher(teacher) cls.removeAdmin(teacher) # add bits for all new (and old) coteachers ccc = ClassCreationController(self.program) for teacher in coteachers: ccc.associate_teacher_with_class(cls, teacher) ccc.send_class_mail_to_directors(cls) return self.goToCore(tl) return render_to_response(self.baseDir()+'coteachers.html', request, (prog, tl),{'class':cls, 'ajax':ajax, 'txtTeachers': txtTeachers, 'coteachers': coteachers, 'conflicts': conflictingusers})
class TeacherCheckinModuleTest(ProgramFrameworkTest): def setUp(self, *args, **kwargs): super(TeacherCheckinModuleTest, self).setUp(*args, **kwargs) self.add_user_profiles() self.schedule_randomly() # only scheduled classes used in module self.ccc = ClassCreationController(self.program) pm = ProgramModule.objects.get(handler='TeacherCheckinModule') self.module = ProgramModuleObj.getFromProgModule(self.program, pm) self.now = self.settings['start_time'] self.past = datetime.datetime(1970, 1, 1) self.future = datetime.datetime.max self.admin = self.admins[0] self.teacher = self.teachers[0] self.cls = self.teacher.getTaughtClasses()[0] self.event = 'teacher_checked_in' self.teacher2 = ESPUser.objects.create(username='******') self.teacher2.makeRole("Teacher") def tearDown(self): Record.objects.filter(program=self.program, event=self.event).delete() super(TeacherCheckinModuleTest, self).tearDown() def addCoteacher(self, cls, coteacher): self.ccc.associate_teacher_with_class(cls, coteacher) # Aliases so full set of args don't need to be typed each time. # 'when' defaults to self.now (the datetime of the program), and # 'teacher' defaults to self.teacher. def isCheckedIn(self, when=None, teacher=None): if when is None: when = self.now if teacher is None: teacher = self.teacher return Record.user_completed(teacher, self.event, self.program, when, only_today=True) def checkIn(self, when=None, teacher=None): if when is None: when = self.now if teacher is None: teacher = self.teacher return self.module.checkIn(teacher, self.program, when) def undoCheckIn(self, when=None, teacher=None): if when is None: when = self.now if teacher is None: teacher = self.teacher return self.module.undoCheckIn(teacher, self.program, when) # End aliases. def test_checkIn(self): """Run tests for checkIn() and undoCheckIn().""" # Test that calling checkIn() works, and # that calling it again does nothing. self.assertFalse(self.isCheckedIn()) self.assertIn('is checked in until', self.checkIn()) self.assertTrue(self.isCheckedIn()) self.assertIn('has already been checked in until', self.checkIn()) self.assertTrue(self.isCheckedIn()) # Test that checking in the teacher in the present has no effect on # check-in status in the past or future, and that checking in the # teacher in the future has no effect on check-in status in the # present or past. self.assertFalse(self.isCheckedIn(self.past)) self.assertFalse(self.isCheckedIn(self.future)) self.assertIn('is checked in until', self.checkIn(self.future)) self.assertTrue(self.isCheckedIn()) self.assertTrue(self.isCheckedIn(self.future)) self.assertFalse(self.isCheckedIn(self.past)) # Test that undoing check-in in the future has no effect on check-in # status in the present or past. self.assertIn('is no longer checked in.', self.undoCheckIn(self.future)) self.assertFalse(self.isCheckedIn(self.future)) self.assertTrue(self.isCheckedIn()) self.assertFalse(self.isCheckedIn(self.past)) # Test that calling undoCheckIn() works, and # that calling it again does nothing. self.assertIn('is no longer checked in.', self.undoCheckIn()) self.assertFalse(self.isCheckedIn()) self.assertIn('was not checked in for', self.undoCheckIn()) self.assertFalse(self.isCheckedIn()) # Test that you can't successfully call checkIn() or undoCheckIn() # for a user who is not teaching a class for the program. self.assertIn('is not a teacher for', self.checkIn(teacher=self.teacher2)) self.assertIn('was not checked in for', self.undoCheckIn(teacher=self.teacher2)) def test_phone_numbers_on_checkin_page(self): self.assertTrue( self.client.login(username=self.admin.username, password='******'), "Couldn't log in as admin %s" % self.admin.username) response = self.client.get(u'%smissingteachers' % self.program.get_onsite_url()) phone = self.teacher.getLastProfile().contact_user.phone_cell self.assertIn(phone, response.content.decode('utf-8'))
class TeacherCheckinModuleTest(ProgramFrameworkTest): def setUp(self, *args, **kwargs): super(TeacherCheckinModuleTest, self).setUp(*args, **kwargs) self.add_user_profiles() self.schedule_randomly() # only scheduled classes used in module self.ccc = ClassCreationController(self.program) pm = ProgramModule.objects.get(handler='TeacherCheckinModule') self.module = ProgramModuleObj.getFromProgModule(self.program, pm) self.now = self.settings['start_time'] self.past = datetime.datetime(1970, 1, 1) self.future = datetime.datetime.max self.admin = self.admins[0] self.teacher = self.teachers[0] self.cls = self.teacher.getTaughtClasses()[0] self.event = 'teacher_checked_in' self.teacher2 = ESPUser.objects.create(username='******') self.teacher2.makeRole("Teacher") def tearDown(self): Record.objects.filter(program=self.program, event=self.event).delete() super(TeacherCheckinModuleTest, self).tearDown() def addCoteacher(self, cls, coteacher): self.ccc.associate_teacher_with_class(cls, coteacher) # Aliases so full set of args don't need to be typed each time. # 'when' defaults to self.now (the datetime of the program), and # 'teacher' defaults to self.teacher. def isCheckedIn(self, when=None, teacher=None): if when is None: when = self.now if teacher is None: teacher = self.teacher return Record.user_completed(teacher, self.event, self.program, when, only_today=True) def checkIn(self, when=None, teacher=None): if when is None: when = self.now if teacher is None: teacher = self.teacher return self.module.checkIn(teacher, self.program, when) def undoCheckIn(self, when=None, teacher=None): if when is None: when = self.now if teacher is None: teacher = self.teacher return self.module.undoCheckIn(teacher, self.program, when) # End aliases. def test_checkIn(self): """Run tests for checkIn() and undoCheckIn().""" # Test that calling checkIn() works, and # that calling it again does nothing. self.assertFalse(self.isCheckedIn()) self.assertIn('is checked in until', self.checkIn()) self.assertTrue(self.isCheckedIn()) self.assertIn('has already been checked in until', self.checkIn()) self.assertTrue(self.isCheckedIn()) # Test that checking in the teacher in the present has no effect on # check-in status in the past or future, and that checking in the # teacher in the future has no effect on check-in status in the # present or past. self.assertFalse(self.isCheckedIn(self.past)) self.assertFalse(self.isCheckedIn(self.future)) self.assertIn('is checked in until', self.checkIn(self.future)) self.assertTrue(self.isCheckedIn()) self.assertTrue(self.isCheckedIn(self.future)) self.assertFalse(self.isCheckedIn(self.past)) # Test that undoing check-in in the future has no effect on check-in # status in the present or past. self.assertIn('is no longer checked in.', self.undoCheckIn(self.future)) self.assertFalse(self.isCheckedIn(self.future)) self.assertTrue(self.isCheckedIn()) self.assertFalse(self.isCheckedIn(self.past)) # Test that calling undoCheckIn() works, and # that calling it again does nothing. self.assertIn('is no longer checked in.', self.undoCheckIn()) self.assertFalse(self.isCheckedIn()) self.assertIn('was not checked in for', self.undoCheckIn()) self.assertFalse(self.isCheckedIn()) # Test that you can't successfully call checkIn() or undoCheckIn() # for a user who is not teaching a class for the program. self.assertIn('is not a teacher for', self.checkIn(teacher=self.teacher2)) self.assertIn('was not checked in for', self.undoCheckIn(teacher=self.teacher2)) def test_phone_numbers_on_checkin_page(self): self.assertTrue(self.client.login(username=self.admin.username, password='******'), "Couldn't log in as admin %s" % self.admin.username) response = self.client.get(u'%smissingteachers' % self.program.get_onsite_url()) phone = self.teacher.getLastProfile().contact_user.phone_cell self.assertIn(phone, response.content.decode('utf-8'))
def coteachers(self, request, tl, one, two, module, extra, prog): from esp.users.models import ESPUser # Allow submitting class ID via either GET or POST. if 'clsid' in request.GET: clsid = request.GET['clsid'] elif 'clsid' in request.POST: clsid = request.POST['clsid'] else: return self.goToCore(tl) # just fails. if extra == 'nojs': ajax = False else: ajax = True classes = ClassSubject.objects.filter(id = clsid) if len(classes) != 1 or not request.user.canEdit(classes[0]): return render_to_response(self.baseDir()+'cannoteditclass.html', request, {}) cls = classes[0] # set txtTeachers and coteachers.... if not 'coteachers' in request.POST: coteachers = cls.get_teachers() coteachers = [ user for user in coteachers if user.id != request.user.id ] txtTeachers = ",".join([str(user.id) for user in coteachers ]) else: txtTeachers = request.POST['coteachers'] coteachers = txtTeachers.split(',') coteachers = [ x for x in coteachers if x != '' ] coteachers = [ ESPUser.objects.get(id=userid) for userid in coteachers ] op = '' if 'op' in request.POST: op = request.POST['op'] conflictingusers = [] error = False if op == 'add': if len(request.POST['teacher_selected'].strip()) == 0: error = 'Error - Please click on the name when it drops down.' elif request.POST['teacher_selected'] in txtTeachers.split(','): error = 'Error - You already added this teacher as a coteacher!' if error: return render_to_response(self.baseDir()+'coteachers.html', request, {'class': cls, 'ajax': ajax, 'txtTeachers': txtTeachers, 'coteachers': coteachers, 'error': error}) # add schedule conflict checking here... teacher = ESPUser.objects.get(id = request.POST['teacher_selected']) if cls.conflicts(teacher): conflictingusers.append(teacher.first_name+' '+teacher.last_name) else: coteachers.append(teacher) txtTeachers = ",".join([str(coteacher.id) for coteacher in coteachers ]) elif op == 'del': ids = request.POST.getlist('delete_coteachers') newcoteachers = [] for coteacher in coteachers: if str(coteacher.id) not in ids: newcoteachers.append(coteacher) coteachers = newcoteachers txtTeachers = ",".join([str(coteacher.id) for coteacher in coteachers ]) elif op == 'save': # if for teacher in coteachers: if cls.conflicts(teacher): conflictingusers.append(teacher.first_name+' '+teacher.last_name) if len(conflictingusers) == 0: for teacher in cls.get_teachers(): cls.removeTeacher(teacher) # add bits for all new (and old) coteachers ccc = ClassCreationController(self.program) for teacher in coteachers: ccc.associate_teacher_with_class(cls, teacher) ccc.send_class_mail_to_directors(cls) return self.goToCore(tl) return render_to_response(self.baseDir()+'coteachers.html', request, {'class': cls, 'ajax': ajax, 'txtTeachers': txtTeachers, 'coteachers': coteachers, 'conflicts': conflictingusers})