def test_json_view(self): self.client.login(username='******', password='******') r = self.client.get('/onsite/' + self.program.url + '/unenroll_status') data = json.loads(r.content) self.assertGreaterEqual(len(data['student_timeslots']), 20) self.assertGreater(len(data['section_timeslots']), 0) self.assertGreater(len(data['enrollments']), 0) for student_id, ts_id in data['student_timeslots'].items(): self.assertTrue(self.timeslots.filter(id=ts_id).exists()) self.assertTrue(StudentRegistration.valid_objects().filter( user=student_id, section__meeting_times=ts_id).exists()) self.assertFalse( Record.objects.filter(event='attended', program=self.program, user=student_id).exists()) for section_id, ts_id in data['section_timeslots'].items(): self.assertTrue(self.timeslots.filter(id=ts_id).exists()) sec = ClassSection.objects.get(id=section_id) self.assertTrue(sec.meeting_times.filter(id=ts_id).exists()) self.assertTrue(StudentRegistration.valid_objects().filter( section=section_id).exists()) for sr_id, (user_id, section_id) in data['enrollments'].items(): sr = StudentRegistration.objects.get(id=sr_id) self.assertEqual(sr.user_id, user_id) self.assertEqual(sr.section_id, section_id) self.assertIn(str(user_id), data['student_timeslots']) self.assertIn(str(section_id), data['section_timeslots'])
def test_json_view(self): self.client.login(username='******', password='******') r = self.client.get('/onsite/' + self.program.url + '/unenroll_status') data = json.loads(r.content) self.assertGreaterEqual(len(data['student_timeslots']), 20) self.assertGreater(len(data['section_timeslots']), 0) self.assertGreater(len(data['enrollments']), 0) for student_id, ts_id in data['student_timeslots'].items(): self.assertTrue(self.timeslots.filter(id=ts_id).exists()) self.assertTrue(StudentRegistration.valid_objects().filter( user=student_id, section__meeting_times=ts_id).exists()) self.assertFalse(Record.objects.filter( event='attended', program=self.program, user=student_id).exists()) for section_id, ts_id in data['section_timeslots'].items(): self.assertTrue(self.timeslots.filter(id=ts_id).exists()) sec = ClassSection.objects.get(id=section_id) self.assertTrue(sec.meeting_times.filter(id=ts_id).exists()) self.assertTrue(StudentRegistration.valid_objects().filter( section=section_id).exists()) for sr_id, (user_id, section_id) in data['enrollments'].items(): sr = StudentRegistration.objects.get(id=sr_id) self.assertEqual(sr.user_id, user_id) self.assertEqual(sr.section_id, section_id) self.assertIn(str(user_id), data['student_timeslots']) self.assertIn(str(section_id), data['section_timeslots'])
def lottery_preferences_legacy(self, request, prog): # DEPRECATED: see comments in lottery_preferences method sections = list(prog.sections().values('id')) sections_interested = StudentRegistration.valid_objects().filter( relationship__name='Interested', user=request.user, section__parent_class__parent_program=prog).select_related( 'section__id').values_list('section__id', flat=True).distinct() sections_priority = StudentRegistration.valid_objects().filter( relationship__name='Priority/1', user=request.user, section__parent_class__parent_program=prog).select_related( 'section__id').values_list('section__id', flat=True).distinct() for item in sections: if item['id'] in sections_interested: item['lottery_interested'] = True else: item['lottery_interested'] = False if item['id'] in sections_priority: item['lottery_priority'] = True else: item['lottery_priority'] = False return {'sections': sections}
def viewlotteryprefs(self, request, tl, one, two, module, extra, prog): context = {} context['student'] = request.user priority_classids = set() uniquified_flags = [] priority_flags = StudentRegistration.valid_objects().filter(user=request.user, section__parent_class__parent_program=prog, relationship__name='Priority/1') for flag in priority_flags: if flag.section.id not in priority_classids: priority_classids.add(flag.section.id) uniquified_flags.append(flag) context['priority'] = uniquified_flags if priority_flags.count() == 0: context['pempty'] = True else: context['pempty'] = False interested_classids = set() uniquified_interested = [] interested = StudentRegistration.valid_objects().filter(user=request.user, section__parent_class__parent_program=prog, relationship__name='Interested') for flag in interested: if flag.section.id not in interested_classids: interested_classids.add(flag.section.id) uniquified_interested.append(flag) context['interested' ] = uniquified_interested if interested.count() == 0: context['iempty'] = True else: context['iempty'] = False return render_to_response(self.baseDir()+'view_lottery_prefs.html', request, context)
def viewlotteryprefs(self, request, tl, one, two, module, extra, prog): context = {} context['student'] = request.user context['program'] = prog priority_classids = set() uniquified_flags = [] priority_flags = StudentRegistration.valid_objects().filter(user=request.user, section__parent_class__parent_program=prog, relationship__name='Priority/1') for flag in priority_flags: if flag.section.id not in priority_classids: priority_classids.add(flag.section.id) uniquified_flags.append(flag) context['priority'] = uniquified_flags if priority_flags.count() == 0: context['pempty'] = True else: context['pempty'] = False interested_classids = set() uniquified_interested = [] interested = StudentRegistration.valid_objects().filter(user=request.user, section__parent_class__parent_program=prog, relationship__name='Interested') for flag in interested: if flag.section.id not in interested_classids: interested_classids.add(flag.section.id) uniquified_interested.append(flag) context['interested' ] = uniquified_interested if interested.count() == 0: context['iempty'] = True else: context['iempty'] = False return render_to_response(self.baseDir()+'view_lottery_prefs.html', request, (prog, tl), context)
def classchangerequest(self, request, tl, one, two, module, extra, prog): timeslots = prog.getTimeSlots() sections = prog.sections().filter(status=10, meeting_times__isnull=False).distinct() enrollments = {} for timeslot in timeslots: try: enrollments[timeslot] = ClassSubject.objects.get(nest_Q(StudentRegistration.is_valid_qobject(), 'sections__studentregistration'), sections__studentregistration__relationship__name="Enrolled", sections__studentregistration__user=request.user, sections__meeting_times=timeslot, parent_program=prog) except ClassSubject.DoesNotExist: enrollments[timeslot] = None context = {} context['timeslots'] = timeslots context['enrollments'] = enrollments context['user'] = request.user if 'success' in request.GET: context['success'] = True else: context['success'] = False if request.user.isStudent(): sections_by_slot = dict([(timeslot,[(section, 1 == StudentRegistration.valid_objects().filter(user=context['user'], section=section, relationship__name="Request").count()) for section in sections if section.get_meeting_times()[0] == timeslot and section.parent_class.grade_min <= request.user.getGrade(prog) <= section.parent_class.grade_max and section.parent_class not in enrollments.values() and ESPUser.getRankInClass(request.user, section.parent_class) in (5,10)]) for timeslot in timeslots]) else: sections_by_slot = dict([(timeslot,[(section, False) for section in sections if section.get_meeting_times()[0] == timeslot]) for timeslot in timeslots]) fields = {} for i, timeslot in enumerate(sections_by_slot.keys()): choices = [('0', "I'm happy with my current enrollment.")] initial = '0' for section in sections_by_slot[timeslot]: choices.append((section[0].emailcode(), section[0].emailcode()+": "+section[0].title())) if section[1]: initial = section[0].emailcode() fields['timeslot_'+str(i+1)] = forms.ChoiceField(label="Timeslot "+str(i+1)+" ("+timeslot.pretty_time()+")", choices=choices, initial=initial) form = type('ClassChangeRequestForm', (forms.Form,), fields) context['form'] = form() if request.method == "POST": old_requests = StudentRegistration.valid_objects().filter(user=context['user'], section__parent_class__parent_program=prog, relationship__name="Request") for r in old_requests: r.expire() form = form(request.POST) if form.is_valid(): for value in form.cleaned_data.values(): section = None for s in sections: if s.emailcode() == value: section = s break if not section: continue r = StudentRegistration.valid_objects().get_or_create(user=context['user'], section=section, relationship=RegistrationType.objects.get_or_create(name="Request", category="student")[0])[0] r.save() return HttpResponseRedirect(request.path.rstrip('/')+'/?success') else: return render_to_response(self.baseDir() + 'classchangerequest.html', request, context)
def lottery_preferences_legacy(self, request, prog): # DEPRECATED: see comments in lottery_preferences method sections = list(prog.sections().values('id')) sections_interested = StudentRegistration.valid_objects().filter(relationship__name='Interested', user=request.user, section__parent_class__parent_program=prog).select_related('section__id').values_list('section__id', flat=True).distinct() sections_priority = StudentRegistration.valid_objects().filter(relationship__name='Priority/1', user=request.user, section__parent_class__parent_program=prog).select_related('section__id').values_list('section__id', flat=True).distinct() for item in sections: if item['id'] in sections_interested: item['lottery_interested'] = True else: item['lottery_interested'] = False if item['id'] in sections_priority: item['lottery_priority'] = True else: item['lottery_priority'] = False return {'sections': sections}
def students(self, QObject=False): Enrolled = Q(studentregistration__relationship__name='Enrolled') Par = Q(studentregistration__section__parent_class__parent_program=self .program) Unexpired = nest_Q(StudentRegistration.is_valid_qobject(), 'studentregistration') # Force Django to generate two subqueries without joining SRs to SSIs, # as efficiently as possible since it's still a big query. sr_ids = StudentRegistration.valid_objects().filter( section__parent_class__parent_program=self.program).values( 'user').distinct() ssi_ids = StudentSubjectInterest.valid_objects().filter( subject__parent_program=self.program).values('user').distinct() any_reg_q = Q(id__in=sr_ids) | Q(id__in=ssi_ids) qobjects = { 'enrolled': Enrolled & Par & Unexpired, 'classreg': any_reg_q, } if QObject: return qobjects else: return { k: ESPUser.objects.filter(v).distinct() for k, v in qobjects.iteritems() }
def getSchedule(program, student): schedule = """ Student schedule for %s: Time | Class | Room""" % student.name() regs = StudentRegistration.valid_objects().filter( user=student, section__parent_class__parent_program=program, relationship__name='Accepted') classes = [x.section.parent_class for x in regs] # now we sort them by time/title classes.sort() for cls in classes: rooms = cls.prettyrooms() if len(rooms) == 0: rooms = 'N/A' else: rooms = ", ".join(rooms) schedule += """ %s|%s|%s""" % (",".join( cls.friendly_times()).ljust(20), cls.title.ljust(25), rooms) return schedule
def students(self, QObject = False): Enrolled = Q(studentregistration__relationship__name='Enrolled') Par = Q(studentregistration__section__parent_class__parent_program=self.program) Unexpired = nest_Q(StudentRegistration.is_valid_qobject(), 'studentregistration') # Force Django to generate two subqueries without joining SRs to SSIs, # as efficiently as possible since it's still a big query. sr_ids = StudentRegistration.valid_objects().filter( section__parent_class__parent_program=self.program ).values('user').distinct() ssi_ids = StudentSubjectInterest.valid_objects().filter( subject__parent_program=self.program).values('user').distinct() any_reg_q = Q(id__in = sr_ids) | Q(id__in = ssi_ids) qobjects = { 'enrolled': Enrolled & Par & Unexpired, 'classreg': any_reg_q, } if QObject: return qobjects else: return {k: ESPUser.objects.filter(v).distinct() for k, v in qobjects.iteritems()}
def num_users_enrolled(self, prog): # Querying for SRs and then extracting the users saves us joining the # users table. return StudentRegistration.valid_objects().filter( section__parent_class__parent_program=prog, relationship__name='Enrolled').values_list( 'user').distinct().count()
def getSchedule(program, student): schedule = u""" Student schedule for %s: Time | Class | Room""" % student.name() regs = StudentRegistration.valid_objects().filter(user=student, section__parent_class__parent_program=program, relationship__name='Accepted') classes = [x.section.parent_class for x in regs] # now we sort them by time/title classes.sort() for cls in classes: rooms = cls.prettyrooms() if len(rooms) == 0: rooms = u'N/A' else: rooms = u", ".join(rooms) schedule += u""" %s|%s|%s""" % (u",".join(cls.friendly_times()).ljust(20), cls.title.ljust(25), rooms) return schedule
def num_users_enrolled(self, prog): # Querying for SRs and then extracting the users saves us joining the # users table. return StudentRegistration.valid_objects().filter( section__parent_class__parent_program=prog, relationship__name='Enrolled' ).values_list('user').distinct().count()
def lsr_submit_HSSP(request, program, priority_limit, data): # temporary function. will merge the two later -jmoldow 05/31 classes_flagged = [set() for i in range(0,priority_limit+1)] # 1-indexed sections_by_block = [defaultdict(set) for i in range(0,priority_limit+1)] # 1-indexed - sections_by_block[i][block] is a set of classes that were given priority i in timeblock block. This should hopefully be a set of size 0 or 1. for section_id, (priority, block_id) in data.iteritems(): section_id = int(section_id) priority = int(priority) block_id = int(block_id) classes_flagged[0].add(section_id) classes_flagged[priority].add(section_id) sections_by_block[priority][block_id].add(section_id) errors = [] for i in range(1, priority_limit+1): for block in sections_by_block[i].keys(): if len(sections_by_block[i][block]) > 1: errors.append({"text": "Can't flag two classes with the same priority at the same time!", "cls_sections": list(sections_by_block[i][block]), "block": block, "priority": i, "doubled_priority": True}) if len(errors): return HttpResponse(json.dumps(errors), content_type='application/json') reg_priority = [(None,None)] + [RegistrationType.objects.get_or_create(name="Priority/"+str(i), category="student") for i in range(1,priority_limit+1)] reg_priority = [reg_priority[i][0] for i in range(0, priority_limit+1)] allStudentRegistrations = StudentRegistration.valid_objects().filter(section__parent_class__parent_program=program, user=request.user) oldRegistrations = [] #[[] for i in range(0, priority_limit+1)] # 1-indexed for priority registrations, the 0-index is for interested registrations for i in range(1, priority_limit+1): oldRegistrations += [(oldRegistration, i) for oldRegistration in list(allStudentRegistrations.filter(relationship=reg_priority[i]))] for (oldRegistration, priority) in oldRegistrations: if oldRegistration.section.id not in classes_flagged[0]: oldRegistration.expire() continue for i in range(1, priority_limit + 1): if oldRegistration.section.id in classes_flagged[i]: if i != priority: oldRegistration.expire() elif i == priority: classes_flagged[i].remove(oldRegistration.section.id) classes_flagged[0].remove(oldRegistration.section.id) break flagworthy_sections = [None] + [ClassSection.objects.filter(id__in=classes_flagged[i]).annotate(first_block=Min('meeting_times__start')) for i in range(1, priority_limit + 1)] for i in range(1, priority_limit + 1): for s in list(flagworthy_sections[i]): if not s.preregister_student(request.user, prereg_verb=reg_priority[i].name, overridefull=True): errors.append({"text": "Unable to add flagged class", "cls_sections": [s.id], "emailcode": s.emailcode(), "block": s.first_block, "flagged": True, "priority": i, "doubled_priority": False}) if len(errors) != 0: s = StringIO() pprint(errors, s) mail_admins('Error in class reg', s.getvalue(), fail_silently=True) return HttpResponse(json.dumps(errors), content_type='application/json')
def lsr_submit_HSSP(request, program, priority_limit, data): # temporary function. will merge the two later -jmoldow 05/31 classes_flagged = [set() for i in range(0,priority_limit+1)] # 1-indexed sections_by_block = [defaultdict(set) for i in range(0,priority_limit+1)] # 1-indexed - sections_by_block[i][block] is a set of classes that were given priority i in timeblock block. This should hopefully be a set of size 0 or 1. for section_id, (priority, block_id) in data.iteritems(): section_id = int(section_id) priority = int(priority) block_id = int(block_id) classes_flagged[0].add(section_id) classes_flagged[priority].add(section_id) sections_by_block[priority][block_id].add(section_id) errors = [] for i in range(1, priority_limit+1): for block in sections_by_block[i].keys(): if len(sections_by_block[i][block]) > 1: errors.append({"text": "Can't flag two classes with the same priority at the same time!", "cls_sections": list(sections_by_block[i][block]), "block": block, "priority": i, "doubled_priority": True}) if len(errors): return HttpResponse(json.dumps(errors), mimetype='application/json') reg_priority = [(None,None)] + [RegistrationType.objects.get_or_create(name="Priority/"+str(i), category="student") for i in range(1,priority_limit+1)] reg_priority = [reg_priority[i][0] for i in range(0, priority_limit+1)] allStudentRegistrations = StudentRegistration.valid_objects().filter(section__parent_class__parent_program=program, user=request.user) oldRegistrations = [] #[[] for i in range(0, priority_limit+1)] # 1-indexed for priority registrations, the 0-index is for interested registrations for i in range(1, priority_limit+1): oldRegistrations += [(oldRegistration, i) for oldRegistration in list(allStudentRegistrations.filter(relationship=reg_priority[i]).select_related(depth=3))] for (oldRegistration, priority) in oldRegistrations: if oldRegistration.section.id not in classes_flagged[0]: oldRegistration.expire() continue for i in range(1, priority_limit + 1): if oldRegistration.section.id in classes_flagged[i]: if i != priority: oldRegistration.expire() elif i == priority: classes_flagged[i].remove(oldRegistration.section.id) classes_flagged[0].remove(oldRegistration.section.id) break flagworthy_sections = [None] + [ClassSection.objects.filter(id__in=classes_flagged[i]).select_related(depth=2).annotate(first_block=Min('meeting_times__start')) for i in range(1, priority_limit + 1)] for i in range(1, priority_limit + 1): for s in list(flagworthy_sections[i]): if not s.preregister_student(request.user, prereg_verb=reg_priority[i].name, overridefull=True): errors.append({"text": "Unable to add flagged class", "cls_sections": [s.id], "emailcode": s.emailcode(), "block": s.first_block, "flagged": True, "priority": i, "doubled_priority": False}) if len(errors) != 0: s = StringIO() pprint(errors, s) mail_admins('Error in class reg', s.getvalue(), fail_silently=True) return HttpResponse(json.dumps(errors), mimetype='application/json')
def enrollment_status(self, request, tl, one, two, module, extra, prog): resp = HttpResponse(mimetype='application/json') data = StudentRegistration.valid_objects().filter( section__status__gt=0, section__parent_class__status__gt=0, section__parent_class__parent_program=prog, relationship__name='Enrolled').values_list('user__id', 'section__id') simplejson.dump(list(data), resp) return resp
def load_data(self): lunch_registrations = list(StudentRegistration.valid_objects().filter( user=self.user, section__parent_class__category__category='Lunch', section__parent_class__parent_program=self.program)) if len(lunch_registrations) > 0: section = lunch_registrations[0].section if len(section.get_meeting_times()) > 0: print 'Set initial to %s' % section.get_meeting_times()[0] self.initial['timeslot'] = section.get_meeting_times()[0].id
def lottery_preferences_usepriority(self, request, prog): sections = list(prog.sections().values('id')) for i in range(1, prog.priorityLimit()+1, 1): priority_name = 'Priority/' + str(i) sections_priority = StudentRegistration.valid_objects().filter(relationship__name=priority_name, user=request.user, section__parent_class__parent_program=prog).select_related('section__id').values_list('section__id', flat=True).distinct() for item in sections: if item['id'] in sections_priority: item[priority_name] = True #else: # item['lottery_priority'] = False return {'sections': sections}
def num_users_with_lottery(self, prog): # Past empirical observation has shown that doing the union in SQL is # much, much slower for unknown reasons; it also means we would have to # query over the users table, so this saves us joining that table. users_with_ssis = set(StudentSubjectInterest.valid_objects().filter( subject__parent_program=prog).values_list('user').distinct()) users_with_srs = set(StudentRegistration.valid_objects().filter( Q(relationship__name='Interested') | Q(relationship__name__contains='Priority/'), section__parent_class__parent_program=prog).values_list( 'user').distinct()) return len(users_with_ssis | users_with_srs)
def review_students(self, request, tl, one, two, module, extra, prog): """ Show a roster of the students in the class, allowing the administrators to accept students into the program based on the teachers' reviews and the students' applications. """ try: cls = ClassSubject.objects.get(id=extra) except ClassSubject.DoesNotExist: raise ESPError(False), 'Cannot find class.' if not request.user.canEdit(cls): raise ESPError(False), 'You cannot edit class "%s"' % cls # Fetch any student even remotely related to the class. students_dict = cls.students_dict() students = [] for key in students_dict: students += students_dict[key] students = filter( lambda x: x.studentapplication_set.filter(program=self.program). count() > 0, students) for student in students: student.added_class = student.studentregistration_set.filter( section__parent_class=cls)[0].start_date try: student.app = student.studentapplication_set.get( program=self.program) except: student.app = None if student.app: reviews = student.app.reviews.all() else: reviews = [] if StudentRegistration.valid_objects().filter( user=student, section__parent_class=cls, relationship__name='Accepted').count() > 0: student.status = 'Accepted' else: student.status = 'Not accepted' students = list(students) students.sort(key=lambda x: x.last_name) return render_to_response(self.baseDir() + 'roster.html', request, { 'class': cls, 'students': students, 'program': prog })
def unenroll_status(prog): """ Assemble the data necessary to compute the set of enrollments to expire for a given combination of student first class times and section start times. Returns: enrollments: { enrollment id -> (user id, section id) } student_timeslots: { user id -> event id of first class timeslot } section_timeslots: { section id -> event id of first timeslot } """ enrolled = RegistrationType.objects.get(name='Enrolled') sections = prog.sections().filter( status__gt=0, parent_class__status__gt=0) sections = sections.exclude( parent_class__category__category='Lunch') enrollments = StudentRegistration.valid_objects().filter( relationship=enrolled, section__in=sections) # students not checked in students = ESPUser.objects.filter( id__in=enrollments.values('user')) students = students.exclude( record__program=prog, record__event='attended') # enrollments for those students relevant = enrollments.filter(user__in=students).values_list( 'id', 'user', 'section', 'section__meeting_times') relevant = relevant.order_by('section__meeting_times__start') section_timeslots = {} # section -> starting timeslot id student_timeslots = {} # student -> starting timeslot id enrollments = {} # id -> (student, section) for id, student, section, ts in relevant: if ts is None: continue if section not in section_timeslots: section_timeslots[section] = ts if student not in student_timeslots: student_timeslots[student] = ts enrollments[id] = (student, section) return { 'section_timeslots': section_timeslots, 'student_timeslots': student_timeslots, 'enrollments': enrollments }
def catalog_registered_classes_json(self, request, tl, one, two, module, extra, prog, timeslot=None): reg_bits = StudentRegistration.valid_objects().filter(user=request.user, section__parent_class__parent_program=prog).select_related() reg_bits_data = [ { 'user': b.user.username, 'section_id': b.section_id, 'type': b.relationship.name } for b in reg_bits ] resp = HttpResponse(content_type='application/json') json.dump(reg_bits_data, resp) return resp
def load_data(self): lunch_registrations = StudentRegistration.valid_objects().filter( user=self.user, section__parent_class__category__category='Lunch', section__parent_class__parent_program=self.program).select_related( 'section').prefetch_related('section__meeting_times') lunch_registrations = [ lunch_registration for lunch_registration in lunch_registrations if list(lunch_registration.section.meeting_times.all()) [0].start.day == self.day.day ] if len(lunch_registrations) > 0: section = lunch_registrations[0].section if len(section.get_meeting_times()) > 0: self.initial['timeslot'] = section.get_meeting_times()[0].id
def lottery_preferences_usepriority(self, request, prog): sections = list(prog.sections().values('id')) for i in range(1, prog.priorityLimit() + 1, 1): priority_name = 'Priority/' + str(i) sections_priority = StudentRegistration.valid_objects().filter( relationship__name=priority_name, user=request.user, section__parent_class__parent_program=prog).select_related( 'section__id').values_list('section__id', flat=True).distinct() for item in sections: if item['id'] in sections_priority: item[priority_name] = True #else: # item['lottery_priority'] = False return {'sections': sections}
def num_users_with_lottery(self, prog): # Past empirical observation has shown that doing the union in SQL is # much, much slower for unknown reasons; it also means we would have to # query over the users table, so this saves us joining that table. users_with_ssis = set( StudentSubjectInterest.valid_objects() .filter(subject__parent_program=prog) .values_list('user').distinct()) users_with_srs = set( StudentRegistration.valid_objects() .filter( Q(relationship__name='Interested') | Q(relationship__name__contains='Priority/'), section__parent_class__parent_program=prog) .values_list('user').distinct()) return len(users_with_ssis | users_with_srs)
def review_students(self, request, tl, one, two, module, extra, prog): """ Show a roster of the students in the class, allowing the administrators to accept students into the program based on the teachers' reviews and the students' applications. """ try: cls = ClassSubject.objects.get(id = extra) except ClassSubject.DoesNotExist: raise ESPError('Cannot find class.', log=False) if not request.user.canEdit(cls): raise ESPError('You cannot edit class "%s"' % cls, log=False) # Fetch any student even remotely related to the class. students_dict = cls.students_dict() students = [] for key in students_dict: students += students_dict[key] students = filter(lambda x: x.studentapplication_set.filter(program=self.program).count() > 0, students) for student in students: student.added_class = student.studentregistration_set.filter(section__parent_class=cls)[0].start_date try: student.app = student.studentapplication_set.get(program = self.program) except: student.app = None if student.app: reviews = student.app.reviews.all() else: reviews = [] if StudentRegistration.valid_objects().filter(user=student, section__parent_class=cls, relationship__name='Accepted').count() > 0: student.status = 'Accepted' else: student.status = 'Not accepted' students = list(students) students.sort(key=lambda x: x.last_name) return render_to_response(self.baseDir()+'roster.html', request, {'class': cls, 'students':students, 'program': prog})
def catalog_registered_classes_json(self, request, tl, one, two, module, extra, prog, timeslot=None): reg_bits = StudentRegistration.valid_objects().filter( user=request.user, section__parent_class__parent_program=prog).select_related() reg_bits_data = [{ 'user': b.user.username, 'section_id': b.section_id, 'type': b.relationship.name } for b in reg_bits] resp = HttpResponse(content_type='application/json') json.dump(reg_bits_data, resp) return resp
def num_prefs(self, prog): num_srs = StudentRegistration.valid_objects().filter( section__parent_class__parent_program=prog).count() return num_srs + self.num_ssis(prog)
def studentreg2phase(self, request, tl, one, two, module, extra, prog): """ Serves the two-phase student reg page. This page includes instructions for registration, and links to the phase1/phase2 sub-pages. """ timeslot_dict = {} # Populate the timeslot dictionary with the priority to class title # mappings for each timeslot. priority_regs = StudentRegistration.valid_objects().filter( user=request.user, relationship__name__startswith='Priority') priority_regs = priority_regs.select_related( 'relationship', 'section', 'section__parent_class') for student_reg in priority_regs: rel = student_reg.relationship title = student_reg.section.parent_class.title sec = student_reg.section times = sec.meeting_times.all().order_by('start') if times.count() == 0: continue timeslot = times[0].id if not timeslot in timeslot_dict: timeslot_dict[timeslot] = {rel: title} else: timeslot_dict[timeslot][rel] = title star_counts = {} interests = StudentSubjectInterest.valid_objects().filter( user=request.user, subject__parent_program=prog) interests = interests.select_related( 'subject').prefetch_related('subject__sections__meeting_times') for interest in interests: cls = interest.subject for sec in cls.sections.all(): times = sec.meeting_times.all() if len(times) == 0: continue timeslot = min(times, key=lambda t: t.start).id if not timeslot in star_counts: star_counts[timeslot] = 1 else: star_counts[timeslot] += 1 # Iterate through timeslots and create a list of tuples of information prevTimeSlot = None blockCount = 0 schedule = [] timeslots = prog.getTimeSlots(types=['Class Time Block', 'Compulsory']) for i in range(len(timeslots)): timeslot = timeslots[i] if prevTimeSlot != None: if not Event.contiguous(prevTimeSlot, timeslot): blockCount += 1 if timeslot.id in timeslot_dict: priority_dict = timeslot_dict[timeslot.id] priority_list = sorted(priority_dict.items()) else: priority_list = [] if timeslot.id in star_counts: priority_list.append(( 'Starred', "(%d classes)" % star_counts[timeslot.id])) schedule.append((timeslot, priority_list, blockCount + 1)) prevTimeSlot = timeslot context = {} context['timeslots'] = schedule return render_to_response( self.baseDir()+'studentregtwophase.html', request, context)
# lunch randomly for users with both lunch blocks free. from script_setup import * import random from esp.cal.models import Event from esp.program.models import Program, StudentRegistration, RegistrationType from esp.program.models.class_ import ClassSection from esp.users.models import ESPUser program = Program.objects.get(id=115) # Change me! (Splash 2014) relationship = RegistrationType.objects.get(name='Enrolled') srs = StudentRegistration.valid_objects().filter( section__parent_class__parent_program=program, relationship=relationship) srs_pairs = srs.values_list('user', 'section') users = ESPUser.objects.filter(id__in=srs.values_list('user')) sections = ClassSection.objects.filter( parent_class__parent_program=program ).prefetch_related('meeting_times') timeblocks = Event.objects.filter( program=program, event_type__description='Class Time Block') users_by_id = {user.id: user for user in users} sections_by_id = {section.id: section for section in sections} timeblocks_by_id = {timeblock.id: timeblock for timeblock in timeblocks} sections_by_user_timeblock = {
def review_student(self, request, tl, one, two, module, extra, prog): scrmi = prog.studentclassregmoduleinfo reg_nodes = scrmi.reg_verbs() try: cls = ClassSubject.objects.get(id = extra) except ClassSubject.DoesNotExist: raise ESPError('Cannot find class.', log=False) if not request.user.canEdit(cls): raise ESPError('You cannot edit class "%s"' % cls, log=False) student = request.GET.get('student',None) if not student: student = request.POST.get('student','') try: student = ESPUser.objects.get(id = int(student)) except ESPUser.DoesNotExist: raise ESPError('Cannot find student, %s' % student, log=False) not_registered = not StudentRegistration.valid_objects().filter(section__parent_class = cls, user = student).exists() if not_registered: raise ESPError('Student not a student of this class.', log=False) try: student.app = student.studentapplication_set.get(program = self.program) except: student.app = None raise ESPError('Error: Student did not start an application.', log=False) student.added_class = StudentRegistration.valid_objects().filter(section__parent_class = cls, user = student)[0].start_date teacher_reviews = student.app.reviews.all().filter(reviewer=request.user) if teacher_reviews.count() > 0: this_review = teacher_reviews.order_by('id')[0] else: this_review = StudentAppReview(reviewer=request.user) this_review.save() student.app.reviews.add(this_review) if request.method == 'POST': form = this_review.get_form(request.POST) if form.is_valid(): form.target.update(form) if 'submit_next' in request.POST or 'submit_return' in request.POST: url = '/%s/%s/%s/review_students/%s/' % (tl, one, two, extra) if 'submit_next' in request.POST: url += '?prev=%s' % student.id from django.shortcuts import redirect return redirect(url) # self.review_students(request, tl, one, two, module, extra, prog) else: form = this_review.get_form() return render_to_response(self.baseDir()+'review.html', request, {'class': cls, 'reviews': teacher_reviews, 'program': prog, 'student':student, 'form': form})
def studentreg2phase(self, request, tl, one, two, module, extra, prog): """ Serves the two-phase student reg page. This page includes instructions for registration, and links to the phase1/phase2 sub-pages. """ context = {} timeslot_dict = {} # Populate the timeslot dictionary with the priority to class title # mappings for each timeslot. priority_regs = StudentRegistration.valid_objects().filter( user=request.user, relationship__name__startswith='Priority') priority_regs = priority_regs.select_related('relationship', 'section', 'section__parent_class') for student_reg in priority_regs: rel = student_reg.relationship title = student_reg.section.parent_class.title sec = student_reg.section times = sec.meeting_times.all().order_by('start') if times.count() == 0: continue timeslot = times[0].id if not timeslot in timeslot_dict: timeslot_dict[timeslot] = {rel: title} else: timeslot_dict[timeslot][rel] = title star_counts = {} interests = StudentSubjectInterest.valid_objects().filter( user=request.user, subject__parent_program=prog) interests = interests.select_related('subject').prefetch_related( 'subject__sections__meeting_times') for interest in interests: cls = interest.subject for sec in cls.sections.all(): times = sec.meeting_times.all() if len(times) == 0: continue timeslot = min(times, key=lambda t: t.start).id if not timeslot in star_counts: star_counts[timeslot] = 1 else: star_counts[timeslot] += 1 # Iterate through timeslots and create a list of tuples of information prevTimeSlot = None blockCount = 0 schedule = [] timeslots = prog.getTimeSlots(types=['Class Time Block', 'Compulsory']) context['num_priority'] = prog.priorityLimit() context['num_star'] = Tag.getProgramTag("num_stars", program=prog, default=10) for i in range(len(timeslots)): timeslot = timeslots[i] if prevTimeSlot != None: if not Event.contiguous(prevTimeSlot, timeslot): blockCount += 1 if timeslot.id in timeslot_dict: priority_dict = timeslot_dict[timeslot.id] # (relationship, class_title) -> relationship.name priority_list = sorted(priority_dict.items(), key=lambda item: item[0].name) else: priority_list = [] temp_list = [] for i in range(0, context['num_priority']): if i < len(priority_list): temp_list.append( ("Priority " + str(i + 1), priority_list[i][1])) else: temp_list.append(("Priority " + str(i + 1), "")) priority_list = temp_list star_count = 0 if timeslot.id in star_counts: star_count = star_counts[timeslot.id] schedule.append( (timeslot, priority_list, blockCount + 1, star_count, float(star_count) / context['num_star'] * 100)) prevTimeSlot = timeslot context['timeslots'] = schedule return render_to_response(self.baseDir() + 'studentregtwophase.html', request, context)
def num_prefs(self, prog): num_srs = StudentRegistration.valid_objects().filter( section__parent_class__parent_program=prog).count() return num_srs + self.num_ssis(prog)
def num_priority1s(self, prog): return StudentRegistration.valid_objects().filter( relationship__name='Priority/1', section__parent_class__parent_program=prog).count()
def initialize(self): """ Gather all of the information needed to run the lottery assignment. This includes: - Students' interest (priority and interested bits) - Class schedules and capacities - Timeslots (incl. lunch periods for each day) """ self.interest = numpy.zeros((self.num_students, self.num_sections), dtype=numpy.bool) self.priority = [numpy.zeros((self.num_students, self.num_sections), dtype=numpy.bool) for i in range(self.effective_priority_limit+1)] self.ranks = 10*numpy.ones((self.num_students, self.num_sections), dtype=numpy.int32) self.section_schedules = numpy.zeros((self.num_sections, self.num_timeslots), dtype=numpy.bool) self.section_start_schedules = numpy.zeros((self.num_sections, self.num_timeslots), dtype=numpy.bool) self.section_capacities = numpy.zeros((self.num_sections,), dtype=numpy.uint32) self.section_overlap = numpy.zeros((self.num_sections, self.num_sections), dtype=numpy.bool) # One array to keep track of the utility of each student # (defined as hours of interested class + 1.5*hours of priority classes) # and the other arrary to keep track of student weigths (defined as # of classes signed up for) self.student_utility_weights = numpy.zeros((self.num_students, ), dtype=numpy.float) self.student_utilities = numpy.zeros((self.num_students, ), dtype=numpy.float) # Get student, section, timeslot IDs and prepare lookup table (self.student_ids, self.student_indices) = self.get_ids_and_indices(self.lotteried_students) (self.section_ids, self.section_indices) = self.get_ids_and_indices(self.sections) (self.timeslot_ids, self.timeslot_indices) = self.get_ids_and_indices(self.timeslots) self.parent_classes = numpy.array(self.sections.values_list('parent_class__id', flat=True)) # Get IDs of timeslots allocated to lunch by day # (note: requires that this is constant across days) self.lunch_schedule = numpy.zeros((self.num_timeslots,)) lunch_timeslots = Event.objects.filter(meeting_times__parent_class__parent_program=self.program, meeting_times__parent_class__category__category='Lunch').order_by('start').distinct() # Note: this code should not be necessary once lunch-constraints branch is merged (provides Program.dates()) dates = [] for ts in self.timeslots: ts_day = date(ts.start.year, ts.start.month, ts.start.day) if ts_day not in dates: dates.append(ts_day) lunch_by_day = [[] for x in dates] ts_count = 0 for ts in lunch_timeslots: d = date(ts.start.year, ts.start.month, ts.start.day) lunch_by_day[dates.index(d)].append(ts.id) self.lunch_schedule[self.timeslot_indices[ts.id]] = True self.lunch_timeslots = numpy.array(lunch_by_day) # Populate interest matrix; this uses both the StudentRegistrations (which apply to a particular section) and StudentSubjectIntegests (which apply to all sections of the class). If one does not exist, ignore it. Be careful to only return SRs and SSIs for accepted sections of accepted classes; this might matter for SSIs where only some sections of the class are accepted. interest_regs_sr = StudentRegistration.valid_objects().filter(section__parent_class__parent_program=self.program, section__status__gt=0, section__parent_class__status__gt=0, section__registration_status=0, section__meeting_times__isnull=False, relationship__name='Interested').values_list('user__id', 'section__id').distinct() interest_regs_ssi = StudentSubjectInterest.valid_objects().filter(subject__parent_program=self.program, subject__status__gt=0, subject__sections__status__gt=0, subject__sections__registration_status=0, subject__sections__meeting_times__isnull=False).values_list('user__id', 'subject__sections__id').distinct() self.put_prefs_in_array(interest_regs_sr, self.interest) self.put_prefs_in_array(interest_regs_ssi, self.interest) # Populate priority matrix priority_regs = [StudentRegistration.valid_objects().filter(section__parent_class__parent_program=self.program, relationship__name='Priority/%s'%i).values_list('user__id', 'section__id').distinct() for i in range(self.real_priority_limit+1)] if self.grade_range_exceptions: priority_regs.append(StudentRegistration.valid_objects().filter(section__parent_class__parent_program=self.program, relationship__name='GradeRangeException').values_list('user__id', 'section__id').distinct()) for i in range(1,self.effective_priority_limit+1): self.put_prefs_in_array(priority_regs[i], self.priority[i]) if self.options['use_student_apps']: for i in range(1,self.effective_priority_limit+1): for (student_id,section_id) in priority_regs[i]: self.ranks[self.student_indices[student_id],self.section_indices[section_id]] = ESPUser.getRankInClass(student_id,self.parent_classes[self.section_indices[section_id]]) for (student_id,section_id) in interest_regs_sr + interest_regs_ssi: self.ranks[self.student_indices[student_id],self.section_indices[section_id]] = ESPUser.getRankInClass(student_id,self.parent_classes[self.section_indices[section_id]]) # Set student utility weights. Counts number of classes that students selected. Used only for computing the overall_utility stat self.student_utility_weights = numpy.sum(self.interest.astype(float), 1) + sum([numpy.sum(self.priority[i].astype(float), 1) for i in range(1,self.effective_priority_limit+1)]) # Populate section schedule section_times = numpy.array(self.sections.values_list('id', 'meeting_times__id')) start_times = numpy.array(self.sections.annotate(start_time=Min('meeting_times')).values_list('id','start_time')) self.section_schedules[self.section_indices[section_times[:, 0]], self.timeslot_indices[section_times[:, 1]]] = True self.section_start_schedules[self.section_indices[start_times[:, 0]], self.timeslot_indices[start_times[:, 1]]] = True # Populate section overlap matrix for i in range(self.num_sections): group_ids = numpy.nonzero(self.parent_classes == self.parent_classes[i])[0] self.section_overlap[numpy.meshgrid(group_ids, group_ids)] = True # Populate section grade limits self.section_grade_min = numpy.array(self.sections.values_list('parent_class__grade_min', flat=True), dtype=numpy.uint32) self.section_grade_max = numpy.array(self.sections.values_list('parent_class__grade_max', flat=True), dtype=numpy.uint32) # Populate student grades; grade will be assumed to be 0 if not entered on profile self.student_grades = numpy.zeros((self.num_students,)) gradyear_pairs = numpy.array(RegistrationProfile.objects.filter(user__id__in=list(self.student_ids), most_recent_profile=True, student_info__graduation_year__isnull=False).values_list('user__id', 'student_info__graduation_year'), dtype=numpy.uint32) self.student_grades[self.student_indices[gradyear_pairs[:, 0]]] = 12 + ESPUser.program_schoolyear(self.program) - gradyear_pairs[:, 1] # Find section capacities (TODO: convert to single query) for sec in self.sections: self.section_capacities[self.section_indices[sec.id]] = sec.capacity # Populate section lengths (hours) self.section_lengths = numpy.array([x.nonzero()[0].size for x in self.section_schedules]) if self.options['fill_low_priorities']: # Compute who has a priority when. Includes lower priorities, since this is used for places where we check not clobbering priorities. self.has_priority = [numpy.zeros((self.num_students, self.num_timeslots), dtype=numpy.bool) for i in range(self.effective_priority_limit+1)] for i in range(1,self.effective_priority_limit+1): priority_at_least_i = reduce(operator.or_,[self.priority[j] for j in range(i,self.effective_priority_limit+1)]) numpy.dot(priority_at_least_i,self.section_schedules,out=self.has_priority[i]) self.sections_at_same_time = numpy.dot(self.section_schedules, numpy.transpose(self.section_schedules)) # And the same, overlappingly. self.has_overlapping_priority = [numpy.zeros((self.num_students, self.num_timeslots), dtype=numpy.bool) for i in range(self.effective_priority_limit+1)] for i in range(1,self.effective_priority_limit+1): priority_at_least_i = reduce(operator.or_,[self.priority[j] for j in range(i,self.effective_priority_limit+1)]) numpy.dot(numpy.dot(priority_at_least_i,self.sections_at_same_time),self.section_schedules,out=self.has_overlapping_priority[i]) # Fill in preferences for students who haven't ranked them. In particular, if a student has ranked some level of class in a timeblock (i.e. they plan to be at Splash that timeblock), but has not ranked any priority/n or lower-priority classes overlapping it, add a random class from their interesteds. for i in range(1,self.real_priority_limit+1): #Use self.real_priority_limit since we don't want to give people free grade range exceptions! should_fill = numpy.transpose(numpy.nonzero(self.has_priority[1]&~self.has_overlapping_priority[i])) if len(should_fill): for student, timeslot in should_fill: # student is interested, and class starts in this timeslot, and class does not overlap any lower or equal priorities possible_classes = numpy.nonzero(self.interest[student] & self.section_start_schedules[:,timeslot] & ~numpy.dot(self.section_schedules, numpy.transpose(self.has_priority[i][student])))[0] if len(possible_classes): choice = numpy.random.choice(possible_classes) self.priority[i][student,choice]=True
def get_regdate(self, ordering='start_date'): regs = StudentRegistration.valid_objects().filter(user=self.user, section__parent_class__parent_program=self.program, relationship__name='Enrolled') if regs.exists(): return regs.order_by(ordering).values_list('start_date', flat=True)[0].strftime("%Y-%m-%d %H:%M:%S")
from django.db.models.aggregates import Min parser = argparse.ArgumentParser(description='Unenroll missing students from classes.') parser.add_argument('program_id', type=int, help='ID of the current program') parser.add_argument('--per-hour', dest='per_hour', action='store_true', help='Include this argument to clear registrations only for classes starting in the next 60 minutes.') args = parser.parse_args() enrolled = RegistrationType.objects.get(name='Enrolled') prog = Program.objects.get(id=args.program_id) relevant_sections = prog.sections().annotate(begin_time=Min("meeting_times__start")).filter(status=10, parent_class__status=10).exclude(parent_class__category__category='Lunch') # classes that started more than 60 minutes ago passed_sections = relevant_sections.filter(begin_time__lt=datetime.now() - timedelta(minutes=60)) # students who are enrolled in a class that started more than 60 minutes ago, who have not checked in students = ESPUser.objects.filter(studentregistration__in=StudentRegistration.valid_objects(), studentregistration__relationship=enrolled, studentregistration__section__in=passed_sections).distinct().exclude(record__program=prog, record__event='attended') # classes that start in the next 60 minutes upcoming_sections = relevant_sections.filter(begin_time__gt=datetime.now()) if args.per_hour: upcoming_sections = upcoming_sections.filter(begin_time__lt=datetime.now() + timedelta(minutes=60)) # registrations of missing students for upcoming classes registrations = StudentRegistration.valid_objects().filter(user__in=students, section__in=upcoming_sections, relationship=enrolled) print "Candidate Registrations to Delete:", len(registrations) print registrations cmd_str = raw_input("Would you like to delete these registrations [y/N]? --> ") if cmd_str.strip().lower() == 'y': registrations.update(end_date=datetime.now()) print 'Expired:', registrations else: print 'Action cancelled.'
def classchangerequest(self, request, tl, one, two, module, extra, prog): timeslots = prog.getTimeSlots() sections = prog.sections().filter( status=10, meeting_times__isnull=False).distinct() enrollments = {} for timeslot in timeslots: try: enrollments[timeslot] = ClassSubject.objects.get( nest_Q(StudentRegistration.is_valid_qobject(), 'sections__studentregistration'), sections__studentregistration__relationship__name= "Enrolled", sections__studentregistration__user=request.user, sections__meeting_times=timeslot, parent_program=prog) except ClassSubject.DoesNotExist: enrollments[timeslot] = None context = {} context['timeslots'] = timeslots context['enrollments'] = enrollments context['user'] = request.user if 'success' in request.GET: context['success'] = True else: context['success'] = False if request.user.isStudent(): sections_by_slot = dict([(timeslot, [ (section, 1 == StudentRegistration.valid_objects().filter( user=context['user'], section=section, relationship__name="Request").count()) for section in sections if section.get_meeting_times()[0] == timeslot and section.parent_class.grade_min <= request.user.getGrade( prog) <= section.parent_class.grade_max and section.parent_class not in enrollments.values() and ESPUser. getRankInClass(request.user, section.parent_class) in (5, 10) ]) for timeslot in timeslots]) else: sections_by_slot = dict([(timeslot, [ (section, False) for section in sections if section.get_meeting_times()[0] == timeslot ]) for timeslot in timeslots]) fields = {} for i, timeslot in enumerate(sections_by_slot.keys()): choices = [('0', "I'm happy with my current enrollment.")] initial = '0' for section in sections_by_slot[timeslot]: choices.append( (section[0].emailcode(), section[0].emailcode() + ": " + section[0].title())) if section[1]: initial = section[0].emailcode() fields['timeslot_' + str(i + 1)] = forms.ChoiceField( label="Timeslot " + str(i + 1) + " (" + timeslot.pretty_time() + ")", choices=choices, initial=initial) form = type('ClassChangeRequestForm', (forms.Form, ), fields) context['form'] = form() if request.method == "POST": old_requests = StudentRegistration.valid_objects().filter( user=context['user'], section__parent_class__parent_program=prog, relationship__name="Request") for r in old_requests: r.expire() form = form(request.POST) if form.is_valid(): for value in form.cleaned_data.values(): section = None for s in sections: if s.emailcode() == value: section = s break if not section: continue r = StudentRegistration.valid_objects().get_or_create( user=context['user'], section=section, relationship=RegistrationType.objects.get_or_create( name="Request", category="student")[0])[0] r.save() return HttpResponseRedirect( request.path.rstrip('/') + '/?success') else: return render_to_response( self.baseDir() + 'classchangerequest.html', request, context)
def initialize(self): """ Gather all of the information needed to run the lottery assignment. This includes: - Students' interest (priority and interested bits) - Class schedules and capacities - Timeslots (incl. lunch periods for each day) """ self.interest = numpy.zeros((self.num_students, self.num_sections), dtype=numpy.bool) self.priority = numpy.zeros((self.num_students, self.num_sections), dtype=numpy.bool) self.section_schedules = numpy.zeros( (self.num_sections, self.num_timeslots), dtype=numpy.bool) self.section_capacities = numpy.zeros((self.num_sections, ), dtype=numpy.uint32) self.section_overlap = numpy.zeros( (self.num_sections, self.num_sections), dtype=numpy.bool) # One array to keep track of the utility of each student # (defined as hours of interested class + 1.5*hours of priority classes) # and the other arrary to keep track of student weigths (defined as # of classes signed up for) self.student_utility_weights = numpy.zeros((self.num_students, ), dtype=numpy.float) self.student_utilities = numpy.zeros((self.num_students, ), dtype=numpy.float) # Get student, section, timeslot IDs and prepare lookup table (self.student_ids, self.student_indices) = self.get_ids_and_indices( self.program.students()['lotteried_students']) (self.section_ids, self.section_indices) = self.get_ids_and_indices( self.program.sections().filter(status__gt=0, registration_status=0)) (self.timeslot_ids, self.timeslot_indices) = self.get_ids_and_indices( self.program.getTimeSlots()) # Get IDs of timeslots allocated to lunch by day # (note: requires that this is constant across days) self.lunch_schedule = numpy.zeros((self.num_timeslots, )) lunch_timeslots = Event.objects.filter( meeting_times__parent_class__parent_program=self.program, meeting_times__parent_class__category__category='Lunch').order_by( 'start').distinct() # Note: this code should not be necessary once lunch-constraints branch is merged (provides Program.dates()) dates = [] for ts in self.program.getTimeSlots(): ts_day = date(ts.start.year, ts.start.month, ts.start.day) if ts_day not in dates: dates.append(ts_day) lunch_by_day = [[] for x in dates] ts_count = 0 for ts in lunch_timeslots: d = date(ts.start.year, ts.start.month, ts.start.day) lunch_by_day[dates.index(d)].append(ts.id) self.lunch_schedule[self.timeslot_indices[ts.id]] = True for i in range(len(lunch_by_day)): if len(lunch_by_day[i]) > ts_count: ts_count = len(lunch_by_day[i]) self.lunch_timeslots = numpy.zeros((len(lunch_by_day), ts_count), dtype=numpy.int32) for i in range(len(lunch_by_day)): self.lunch_timeslots[i, :len(lunch_by_day[i])] = numpy.array( lunch_by_day[i]) # Populate interest matrix interest_regs = StudentRegistration.valid_objects().filter( section__parent_class__parent_program=self.program, relationship__name='Interested').values_list( 'user__id', 'section__id').distinct() ira = numpy.array(interest_regs, dtype=numpy.uint32) self.interest[self.student_indices[ira[:, 0]], self.section_indices[ira[:, 1]]] = True # Populate priority matrix priority_regs = StudentRegistration.valid_objects().filter( section__parent_class__parent_program=self.program, relationship__name='Priority/1').values_list( 'user__id', 'section__id').distinct() pra = numpy.array(priority_regs, dtype=numpy.uint32) self.priority[self.student_indices[pra[:, 0]], self.section_indices[pra[:, 1]]] = True # Set student utility weights. Counts number of classes that students selected. Used only for computing the overall_utility stat # NOTE: Uses fixed (interest + priority) formula, needs attention when multiple priority levels are merged. self.student_utility_weights = numpy.sum( self.interest.astype(float), 1) + numpy.sum( self.priority.astype(float), 1) # Populate section schedule section_times = numpy.array(self.program.sections().filter( status__gt=0, registration_status=0).filter( meeting_times__id__isnull=False).distinct().values_list( 'id', 'meeting_times__id')) self.section_schedules[self.section_indices[section_times[:, 0]], self.timeslot_indices[section_times[:, 1]]] = True # Populate section overlap matrix parent_classes = numpy.array(self.program.sections().filter( status__gt=0, registration_status=0).order_by('id').values_list( 'parent_class__id', flat=True)) for i in range(self.num_sections): group_ids = numpy.nonzero(parent_classes == parent_classes[i])[0] self.section_overlap[numpy.meshgrid(group_ids, group_ids)] = True # Populate section grade limits self.section_grade_min = numpy.array(self.program.sections().filter( status__gt=0, registration_status=0).order_by('id').values_list( 'parent_class__grade_min', flat=True), dtype=numpy.uint32) self.section_grade_max = numpy.array(self.program.sections().filter( status__gt=0, registration_status=0).order_by('id').values_list( 'parent_class__grade_max', flat=True), dtype=numpy.uint32) # Populate student grades; grade will be assumed to be 0 if not entered on profile self.student_grades = numpy.zeros((self.num_students, )) gradyear_pairs = numpy.array(RegistrationProfile.objects.filter( user__id__in=list(self.student_ids), most_recent_profile=True, student_info__graduation_year__isnull=False).values_list( 'user__id', 'student_info__graduation_year'), dtype=numpy.uint32) self.student_grades[self.student_indices[ gradyear_pairs[:, 0]]] = 12 + ESPUser.current_schoolyear( ) - gradyear_pairs[:, 1] # Find section capacities (TODO: convert to single query) for sec in self.program.sections().filter(status__gt=0, registration_status=0): self.section_capacities[self.section_indices[ sec.id]] = sec.capacity # Populate section lengths (hours) self.section_lengths = numpy.array( [x.nonzero()[0].size for x in self.section_schedules])
args = parser.parse_args() enrolled = RegistrationType.objects.get(name='Enrolled') prog = Program.objects.get(id=args.program_id) relevant_sections = prog.sections().annotate( begin_time=Min("meeting_times__start")).filter( status=10, parent_class__status=10).exclude( parent_class__category__category='Lunch') # classes that started more than 60 minutes ago passed_sections = relevant_sections.filter(begin_time__lt=datetime.now() - timedelta(minutes=60)) # students who are enrolled in a class that started more than 60 minutes ago, who have not checked in students = ESPUser.objects.filter( studentregistration__in=StudentRegistration.valid_objects(), studentregistration__relationship=enrolled, studentregistration__section__in=passed_sections).distinct().exclude( record__program=prog, record__event='attended') # classes that start in the next 60 minutes upcoming_sections = relevant_sections.filter(begin_time__gt=datetime.now()) if args.per_hour: upcoming_sections = upcoming_sections.filter( begin_time__lt=datetime.now() + timedelta(minutes=60)) # registrations of missing students for upcoming classes registrations = StudentRegistration.valid_objects().filter( user__in=students, section__in=upcoming_sections, relationship=enrolled) print "Candidate Registrations to Delete:", len(registrations) print registrations cmd_str = raw_input("Would you like to delete these registrations [y/N]? --> ")
def classchangerequest(request, tl, one, two): from esp.program.models import Program, StudentAppResponse, StudentRegistration, RegistrationType from esp.program.models.class_ import ClassSubject from urllib import quote try: prog = Program.by_prog_inst(one, two) #DataTree.get_by_uri(treeItem) except Program.DoesNotExist: raise Http404("Program not found.") if tl != "learn": raise Http404 if not request.user or not request.user.is_authenticated(): return HttpResponseRedirect( '%s?%s=%s' % (LOGIN_URL, REDIRECT_FIELD_NAME, quote(request.get_full_path()))) if not request.user.isStudent() and not request.user.isAdmin(prog): allowed_student_types = Tag.getTag("allowed_student_types", prog, default='') matching_user_types = any( x in request.user.groups.all().values_list("name", flat=True) for x in allowed_student_types.split(",")) if not matching_user_types: return render_to_response('errors/program/notastudent.html', request, {}) errorpage = 'errors/program/wronggrade.html' cur_grade = request.user.getGrade(prog) if (not Permission.user_has_perm( request.user, 'GradeOverride', program=prog) and (cur_grade != 0 and (cur_grade < prog.grade_min or cur_grade > prog.grade_max))): return render_to_response(errorpage, request, {}) setattr(request, "program", prog) setattr(request, "tl", tl) setattr(request, "module", "classchangerequest") from django import forms from datetime import datetime from esp.utils.scheduling import getRankInClass timeslots = prog.getTimeSlots() sections = prog.sections().filter(status=10) enrollments = {} for timeslot in timeslots: try: enrollments[timeslot] = ClassSubject.objects.get( nest_Q(StudentRegistration.is_valid_qobject(), 'sections__studentregistration'), sections__studentregistration__relationship__name="Enrolled", sections__studentregistration__user=request.user, sections__meeting_times=timeslot, parent_program=prog) except ClassSubject.DoesNotExist: enrollments[timeslot] = None context = {} context['timeslots'] = timeslots context['enrollments'] = enrollments context['user'] = request.user if 'success' in request.GET: context['success'] = True else: context['success'] = False if request.user.isStudent(): sections_by_slot = dict([(timeslot, [ (section, 1 == StudentRegistration.valid_objects().filter( user=context['user'], section=section, relationship__name="Request").count()) for section in sections if section.get_meeting_times()[0] == timeslot and section.parent_class.grade_min <= request.user.getGrade( prog) <= section.parent_class.grade_max and section.parent_class not in enrollments.values() and getRankInClass(request.user, section) in (5, 10) ]) for timeslot in timeslots]) else: sections_by_slot = dict([(timeslot, [ (section, False) for section in sections if section.get_meeting_times()[0] == timeslot ]) for timeslot in timeslots]) fields = {} for i, timeslot in enumerate(sections_by_slot.keys()): choices = [('0', "I'm happy with my current enrollment.")] initial = '0' for section in sections_by_slot[timeslot]: choices.append( (section[0].emailcode(), section[0].emailcode() + ": " + section[0].title())) if section[1]: initial = section[0].emailcode() fields['timeslot_' + str(i + 1)] = forms.ChoiceField( label="Timeslot " + str(i + 1) + " (" + timeslot.pretty_time() + ")", choices=choices, initial=initial) form = type('ClassChangeRequestForm', (forms.Form, ), fields) context['form'] = form() if request.method == "POST": old_requests = StudentRegistration.valid_objects().filter( user=context['user'], section__parent_class__parent_program=prog, relationship__name="Request") for r in old_requests: r.expire() form = form(request.POST) if form.is_valid(): for value in form.cleaned_data.values(): section = None for s in sections: if s.emailcode() == value: section = s break if not section: continue r = StudentRegistration.objects.get_or_create( user=context['user'], section=section, relationship=RegistrationType.objects.get_or_create( name="Request", category="student")[0])[0] r.end_date = datetime(9999, 1, 1, 0, 0, 0, 0) r.save() return HttpResponseRedirect(request.path.rstrip('/') + '/?success') else: return render_to_response('program/classchangerequest.html', request, context)
def enrollment_status(self, request, tl, one, two, module, extra, prog): resp = HttpResponse(content_type='application/json') data = StudentRegistration.valid_objects().filter(section__status__gt=0, section__parent_class__status__gt=0, section__parent_class__parent_program=prog, relationship__name='Enrolled').values_list('user__id', 'section__id') json.dump(list(data), resp) return resp
def select_students(self, request, tl, one, two, module, extra, prog): # Get preregistered and enrolled students try: sec = ClassSection.objects.get(id=extra) except (ValueError, ClassSection.DoesNotExist): raise ESPError( 'Class section not found. If you came from a link on our site, please notify the webmasters.', log=False) students_list = sec.students_prereg() if request.method == 'POST': # Handle form submission # result_strs = [] data = request.POST.copy() sections_dict = {} for key in data: key_dir = key.split('_') if key_dir[0] == 'regstatus' and len(key_dir) == 3: student_id = int(key_dir[1]) sec_id = int(key_dir[2]) if sec_id not in sections_dict: sections_dict[sec_id] = [{ 'id': student_id, 'status': data[key] }] else: sections_dict[sec_id].append({ 'id': student_id, 'status': data[key] }) for sec_id in sections_dict: sec = ClassSection.objects.get(id=sec_id) sec.cache['students'] = None sec.cache['num_students'] = None for item in sections_dict[sec_id]: student = ESPUser.objects.get(id=item['id']) ignore = False value = item['status'] if value == 'enroll': verb_name = 'Enrolled' elif value == 'reject': verb_name = 'Rejected' else: ignore = True if not ignore: rel = RegistrationType.get_map( include=['Enrolled', 'Rejected'], category='student')[verb_name] other_regs = sec.getRegistrations(student).filter( relationship__name__in=['Enrolled', 'Rejected']) found = False for reg in other_regs: if not found and reg.relationship == rel: found = True else: reg.expire() if not found: new_reg = StudentRegistration(user=student, relationship=rel, section=sec) new_reg.save() # Jazz up this information a little #Not having much luck with query count/performance when selecting related parent_class and parent_class__category #Creating a lookup dict instead to strip out duplicate ClassSubject instances student_regs = StudentRegistration.valid_objects().filter(user__in=students_list) \ .order_by('start_date').select_related('section','user','relationship') student_regs = student_regs.filter( section__parent_class__parent_program=self.program) student_sections_dict = defaultdict(set) student_reg_dict = defaultdict(set) #need a unique set of parent_class ids #creating lookup dicts to avoid hitting database(was not solved with #select_related or prefecth_related parent_class_id_set = set() sections = set() for reg in student_regs: student_sections_dict[reg.user].add(reg.section) display_name = reg.relationship.displayName or reg.relationship.name sections.add(reg.section) parent_class_id_set.add(reg.section.parent_class_id) student_reg_dict['%i_%i' % ( reg.user.id, reg.section.id, )].add(display_name) subjects = ClassSubject.objects.filter( id__in=parent_class_id_set).select_related('category') subject_categories_dict = dict([(s.id, (s, s.category)) for s in subjects]) for student in students_list: student.bits = student_reg_dict['%i_%i' % ( student.id, sec.id, )] #this is a bit of a problem because it produces the side affect of application #creation if not found student.app = student.getApplication(self.program, False) student.other_classes = [] for section in student_sections_dict[student]: parent_class, category = subject_categories_dict.get( section.parent_class_id) regtypes = student_reg_dict['%i_%i' % ( student.id, section.id, )] section_row = (section, regtypes, parent_class, category) student.other_classes.append(section_row) preregs = sec.getRegistrations(student).exclude( relationship__name__in=['Enrolled', 'Rejected']) if preregs.count() != 0: student.added_class = preregs[0].start_date if 'Enrolled' in student.bits: student.enrolled = True elif 'Rejected' in student.bits: student.rejected = True # Detect if there is an application module from esp.program.modules.handlers.studentjunctionappmodule import StudentJunctionAppModule has_app_module = False for module in prog.getModules(): if isinstance(module, StudentJunctionAppModule): has_app_module = True return render_to_response( self.baseDir() + 'select_students.html', request, { 'has_app_module': has_app_module, 'prog': prog, 'sec': sec, 'students_list': students_list })
# Adds lunches in an empty block for users who don't have one. Chooses the # lunch randomly for users with both lunch blocks free. from script_setup import * import random from esp.cal.models import Event from esp.program.models import Program, StudentRegistration, RegistrationType from esp.program.models.class_ import ClassSection from esp.users.models import ESPUser program = Program.objects.get(id=115) # Change me! (Splash 2014) relationship = RegistrationType.objects.get(name='Enrolled') srs = StudentRegistration.valid_objects().filter( section__parent_class__parent_program=program, relationship=relationship) srs_pairs = srs.values_list('user', 'section') users = ESPUser.objects.filter(id__in=srs.values_list('user')) sections = ClassSection.objects.filter( parent_class__parent_program=program).prefetch_related('meeting_times') timeblocks = Event.objects.filter(program=program, event_type__description='Class Time Block') users_by_id = {user.id: user for user in users} sections_by_id = {section.id: section for section in sections} timeblocks_by_id = {timeblock.id: timeblock for timeblock in timeblocks} sections_by_user_timeblock = { (user_id, timeblock.id): section_id for user_id, section_id in srs_pairs
def review_students(self, request, tl, one, two, module, extra, prog): try: cls = ClassSubject.objects.get(id = extra) except ClassSubject.DoesNotExist: raise ESPError('Cannot find class.', log=False) if not request.user.canEdit(cls): raise ESPError('You cannot edit class "%s"' % cls, log=False) # Fetch any student even remotely related to the class. students_dict = cls.students_dict() students = [] for key in students_dict: students += students_dict[key] for student in students: now = datetime.now() student.added_class = StudentRegistration.valid_objects().filter(section__parent_class = cls, user = student)[0].start_date try: student.app = student.studentapplication_set.get(program = self.program) except: student.app = None if student.app: reviews = student.app.reviews.all().filter(reviewer=request.user, score__isnull=False) questions = student.app.questions.all().filter(subject=cls) else: reviews = [] questions = [] if len(reviews) > 0: student.app_reviewed = reviews[0] else: student.app_reviewed = None student.app_completed = False for i in questions: for j in i.studentappresponse_set.all(): if j.complete: student.app_completed = True students = list(students) students.sort(lambda x,y: cmp(x.added_class,y.added_class)) if 'prev' in request.GET: prev_id = int(request.GET.get('prev')) prev = students[0] current = None for current in students[1:]: if prev.id == prev_id and current.app_completed: from django.shortcuts import redirect url = "/%s/%s/%s/review_student/%s/?student=%s" % (tl, one, two, extra, current.id) return redirect(url) if prev.id != prev_id: prev = current return render_to_response(self.baseDir()+'roster.html', request, {'class': cls, 'students':students})
def isCompleted(self): return StudentRegistration.valid_objects().filter( user=get_current_request().user, relationship__name="Request").exists()
def isCompleted(self): return bool(StudentRegistration.valid_objects().filter(section__parent_class__parent_program=self.program, user=get_current_request().user))
def isCompleted(self): return bool(StudentRegistration.valid_objects().filter( section__parent_class__parent_program=self.program, user=get_current_request().user))
def num_priority1s(self, prog): return StudentRegistration.valid_objects().filter( relationship__name='Priority/1', section__parent_class__parent_program=prog).count()
def isCompleted(self): return StudentRegistration.valid_objects().filter(user=get_current_request().user, relationship__name="Request").exists()