def medliab(self, request, tl, one, two, module, extra, prog): """ Landing page redirecting to med-liab form on Formstack. """ t = Tag.getProgramTag("formstack_id", self.program) v = Tag.getProgramTag("formstack_viewkey", self.program) context = {"formstack_id": t, "formstack_viewkey": v} return render_to_response(self.baseDir()+'medliab.html', request, context)
def medliab(self, request, tl, one, two, module, extra, prog): """ Landing page redirecting to med-liab form on Formstack. """ t = Tag.getProgramTag("formstack_id", self.program) v = Tag.getProgramTag("formstack_viewkey", self.program) context = {"formstack_id": t, "formstack_viewkey": v} return render_to_response(self.baseDir() + 'medliab.html', request, context)
def render_class_core_helper(cls, prog=None, scrmi=None, colorstring=None, collapse_full_classes=None): if not prog: prog = cls.parent_program # Show e-mail codes? We need to look in the settings. if not scrmi: scrmi = cls.parent_program.getModuleExtension('StudentClassRegModuleInfo') # Okay, chose a program? Good. Now fetch the color from its hiding place and format it... if not colorstring: colorstring = prog.getColor() if colorstring is not None: colorstring = ' background-color:#' + colorstring + ';' # HACK for Harvard HSSP -- show application counts with enrollment #if cls.studentappquestion_set.count(): # cls._sections = list(cls.get_sections()) # for sec in cls._sections: # sec.num_apps = sec.num_students(verbs=['Applied']) # Allow tag configuration of whether class descriptions get collapsed # when the class is full (default: yes) if collapse_full_classes is None: collapse_full_classes = ('false' not in Tag.getProgramTag('collapse_full_classes', prog, 'True').lower()) return {'class': cls, 'collapse_full': collapse_full_classes, 'colorstring': colorstring, 'show_enrollment': scrmi.visible_enrollments, 'show_emailcodes': scrmi.show_emailcodes, 'show_meeting_times': scrmi.visible_meeting_times}
def __init__(self, *args, **kwargs): # Extract a program if one was provided if 'program' in kwargs: program = kwargs['program'] del kwargs['program'] else: program = None # Run default init function super(SplashInfoForm, self).__init__(*args, **kwargs) # Set choices from Tag data (try to get program-specific choices if they exist) tag_data = None if program: tag_data = Tag.getProgramTag('splashinfo_choices', program) if not tag_data: tag_data = Tag.getTag('splashinfo_choices') if tag_data: tag_struct = json.loads(tag_data) self.fields['lunchsat'].choices = tag_struct['lunchsat'] self.fields['lunchsun'].choices = tag_struct['lunchsun'] if not Tag.getBooleanTag('splashinfo_siblingdiscount', default=True): del self.fields['siblingdiscount'] del self.fields['siblingname'] if not Tag.getBooleanTag('splashinfo_lunchsat', default=True): del self.fields['lunchsat'] if not Tag.getBooleanTag('splashinfo_lunchsun', default=True): del self.fields['lunchsun']
def get_forms(self, reg_data, form_class=TeacherClassRegForm): reg_form = form_class(self.crmi, reg_data) static_resource_requests = Tag.getProgramTag( 'static_resource_requests', self.program, ) try: resource_formset = ResourceRequestFormSet( reg_data, prefix='request', static_resource_requests=static_resource_requests, ) except ValidationError: resource_formset = None try: restype_formset = ResourceTypeFormSet(reg_data, prefix='restype') except ValidationError: restype_formset = None if not reg_form.is_valid() or ( resource_formset and not resource_formset.is_valid()) or ( restype_formset and not restype_formset.is_valid()): raise ClassCreationValidationError, ( reg_form, resource_formset, restype_formset, "Invalid form data. Please make sure you are using the official registration form, on esp.mit.edu. If you are, please let us know how you got this error." ) return reg_form, resource_formset, restype_formset
def quiz(self, request, tl, one, two, module, extra, prog): custom_form_id = Tag.getProgramTag('quiz_form_id', prog, None) if custom_form_id: cf = Form.objects.get(id=int(custom_form_id)) else: raise ESPError( 'Cannot find an appropriate form for the quiz. Please ask your administrator to create a form and set the quiz_form_id Tag.' ) form_wizard = FormHandler(cf, request, request.user).get_wizard() form_wizard.curr_request = request if request.method == 'POST': form = form_wizard.get_form(0, request.POST, request.FILES) if form.is_valid(): form_wizard.done([form]) self.controller.markCompleted(request.user) return self.goToCore(tl) else: form = form_wizard.get_form(0) return render_to_response(self.baseDir() + 'quiz.html', request, (prog, tl), { 'prog': prog, 'form': form })
def extraform(self, request, tl, one, two, module, extra, prog): custom_form_id = Tag.getProgramTag('%s_extraform_id' % tl, prog, None) if custom_form_id: cf = Form.objects.get(id=int(custom_form_id)) else: raise ESPError( False ), 'Cannot find an appropriate form for the quiz. Please ask your administrator to create a form and set the %s_extraform_id Tag.' % tl form_wizard = FormHandler(cf, request, request.user).get_wizard() form_wizard.curr_request = request if request.method == 'POST': form = form_wizard.get_form(0, request.POST, request.FILES) if form.is_valid(): # Delete previous responses from this user dmh = DynamicModelHandler(cf) form_model = dmh.createDynModel() form_model.objects.filter(user=request.user).delete() form_wizard.done([form]) bit, created = UserBit.valid_objects().get_or_create( user=request.user, qsc=self.program.anchor, verb=self.reg_verb) return self.goToCore(tl) else: # If the user already filled out the form, use their earlier response for the initial values if self.isCompleted(): dmh = DynamicModelHandler(cf) form_model = dmh.createDynModel() prev_results = form_model.objects.filter( user=request.user).order_by('-id') if prev_results.exists(): prev_result_data = {} plain_form = form_wizard.get_form(0) # Load previous results, with a hack for multiple choice questions. for field in plain_form.fields: if isinstance(plain_form.fields[field], forms.MultipleChoiceField): prev_result_data[field] = getattr( prev_results[0], field).split(';') else: prev_result_data[field] = getattr( prev_results[0], field) form_wizard = FormHandler( cf, request, request.user).get_wizard( initial_data={0: prev_result_data}) form = form_wizard.get_form(0) return render_to_response(self.baseDir() + 'custom_form.html', request, (prog, tl), { 'prog': prog, 'form': form, 'tl': tl })
def phasezero(self, request, tl, one, two, module, extra, prog): context = {} role = str(prog) + " Winners" context['role'] = role q_phasezero = Q(phasezerorecord__program=self.program) entrants = ESPUser.objects.filter(q_phasezero).distinct() context['entrants'] = entrants context['nentrants'] = len(entrants) grades = range(prog.grade_min, prog.grade_max + 1) stats = {} #Calculate grade counts for grade in grades: stats[grade] = {} stats[grade]['in_lottery'] = 0 for entrant in entrants: stats[entrant.getGrade(prog)]['in_lottery'] += 1 #Run lottery if requested if request.POST: if Tag.getBooleanTag('student_lottery_run', prog, default=False): context['error'] = "You've already run the student lottery!" else: if "confirm" in request.POST: if Tag.getProgramTag('program_size_by_grade', prog): role = request.POST['rolename'] context['role'] = role self.lottery(prog, role) context[ 'success'] = "The student lottery has been run successfully." else: context[ 'error'] = "You haven't set the grade caps tag yet." else: context[ 'error'] = "You did not confirm that you would like to run the lottery" #If lottery has been run, calculate acceptance stats if Tag.getBooleanTag('student_lottery_run', prog, default=False): for grade in grades: stats[grade]['num_accepted'] = stats[grade]['per_accepted'] = 0 winners = ESPUser.objects.filter(groups__name=role).distinct() for winner in winners: stats[winner.getGrade(prog)]['num_accepted'] += 1 for grade in grades: if stats[grade]['in_lottery'] == 0: stats[grade]['per_accepted'] = "NA" else: stats[grade]['per_accepted'] = round( stats[grade]['num_accepted'], 1) / stats[grade]['in_lottery'] * 100 context['stats'] = stats return render_to_response( 'program/modules/studentregphasezero/status.html', request, context)
def apply_settings(self): # Rather than using a model in module_ext.*, configure the module # from a Tag (which can be per-program or global), combining the # Tag's specifications with defaults in the code. DEFAULTS = { 'donation_text': 'Donation to Learning Unlimited', 'donation_options': [10, 20, 50], } tag_data = json.loads(Tag.getProgramTag('donation_settings', self.program, "{}")) self.settings = DEFAULTS.copy() self.settings.update(tag_data) return self.settings
def submit_transaction(request): # We might also need to forward post variables to http://shopmitprd.mit.edu/controller/index.php?action=log_transaction if request.POST.has_key( "decision") and request.POST["decision"] != "REJECT": # Figure out which user and program the payment are for. post_identifier = request.POST.get('merchantDefinedData1', '') iac = IndividualAccountingController.from_identifier(post_identifier) post_amount = Decimal(request.POST.get('orderAmount', '0.0')) # Warn for possible duplicate payments prev_payments = iac.get_transfers().filter( line_item=iac.default_payments_lineitemtype()) if prev_payments.count() > 0 and iac.amount_due() <= 0: from django.conf import settings recipient_list = [contact[1] for contact in settings.ADMINS] recipient_list.append(settings.DEFAULT_EMAIL_ADDRESSES['treasury']) refs = 'Cybersource request ID: %s' % post_identifier subject = 'Possible Duplicate Postback/Payment' refs = 'User: %s (%d); Program: %s (%d)' % (iac.user.name( ), iac.user.id, iac.program.niceName(), iac.program.id) refs += '\n\nPrevious payments\' Transfer IDs: ' + (u', '.join( [str(x.id) for x in prev_payments])) # Send mail! send_mail('[ ESP CC ] ' + subject + ' by ' + iac.user.first_name + ' ' + iac.user.last_name, \ """%s Notification\n--------------------------------- \n\n%s\n\nUser: %s %s (%s)\n\nCardholder: %s, %s\n\nRequest: %s\n\n""" % \ (subject, refs, request.user.first_name, request.user.last_name, request.user.id, request.POST.get('billTo_lastName', '--'), request.POST.get('billTo_firstName', '--'), request) , \ settings.SERVER_EMAIL, recipient_list, True) # Save the payment as a transfer in the database iac.submit_payment(post_amount) tl = 'learn' one, two = iac.program.url.split('/') destination = Tag.getProgramTag("cc_redirect", iac.program, default="confirmreg") if destination.startswith('/') or '//' in destination: pass else: # simple urls like 'confirmreg' are relative to the program destination = "/%s/%s/%s/%s" % (tl, one, two, destination) return HttpResponseRedirect(destination) return render_to_response('accounting_docs/credit_rejected.html', request, {})
def render(self, context): key = self.key.resolve(context) if self.program: program = self.program.resolve(context) else: program = None if self.default: default = self.default.resolve(context) else: default = None if self.boolean: return str(Tag.getBooleanTag(key, program, default)).lower() else: return str(Tag.getProgramTag(key, program, default))
def prepare(self, context={}): """ prepare returns the context for the main teacherreg page. This will just set the teacherclsmodule as this module, since everything else can be gotten from hooks. """ context['can_edit'] = self.deadline_met('/Classes/Edit') context['can_create'] = self.deadline_met('/Classes/Create') context['teacherclsmodule'] = self # ... context['clslist'] = self.clslist(get_current_request().user) context['friendly_times_with_date'] = (Tag.getProgramTag( key='friendly_times_with_date', program=self.program, default=False) == "True") context['allow_class_import'] = 'false' not in Tag.getTag( 'allow_class_import', default='true').lower() return context
def render_class_teacher_list_row(klass): return { 'cls': klass, 'program': klass.parent_program, 'teacherclsmodule': klass.parent_program.getModuleExtension('ClassRegModuleInfo'), 'friendly_times_with_date': (Tag.getProgramTag(key='friendly_times_with_date', program=klass.parent_program, default=False) == "True"), 'email_host': settings.EMAIL_HOST }
def apply_settings(self): # Rather than using a model in module_ext.*, configure the module # from a Tag (which can be per-program or global), combining the # Tag's specifications with defaults in the code. DEFAULTS = { 'offer_donation': True, 'donation_text': 'Donation to Learning Unlimited', 'donation_options': [10, 20, 50], 'invoice_prefix': settings.INSTITUTION_NAME.lower(), } DEFAULTS.update(settings.STRIPE_CONFIG) tag_data = json.loads(Tag.getProgramTag('stripe_settings', self.program, "{}")) self.settings = DEFAULTS.copy() self.settings.update(tag_data) return self.settings
def __init__(self, program, **kwargs): """ Set constant parameters for a lottery assignment. """ self.program = program if Tag.getProgramTag('program_size_by_grade', self.program): # TODO(benkraft): Consider implementing this. Stanford's use case # as of Fall 2015 (for which program_size_by_grade was written) # doesn't need it, but we might want to implement it anyway, or # remove the program size logic from the lottery entirely. print ("WARNING: The lottery doesn't support the " "program_size_by_grade Tag yet. It will run without a " "program cap, and allow all students who have marked " "preferences to get classes.") self.program_size_max = 0 else: self.program_size_max = self.program.program_size_max students = self.program.students() if 'twophase_star_students' in students: # We can't do the join in SQL, because the query generated takes at least half an hour. So do it in python. stars = set(students['twophase_star_students'].values_list('id',flat=True)) prioritys = set(students['twophase_priority_students'].values_list('id',flat=True)) self.lotteried_students = list(stars|prioritys) elif 'lotteried_students' in students: self.lotteried_students = students['lotteried_students'] else: raise Exception('Cannot retrieve lottery preferences for program, please ensure that it has the lottery module.') self.sections = self.program.sections().filter(status__gt=0, parent_class__status__gt=0, registration_status=0, meeting_times__isnull=False).order_by('id').select_related('parent_class','parent_class__parent_program').prefetch_related('meeting_times').distinct() self.timeslots = self.program.getTimeSlots() self.num_timeslots = len(self.timeslots) self.num_students = len(self.lotteried_students) self.num_sections = len(self.sections) self.real_priority_limit = self.program.priorityLimit() # For most purposes, you probably want to use self.effective_priority_limit instead. self.grade_range_exceptions = self.program.useGradeRangeExceptions() self.effective_priority_limit = self.real_priority_limit + 1 if self.grade_range_exceptions else self.real_priority_limit self.options = LotteryAssignmentController.default_options.copy() self.options.update(kwargs) self.now = datetime.now() numpy.random.seed(self.now.microsecond) self.initialize() if self.options['stats_display']: logger.info('Initialized lottery assignment for %d students, %d sections, %d timeslots', self.num_students, self.num_sections, self.num_timeslots)
def apply_settings(self): # Rather than using a model in module_ext.*, configure the module # from a Tag (which can be per-program or global), combining the # Tag's specifications with defaults in the code. DEFAULTS = { 'offer_donation': True, 'donation_text': 'Donation to Learning Unlimited', 'donation_options': [10, 20, 50], 'invoice_prefix': settings.INSTITUTION_NAME.lower(), } DEFAULTS.update(settings.STRIPE_CONFIG) tag_data = json.loads( Tag.getProgramTag('stripe_settings', self.program, "{}")) self.settings = DEFAULTS.copy() self.settings.update(tag_data) return self.settings
def render(self, context): key = self.key.resolve(context) if self.program: program = self.program.resolve(context) else: program = None if self.default: default = self.default.resolve(context) else: default = None if self.boolean: result = Tag.getBooleanTag(key, program, default) if isinstance(result, bool): return str(result).lower() else: return 'false' else: return str(Tag.getProgramTag(key, program, default))
def getVisibleRegistrationTypeNames(cls, prog, for_VRT_form=False): if not (prog and isinstance(prog, (Program, int))): return set(cls.default_names) if isinstance(prog, int): try: prog = Program.objects.get(pk=prog) except Exception: return set(cls.default_names) display_names = Tag.getProgramTag(key=cls.key, program=prog) if display_names: display_names = simplejson.loads(display_names) + cls.default_names else: display_names = cls.default_names if "All" in display_names: display_names = list(RegistrationType.objects.all().values_list( 'name', flat=True).distinct().order_by('name')) if for_VRT_form: display_names.append("All") return display_names
def special_classroom_types(self): """ Check special classrooms types (music, computer, kitchen). Configuration Tag: special_classroom_types, a dictionary mapping resource request type desired_value regexes to a list of classrooms (by resource ID). Any classroom whose name matches the regex will automatically be included. """ DEFAULT_CONFIG = { r'^.*(computer|cluster).*$': [], r'^.*music.*$': [], r'^.*kitchen.*$': [] } config = json.loads( Tag.getProgramTag('special_classroom_types', program=self.p, default='{}')) config = config if config else DEFAULT_CONFIG HEADINGS = ["Class Section", "Unfulfilled Request", "Current Room"] mismatches = [] for type_regex, matching_rooms in DEFAULT_CONFIG.iteritems(): resource_requests = ResourceRequest.objects.filter( res_type__program=self.p, desired_value__iregex=type_regex) for rr in resource_requests: if all(room.id in matching_rooms or re.match(type_regex, room.name, re.IGNORECASE) for room in rr.target.classrooms()): continue mismatches.append({ HEADINGS[0]: rr.target, HEADINGS[1]: rr.desired_value, HEADINGS[2]: rr.target.classrooms()[0].name }) return self.formatter.format_table( mismatches, {'headings': HEADINGS}, help_text=self.special_classroom_types.__doc__)
def extraform(self, request, tl, one, two, module, extra, prog): custom_form_id = Tag.getProgramTag('%s_extraform_id' % tl, prog, None) if custom_form_id: cf = Form.objects.get(id=int(custom_form_id)) else: raise ESPError('Cannot find an appropriate form for the quiz. Please ask your administrator to create a form and set the %s_extraform_id Tag.' % tl, log=False) form_wizard = FormHandler(cf, request, request.user).get_wizard() form_wizard.curr_request = request if request.method == 'POST': form = form_wizard.get_form(0, request.POST, request.FILES) if form.is_valid(): # Delete previous responses from this user dmh = DynamicModelHandler(cf) form_model = dmh.createDynModel() form_model.objects.filter(user=request.user).delete() form_wizard.done([form]) bit, created = Record.objects.get_or_create(user=request.user, program=self.program, event=self.event) return self.goToCore(tl) else: # If the user already filled out the form, use their earlier response for the initial values if self.isCompleted(): dmh = DynamicModelHandler(cf) form_model = dmh.createDynModel() prev_results = form_model.objects.filter(user=request.user).order_by('-id') if prev_results.exists(): prev_result_data = {} plain_form = form_wizard.get_form(0) # Load previous results, with a hack for multiple choice questions. for field in plain_form.fields: if isinstance(plain_form.fields[field], forms.MultipleChoiceField): prev_result_data[field] = getattr(prev_results[0], field).split(';') else: prev_result_data[field] = getattr(prev_results[0], field) form_wizard = FormHandler(cf, request, request.user).get_wizard(initial_data={0: prev_result_data}) form = form_wizard.get_form(0) return render_to_response(self.baseDir()+'custom_form.html', request, {'prog':prog, 'form': form, 'qsd_name': tl+':customform_header'})
def special_classroom_types(self): """ Check special classrooms types (music, computer, kitchen). Configuration Tag: special_classroom_types, a dictionary mapping resource request type desired_value regexes to a list of classrooms (by resource ID). Any classroom whose name matches the regex will automatically be included. """ DEFAULT_CONFIG = {r'^.*(computer|cluster).*$': [], r'^.*music.*$': [], r'^.*kitchen.*$': []} config = json.loads(Tag.getProgramTag('special_classroom_types', program=self.p, default='{}')) config = config if config else DEFAULT_CONFIG HEADINGS = ["Class Section", "Unfulfilled Request", "Current Room"] mismatches = [] for type_regex, matching_rooms in DEFAULT_CONFIG.iteritems(): resource_requests = ResourceRequest.objects.filter( res_type__program=self.p, desired_value__iregex=type_regex) for rr in resource_requests: if all(room.id in matching_rooms or re.match(type_regex, room.name, re.IGNORECASE) for room in rr.target.classrooms()): continue mismatches.append({ HEADINGS[0]: rr.target, HEADINGS[1]: rr.desired_value, HEADINGS[2]: rr.target.classrooms()[0].name }) return self.formatter.format_table(mismatches, {'headings': HEADINGS}, help_text=self.special_classroom_types.__doc__)
def no_overlap_classes(self): '''Gets a list of classes from the tag no_overlap_classes, and checks that they don't overlap. The tag should contain a dict of {'comment': [list,of,class,ids]}.''' classes = json.loads( Tag.getProgramTag('no_overlap_classes', program=self.p, default="{}")) classes_lookup = { x.id: x for x in ClassSubject.objects.filter( id__in=sum(classes.values(), [])) } bad_classes = [] for key, l in classes.iteritems(): eventtuples = list( Event.objects.filter( meeting_times__parent_class__in=l).values_list( 'description', 'meeting_times', 'meeting_times__parent_class')) overlaps = {} for event, sec, cls in eventtuples: if event in overlaps: overlaps[event].append(classes_lookup[cls]) else: overlaps[event] = [classes_lookup[cls]] for event in overlaps: if len(overlaps[event]) > 1: bad_classes.append({ 'Comment': key, 'Timeblock': event, 'Classes': overlaps[event] }) return self.formatter.format_table( bad_classes, {'headings': ['Comment', 'Timeblock', 'Classes']}, help_text= "Given a list of classes that should not overlap, compute which overlap. This is to be used for example for classes using the same materials which are not tracked by the website, or to check that directors' classes don't overlap. The classes should be put in the Tag no_overlap_classes, in the format of a dictionary with keys various comments (e.g. 'classes using the Quiz Bowl buzzers') and values as corresponding lists of class IDs." )
def no_overlap_classes(self): '''Gets a list of classes from the tag no_overlap_classes, and checks that they don't overlap. The tag should contain a dict of {'comment': [list,of,class,ids]}.''' classes = json.loads(Tag.getProgramTag('no_overlap_classes',program=self.p, default="{}")) classes_lookup = {x.id: x for x in ClassSubject.objects.filter(id__in=sum(classes.values(),[]))} bad_classes = [] for key, l in classes.iteritems(): eventtuples = list(Event.objects.filter(meeting_times__parent_class__in=l).values_list('description', 'meeting_times', 'meeting_times__parent_class')) overlaps = {} for event, sec, cls in eventtuples: if event in overlaps: overlaps[event].append(classes_lookup[cls]) else: overlaps[event]=[classes_lookup[cls]] for event in overlaps: if len(overlaps[event])>1: bad_classes.append({ 'Comment': key, 'Timeblock': event, 'Classes': overlaps[event] }) return self.formatter.format_table(bad_classes, {'headings': ['Comment', 'Timeblock', 'Classes']}, help_text="Given a list of classes that should not overlap, compute which overlap. This is to be used for example for classes using the same materials which are not tracked by the website, or to check that directors' classes don't overlap. The classes should be put in the Tag no_overlap_classes, in the format of a dictionary with keys various comments (e.g. 'classes using the Quiz Bowl buzzers') and values as corresponding lists of class IDs." )
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 catalog_render(self, request, tl, one, two, module, extra, prog, timeslot=None): """ Return the program class catalog """ # using .extra() to select all the category text simultaneously classes = ClassSubject.objects.catalog(self.program) categories = {} for cls in classes: categories[cls.category_id] = { 'id': cls.category_id, 'category': cls.category_txt if hasattr(cls, 'category_txt') else cls.category.category } # Allow tag configuration of whether class descriptions get collapsed # when the class is full (default: yes) collapse_full = ('false' not in Tag.getProgramTag('collapse_full_classes', prog, 'True').lower()) hide_full = Tag.getBooleanTag('hide_full_classes', prog, False) context = { 'classes': classes, 'one': one, 'two': two, 'categories': categories.values(), 'hide_full': hide_full, 'collapse_full': collapse_full } scrmi = prog.getModuleExtension('StudentClassRegModuleInfo') context['register_from_catalog'] = scrmi.register_from_catalog prog_color = prog.getColor() collapse_full_classes = ('false' not in Tag.getProgramTag( 'collapse_full_classes', prog, 'True').lower()) class_blobs = [] category_header_str = """<hr size="1"/> <a name="cat%d"></a> <p style="font-size: 1.2em;" class="category"> %s </p> <p class="linktop"> <a href="#top">[ Return to Category List ]</a> </p> """ class_category_id = None for cls in classes: if cls.category.id != class_category_id: class_category_id = cls.category.id class_blobs.append(category_header_str % (class_category_id, cls.category.category)) class_blobs.append(render_class_direct(cls)) class_blobs.append('<br />') context['class_descs'] = ''.join(class_blobs) return render_to_response(self.baseDir() + 'catalog.html', request, (prog, tl), context, use_request_context=False)
def __init__(self, module, *args, **kwargs): from esp.program.controllers.classreg import get_custom_fields def hide_field(field, default=None): field.widget = forms.HiddenInput() if default is not None: field.initial = default def hide_choice_if_useless(field): """ Hide a choice field if there's only one choice """ if len(field.choices) == 1: hide_field(field, default=field.choices[0][0]) super(TeacherClassRegForm, self).__init__(*args, **kwargs) prog = module.get_program() section_numbers = module.allowed_sections_actual section_numbers = zip(section_numbers, section_numbers) class_sizes = module.getClassSizes() class_sizes = zip(class_sizes, class_sizes) class_grades = module.getClassGrades() class_grades = zip(class_grades, class_grades) class_ranges = ClassSizeRange.get_ranges_for_program(prog) class_ranges = [(range.id, range.range_str()) for range in class_ranges] # num_sections: section_list; hide if useless self.fields['num_sections'].choices = section_numbers hide_choice_if_useless(self.fields['num_sections']) # category: program.class_categories.all() self.fields['category'].choices = [ (x.id, x.category) for x in prog.class_categories.all() ] # grade_min, grade_max: module.getClassGrades self.fields['grade_min'].choices = class_grades self.fields['grade_max'].choices = class_grades if module.use_class_size_max: # class_size_max: module.getClassSizes self.fields['class_size_max'].choices = class_sizes else: del self.fields['class_size_max'] if Tag.getTag('use_class_size_optimal', default=False): if not module.use_class_size_optimal: del self.fields['class_size_optimal'] if module.use_optimal_class_size_range: self.fields['optimal_class_size_range'].choices = class_ranges else: del self.fields['optimal_class_size_range'] if module.use_allowable_class_size_ranges: self.fields[ 'allowable_class_size_ranges'].choices = class_ranges else: del self.fields['allowable_class_size_ranges'] else: del self.fields['class_size_optimal'] del self.fields['optimal_class_size_range'] del self.fields['allowable_class_size_ranges'] # global_resources: module.getResourceTypes(is_global=True) self.fields['global_resources'].choices = module.getResourceTypes( is_global=True) # resources: module.getResourceTypes(is_global=False) resource_choices = module.getResourceTypes(is_global=False) # decide whether to display certain fields # resources if len(resource_choices) > 0: self.fields['resources'].choices = resource_choices else: self.fields['resources'].widget = forms.HiddenInput() # prereqs if not module.set_prereqs: self.fields['prereqs'].widget = forms.HiddenInput() # allow_lateness if not module.allow_lateness: self.fields['allow_lateness'].widget = forms.HiddenInput() self.fields['allow_lateness'].initial = 'False' self.fields['duration'].choices = sorted(module.getDurations()) hide_choice_if_useless(self.fields['duration']) # session_count if module.session_counts: session_count_choices = module.session_counts_ints session_count_choices = zip(session_count_choices, session_count_choices) self.fields['session_count'].choices = session_count_choices hide_choice_if_useless(self.fields['session_count']) # requested_room if not module.ask_for_room: hide_field(self.fields['requested_room']) # Hide resource fields since separate forms are now being used. - Michael P resource_fields = [ 'has_own_space', 'global_resources', 'resources', 'requested_special_resources' ] for field in resource_fields: self.fields[field].widget = forms.HiddenInput() # Add program-custom form components (for inlining additional questions without # introducing a separate program module) custom_fields = get_custom_fields() for field_name in custom_fields: self.fields[field_name] = custom_fields[field_name] # Modify help text on these fields if necessary. custom_helptext_fields = [ 'duration', 'class_size_max', 'num_sections', 'requested_room', 'message_for_directors', 'purchase_requests', 'class_info' ] + custom_fields.keys() for field in custom_helptext_fields: tag_data = Tag.getTag('teacherreg_label_%s' % field) if tag_data: self.fields[field].label = tag_data tag_data = Tag.getTag('teacherreg_help_text_%s' % field) if tag_data: self.fields[field].help_text = tag_data # Hide fields as desired. tag_data = Tag.getProgramTag('teacherreg_hide_fields', prog) if tag_data: for field_name in tag_data.split(','): hide_field(self.fields[field_name]) tag_data = Tag.getProgramTag('teacherreg_default_min_grade', prog) if tag_data: print tag_data self.fields['grade_min'].initial = tag_data tag_data = Tag.getProgramTag('teacherreg_default_max_grade', prog) if tag_data: print tag_data self.fields['grade_max'].initial = tag_data tag_data = Tag.getProgramTag('teacherreg_default_class_size_max', prog) if tag_data: print tag_data self.fields['class_size_max'].initial = tag_data # Rewrite difficulty label/choices if desired: if Tag.getTag('teacherreg_difficulty_choices'): self.fields['hardness_rating'].choices = json.loads( Tag.getTag('teacherreg_difficulty_choices')) if Tag.getTag('teacherreg_difficulty_label'): self.fields['hardness_rating'].label = Tag.getTag( 'teacherreg_difficulty_label')
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} static_resource_requests = Tag.getProgramTag( 'static_resource_requests', self.program, ) if request.method == 'POST' and request.POST.has_key('class_reg_page'): 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.has_key( 'manage') and request.POST['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 restype_formset = e.restype_formset
def __init__(self, crmi, *args, **kwargs): from esp.program.controllers.classreg import get_custom_fields def hide_field(field, default=None): field.widget = forms.HiddenInput() if default is not None: field.initial = default def hide_choice_if_useless(field): """ Hide a choice field if there's only one choice """ if len(field.choices) == 1: hide_field(field, default=field.choices[0][0]) super(TeacherClassRegForm, self).__init__(*args, **kwargs) prog = crmi.program section_numbers = crmi.allowed_sections_actual section_numbers = zip(section_numbers, section_numbers) class_sizes = crmi.getClassSizes() class_sizes = zip(class_sizes, class_sizes) class_grades = crmi.getClassGrades() class_grades = zip(class_grades, class_grades) class_ranges = ClassSizeRange.get_ranges_for_program(prog) class_ranges = [(range.id, range.range_str()) for range in class_ranges] # num_sections: section_list; hide if useless self.fields['num_sections'].choices = section_numbers hide_choice_if_useless( self.fields['num_sections'] ) # category: program.class_categories.all() self.fields['category'].choices = [ (x.id, x.category) for x in prog.class_categories.all() ] # grade_min, grade_max: crmi.getClassGrades self.fields['grade_min'].choices = class_grades self.fields['grade_max'].choices = class_grades if crmi.use_class_size_max: # class_size_max: crmi.getClassSizes self.fields['class_size_max'].choices = class_sizes else: del self.fields['class_size_max'] if Tag.getBooleanTag('use_class_size_optimal', default=False): if not crmi.use_class_size_optimal: del self.fields['class_size_optimal'] if crmi.use_optimal_class_size_range: self.fields['optimal_class_size_range'].choices = class_ranges else: del self.fields['optimal_class_size_range'] if crmi.use_allowable_class_size_ranges: self.fields['allowable_class_size_ranges'].choices = class_ranges else: del self.fields['allowable_class_size_ranges'] else: del self.fields['class_size_optimal'] del self.fields['optimal_class_size_range'] del self.fields['allowable_class_size_ranges'] # decide whether to display certain fields # prereqs if not crmi.set_prereqs: self.fields['prereqs'].widget = forms.HiddenInput() # allow_lateness if not crmi.allow_lateness: self.fields['allow_lateness'].widget = forms.HiddenInput() self.fields['allow_lateness'].initial = 'False' self.fields['duration'].choices = sorted(crmi.getDurations()) hide_choice_if_useless( self.fields['duration'] ) # session_count if crmi.session_counts: session_count_choices = crmi.session_counts_ints session_count_choices = zip(session_count_choices, session_count_choices) self.fields['session_count'].choices = session_count_choices hide_choice_if_useless( self.fields['session_count'] ) # requested_room if not crmi.ask_for_room: hide_field( self.fields['requested_room'] ) # Hide resource fields since separate forms are now being used. - Michael P # Most have now been removed, but this one gets un-hidden by open classes. self.fields['requested_special_resources'].widget = forms.HiddenInput() # Add program-custom form components (for inlining additional questions without # introducing a separate program module) custom_fields = get_custom_fields() for field_name in custom_fields: self.fields[field_name] = custom_fields[field_name] # Modify help text on these fields if necessary. custom_helptext_fields = ['duration', 'class_size_max', 'num_sections', 'requested_room', 'message_for_directors', 'purchase_requests', 'class_info'] + custom_fields.keys() for field in custom_helptext_fields: tag_data = Tag.getProgramTag('teacherreg_label_%s' % field, prog) if tag_data: self.fields[field].label = tag_data tag_data = Tag.getProgramTag('teacherreg_help_text_%s' % field, prog) if tag_data: self.fields[field].help_text = tag_data # Hide fields as desired. tag_data = Tag.getProgramTag('teacherreg_hide_fields', prog) if tag_data: for field_name in tag_data.split(','): hide_field(self.fields[field_name]) tag_data = Tag.getProgramTag('teacherreg_default_min_grade', prog) if tag_data: self.fields['grade_min'].initial = tag_data tag_data = Tag.getProgramTag('teacherreg_default_max_grade', prog) if tag_data: self.fields['grade_max'].initial = tag_data tag_data = Tag.getProgramTag('teacherreg_default_class_size_max', prog) if tag_data: self.fields['class_size_max'].initial = tag_data # Rewrite difficulty label/choices if desired: if Tag.getTag('teacherreg_difficulty_choices'): self.fields['hardness_rating'].choices = json.loads(Tag.getTag('teacherreg_difficulty_choices'))
def stats(prog): # Create a dictionary to assemble the output dictOut = {"stats": []} classes = prog.classes().select_related() vitals = {'id': 'vitals'} class_num_list = [] class_num_list.append( ("Total # of Classes", classes.distinct().count())) class_num_list.append( ("Total # of Class Sections", prog.sections().select_related().distinct().count())) class_num_list.append( ("Total # of Lunch Classes", classes.filter(category__category="Lunch").filter( status=10).distinct().count())) class_num_list.append( ("Total # of Classes <span style='color: #00C;'>Unreviewed</span>", classes.filter(status=0).distinct().count())) class_num_list.append( ("Total # of Classes <span style='color: #0C0;'>Accepted</span>", classes.filter(status=10).distinct().count())) class_num_list.append( ("Total # of Classes <span style='color: #C00;'>Rejected</span>", classes.filter(status=-10).distinct().count())) class_num_list.append( ("Total # of Classes <span style='color: #990;'>Cancelled</span>", classes.filter(status=-20).distinct().count())) for ft in ClassFlagType.get_flag_types(prog): class_num_list.append( ('Total # of Classes with the "%s" flag' % ft.name, classes.filter(flags__flag_type=ft).distinct().count())) vitals['classnum'] = class_num_list # Display pretty labels for teacher and student numbers teacher_labels_dict = {} for module in prog.getModules(): teacher_labels_dict.update(module.teacherDesc()) vitals['teachernum'] = [] ## Ew, queries in a for loop... ## Not much to be done about it, though; ## the loop is iterating over a list of independent queries and running each. teachers = prog.teachers() for key in teachers.keys(): if key in teacher_labels_dict: vitals['teachernum'].append(( teacher_labels_dict[key], ## Unfortunately, teachers[key].filter(is_active=True).distinct().count())) else: vitals['teachernum'].append( (key, teachers[key].filter(is_active=True).distinct().count())) student_labels_dict = {} for module in prog.getModules(): student_labels_dict.update(module.studentDesc()) vitals['studentnum'] = [] ## Ew, another set of queries in a for loop... ## Same justification, though. students = prog.students() for key in students.keys(): if key in student_labels_dict: vitals['studentnum'].append( (student_labels_dict[key], students[key].filter(is_active=True).distinct().count())) else: vitals['studentnum'].append( (key, students[key].filter(is_active=True).distinct().count())) timeslots = prog.getTimeSlots() vitals['timeslots'] = [] shours = 0.0 chours = 0.0 crhours = 0.0 ## Write this as a 'for' loop because PostgreSQL can't do it in ## one go without a subquery or duplicated logic, and Django ## doesn't have enough power to expose either approach directly. ## At least there aren't any queries in the for loop... ## (In MySQL, this could I believe be done with a minimally-painful extra() clause.) ## Also, since we're iterating over a big data set, use .values() ## minimize the number of objects that we're creating. ## One dict and two Decimals per row, as opposed to ## an Object per field and all kinds of stuff... for cls in prog.classes().exclude(category__category='Lunch').annotate( num_sections=Count('sections'), subject_duration=Sum('sections__duration'), subject_students=Sum('sections__enrolled_students')).values( 'num_sections', 'subject_duration', 'subject_students', 'class_size_max'): if cls['subject_duration']: chours += float(cls['subject_duration']) shours += float(cls['subject_duration']) * (float( cls['class_size_max']) if cls['class_size_max'] else 0) crhours += float(cls['subject_duration']) * float( cls['subject_students']) / float(cls['num_sections']) vitals["hournum"] = [] vitals["hournum"].append(("Total # of Class-Hours", chours)) vitals["hournum"].append( ("Total # of Class-Student-Hours (capacity)", shours)) vitals["hournum"].append( ("Total # of Class-Student-Hours (registered)", crhours)) ## Prefetch enough data that get_meeting_times() and num_students() don't have to hit the db curclasses = ClassSection.prefetch_catalog_data( ClassSection.objects.filter( parent_class__parent_program=prog).select_related( 'parent_class', 'parent_class__category')) ## Is it really faster to do this logic in Python? ## It'd be even faster to just write a raw SQL query to do it. ## But this is probably good enough. timeslot_dict = defaultdict(list) timeslot_set = set(timeslots) for section in curclasses: for timeslot in set.intersection(timeslot_set, section.get_meeting_times()): timeslot_dict[timeslot].append(section) for timeslot in timeslots: curTimeslot = {'slotname': timeslot.short_description} curTimeslot['classcount'] = len(timeslot_dict[timeslot]) def student_count(clslist): lst = [0] + [ x.num_students() for x in clslist if x.category.category != 'Lunch' ] return reduce(operator.add, lst) def student_max_count(clslist): lst = [0] + [ x.capacity for x in clslist if x.category.category != 'Lunch' ] return reduce(operator.add, lst) curTimeslot['studentcount'] = { 'count': student_count(timeslot_dict[timeslot]), 'max_count': student_max_count(timeslot_dict[timeslot]) } vitals['timeslots'].append(curTimeslot) dictOut["stats"].append(vitals) shirt_data = { "id": "shirtnum" } adminvitals_shirt = prog.getShirtInfo() shirt_data["sizes"] = adminvitals_shirt['shirt_sizes'] shirt_data["types"] = adminvitals_shirt['shirt_types'] shirt_data["data"] = adminvitals_shirt['shirts'] dictOut["stats"].append(shirt_data) Q_categories = Q(program=prog) crmi = prog.classregmoduleinfo if crmi.open_class_registration: Q_categories |= Q(pk=prog.open_class_category.pk) # Introduce a separate query to get valid categories, since the single query seemed to introduce duplicates program_categories = ClassCategories.objects.filter( Q_categories).distinct().values_list('id', flat=True) annotated_categories = ClassCategories.objects.filter( cls__parent_program=prog, cls__status__gte=0).annotate( num_subjects=Count('cls', distinct=True), num_sections=Count('cls__sections'), num_class_hours=Sum('cls__sections__duration')).order_by( '-num_subjects').values('id', 'num_sections', 'num_subjects', 'num_class_hours', 'category').distinct() # Convert Decimal values to float for serialization for i in range(len(annotated_categories)): annotated_categories[i]['num_class_hours'] = float( annotated_categories[i]['num_class_hours']) dictOut["stats"].append({ "id": "categories", "data": filter(lambda x: x['id'] in program_categories, annotated_categories) }) ## Calculate the grade data: grades = [i for i in range(prog.grade_min, prog.grade_max + 1)] # We can't perfectly trust most_recent_profile, but it's good enough for stats students_grades = students['enrolled'].filter( registrationprofile__most_recent_profile=True) students_grades = students_grades.values_list( 'registrationprofile__student_info__graduation_year') students_grades = students_grades.annotate(Count('id', distinct=True)) grades_dict = {result[0]: result[1] for result in students_grades} grades_results = [] for g in grades: year = ESPUser.YOGFromGrade(g, ESPUser.program_schoolyear(prog)) grade_classes = classes.filter(status__gte=0, grade_min__lte=g, grade_max__gte=g) grade_sections = prog.sections().filter( status__gte=0, parent_class__in=grade_classes) grades_results.append({ 'grade': g, 'num_subjects': grade_classes.count(), 'num_sections': grade_sections.count(), 'num_students': grades_dict[year] if year in grades_dict else 0 }) dictOut["stats"].append({"id": "grades", "data": grades_results}) # Add SplashInfo statistics if our program has them splashinfo_data = {} splashinfo_modules = filter(lambda x: isinstance(x, SplashInfoModule), prog.getModules('learn')) if len(splashinfo_modules) > 0: splashinfo_module = splashinfo_modules[0] tag_data = Tag.getProgramTag('splashinfo_choices', prog) if tag_data: splashinfo_choices = json.loads(tag_data) else: splashinfo_choices = { 'lunchsat': SplashInfoForm.default_choices, 'lunchsun': SplashInfoForm.default_choices } for key in splashinfo_choices: counts = {} for item in splashinfo_choices[key]: filter_kwargs = {'program': prog} filter_kwargs[key] = item[0] counts[item[1]] = SplashInfo.objects.filter( **filter_kwargs).distinct().count() splashinfo_data[key] = counts splashinfo_data['siblings'] = { 'yes': SplashInfo.objects.filter( program=prog, siblingdiscount=True).distinct().count(), 'no': SplashInfo.objects.filter(program=prog).exclude( siblingdiscount=True).distinct().count() } dictOut["stats"].append({ "id": "splashinfo", "data": splashinfo_data }) # Add accounting stats pac = ProgramAccountingController(prog) (num_payments, total_payment) = pac.payments_summary() accounting_data = { 'num_payments': num_payments, # We need to convert to a float in order for json to serialize it. # Since we're not doing any computation client-side with these # numbers, this doesn't cause accuracy issues. If the # total_payment is None, just coerce it to zero for display # purposes. 'total_payments': float(total_payment or 0), } dictOut["stats"].append({"id": "accounting", "data": accounting_data}) return dictOut
def newprogram(request): template_prog = None template_prog_id = None if 'template_prog' in request.GET and ( int(request.GET["template_prog"]) ) != 0: # if user selects None which value is 0,so we need to check for 0. #try: template_prog_id = int(request.GET["template_prog"]) tprogram = Program.objects.get(id=template_prog_id) template_prog = {} template_prog.update(tprogram.__dict__) del template_prog["id"] template_prog["program_modules"] = tprogram.program_modules.all( ).values_list("id", flat=True) template_prog["class_categories"] = tprogram.class_categories.all( ).values_list("id", flat=True) ''' As Program Name should be new for each new program created then it is better to not to show old program names in input box . template_prog["term"] = tprogram.anchor.name template_prog["term_friendly"] = tprogram.anchor.friendly_name ''' template_prog["anchor"] = tprogram.anchor.parent.id # aseering 5/18/2008 -- List everyone who was granted V/Administer on the specified program template_prog["admins"] = ESPUser.objects.filter( userbit__verb=GetNode("V/Administer"), userbit__qsc=tprogram.anchor).values_list("id", flat=True) # aseering 5/18/2008 -- More aggressively list everyone who was an Admin #template_prog["admins"] = [ x.id for x in UserBit.objects.bits_get_users(verb=GetNode("V/Administer"), qsc=tprogram.anchor, user_objs=True) ] program_visible_bits = list( UserBit.objects.bits_get_users( verb=GetNode("V/Flags/Public"), qsc=tprogram.anchor).filter( user__isnull=True).order_by("-startdate")) if len(program_visible_bits) > 0: newest_bit = program_visible_bits[0] oldest_bit = program_visible_bits[-1] template_prog["publish_start"] = oldest_bit.startdate template_prog["publish_end"] = newest_bit.enddate student_reg_bits = list( UserBit.objects.bits_get_users( verb=GetNode("V/Deadline/Registration/Student"), qsc=tprogram.anchor).filter( user__isnull=True).order_by("-startdate")) if len(student_reg_bits) > 0: newest_bit = student_reg_bits[0] oldest_bit = student_reg_bits[-1] template_prog["student_reg_start"] = oldest_bit.startdate template_prog["student_reg_end"] = newest_bit.enddate teacher_reg_bits = list( UserBit.objects.bits_get_users( verb=GetNode("V/Deadline/Registration/Teacher"), qsc=tprogram.anchor).filter( user__isnull=True).order_by("-startdate")) if len(teacher_reg_bits) > 0: newest_bit = teacher_reg_bits[0] oldest_bit = teacher_reg_bits[-1] template_prog["teacher_reg_start"] = oldest_bit.startdate template_prog["teacher_reg_end"] = newest_bit.enddate line_items = LineItemType.objects.filter( anchor__name="Required", anchor__parent__parent=tprogram.anchor).values( "amount", "finaid_amount") template_prog["base_cost"] = int( -sum([x["amount"] for x in line_items])) template_prog["finaid_cost"] = int( -sum([x["finaid_amount"] for x in line_items])) if 'checked' in request.GET: # Our form's anchor is wrong, because the form asks for the parent of the anchor that we really want. # Don't bother trying to fix the form; just re-set the anchor when we're done. context = pickle.loads(request.session['context_str']) pcf = ProgramCreationForm(context['prog_form_raw']) if pcf.is_valid(): # Fix the anchor friendly name right away, otherwise in-memory caches cause (mild) issues later on anchor = GetNode(pcf.cleaned_data['anchor'].get_uri() + "/" + pcf.cleaned_data["term"]) anchor.friendly_name = pcf.cleaned_data['term_friendly'] anchor.save() new_prog = pcf.save( commit=False) # don't save, we need to fix it up: new_prog.anchor = anchor new_prog.save() pcf.save_m2m() commit_program(new_prog, context['datatrees'], context['userbits'], context['modules'], context['costs']) # Create the default resource types now default_restypes = Tag.getProgramTag('default_restypes', program=new_prog) if default_restypes: resource_type_labels = json.loads(default_restypes) resource_types = [ ResourceType.get_or_create(x, new_prog) for x in resource_type_labels ] # Force all ProgramModuleObjs and their extensions to be created now new_prog.getModules() manage_url = '/manage/' + new_prog.url() + '/resources' if settings.USE_MAILMAN and 'mailman_moderator' in settings.DEFAULT_EMAIL_ADDRESSES.keys( ): # While we're at it, create the program's mailing list mailing_list_name = "%s_%s" % (new_prog.anchor.parent.name, new_prog.anchor.name) teachers_list_name = "%s-%s" % (mailing_list_name, "teachers") students_list_name = "%s-%s" % (mailing_list_name, "students") create_list( students_list_name, settings.DEFAULT_EMAIL_ADDRESSES['mailman_moderator']) create_list( teachers_list_name, settings.DEFAULT_EMAIL_ADDRESSES['mailman_moderator']) load_list_settings(teachers_list_name, "lists/program_mailman.config") load_list_settings(students_list_name, "lists/program_mailman.config") apply_list_settings( teachers_list_name, { 'owner': [ settings. DEFAULT_EMAIL_ADDRESSES['mailman_moderator'], new_prog.director_email ] }) apply_list_settings( students_list_name, { 'owner': [ settings. DEFAULT_EMAIL_ADDRESSES['mailman_moderator'], new_prog.director_email ] }) if 'archive' in settings.DEFAULT_EMAIL_ADDRESSES.keys(): add_list_member(students_list_name, [ new_prog.director_email, settings.DEFAULT_EMAIL_ADDRESSES['archive'] ]) add_list_member(teachers_list_name, [ new_prog.director_email, settings.DEFAULT_EMAIL_ADDRESSES['archive'] ]) return HttpResponseRedirect(manage_url) else: raise ESPError(False), "Improper form data submitted." # If the form has been submitted, process it. if request.method == 'POST': form = ProgramCreationForm(request.POST) if form.is_valid(): temp_prog = form.save(commit=False) datatrees, userbits, modules = prepare_program( temp_prog, form.cleaned_data) # Save the form's raw data instead of the form itself, or its clean data. # Unpacking of the data happens at the next step. context_pickled = pickle.dumps({ 'prog_form_raw': form.data, 'datatrees': datatrees, 'userbits': userbits, 'modules': modules, 'costs': (form.cleaned_data['base_cost'], form.cleaned_data['finaid_cost']) }) request.session['context_str'] = context_pickled return render_to_response( 'program/newprogram_review.html', request, GetNode('Q/Programs/'), { 'prog': temp_prog, 'datatrees': datatrees, 'userbits': userbits, 'modules': modules }) else: # Otherwise, the default view is a blank form. if template_prog: form = ProgramCreationForm(template_prog) else: form = ProgramCreationForm() return render_to_response( 'program/newprogram.html', request, GetNode('Q/Programs/'), { 'form': form, 'programs': Program.objects.all().order_by('-id'), 'template_prog_id': template_prog_id })
def newprogram(request): template_prog = None template_prog_id = None if 'template_prog' in request.GET and (int(request.GET["template_prog"])) != 0: # if user selects None which value is 0,so we need to check for 0. #try: template_prog_id = int(request.GET["template_prog"]) tprogram = Program.objects.get(id=template_prog_id) template_prog = {} template_prog.update(tprogram.__dict__) del template_prog["id"] template_prog["program_type"] = tprogram.program_type template_prog["program_modules"] = tprogram.program_modules.all().values_list("id", flat=True) template_prog["class_categories"] = tprogram.class_categories.all().values_list("id", flat=True) ''' As Program Name should be new for each new program created then it is better to not to show old program names in input box . template_prog["term"] = tprogram.program_instance() template_prog["term_friendly"] = tprogram.niceName() ''' student_reg_bits = list(Permission.objects.filter(permission_type__startswith='Student', program=template_prog_id).order_by('-start_date')) if len(student_reg_bits) > 0: newest_bit = student_reg_bits[0] oldest_bit = student_reg_bits[-1] template_prog["student_reg_start"] = oldest_bit.start_date template_prog["student_reg_end"] = newest_bit.end_date teacher_reg_bits = list(Permission.objects.filter(permission_type__startswith='Teacher', program=template_prog_id).order_by('-start_date')) if len(teacher_reg_bits) > 0: newest_bit = teacher_reg_bits[0] oldest_bit = teacher_reg_bits[-1] template_prog["teacher_reg_start"] = oldest_bit.start_date template_prog["teacher_reg_end"] = newest_bit.end_date pac = ProgramAccountingController(tprogram) line_items = pac.get_lineitemtypes(required_only=True).values('amount_dec') template_prog["base_cost"] = int(sum(x["amount_dec"] for x in line_items)) template_prog["sibling_discount"] = tprogram.sibling_discount if 'checked' in request.GET: # Our form's anchor is wrong, because the form asks for the parent of the anchor that we really want. # Don't bother trying to fix the form; just re-set the anchor when we're done. context = pickle.loads(request.session['context_str']) pcf = ProgramCreationForm(context['prog_form_raw']) if pcf.is_valid(): new_prog = pcf.save(commit = True) commit_program(new_prog, context['perms'], context['modules'], context['cost'], context['sibling_discount']) # Create the default resource types now default_restypes = Tag.getProgramTag('default_restypes', program=new_prog) if default_restypes: resource_type_labels = json.loads(default_restypes) resource_types = [ResourceType.get_or_create(x, new_prog) for x in resource_type_labels] # Force all ProgramModuleObjs and their extensions to be created now new_prog.getModules() manage_url = '/manage/' + new_prog.url + '/resources' if settings.USE_MAILMAN and 'mailman_moderator' in settings.DEFAULT_EMAIL_ADDRESSES.keys(): # While we're at it, create the program's mailing list mailing_list_name = "%s_%s" % (new_prog.program_type, new_prog.program_instance) teachers_list_name = "%s-%s" % (mailing_list_name, "teachers") students_list_name = "%s-%s" % (mailing_list_name, "students") create_list(students_list_name, settings.DEFAULT_EMAIL_ADDRESSES['mailman_moderator']) create_list(teachers_list_name, settings.DEFAULT_EMAIL_ADDRESSES['mailman_moderator']) load_list_settings(teachers_list_name, "lists/program_mailman.config") load_list_settings(students_list_name, "lists/program_mailman.config") apply_list_settings(teachers_list_name, {'owner': [settings.DEFAULT_EMAIL_ADDRESSES['mailman_moderator'], new_prog.director_email]}) apply_list_settings(students_list_name, {'owner': [settings.DEFAULT_EMAIL_ADDRESSES['mailman_moderator'], new_prog.director_email]}) if 'archive' in settings.DEFAULT_EMAIL_ADDRESSES.keys(): add_list_members(students_list_name, [new_prog.director_email, settings.DEFAULT_EMAIL_ADDRESSES['archive']]) add_list_members(teachers_list_name, [new_prog.director_email, settings.DEFAULT_EMAIL_ADDRESSES['archive']]) return HttpResponseRedirect(manage_url) else: raise ESPError("Improper form data submitted.", log=False) # If the form has been submitted, process it. if request.method == 'POST': form = ProgramCreationForm(request.POST) if form.is_valid(): temp_prog = form.save(commit=False) perms, modules = prepare_program(temp_prog, form.cleaned_data) # Save the form's raw data instead of the form itself, or its clean data. # Unpacking of the data happens at the next step. context_pickled = pickle.dumps({'prog_form_raw': form.data, 'perms': perms, 'modules': modules, 'cost': form.cleaned_data['base_cost'], 'sibling_discount': form.cleaned_data['sibling_discount']}) request.session['context_str'] = context_pickled return render_to_response('program/newprogram_review.html', request, {'prog': temp_prog, 'perms':perms, 'modules': modules}) else: # Otherwise, the default view is a blank form. if template_prog: form = ProgramCreationForm(template_prog) else: form = ProgramCreationForm() return render_to_response('program/newprogram.html', request, {'form': form, 'programs': Program.objects.all().order_by('-id'),'template_prog_id':template_prog_id})
def testProgramTag(self): '''Test the logic of getProgramTag in a bunch of different conditions.''' # Delete any existing tags that might interfere Tag.objects.filter(key="test").delete() # Dump any existing Tag cache Tag._getTag.delete_all() #Caching is hard, so what the hell, let's run every assertion twice. self.assertFalse(Tag.getProgramTag("test", program=self.program)) self.assertFalse(Tag.getProgramTag("test", program=self.program)) self.assertFalse(Tag.getProgramTag("test", program=None)) self.assertFalse(Tag.getProgramTag("test", program=None)) self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "the default") self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "the default") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "the default") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "the default") # Set the program-specific tag Tag.setTag("test", target=self.program, value="program tag value") self.assertFalse(Tag.getProgramTag("test", program=None)) self.assertFalse(Tag.getProgramTag("test", program=None)) self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "the default") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "the default") self.assertEqual(Tag.getProgramTag("test", program=self.program), "program tag value") self.assertEqual(Tag.getProgramTag("test", program=self.program), "program tag value") self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "program tag value") self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "program tag value") # Now set the general tag Tag.setTag("test", target=None, value="general tag value") self.assertEqual(Tag.getProgramTag("test", program=None), "general tag value") self.assertEqual(Tag.getProgramTag("test", program=None), "general tag value") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "general tag value") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "general tag value") self.assertEqual(Tag.getProgramTag("test", program=self.program), "program tag value") self.assertEqual(Tag.getProgramTag("test", program=self.program), "program tag value") self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "program tag value") self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "program tag value") # Now unset the program-specific tag Tag.unSetTag("test", target=self.program) self.assertEqual(Tag.getProgramTag("test", program=None), "general tag value") self.assertEqual(Tag.getProgramTag("test", program=None), "general tag value") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "general tag value") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "general tag value") self.assertEqual(Tag.getProgramTag("test", program=self.program), "general tag value") self.assertEqual(Tag.getProgramTag("test", program=self.program), "general tag value") self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "general tag value") self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "general tag value") #just to clean up Tag.unSetTag("test", target=None) self.assertFalse(Tag.getProgramTag("test", program=self.program)) self.assertFalse(Tag.getProgramTag("test", program=self.program)) self.assertFalse(Tag.getProgramTag("test", program=None)) self.assertFalse(Tag.getProgramTag("test", program=None)) self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "the default") self.assertEqual( Tag.getProgramTag("test", program=self.program, default="the default"), "the default") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "the default") self.assertEqual( Tag.getProgramTag("test", program=None, default="the default"), "the default")
def newprogram(request): template_prog = None template_prog_id = None if 'template_prog' in request.GET and ( int(request.GET["template_prog"]) ) != 0: # if user selects None which value is 0,so we need to check for 0. #try: template_prog_id = int(request.GET["template_prog"]) tprogram = Program.objects.get(id=template_prog_id) template_prog = {} template_prog.update(tprogram.__dict__) del template_prog["id"] template_prog["program_type"] = tprogram.program_type template_prog["program_modules"] = tprogram.program_modules.all( ).values_list("id", flat=True) template_prog["class_categories"] = tprogram.class_categories.all( ).values_list("id", flat=True) ''' As Program Name should be new for each new program created then it is better to not to show old program names in input box . template_prog["term"] = tprogram.anchor.name template_prog["term_friendly"] = tprogram.anchor.friendly_name ''' template_prog["admins"] = ESPUser.objects.filter( permission__permission_type="Administer", permission__program=tprogram).values_list("id", flat=True) # aseering 5/18/2008 -- More aggressively list everyone who was an Admin #template_prog["admins"] = [ x.id for x in UserBit.objects.bits_get_users(verb=GetNode("V/Administer"), qsc=tprogram.anchor, user_objs=True) ] student_reg_bits = list( Permission.objects.filter( permission_type__startswith='Student', program=template_prog_id).order_by('-start_date')) if len(student_reg_bits) > 0: newest_bit = student_reg_bits[0] oldest_bit = student_reg_bits[-1] template_prog["student_reg_start"] = oldest_bit.start_date template_prog["student_reg_end"] = newest_bit.end_date teacher_reg_bits = list( Permission.objects.filter( permission_type__startswith='Teacher', program=template_prog_id).order_by('-start_date')) if len(teacher_reg_bits) > 0: newest_bit = teacher_reg_bits[0] oldest_bit = teacher_reg_bits[-1] template_prog["teacher_reg_start"] = oldest_bit.start_date template_prog["teacher_reg_end"] = newest_bit.end_date pac = ProgramAccountingController(tprogram) line_items = pac.get_lineitemtypes( required_only=True).values('amount_dec') template_prog["base_cost"] = int( sum(x["amount_dec"] for x in line_items)) template_prog["sibling_discount"] = tprogram.sibling_discount if 'checked' in request.GET: # Our form's anchor is wrong, because the form asks for the parent of the anchor that we really want. # Don't bother trying to fix the form; just re-set the anchor when we're done. context = pickle.loads(request.session['context_str']) pcf = ProgramCreationForm(context['prog_form_raw']) if pcf.is_valid(): new_prog = pcf.save(commit=True) commit_program(new_prog, context['perms'], context['modules'], context['cost'], context['sibling_discount']) # Create the default resource types now default_restypes = Tag.getProgramTag('default_restypes', program=new_prog) if default_restypes: resource_type_labels = json.loads(default_restypes) resource_types = [ ResourceType.get_or_create(x, new_prog) for x in resource_type_labels ] # Force all ProgramModuleObjs and their extensions to be created now new_prog.getModules() manage_url = '/manage/' + new_prog.url + '/resources' if settings.USE_MAILMAN and 'mailman_moderator' in settings.DEFAULT_EMAIL_ADDRESSES.keys( ): # While we're at it, create the program's mailing list mailing_list_name = "%s_%s" % (new_prog.program_type, new_prog.program_instance) teachers_list_name = "%s-%s" % (mailing_list_name, "teachers") students_list_name = "%s-%s" % (mailing_list_name, "students") create_list( students_list_name, settings.DEFAULT_EMAIL_ADDRESSES['mailman_moderator']) create_list( teachers_list_name, settings.DEFAULT_EMAIL_ADDRESSES['mailman_moderator']) load_list_settings(teachers_list_name, "lists/program_mailman.config") load_list_settings(students_list_name, "lists/program_mailman.config") apply_list_settings( teachers_list_name, { 'owner': [ settings. DEFAULT_EMAIL_ADDRESSES['mailman_moderator'], new_prog.director_email ] }) apply_list_settings( students_list_name, { 'owner': [ settings. DEFAULT_EMAIL_ADDRESSES['mailman_moderator'], new_prog.director_email ] }) if 'archive' in settings.DEFAULT_EMAIL_ADDRESSES.keys(): add_list_member(students_list_name, [ new_prog.director_email, settings.DEFAULT_EMAIL_ADDRESSES['archive'] ]) add_list_member(teachers_list_name, [ new_prog.director_email, settings.DEFAULT_EMAIL_ADDRESSES['archive'] ]) return HttpResponseRedirect(manage_url) else: raise ESPError(False), "Improper form data submitted." # If the form has been submitted, process it. if request.method == 'POST': form = ProgramCreationForm(request.POST) if form.is_valid(): temp_prog = form.save(commit=False) perms, modules = prepare_program(temp_prog, form.cleaned_data) # Save the form's raw data instead of the form itself, or its clean data. # Unpacking of the data happens at the next step. context_pickled = pickle.dumps({ 'prog_form_raw': form.data, 'perms': perms, 'modules': modules, 'cost': form.cleaned_data['base_cost'], 'sibling_discount': form.cleaned_data['sibling_discount'] }) request.session['context_str'] = context_pickled return render_to_response('program/newprogram_review.html', request, { 'prog': temp_prog, 'perms': perms, 'modules': modules }) else: # Otherwise, the default view is a blank form. if template_prog: form = ProgramCreationForm(template_prog) else: form = ProgramCreationForm() return render_to_response( 'program/newprogram.html', request, { 'form': form, 'programs': Program.objects.all().order_by('-id'), 'template_prog_id': template_prog_id })
def __init__(self, crmi, *args, **kwargs): from esp.program.controllers.classreg import get_custom_fields def hide_field(field, default=None): field.widget = forms.HiddenInput() if default is not None: field.initial = default def hide_choice_if_useless(field): """ Hide a choice field if there's only one choice """ if len(field.choices) == 1: hide_field(field, default=field.choices[0][0]) super(TeacherClassRegForm, self).__init__(*args, **kwargs) prog = crmi.program section_numbers = crmi.allowed_sections_actual section_numbers = zip(section_numbers, section_numbers) class_sizes = crmi.getClassSizes() class_sizes = zip(class_sizes, class_sizes) class_grades = crmi.getClassGrades() class_grades = zip(class_grades, class_grades) class_ranges = ClassSizeRange.get_ranges_for_program(prog) class_ranges = [(range.id, range.range_str()) for range in class_ranges] # num_sections: section_list; hide if useless self.fields['num_sections'].choices = section_numbers hide_choice_if_useless( self.fields['num_sections'] ) # category: program.class_categories.all() self.fields['category'].choices = [ (x.id, x.category) for x in prog.class_categories.all() ] # grade_min, grade_max: crmi.getClassGrades self.fields['grade_min'].choices = class_grades self.fields['grade_max'].choices = class_grades if Tag.getTag('grade_ranges'): grade_ranges = json.loads(Tag.getTag('grade_ranges')) self.fields['grade_range'].choices = [(range,str(range[0]) + " - " + str(range[1])) for range in grade_ranges] self.fields['grade_range'].required = True hide_field( self.fields['grade_min'] ) self.fields['grade_min'].required = False hide_field( self.fields['grade_max'] ) self.fields['grade_max'].required = False else: hide_field( self.fields['grade_range'] ) if crmi.use_class_size_max: # class_size_max: crmi.getClassSizes self.fields['class_size_max'].choices = class_sizes else: del self.fields['class_size_max'] if Tag.getBooleanTag('use_class_size_optimal', default=False): if not crmi.use_class_size_optimal: del self.fields['class_size_optimal'] if crmi.use_optimal_class_size_range: self.fields['optimal_class_size_range'].choices = class_ranges else: del self.fields['optimal_class_size_range'] if crmi.use_allowable_class_size_ranges: self.fields['allowable_class_size_ranges'].choices = class_ranges else: del self.fields['allowable_class_size_ranges'] else: del self.fields['class_size_optimal'] del self.fields['optimal_class_size_range'] del self.fields['allowable_class_size_ranges'] # decide whether to display certain fields # prereqs if not crmi.set_prereqs: self.fields['prereqs'].widget = forms.HiddenInput() # allow_lateness if not crmi.allow_lateness: self.fields['allow_lateness'].widget = forms.HiddenInput() self.fields['allow_lateness'].initial = 'False' self.fields['duration'].choices = sorted(crmi.getDurations()) hide_choice_if_useless( self.fields['duration'] ) # session_count if crmi.session_counts: session_count_choices = crmi.session_counts_ints session_count_choices = zip(session_count_choices, session_count_choices) self.fields['session_count'].choices = session_count_choices hide_choice_if_useless( self.fields['session_count'] ) # requested_room if not crmi.ask_for_room: hide_field( self.fields['requested_room'] ) # Hide resource fields since separate forms are now being used. - Michael P # Most have now been removed, but this one gets un-hidden by open classes. self.fields['requested_special_resources'].widget = forms.HiddenInput() # Add program-custom form components (for inlining additional questions without # introducing a separate program module) custom_fields = get_custom_fields() for field_name in custom_fields: self.fields[field_name] = custom_fields[field_name] # Modify help text on these fields if necessary. # TODO(benkraft): Is there a reason not to allow this on all fields? custom_helptext_fields = [ 'duration', 'class_size_max', 'num_sections', 'requested_room', 'message_for_directors', 'purchase_requests', 'class_info', 'grade_max', 'grade_min'] + custom_fields.keys() for field in custom_helptext_fields: tag_data = Tag.getProgramTag('teacherreg_label_%s' % field, prog) if tag_data: self.fields[field].label = tag_data tag_data = Tag.getProgramTag('teacherreg_help_text_%s' % field, prog) if tag_data: self.fields[field].help_text = tag_data # Hide fields as desired. tag_data = Tag.getProgramTag('teacherreg_hide_fields', prog) if tag_data: for field_name in tag_data.split(','): hide_field(self.fields[field_name]) tag_data = Tag.getProgramTag('teacherreg_default_min_grade', prog) if tag_data: self.fields['grade_min'].initial = tag_data tag_data = Tag.getProgramTag('teacherreg_default_max_grade', prog) if tag_data: self.fields['grade_max'].initial = tag_data tag_data = Tag.getProgramTag('teacherreg_default_class_size_max', prog) if tag_data: self.fields['class_size_max'].initial = tag_data # Rewrite difficulty label/choices if desired: if Tag.getTag('teacherreg_difficulty_choices'): self.fields['hardness_rating'].choices = json.loads(Tag.getTag('teacherreg_difficulty_choices')) # Get class_style_choices from tag, otherwise hide the field if Tag.getTag('class_style_choices'): self.fields['class_style'].choices = json.loads(Tag.getTag('class_style_choices')) self.fields['class_style'].required = True else: hide_field(self.fields['class_style'])
def stats(prog): # Create a dictionary to assemble the output dictOut = {"stats": []} classes = prog.classes().select_related() vitals = {'id': 'vitals'} class_num_list = [] class_num_list.append(("Total # of Classes", len(classes))) class_num_list.append(("Total # of Class Sections", len(prog.sections().select_related()))) class_num_list.append( ("Total # of Lunch Classes", len(classes.filter(status=10)))) class_num_list.append( ("Total # of Classes <span style='color: #00C;'>Unreviewed</span>", len(classes.filter(status=0)))) class_num_list.append( ("Total # of Classes <span style='color: #0C0;'>Accepted</span>", len(classes.filter(status=10)))) class_num_list.append( ("Total # of Classes <span style='color: #C00;'>Rejected</span>", len(classes.filter(status=-10)))) class_num_list.append( ("Total # of Classes <span style='color: #990;'>Cancelled</span>", len(classes.filter(status=-20)))) vitals['classnum'] = class_num_list # Display pretty labels for teacher and student numbers teacher_labels_dict = {} for module in prog.getModules(): teacher_labels_dict.update(module.teacherDesc()) vitals['teachernum'] = [] ## Ew, queries in a for loop... ## Not much to be done about it, though; ## the loop is iterating over a list of independent queries and running each. teachers = prog.teachers() for key in teachers.keys(): if key in teacher_labels_dict: vitals['teachernum'].append(( teacher_labels_dict[key], ## Unfortunately, len(teachers[key]))) else: vitals['teachernum'].append((key, len(teachers[key]))) student_labels_dict = {} for module in prog.getModules(): student_labels_dict.update(module.studentDesc()) vitals['studentnum'] = [] ## Ew, another set of queries in a for loop... ## Same justification, though. students = prog.students() for key in students.keys(): if key in student_labels_dict: vitals['studentnum'].append( (student_labels_dict[key], len(students[key]))) else: vitals['studentnum'].append((key, len(students[key]))) timeslots = prog.getTimeSlots() vitals['timeslots'] = [] shours = 0.0 chours = 0.0 crhours = 0.0 ## Write this as a 'for' loop because PostgreSQL can't do it in ## one go without a subquery or duplicated logic, and Django ## doesn't have enough power to expose either approach directly. ## At least there aren't any queries in the for loop... ## (In MySQL, this could I believe be done with a minimally-painful extra() clause.) ## Also, since we're iterating over a big data set, use .values() ## minimize the number of objects that we're creating. ## One dict and two Decimals per row, as opposed to ## an Object per field and all kinds of stuff... for cls in prog.classes().exclude(category__category='Lunch').annotate( num_sections=Count('sections'), subject_duration=Sum('sections__duration'), subject_students=Sum('sections__enrolled_students')).values( 'num_sections', 'subject_duration', 'subject_students', 'class_size_max'): if cls['subject_duration']: chours += float(cls['subject_duration']) shours += float(cls['subject_duration']) * (float( cls['class_size_max']) if cls['class_size_max'] else 0) crhours += float(cls['subject_duration']) * float( cls['subject_students']) / float(cls['num_sections']) vitals["hournum"] = [] vitals["hournum"].append(("Total # of Class-Hours", chours)) vitals["hournum"].append( ("Total # of Class-Student-Hours (capacity)", shours)) vitals["hournum"].append( ("Total # of Class-Student-Hours (registered)", crhours)) ## Prefetch enough data that get_meeting_times() and num_students() don't have to hit the db curclasses = ClassSection.prefetch_catalog_data( ClassSection.objects.filter(parent_class__parent_program=prog)) ## Is it really faster to do this logic in Python? ## It'd be even faster to just write a raw SQL query to do it. ## But this is probably good enough. timeslot_dict = defaultdict(list) timeslot_set = set(timeslots) for section in curclasses: for timeslot in set.intersection(timeslot_set, section.get_meeting_times()): timeslot_dict[timeslot].append(section) for timeslot in timeslots: curTimeslot = {'slotname': timeslot.short_description} curTimeslot['classcount'] = len(timeslot_dict[timeslot]) def student_count(clslist): lst = [0] + [ x.num_students() for x in clslist if x.category.category != 'Lunch' ] return reduce(operator.add, lst) def student_max_count(clslist): lst = [0] + [ x.capacity for x in clslist if x.category.category != 'Lunch' ] return reduce(operator.add, lst) curTimeslot['studentcount'] = { 'count': student_count(timeslot_dict[timeslot]), 'max_count': student_max_count(timeslot_dict[timeslot]) } vitals['timeslots'].append(curTimeslot) dictOut["stats"].append(vitals) shirt_data = { "id": "shirtnum" } adminvitals_shirt = prog.getShirtInfo() shirt_data["sizes"] = adminvitals_shirt['shirt_sizes'] shirt_data["types"] = adminvitals_shirt['shirt_types'] shirt_data["data"] = adminvitals_shirt['shirts'] dictOut["stats"].append(shirt_data) Q_categories = Q(program=prog) crmi = prog.getModuleExtension('ClassRegModuleInfo') if crmi.open_class_registration: Q_categories |= Q(pk=prog.open_class_category.pk) # Introduce a separate query to get valid categories, since the single query seemed to introduce duplicates program_categories = ClassCategories.objects.filter( Q_categories).distinct().values_list('id', flat=True) annotated_categories = ClassCategories.objects.filter( cls__parent_program=prog, cls__status__gte=0).annotate( num_subjects=Count('cls', distinct=True), num_sections=Count('cls__sections')).order_by( '-num_subjects').values('id', 'num_sections', 'num_subjects', 'category').distinct() dictOut["stats"].append({ "id": "categories", "data": filter(lambda x: x['id'] in program_categories, annotated_categories) }) # Add SplashInfo statistics if our program has them splashinfo_data = {} splashinfo_modules = filter(lambda x: isinstance(x, SplashInfoModule), prog.getModules('learn')) if len(splashinfo_modules) > 0: splashinfo_module = splashinfo_modules[0] tag_data = Tag.getProgramTag('splashinfo_choices', prog) if tag_data: splashinfo_choices = json.loads(tag_data) else: splashinfo_choices = { 'lunchsat': SplashInfoForm.default_choices, 'lunchsun': SplashInfoForm.default_choices } for key in splashinfo_choices: counts = {} for item in splashinfo_choices[key]: filter_kwargs = {'program': prog} filter_kwargs[key] = item[0] counts[item[1]] = SplashInfo.objects.filter( **filter_kwargs).distinct().count() splashinfo_data[key] = counts splashinfo_data['siblings'] = { 'yes': SplashInfo.objects.filter( program=prog, siblingdiscount=True).distinct().count(), 'no': SplashInfo.objects.filter(program=prog).exclude( siblingdiscount=True).distinct().count() } dictOut["stats"].append({ "id": "splashinfo", "data": splashinfo_data }) return dictOut
for field_name in get_custom_fields(): if field_name in newclass.custom_form_data: current_data[field_name] = newclass.custom_form_data[ field_name] if newclass.optimal_class_size_range: current_data[ 'optimal_class_size_range'] = newclass.optimal_class_size_range.id if newclass.allowable_class_size_ranges.all(): current_data['allowable_class_size_ranges'] = list( newclass.allowable_class_size_ranges.all().values_list( 'id', flat=True)) # Makes importing a class from a previous program work # These are the only three fields that can currently be hidden # If another one is added later, this will need to be changed hidden_fields = Tag.getProgramTag('teacherreg_hide_fields', prog) if hidden_fields: if 'grade_min' in hidden_fields: current_data['grade_min'] = Tag.getProgramTag( 'teacherreg_default_min_grade', prog) if 'grade_max' in hidden_fields: current_data['grade_max'] = Tag.getProgramTag( 'teacherreg_default_max_grade', prog) if 'class_size_max' in hidden_fields: current_data['class_size_max'] = Tag.getProgramTag( 'teacherreg_default_class_size_max', prog) if not populateonly: context['class'] = newclass if action == 'edit':
def stats(prog): # Create a dictionary to assemble the output dictOut = { "stats": [] } classes = prog.classes().select_related() vitals = {'id': 'vitals'} class_num_list = [] class_num_list.append(("Total # of Classes", classes.distinct().count())) class_num_list.append(("Total # of Class Sections", prog.sections().select_related().distinct().count())) class_num_list.append(("Total # of Lunch Classes", classes.filter(category__category = "Lunch").filter(status=10).distinct().count())) class_num_list.append(("Total # of Classes <span style='color: #00C;'>Unreviewed</span>", classes.filter(status=0).distinct().count())) class_num_list.append(("Total # of Classes <span style='color: #0C0;'>Accepted</span>", classes.filter(status=10).distinct().count())) class_num_list.append(("Total # of Classes <span style='color: #C00;'>Rejected</span>", classes.filter(status=-10).distinct().count())) class_num_list.append(("Total # of Classes <span style='color: #990;'>Cancelled</span>", classes.filter(status=-20).distinct().count())) for ft in ClassFlagType.get_flag_types(prog): class_num_list.append(('Total # of Classes with the "%s" flag' % ft.name, classes.filter(flags__flag_type=ft).distinct().count())) vitals['classnum'] = class_num_list # Display pretty labels for teacher and student numbers teacher_labels_dict = {} for module in prog.getModules(): teacher_labels_dict.update(module.teacherDesc()) vitals['teachernum'] = [] ## Ew, queries in a for loop... ## Not much to be done about it, though; ## the loop is iterating over a list of independent queries and running each. teachers = prog.teachers() for key in teachers.keys(): if key in teacher_labels_dict: vitals['teachernum'].append((teacher_labels_dict[key], ## Unfortunately, teachers[key].filter(is_active = True).distinct().count())) else: vitals['teachernum'].append((key, teachers[key].filter(is_active = True).distinct().count())) student_labels_dict = {} for module in prog.getModules(): student_labels_dict.update(module.studentDesc()) vitals['studentnum'] = [] ## Ew, another set of queries in a for loop... ## Same justification, though. students = prog.students() for key in students.keys(): if key in student_labels_dict: vitals['studentnum'].append((student_labels_dict[key], students[key].filter(is_active = True).distinct().count())) else: vitals['studentnum'].append((key, students[key].filter(is_active = True).distinct().count())) timeslots = prog.getTimeSlots() vitals['timeslots'] = [] shours = 0.0 chours = 0.0 crhours = 0.0 ## Write this as a 'for' loop because PostgreSQL can't do it in ## one go without a subquery or duplicated logic, and Django ## doesn't have enough power to expose either approach directly. ## At least there aren't any queries in the for loop... ## (In MySQL, this could I believe be done with a minimally-painful extra() clause.) ## Also, since we're iterating over a big data set, use .values() ## minimize the number of objects that we're creating. ## One dict and two Decimals per row, as opposed to ## an Object per field and all kinds of stuff... for cls in prog.classes().exclude(category__category='Lunch').annotate(num_sections=Count('sections'), subject_duration=Sum('sections__duration'), subject_students=Sum('sections__enrolled_students')).values('num_sections', 'subject_duration', 'subject_students', 'class_size_max'): if cls['subject_duration']: chours += float(cls['subject_duration']) shours += float(cls['subject_duration']) * (float(cls['class_size_max']) if cls['class_size_max'] else 0) crhours += float(cls['subject_duration']) * float(cls['subject_students']) / float(cls['num_sections']) vitals["hournum"] = [] vitals["hournum"].append(("Total # of Class-Hours", chours)) vitals["hournum"].append(("Total # of Class-Student-Hours (capacity)", shours)) vitals["hournum"].append(("Total # of Class-Student-Hours (registered)", crhours)) ## Prefetch enough data that get_meeting_times() and num_students() don't have to hit the db curclasses = ClassSection.prefetch_catalog_data( ClassSection.objects .filter(parent_class__parent_program=prog) .select_related('parent_class', 'parent_class__category')) ## Is it really faster to do this logic in Python? ## It'd be even faster to just write a raw SQL query to do it. ## But this is probably good enough. timeslot_dict = defaultdict(list) timeslot_set = set(timeslots) for section in curclasses: for timeslot in set.intersection(timeslot_set, section.get_meeting_times()): timeslot_dict[timeslot].append(section) for timeslot in timeslots: curTimeslot = {'slotname': timeslot.short_description} curTimeslot['classcount'] = len(timeslot_dict[timeslot]) def student_count(clslist): lst = [0] + [x.num_students() for x in clslist if x.category.category != 'Lunch'] return reduce(operator.add, lst) def student_max_count(clslist): lst = [0] + [x.capacity for x in clslist if x.category.category != 'Lunch'] return reduce(operator.add, lst) curTimeslot['studentcount'] = { 'count': student_count(timeslot_dict[timeslot]), 'max_count': student_max_count(timeslot_dict[timeslot]) } vitals['timeslots'].append(curTimeslot) dictOut["stats"].append(vitals) shirt_data = {"id": "shirtnum"}; adminvitals_shirt = prog.getShirtInfo() shirt_data["sizes"] = adminvitals_shirt['shirt_sizes']; shirt_data["types"] = adminvitals_shirt['shirt_types']; shirt_data["data"] = adminvitals_shirt['shirts']; dictOut["stats"].append(shirt_data); Q_categories = Q(program=prog) crmi = prog.classregmoduleinfo if crmi.open_class_registration: Q_categories |= Q(pk=prog.open_class_category.pk) # Introduce a separate query to get valid categories, since the single query seemed to introduce duplicates program_categories = ClassCategories.objects.filter(Q_categories).distinct().values_list('id', flat=True) annotated_categories = ClassCategories.objects.filter(cls__parent_program=prog, cls__status__gte=0).annotate(num_subjects=Count('cls', distinct=True), num_sections=Count('cls__sections'), num_class_hours=Sum('cls__sections__duration')).order_by('-num_subjects').values('id', 'num_sections', 'num_subjects', 'num_class_hours', 'category').distinct() # Convert Decimal values to float for serialization for i in range(len(annotated_categories)): annotated_categories[i]['num_class_hours'] = float(annotated_categories[i]['num_class_hours']) dictOut["stats"].append({"id": "categories", "data": filter(lambda x: x['id'] in program_categories, annotated_categories)}) ## Calculate the grade data: grades = [i for i in range(prog.grade_min, prog.grade_max+1)] # We can't perfectly trust most_recent_profile, but it's good enough for stats students_grades = students['enrolled'].filter(registrationprofile__most_recent_profile=True) students_grades = students_grades.values_list('registrationprofile__student_info__graduation_year') students_grades = students_grades.annotate(Count('id', distinct=True)) grades_dict = {result[0]: result[1] for result in students_grades} grades_results = [] for g in grades: year = ESPUser.YOGFromGrade(g, ESPUser.program_schoolyear(prog)) grade_classes = classes.filter(status__gte=0, grade_min__lte=g, grade_max__gte=g) grade_sections = prog.sections().filter(status__gte=0, parent_class__in=grade_classes) grades_results.append({'grade': g, 'num_subjects': grade_classes.count(), 'num_sections': grade_sections.count(), 'num_students': grades_dict[year] if year in grades_dict else 0}) dictOut["stats"].append({"id": "grades", "data": grades_results}) # Add SplashInfo statistics if our program has them splashinfo_data = {} splashinfo_modules = filter(lambda x: isinstance(x, SplashInfoModule), prog.getModules('learn')) if len(splashinfo_modules) > 0: splashinfo_module = splashinfo_modules[0] tag_data = Tag.getProgramTag('splashinfo_choices', prog) if tag_data: splashinfo_choices = json.loads(tag_data) else: splashinfo_choices = {'lunchsat': SplashInfoForm.default_choices, 'lunchsun': SplashInfoForm.default_choices} for key in splashinfo_choices: counts = {} for item in splashinfo_choices[key]: filter_kwargs = {'program': prog} filter_kwargs[key] = item[0] counts[item[1]] = SplashInfo.objects.filter(**filter_kwargs).distinct().count() splashinfo_data[key] = counts splashinfo_data['siblings'] = { 'yes': SplashInfo.objects.filter(program=prog, siblingdiscount=True).distinct().count(), 'no': SplashInfo.objects.filter(program=prog).exclude(siblingdiscount=True).distinct().count() } dictOut["stats"].append({"id": "splashinfo", "data": splashinfo_data}) # Add accounting stats pac = ProgramAccountingController(prog) (num_payments, total_payment) = pac.payments_summary() accounting_data = { 'num_payments': num_payments, # We need to convert to a float in order for json to serialize it. # Since we're not doing any computation client-side with these # numbers, this doesn't cause accuracy issues. If the # total_payment is None, just coerce it to zero for display # purposes. 'total_payments': float(total_payment or 0), } dictOut["stats"].append({"id": "accounting", "data": accounting_data}) return dictOut
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 restype_formset = e.restype_formset else: errors = {} resource_types = set([]) default_restypes = Tag.getProgramTag( 'default_restypes', program=self.program, ) if default_restypes: resource_type_labels = json.loads(default_restypes) resource_types = resource_types.union( set([ ResourceType.get_or_create(x, self.program) for x in resource_type_labels ])) if static_resource_requests: # With static resource requests, we need to display a form # each available type --- there's no way to add the types # that we didn't start out with # Thus, if default_restype isn't set, we display everything # potentially relevant
def ajax_requests(self, request, tl, one, two, module, extra, prog): """ Handle a request for modifying a ResourceRequestFormSet. This view is customized to handle the dynamic form (i.e. resource type is specified in advance and loaded into a hidden field). """ static_resource_requests = Tag.getProgramTag( 'static_resource_requests', prog, ) # Construct a formset from post data resource_formset = ResourceRequestFormSet( request.POST, prefix='request', static_resource_requests=static_resource_requests, ) validity = resource_formset.is_valid() form_dicts = [x.__dict__ for x in resource_formset.forms] # Retrieve data from forms form_datas = [ x.cleaned_data for x in resource_formset.forms if hasattr(x, 'cleaned_data') ] form_datas_filtered = [ x for x in form_datas if x.has_key('resource_type') ] if request.POST.has_key('action'): # Modify form if an action is specified if request.POST['action'] == 'add': # Construct initial data including new form new_restype = ResourceType.objects.get( id=request.POST['restype']) if len(new_restype.choices) > 0: new_data = form_datas_filtered + [{ 'desired_value': new_restype.choices[0] }] else: new_data = form_datas_filtered + [{}] new_types = [x['resource_type'] for x in form_datas_filtered] + [new_restype] elif request.POST['action'] == 'remove': # Construct initial data removing undesired form form_to_remove = int(request.POST['form']) new_data = form_datas_filtered[: form_to_remove] + form_datas_filtered[ (form_to_remove + 1):] new_types = [x['resource_type'] for x in new_data] # Instantiate a new formset having the additional form new_formset = ResourceRequestFormSet( initial=new_data, resource_type=new_types, prefix='request', static_resource_requests=static_resource_requests, ) else: # Otherwise, just send back the original form new_formset = resource_formset # Render an HTML fragment with the new formset context = {} context['formset'] = new_formset context['ajax_request'] = True formset_str = render_to_string( self.baseDir() + 'requests_form_fragment.html', context) formset_script = render_to_string( self.baseDir() + 'requests_form_fragment.js', context) return HttpResponse( json.dumps({ 'request_forms_html': formset_str, 'script': formset_script }))
def testProgramTag(self): '''Test the logic of getProgramTag in a bunch of different conditions.''' # Delete any existing tags that might interfere Tag.objects.filter(key="test").delete() # Dump any existing Tag cache Tag._getTag.delete_all() #Caching is hard, so what the hell, let's run every assertion twice. self.assertFalse(Tag.getProgramTag("test",program=self.program)) self.assertFalse(Tag.getProgramTag("test",program=self.program)) self.assertFalse(Tag.getProgramTag("test",program=None)) self.assertFalse(Tag.getProgramTag("test",program=None)) self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"the default") self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"the default") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"the default") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"the default") # Set the program-specific tag Tag.setTag("test",target=self.program,value="program tag value") self.assertFalse(Tag.getProgramTag("test",program=None)) self.assertFalse(Tag.getProgramTag("test",program=None)) self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"the default") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"the default") self.assertEqual(Tag.getProgramTag("test",program=self.program),"program tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program),"program tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"program tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"program tag value") # Now set the general tag Tag.setTag("test",target=None,value="general tag value") self.assertEqual(Tag.getProgramTag("test",program=None),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=None),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program),"program tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program),"program tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"program tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"program tag value") # Now unset the program-specific tag Tag.unSetTag("test",target=self.program) self.assertEqual(Tag.getProgramTag("test",program=None),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=None),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"general tag value") self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"general tag value") #just to clean up Tag.unSetTag("test",target=None) self.assertFalse(Tag.getProgramTag("test",program=self.program)) self.assertFalse(Tag.getProgramTag("test",program=self.program)) self.assertFalse(Tag.getProgramTag("test",program=None)) self.assertFalse(Tag.getProgramTag("test",program=None)) self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"the default") self.assertEqual(Tag.getProgramTag("test",program=self.program,default="the default"),"the default") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"the default") self.assertEqual(Tag.getProgramTag("test",program=None,default="the default"),"the default")