def testGradeChange(self): # Create the admin user adminUser, c1 = ESPUser.objects.get_or_create(username='******') adminUser.set_password('password') adminUser.makeAdmin() # Create the student user studentUser, c2 = ESPUser.objects.get_or_create(username='******') # Make it a student studentUser.makeRole("Student") # Give it a starting grade student_studentinfo = StudentInfo(user=studentUser, graduation_year=ESPUser.YOGFromGrade(9)) student_studentinfo.save() student_regprofile = RegistrationProfile(user=studentUser, student_info=student_studentinfo, most_recent_profile=True) student_regprofile.save() # Check that the grade starts at 9 self.assertTrue(studentUser.getGrade() == 9) # Login the admin self.assertTrue(self.client.login(username="******", password="******")) testGrade = 11 curYear = ESPUser.current_schoolyear() gradYear = curYear + (12 - testGrade) self.client.get("/manage/userview?username=student&graduation_year="+str(gradYear)) self.assertTrue(studentUser.getGrade() == testGrade, "Grades don't match: %s %s" % (studentUser.getGrade(), testGrade)) # Clean up if (c1): adminUser.delete() if (c2): studentUser.delete()
def testGradeChange(self): # Create the admin user adminUser, c1 = ESPUser.objects.get_or_create(username='******') adminUser.set_password('password') make_user_admin(adminUser) # Create the student user studentUser, c2 = ESPUser.objects.get_or_create(username='******') # Make it a student role_bit, created = UserBit.objects.get_or_create(user=studentUser, qsc=GetNode('Q'), verb=GetNode('V/Flags/UserRole/Student'), recursive=False) # Give it a starting grade student_studentinfo = StudentInfo(user=studentUser, graduation_year=ESPUser.YOGFromGrade(9)) student_studentinfo.save() student_regprofile = RegistrationProfile(user=studentUser, student_info=student_studentinfo, most_recent_profile=True) student_regprofile.save() # Check that the grade starts at 9 self.failUnless(studentUser.getGrade() == 9) # Login the admin self.failUnless(self.client.login(username="******", password="******")) testGrade = 11 curYear = ESPUser.current_schoolyear() gradYear = curYear + (12 - testGrade) self.client.get("/manage/userview?username=student&graduation_year="+str(gradYear)) self.failUnless(studentUser.getGrade() == testGrade, "Grades don't match: %s %s" % (studentUser.getGrade(), testGrade)) # Clean up if (c1): adminUser.delete() if (c2): studentUser.delete()
def userview(request): """ Render a template displaying all the information about the specified user """ try: user = ESPUser.objects.get(username=request.GET['username']) except: raise ESPError(False), "Sorry, can't find anyone with that username." teacherbio = TeacherBio.getLastBio(user) if not teacherbio.picture: teacherbio.picture = 'images/not-available.jpg' from esp.users.forms.user_profile import StudentInfoForm if 'graduation_year' in request.GET: student_info = user.getLastProfile().student_info student_info.graduation_year = int(request.GET['graduation_year']) student_info.save() change_grade_form = StudentInfoForm(user=user) if 'disabled' in change_grade_form.fields['graduation_year'].widget.attrs: del change_grade_form.fields['graduation_year'].widget.attrs['disabled'] change_grade_form.fields['graduation_year'].initial = ESPUser.YOGFromGrade(user.getGrade()) change_grade_form.fields['graduation_year'].choices = filter(lambda choice: bool(choice[0]), change_grade_form.fields['graduation_year'].choices) context = { 'user': user, 'taught_classes' : user.getTaughtClasses().order_by('parent_program', 'id'), 'enrolled_classes' : user.getEnrolledSections().order_by('parent_class__parent_program', 'id'), 'taken_classes' : user.getSections().order_by('parent_class__parent_program', 'id'), 'teacherbio': teacherbio, 'domain': settings.SITE_INFO[1], 'change_grade_form': change_grade_form, } return render_to_response("users/userview.html", request, context )
def __init__(self, user=None, *args, **kwargs): from esp.users.models import ESPUser super(StudentInfoForm, self).__init__(user, *args, **kwargs) self.allow_change_grade_level = Tag.getTag('allow_change_grade_level') ## All of these Tags may someday want to be made per-program somehow. ## We don't know the current program right now, though... show_studentrep_application = Tag.getTag('show_studentrep_application') if not show_studentrep_application: ## Only enable the Student Rep form optionally. del self.fields['studentrep'] if (not show_studentrep_application ) or show_studentrep_application == "no_expl": del self.fields['studentrep_expl'] if not Tag.getTag('show_student_tshirt_size_options'): del self.fields['shirt_size'] del self.fields['shirt_type'] elif Tag.getTag('studentinfo_shirt_type_selection') == 'False': del self.fields['shirt_type'] if not Tag.getTag('show_student_vegetarianism_options'): del self.fields['food_preference'] # Allow grade range of students to be customized by a Tag (default is 7-12) self.fields['graduation_year'].choices = [('', '')] + [(str( ESPUser.YOGFromGrade(x)), str(x)) for x in ESPUser.grade_options()] # Add user's current grade if it is out of range and they have already filled out the profile. if user and user.registrationprofile_set.count() > 0: user_grade = user.getGrade() grade_tup = (str(ESPUser.YOGFromGrade(user_grade)), str(user_grade)) if grade_tup not in self.fields['graduation_year'].choices: self.fields['graduation_year'].choices.insert(0, grade_tup) # Honor several possible Tags for customizing the fields that are displayed. if Tag.getTag('show_student_graduation_years_not_grades'): current_grad_year = self.ESPUser.current_schoolyear() new_choices = [] for x in self.fields['graduation_year'].choices: if len(x[0]) > 0: new_choices.append( (str(x[0]), "%s (%sth grade)" % (x[0], x[1]))) else: new_choices.append(x) self.fields['graduation_year'].choices = new_choices if not Tag.getBooleanTag('student_profile_gender_field'): del self.fields['gender'] if not Tag.getTag('ask_student_about_transportation_to_program'): del self.fields['transportation'] if not Tag.getTag('allow_change_grade_level'): if 'initial' in kwargs: initial_data = kwargs['initial'] # Disable the age and grade fields if they already exist. if 'graduation_year' in initial_data and 'dob' in initial_data: self.fields['graduation_year'].widget.attrs[ 'disabled'] = "true" self.fields['graduation_year'].required = False self.fields['dob'].widget.attrs['disabled'] = "true" self.fields['dob'].required = False # Add field asking about medical needs if directed by the Tag if Tag.getTag('student_medical_needs'): self.fields['medical_needs'].widget = forms.Textarea(attrs={ 'cols': 40, 'rows': 3 }) else: del self.fields['medical_needs'] # The unmatched_school field is for students to opt out of selecting a K12School. # If we don't require a K12School to be selected, don't bother showing that field. if not Tag.getBooleanTag('require_school_field', default=False): del self.fields['unmatched_school'] self._user = user
class StudentInfoForm(FormUnrestrictedOtherUser): """ Extra student-specific information """ from esp.users.models import ESPUser from esp.users.models import shirt_sizes, shirt_types, food_choices gender = forms.ChoiceField(choices=[('', ''), ('M', 'Male'), ('F', 'Female')], required=False) graduation_year = forms.ChoiceField(choices=[('', '')] + [(str(ESPUser.YOGFromGrade(x)), str(x)) for x in range(7, 13)]) k12school = AjaxForeignKeyNewformField(key_type=K12School, field_name='k12school', shadow_field_name='school', required=False, label='School') unmatched_school = forms.BooleanField(required=False) school = forms.CharField(max_length=128, required=False) dob = forms.DateField(widget=SplitDateWidget(min_year=datetime.now().year - 20)) studentrep = forms.BooleanField(required=False) studentrep_expl = forms.CharField(required=False) heard_about = DropdownOtherField( required=False, widget=DropdownOtherWidget( choices=zip(HeardAboutESPChoices, HeardAboutESPChoices ))) #forms.CharField(required=False) shirt_size = forms.ChoiceField(choices=([('', '')] + list(shirt_sizes)), required=False) shirt_type = forms.ChoiceField(choices=([('', '')] + list(shirt_types)), required=False) food_preference = forms.ChoiceField(choices=([('', '')] + list(food_choices)), required=False) medical_needs = forms.CharField(required=False) transportation = DropdownOtherField( required=False, widget=DropdownOtherWidget( choices=zip(HowToGetToProgram, HowToGetToProgram))) studentrep_error = True def __init__(self, user=None, *args, **kwargs): from esp.users.models import ESPUser super(StudentInfoForm, self).__init__(user, *args, **kwargs) self.allow_change_grade_level = Tag.getTag('allow_change_grade_level') ## All of these Tags may someday want to be made per-program somehow. ## We don't know the current program right now, though... show_studentrep_application = Tag.getTag('show_studentrep_application') if not show_studentrep_application: ## Only enable the Student Rep form optionally. del self.fields['studentrep'] if (not show_studentrep_application ) or show_studentrep_application == "no_expl": del self.fields['studentrep_expl'] if not Tag.getTag('show_student_tshirt_size_options'): del self.fields['shirt_size'] del self.fields['shirt_type'] elif Tag.getTag('studentinfo_shirt_type_selection') == 'False': del self.fields['shirt_type'] if not Tag.getTag('show_student_vegetarianism_options'): del self.fields['food_preference'] # Allow grade range of students to be customized by a Tag (default is 7-12) self.fields['graduation_year'].choices = [('', '')] + [(str( ESPUser.YOGFromGrade(x)), str(x)) for x in ESPUser.grade_options()] # Add user's current grade if it is out of range and they have already filled out the profile. if user and user.registrationprofile_set.count() > 0: user_grade = user.getGrade() grade_tup = (str(ESPUser.YOGFromGrade(user_grade)), str(user_grade)) if grade_tup not in self.fields['graduation_year'].choices: self.fields['graduation_year'].choices.insert(0, grade_tup) # Honor several possible Tags for customizing the fields that are displayed. if Tag.getTag('show_student_graduation_years_not_grades'): current_grad_year = self.ESPUser.current_schoolyear() new_choices = [] for x in self.fields['graduation_year'].choices: if len(x[0]) > 0: new_choices.append( (str(x[0]), "%s (%sth grade)" % (x[0], x[1]))) else: new_choices.append(x) self.fields['graduation_year'].choices = new_choices if not Tag.getBooleanTag('student_profile_gender_field'): del self.fields['gender'] if not Tag.getTag('ask_student_about_transportation_to_program'): del self.fields['transportation'] if not Tag.getTag('allow_change_grade_level'): if 'initial' in kwargs: initial_data = kwargs['initial'] # Disable the age and grade fields if they already exist. if 'graduation_year' in initial_data and 'dob' in initial_data: self.fields['graduation_year'].widget.attrs[ 'disabled'] = "true" self.fields['graduation_year'].required = False self.fields['dob'].widget.attrs['disabled'] = "true" self.fields['dob'].required = False # Add field asking about medical needs if directed by the Tag if Tag.getTag('student_medical_needs'): self.fields['medical_needs'].widget = forms.Textarea(attrs={ 'cols': 40, 'rows': 3 }) else: del self.fields['medical_needs'] # The unmatched_school field is for students to opt out of selecting a K12School. # If we don't require a K12School to be selected, don't bother showing that field. if not Tag.getBooleanTag('require_school_field', default=False): del self.fields['unmatched_school'] self._user = user def repress_studentrep_expl_error(self): self.studentrep_error = False def clean_graduation_year(self): gy = self.cleaned_data['graduation_year'].strip() try: gy = str(abs(int(gy))) except: if gy != 'G': gy = 'N/A' return gy def clean_heard_about(self): if self.cleaned_data['heard_about'] == 'Other...:': raise forms.ValidationError( "If 'Other...', please provide details") return self.cleaned_data['heard_about'] def clean_transportation(self): if self.cleaned_data['transportation'] == 'Other...:': raise forms.ValidationError( "If 'Other...', please provide details") return self.cleaned_data['transportation'] def clean(self): super(StudentInfoForm, self).clean() cleaned_data = self.cleaned_data show_studentrep_application = Tag.getTag('show_studentrep_application') if show_studentrep_application and show_studentrep_application != "no_expl": expl = self.cleaned_data['studentrep_expl'].strip() if self.studentrep_error and self.cleaned_data[ 'studentrep'] and expl == '': raise forms.ValidationError( "Please enter an explanation if you would like to become a student rep." ) if not Tag.getTag('allow_change_grade_level'): user = self._user orig_prof = RegistrationProfile.getLastProfile(user) # If graduation year and dob were disabled, get old data. if (orig_prof.id is not None) and (orig_prof.student_info is not None): if not 'graduation_year' in cleaned_data: # Get rid of the error saying this is missing del self.errors['graduation_year'] if not 'dob' in cleaned_data: del self.errors['dob'] # Always use the old birthdate if it exists, so that people can't # use something like Firebug to change their age/grade cleaned_data[ 'graduation_year'] = orig_prof.student_info.graduation_year cleaned_data['dob'] = orig_prof.student_info.dob if Tag.getBooleanTag('require_school_field'): if not cleaned_data['k12school'] and not cleaned_data[ 'unmatched_school']: raise forms.ValidationError( "Please select your school from the dropdown list that appears as you type its name. You will need to click on an entry to select it. If you cannot find your school, please type in its full name and check the box below; we will do our best to add it to our database." ) return cleaned_data
def onsite_create(self, request, tl, one, two, module, extra, prog): if request.method == 'POST': form = OnSiteRegForm(request.POST) if form.is_valid(): new_data = form.cleaned_data username = ESPUser.get_unused_username(new_data['first_name'], new_data['last_name']) new_user = ESPUser.objects.create_user( username=username, first_name=new_data['first_name'], last_name=new_data['last_name'], email=new_data['email']) self.student = new_user regProf = RegistrationProfile.getLastForProgram( new_user, self.program) contact_user = ContactInfo(first_name=new_user.first_name, last_name=new_user.last_name, e_mail=new_user.email, user=new_user) contact_user.save() regProf.contact_user = contact_user student_info = StudentInfo( user=new_user, graduation_year=ESPUser.YOGFromGrade( new_data['grade'], ESPUser.program_schoolyear(self.program))) try: if isinstance(new_data['k12school'], K12School): student_info.k12school = new_data['k12school'] else: if isinstance(new_data['k12school'], int): student_info.k12school = K12School.objects.get( id=int(new_data['k12school'])) else: student_info.k12school = K12School.objects.filter( name__icontains=new_data['k12school'])[0] except: student_info.k12school = None student_info.school = new_data[ 'school'] if not student_info.k12school else student_info.k12school.name student_info.save() regProf.student_info = student_info regProf.save() if new_data['paid']: self.createBit('paid') self.updatePaid(True) else: self.updatePaid(False) self.createBit('Attended') if new_data['medical']: self.createBit('Med') if new_data['liability']: self.createBit('Liab') self.createBit('OnSite') new_user.groups.add(Group.objects.get(name="Student")) new_user.recoverPassword() return render_to_response( self.baseDir() + 'reg_success.html', request, { 'student': new_user, 'retUrl': '/onsite/%s/classchange_grid?student_id=%s' % (self.program.getUrlBase(), new_user.id) }) else: form = OnSiteRegForm() return render_to_response(self.baseDir() + 'reg_info.html', request, {'form': form})
def __init__(self, user=None, *args, **kwargs): from esp.users.models import ESPUser super(StudentInfoForm, self).__init__(user, *args, **kwargs) self.allow_change_grade_level = Tag.getTag('allow_change_grade_level') ## All of these Tags may someday want to be made per-program somehow. ## We don't know the current program right now, though... show_studentrep_application = Tag.getTag('show_studentrep_application') if not show_studentrep_application: ## Only enable the Student Rep form optionally. del self.fields['studentrep'] if (not show_studentrep_application) or show_studentrep_application == "no_expl": del self.fields['studentrep_expl'] if not Tag.getTag('show_student_tshirt_size_options'): del self.fields['shirt_size'] del self.fields['shirt_type'] if not Tag.getTag('show_student_vegetarianism_options'): del self.fields['food_preference'] # Allow grade range of students to be customized by a Tag (default is 7-12) custom_grade_options = Tag.getTag('student_grade_options') if custom_grade_options: custom_grade_options = json.loads(custom_grade_options) self.fields['graduation_year'].choices = [('','')]+[(str(ESPUser.YOGFromGrade(x)), str(x)) for x in custom_grade_options] # Add user's current grade if it is out of range and they have already filled out the profile. if user and user.registrationprofile_set.count() > 0: user_grade = user.getGrade() grade_tup = (str(ESPUser.YOGFromGrade(user_grade)), str(user_grade)) if grade_tup not in self.fields['graduation_year'].choices: self.fields['graduation_year'].choices.insert(0, grade_tup) if Tag.getTag('show_student_graduation_years_not_grades'): current_grad_year = self.ESPUser.current_schoolyear() new_choices = [] for x in self.fields['graduation_year'].choices: if len(x[0]) > 0: new_choices.append((str(x[0]), "%s (%sth grade)" % (x[0], x[1]))) else: new_choices.append(x) self.fields['graduation_year'].choices = new_choices if not Tag.getTag('ask_student_about_post_hs_plans'): del self.fields['post_hs'] if not Tag.getTag('ask_student_about_transportation_to_program'): del self.fields['transportation'] if not Tag.getTag('allow_change_grade_level'): if kwargs.has_key('initial'): initial_data = kwargs['initial'] # Disable the age and grade fields if they already exist. if initial_data.has_key('graduation_year') and initial_data.has_key('dob'): self.fields['graduation_year'].widget.attrs['disabled'] = "true" self.fields['graduation_year'].required = False self.fields['dob'].widget.attrs['disabled'] = "true" self.fields['dob'].required = False # Add schoolsystem fields if directed by the Tag if Tag.getTag('schoolsystem'): sysinfo = json.loads(str(Tag.getTag('schoolsystem'))) for key in ['label', 'required', 'help_text']: if key in sysinfo: setattr(self.fields['schoolsystem_id'], key, sysinfo[key]) if 'use_checkbox' in sysinfo and sysinfo['use_checkbox']: if 'label' in sysinfo: self.fields['schoolsystem_optout'].help_text = '<span style="font-size: 0.8em;">Check this box if you don\'t have a %s</span>' % sysinfo['label'] else: self.fields['schoolsystem_optout'].help_text = '<span style="font-size: 0.8em;">Check this box if you don\'t have an ID number</span>' else: del self.fields['schoolsystem_optout'] else: del self.fields['schoolsystem_id'] del self.fields['schoolsystem_optout'] # Add field asking about medical needs if directed by the Tag if Tag.getTag('student_medical_needs'): self.fields['medical_needs'].widget = forms.Textarea(attrs={'cols': 40, 'rows': 3}) else: del self.fields['medical_needs'] # Make the schoolsystem_id field non-required if schoolsystem_optout is checked if self.data and 'schoolsystem_optout' in self.data and 'schoolsystem_id' in self.data: self.data = self.data.copy() if self.data['schoolsystem_optout']: self.fields['schoolsystem_id'].required = False self.data['schoolsystem_id'] = '' # The unmatched_school field is for students to opt out of selecting a K12School. # If we don't require a K12School to be selected, don't bother showing that field. if not Tag.getTag('require_school_field', default=False): del self.fields['unmatched_school'] self._user = user
class StudentInfoForm(FormUnrestrictedOtherUser): """ Extra student-specific information """ from esp.users.models import ESPUser from esp.users.models import shirt_sizes, shirt_types, food_choices graduation_year = forms.ChoiceField(choices=[('', '')]+[(str(ESPUser.YOGFromGrade(x)), str(x)) for x in range(7,13)]) k12school = AjaxForeignKeyNewformField(key_type=K12School, field_name='k12school', shadow_field_name='school', required=False, label='School') unmatched_school = forms.BooleanField(required=False) school = forms.CharField(max_length=128, required=False) dob = forms.DateField(widget=SplitDateWidget(min_year=datetime.now().year-20)) studentrep = forms.BooleanField(required=False) studentrep_expl = forms.CharField(required=False) heard_about = DropdownOtherField(required=False, widget=DropdownOtherWidget(choices=zip(HeardAboutESPChoices, HeardAboutESPChoices)))#forms.CharField(required=False) shirt_size = forms.ChoiceField(choices=([('','')]+list(shirt_sizes)), required=False) shirt_type = forms.ChoiceField(choices=([('','')]+list(shirt_types)), required=False) food_preference = forms.ChoiceField(choices=([('','')]+list(food_choices)), required=False) medical_needs = forms.CharField(required=False) post_hs = DropdownOtherField(required=False, widget=DropdownOtherWidget(choices=zip(WhatToDoAfterHS, WhatToDoAfterHS))) transportation = DropdownOtherField(required=False, widget=DropdownOtherWidget(choices=zip(HowToGetToProgram, HowToGetToProgram))) schoolsystem_id = forms.CharField(max_length=32, required=False) schoolsystem_optout = forms.BooleanField(required=False) studentrep_error = True def __init__(self, user=None, *args, **kwargs): from esp.users.models import ESPUser super(StudentInfoForm, self).__init__(user, *args, **kwargs) self.allow_change_grade_level = Tag.getTag('allow_change_grade_level') ## All of these Tags may someday want to be made per-program somehow. ## We don't know the current program right now, though... show_studentrep_application = Tag.getTag('show_studentrep_application') if not show_studentrep_application: ## Only enable the Student Rep form optionally. del self.fields['studentrep'] if (not show_studentrep_application) or show_studentrep_application == "no_expl": del self.fields['studentrep_expl'] if not Tag.getTag('show_student_tshirt_size_options'): del self.fields['shirt_size'] del self.fields['shirt_type'] if not Tag.getTag('show_student_vegetarianism_options'): del self.fields['food_preference'] # Allow grade range of students to be customized by a Tag (default is 7-12) custom_grade_options = Tag.getTag('student_grade_options') if custom_grade_options: custom_grade_options = json.loads(custom_grade_options) self.fields['graduation_year'].choices = [('','')]+[(str(ESPUser.YOGFromGrade(x)), str(x)) for x in custom_grade_options] # Add user's current grade if it is out of range and they have already filled out the profile. if user and user.registrationprofile_set.count() > 0: user_grade = user.getGrade() grade_tup = (str(ESPUser.YOGFromGrade(user_grade)), str(user_grade)) if grade_tup not in self.fields['graduation_year'].choices: self.fields['graduation_year'].choices.insert(0, grade_tup) if Tag.getTag('show_student_graduation_years_not_grades'): current_grad_year = self.ESPUser.current_schoolyear() new_choices = [] for x in self.fields['graduation_year'].choices: if len(x[0]) > 0: new_choices.append((str(x[0]), "%s (%sth grade)" % (x[0], x[1]))) else: new_choices.append(x) self.fields['graduation_year'].choices = new_choices if not Tag.getTag('ask_student_about_post_hs_plans'): del self.fields['post_hs'] if not Tag.getTag('ask_student_about_transportation_to_program'): del self.fields['transportation'] if not Tag.getTag('allow_change_grade_level'): if kwargs.has_key('initial'): initial_data = kwargs['initial'] # Disable the age and grade fields if they already exist. if initial_data.has_key('graduation_year') and initial_data.has_key('dob'): self.fields['graduation_year'].widget.attrs['disabled'] = "true" self.fields['graduation_year'].required = False self.fields['dob'].widget.attrs['disabled'] = "true" self.fields['dob'].required = False # Add schoolsystem fields if directed by the Tag if Tag.getTag('schoolsystem'): sysinfo = json.loads(str(Tag.getTag('schoolsystem'))) for key in ['label', 'required', 'help_text']: if key in sysinfo: setattr(self.fields['schoolsystem_id'], key, sysinfo[key]) if 'use_checkbox' in sysinfo and sysinfo['use_checkbox']: if 'label' in sysinfo: self.fields['schoolsystem_optout'].help_text = '<span style="font-size: 0.8em;">Check this box if you don\'t have a %s</span>' % sysinfo['label'] else: self.fields['schoolsystem_optout'].help_text = '<span style="font-size: 0.8em;">Check this box if you don\'t have an ID number</span>' else: del self.fields['schoolsystem_optout'] else: del self.fields['schoolsystem_id'] del self.fields['schoolsystem_optout'] # Add field asking about medical needs if directed by the Tag if Tag.getTag('student_medical_needs'): self.fields['medical_needs'].widget = forms.Textarea(attrs={'cols': 40, 'rows': 3}) else: del self.fields['medical_needs'] # Make the schoolsystem_id field non-required if schoolsystem_optout is checked if self.data and 'schoolsystem_optout' in self.data and 'schoolsystem_id' in self.data: self.data = self.data.copy() if self.data['schoolsystem_optout']: self.fields['schoolsystem_id'].required = False self.data['schoolsystem_id'] = '' # The unmatched_school field is for students to opt out of selecting a K12School. # If we don't require a K12School to be selected, don't bother showing that field. if not Tag.getTag('require_school_field', default=False): del self.fields['unmatched_school'] self._user = user def repress_studentrep_expl_error(self): self.studentrep_error = False def clean_graduation_year(self): gy = self.cleaned_data['graduation_year'].strip() try: gy = str(abs(int(gy))) except: if gy != 'G': gy = 'N/A' return gy def clean_heard_about(self): if self.cleaned_data['heard_about'] == 'Other...:': raise forms.ValidationError("If 'Other...', please provide details") return self.cleaned_data['heard_about'] def clean_post_hs(self): if self.cleaned_data['post_hs'] == 'Other...:': raise forms.ValidationError("If 'Other...', please provide details") return self.cleaned_data['post_hs'] def clean_transportation(self): if self.cleaned_data['transportation'] == 'Other...:': raise forms.ValidationError("If 'Other...', please provide details") return self.cleaned_data['transportation'] def clean_schoolsystem_id(self): if Tag.getTag('schoolsystem'): sysinfo = json.loads(str(Tag.getTag('schoolsystem'))) if 'num_digits' in sysinfo: input_str = self.cleaned_data['schoolsystem_id'].strip() if len(input_str) > 0: if len(input_str) != int(sysinfo['num_digits']) or not input_str.isdigit(): raise forms.ValidationError("Please enter a unique %d-digit number." % int(sysinfo['num_digits'])) if 'check_unique' in sysinfo and sysinfo['check_unique']: if StudentInfo.objects.filter(schoolsystem_id=input_str).exclude(user=self._user).exists(): if len(input_str.strip('0')) != 0: raise forms.ValidationError("Someone else has already entered CPS ID number '%s'." % input_str) return self.cleaned_data['schoolsystem_id'] def clean(self): super(StudentInfoForm, self).clean() cleaned_data = self.cleaned_data show_studentrep_application = Tag.getTag('show_studentrep_application') if show_studentrep_application and show_studentrep_application != "no_expl": expl = self.cleaned_data['studentrep_expl'].strip() if self.studentrep_error and self.cleaned_data['studentrep'] and expl == '': raise forms.ValidationError("Please enter an explanation if you would like to become a student rep.") if not Tag.getTag('allow_change_grade_level'): user = self._user orig_prof = RegistrationProfile.getLastProfile(user) # If graduation year and dob were disabled, get old data. if (orig_prof.id is not None) and (orig_prof.student_info is not None): if not cleaned_data.has_key('graduation_year'): # Get rid of the error saying this is missing del self.errors['graduation_year'] if not cleaned_data.has_key('dob'): del self.errors['dob'] # Always use the old birthdate if it exists, so that people can't # use something like Firebug to change their age/grade cleaned_data['graduation_year'] = orig_prof.student_info.graduation_year cleaned_data['dob'] = orig_prof.student_info.dob if Tag.getTag('require_school_field'): if not cleaned_data['k12school'] and not cleaned_data['unmatched_school']: raise forms.ValidationError("Please select your school from the dropdown list that appears as you type its name. You will need to click on an entry to select it. If you cannot find your school, please type in its full name and check the box below; we will do our best to add it to our database.") return cleaned_data
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 query_from_criteria(self, user_type, criteria): """ Get the "base list" consisting of all the users of a specific type. """ if user_type.lower() == 'any': Q_base = Q() else: if user_type not in ESPUser.getTypes(): raise ESPUser(), 'user_type must be one of ' + str( ESPUser.getTypes()) Q_base = ESPUser.getAllOfType(user_type, True) Q_include = Q() Q_exclude = Q() """ Apply the specified criteria to filter the list of users. """ if criteria.has_key('userid') and len(criteria['userid'].strip()) > 0: ## Select users based on their IDs only userid = [] for digit in criteria['userid'].split(','): try: userid.append(int(digit)) except: raise ESPError( False ), 'User id invalid, please enter a number or comma-separated list of numbers.' if criteria.has_key('userid__not'): Q_exclude &= Q(id__in=userid) else: Q_include &= Q(id__in=userid) self.updated = True else: ## Select users based on all other criteria that was entered for field in ['username', 'last_name', 'first_name', 'email']: if criteria.has_key(field) and len( criteria[field].strip()) > 0: # Check that it's a valid regular expression try: rc = re.compile(criteria[field]) except: raise ESPError( False ), 'Invalid search expression, please check your syntax: %s' % criteria[ field] filter_dict = {'%s__iregex' % field: criteria[field]} if criteria.has_key('%s__not' % field): Q_exclude &= Q(**filter_dict) else: Q_include &= Q(**filter_dict) self.updated = True if criteria.has_key('zipcode') and criteria.has_key('zipdistance') and \ len(criteria['zipcode'].strip()) > 0 and len(criteria['zipdistance'].strip()) > 0: try: zipc = ZipCode.objects.get(zip_code=criteria['zipcode']) except: raise ESPError( False ), 'Zip code not found. This may be because you didn\'t enter a valid US zipcode. Tried: "%s"' % criteria[ 'zipcode'] zipcodes = zipc.close_zipcodes(criteria['zipdistance']) # Excludes zipcodes within a certain radius, giving an annulus; can fail to exclude people who used to live outside the radius. # This may have something to do with the Q_include line below taking more than just the most recent profile. -ageng, 2008-01-15 if criteria.has_key('zipdistance_exclude') and len( criteria['zipdistance_exclude'].strip()) > 0: zipcodes_exclude = zipc.close_zipcodes( criteria['zipdistance_exclude']) zipcodes = [ zipcode for zipcode in zipcodes if zipcode not in zipcodes_exclude ] if len(zipcodes) > 0: Q_include &= Q( registrationprofile__contact_user__address_zip__in= zipcodes, registrationprofile__most_recent_profile=True) self.updated = True if criteria.has_key('states') and len( criteria['states'].strip()) > 0: state_codes = criteria['states'].strip().upper().split(',') if criteria.has_key('states__not'): Q_exclude &= Q( registrationprofile__contact_user__address_state__in= state_codes, registrationprofile__most_recent_profile=True) else: Q_include &= Q( registrationprofile__contact_user__address_state__in= state_codes, registrationprofile__most_recent_profile=True) self.updated = True if criteria.has_key('grade_min'): yog = ESPUser.YOGFromGrade(criteria['grade_min']) if yog != 0: Q_include &= Q( registrationprofile__student_info__graduation_year__lte =yog, registrationprofile__most_recent_profile=True) self.updated = True if criteria.has_key('grade_max'): yog = ESPUser.YOGFromGrade(criteria['grade_max']) if yog != 0: Q_include &= Q( registrationprofile__student_info__graduation_year__gte =yog, registrationprofile__most_recent_profile=True) self.updated = True if criteria.has_key('school'): school = criteria['school'] if school: Q_include &= ( Q(studentinfo__school__icontains=school) | Q(studentinfo__k12school__name__icontains=school)) self.updated = True # Filter by graduation years if specifically looking for teachers. possible_gradyears = range(1920, 2020) if criteria.has_key('gradyear_min') and len( criteria['gradyear_min'].strip()) > 0: try: gradyear_min = int(criteria['gradyear_min']) except: raise ESPError( False ), 'Please enter a 4-digit integer for graduation year limits.' possible_gradyears = filter(lambda x: x >= gradyear_min, possible_gradyears) if criteria.has_key('gradyear_max') and len( criteria['gradyear_min'].strip()) > 0: try: gradyear_max = int(criteria['gradyear_max']) except: raise ESPError( False ), 'Please enter a 4-digit integer for graduation year limits.' possible_gradyears = filter(lambda x: x <= gradyear_max, possible_gradyears) if criteria.get('gradyear_min', None) or criteria.get( 'gradyear_max', None): Q_include &= Q( registrationprofile__teacher_info__graduation_year__in=map( str, possible_gradyears), registrationprofile__most_recent_profile=True) self.updated = True return Q_base & (Q_include & ~Q_exclude)
def onsite_create(self, request, tl, one, two, module, extra, prog): if request.method == 'POST': form = OnSiteRegForm(request.POST) if form.is_valid(): new_data = form.cleaned_data username = ESPUser.get_unused_username(new_data['first_name'], new_data['last_name']) new_user = ESPUser(username = username, first_name = new_data['first_name'], last_name = new_data['last_name'], email = new_data['email'], is_staff = False, is_superuser = False) new_user.save() self.student = new_user regProf = RegistrationProfile.getLastForProgram(new_user, self.program) contact_user = ContactInfo(first_name = new_user.first_name, last_name = new_user.last_name, e_mail = new_user.email, user = new_user) contact_user.save() regProf.contact_user = contact_user student_info = StudentInfo(user = new_user, graduation_year = ESPUser.YOGFromGrade(new_data['grade'])) student_info.save() regProf.student_info = student_info regProf.save() if new_data['paid']: self.createBit('Paid') self.updatePaid(True) else: self.updatePaid(False) self.createBit('Attended') if new_data['medical']: self.createBit('MedicalFiled') if new_data['liability']: self.createBit('LiabilityFiled') self.createBit('OnSite') v = GetNode( 'V/Flags/UserRole/Student') ub = UserBit() ub.user = new_user ub.recursive = False ub.qsc = GetNode('Q') ub.verb = v ub.save() new_user.recoverPassword() return render_to_response(self.baseDir()+'reg_success.html', request, (prog, tl), { 'student': new_user, 'retUrl': '/onsite/%s/classchange_grid?student_id=%s' % (self.program.getUrlBase(), new_user.id) }) else: form = OnSiteRegForm() return render_to_response(self.baseDir()+'reg_info.html', request, (prog, tl), {'form':form, 'current_year':ESPUser.current_schoolyear()})