def test_phase_1(self): #There's a tag that affects phase 1 so we put the tests into a function #and call it twice here Tag.setTag('ask_about_duplicate_accounts',value='true') self.phase_1() Tag.setTag('ask_about_duplicate_accounts',value='false') self.phase_1()
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.getTag('splashinfo_choices', target=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 __init__(self, *args, **kwargs): super(TeacherInfoForm, self).__init__(*args, **kwargs) if Tag.getTag('teacherinfo_shirt_options') == 'False': del self.fields['shirt_size'] del self.fields['shirt_type'] elif Tag.getTag('teacherinfo_shirt_type_selection') == 'False': del self.fields['shirt_type']
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 prepare(self, context={}): context['splashinfo'] = SplashInfo.getForUser(get_current_request().user, self.program) if not Tag.getBooleanTag('splashinfo_siblingdiscount', default=True): context['splashinfo'].include_siblingdiscount = False else: context['splashinfo'].include_siblingdiscount = True context['splashinfo'].include_lunchsat = Tag.getBooleanTag('splashinfo_lunchsat', default=True) context['splashinfo'].include_lunchsun = Tag.getBooleanTag('splashinfo_lunchsun', default=True) return context
def testTagWithTarget(self): '''Test getting and setting of tags with targets.''' # Delete any existing tags that might interfere Tag.objects.filter(key="test").delete() # Dump any existing Tag cache Tag._getTag.delete_all() user, created = User.objects.get_or_create(username="******", email="*****@*****.**", password="") self.assertFalse(Tag.getTag("test", user), "Retrieved a tag for key 'test' target '%s', but we haven't set one yet!" % (user)) Tag.setTag("test", user, "frobbed again") self.assertEqual(Tag.getTag("test", user), "frobbed again") Tag.setTag("test", user) self.assertEqual(Tag.getTag("test", user), Tag.EMPTY_TAG) Tag.unSetTag("test", user) self.assertFalse(Tag.getTag("test", user), "unSetTag() didn't work for per-row tags!")
def phase_1(self): """Testing the phase 1 of registration, the email address page""" #first try an email that shouldn't have an account #first without follow, to see that it redirects correctly response1 = self.client.post("/myesp/register/",data={"email":"*****@*****.**", "confirm_email":"*****@*****.**"}) if not Tag.getBooleanTag('ask_about_duplicate_accounts', default=False): self.assertTemplateUsed(response1,"registration/newuser.html") return self.assertRedirects(response1, "/myesp/register/information?email=tsutton125%40gmail.com") #next, make a user with that email and try the same u=ESPUser.objects.create(email="*****@*****.**") response2 = self.client.post("/myesp/register/",data={"email":"*****@*****.**", "confirm_email":"*****@*****.**"},follow=True) self.assertTemplateUsed(response2, 'registration/newuser_phase1.html') self.assertContains(response2, "do_reg_no_really") #check when there's a user awaiting activation #(we check with a regex searching for _ in the password, since that #can't happen normally) u.password="******" response3 = self.client.post("/myesp/register/",data={"email":"*****@*****.**", "confirm_email":"*****@*****.**"},follow=True) self.assertTemplateUsed(response3, 'registration/newuser_phase1.html') self.assertContains(response3, "do_reg_no_really") #check when you send do_reg_no_really it procedes response4 = self.client.post("/myesp/register/",data={"email":"*****@*****.**", "confirm_email":"*****@*****.**","do_reg_no_really":""},follow=False) self.assertRedirects(response4, "/myesp/register/information?email=tsutton125%40gmail.com") response4 = self.client.post("/myesp/register/",data={"email":"*****@*****.**", "confirm_email":"*****@*****.**","do_reg_no_really":""},follow=True) self.assertContains(response4, "*****@*****.**")
def clean(self): super(UserContactForm, self).clean() if self.user.isTeacher() or Tag.getBooleanTag('request_student_phonenum', default=True): if self.cleaned_data.get('phone_day','') == '' and self.cleaned_data.get('phone_cell','') == '': raise forms.ValidationError("Please provide either a day phone or cell phone number in your personal contact information.") if self.cleaned_data.get('receive_txt_message', None) and self.cleaned_data.get('phone_cell','') == '': raise forms.ValidationError("Please specify your cellphone number if you ask to receive text messages.") return self.cleaned_data
def render_class_teacher_list_row(cls): """Render a class for the teacher list of classes in teacherreg.""" return {'cls': cls, 'program': cls.parent_program, 'crmi': cls.parent_program.classregmoduleinfo, 'friendly_times_with_date': Tag.getBooleanTag( 'friendly_times_with_date', cls.parent_program, False), 'email_host_sender': settings.EMAIL_HOST_SENDER }
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 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 = Tag.getBooleanTag('collapse_full_classes', prog, True) context = {'classes': classes, 'one': one, 'two': two, 'categories': categories.values(), 'collapse_full': collapse_full} scrmi = prog.studentclassregmoduleinfo context['register_from_catalog'] = scrmi.register_from_catalog prog_color = prog.getColor() collapse_full_classes = Tag.getBooleanTag('collapse_full_classes', prog, True) 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) # Include the program explicitly; this is a cached page, without RequestContext context['program'] = self.program return render_to_response(self.baseDir()+'catalog.html', request, context, use_request_context=False)
def get_custom_fields(): result = SortedDict() form_list_str = Tag.getTag('teacherreg_custom_forms') if form_list_str: form_cls_list = json.loads(form_list_str) for item in form_cls_list: mod = __import__('esp.program.modules.forms.teacherreg_custom', (), (), [item]) cls = getattr(mod, item) for field in cls.base_fields: result[field] = cls.base_fields[field] return result
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 load_from_tag(cls, theme_name=None, just_selected=False): data = json.loads(Tag.getTag('theme_template_control', default='{}')) if theme_name is None: tc = ThemeController() theme_name = tc.get_current_theme() data['theme'] = theme_name form_temp = cls(initial=data) data = form_temp.recover_from_serialization(data) data['just_selected'] = just_selected form = cls(initial=data) return form
def get_custom_fields(): result = OrderedDict() form_list_str = Tag.getTag('teacherreg_custom_forms') if form_list_str: form_cls_list = json.loads(form_list_str) for item in form_cls_list: mod = __import__('esp.program.modules.forms.teacherreg_custom', (), (), [item]) cls = getattr(mod, item) for field in cls.base_fields: result[field] = cls.base_fields[field] return result
def render_qsd(qsd): # check whether we should display the date and author footer (only affects non-administrator users) display_date_author_tag = Tag.getTag('qsd_display_date_author', default='Both') display_date_author = 2 # display date and author if display_date_author_tag == 'Date': display_date_author = 1 # display date only elif display_date_author_tag == 'None': display_date_author = 0 # hide footer return {'qsdrec': qsd, 'display_date_author' : display_date_author}
def finaid(self, request, tl, one, two, module, extra, prog): """ Student financial aid requests. This template will redirect the person to an HTTPS address if the appropriate tag is set. """ if Tag.getTag('finaid_directions_step'): return render_to_response(self.baseDir() + 'aid_direct.html', request, (self.program, tl), {}) else: return self.finaid_app(request, tl, one, two, module, extra, prog)
def render_class_helper(cls, user=None, prereg_url=None, filter=False, timeslot=None): errormsg = None if timeslot: section = cls.get_section(timeslot=timeslot) else: section = None # Add ajax_addclass to prereg_url if registering from catalog is allowed ajax_prereg_url = None scrmi = cls.parent_program.getModuleExtension('StudentClassRegModuleInfo') crmi = cls.parent_program.getModuleExtension('ClassRegModuleInfo') # Ensure cached catalog shows buttons and fillslots don't # NOTE: I believe that this is deprecated; it isn't referred to anywhere. # Which means that scrmi.register_from_catalog is currently useless. # This should be fixed. -jmoldow 11/06/2011 if scrmi.register_from_catalog and not timeslot: ajax_prereg_url = cls.parent_program.get_learn_url() + 'ajax_addclass' prereg_url = None if not (crmi.open_class_registration and cls.category == cls.parent_program.open_class_category): prereg_url = cls.parent_program.get_learn_url() + 'addclass' if user and prereg_url and timeslot: errormsg = cls.cannotAdd(user, which_section=section) show_class = (not filter) or (not errormsg) return { 'class': cls, 'section': section, 'user': user, 'prereg_url': prereg_url, 'ajax_prereg_url': ajax_prereg_url, 'errormsg': errormsg, 'temp_full_message': scrmi.temporarily_full_text, 'show_class': show_class, 'hide_full': Tag.getBooleanTag('hide_full_classes', cls.parent_program, False) }
def render_qsd(qsd): # check whether we should display the date and author footer (only affects non-administrator users) display_date_author_tag = Tag.getTag('qsd_display_date_author', default='Both') display_date_author = 2 # display date and author if display_date_author_tag == 'Date': display_date_author = 1 # display date only elif display_date_author_tag == 'None': display_date_author = 0 # hide footer return {'qsdrec': qsd, 'display_date_author': display_date_author}
def filter_username(username, password): # Allow login by e-mail address if so specified if username and '@' in username and Tag.getTag('login_by_email'): accounts = ESPUser.objects.filter(email=username) matches = [] for u in accounts: if u.check_password(password): matches.append(u) if len(matches) > 0: username = matches[0].username return username
def __init__(self, *args, **kwargs): if 'program' in kwargs: self.program = kwargs['program'] del kwargs['program'] else: raise KeyError('Need to supply program as named argument to VolunteerOfferForm') super(VolunteerOfferForm, self).__init__(*args, **kwargs) vrs = self.program.getVolunteerRequests() self.fields['requests'].choices = [(v.id, '%s: %s (%d more needed)' % (v.timeslot.pretty_time(), v.timeslot.description, v.num_volunteers - v.num_offers())) for v in vrs if v.num_offers() < v.num_volunteers] + [(v.id, '%s: %s (no more needed)' % (v.timeslot.pretty_time(), v.timeslot.description)) for v in vrs if v.num_offers() >= v.num_volunteers] # Show t-shirt fields if specified by Tag (disabled by default) if not Tag.getTag('volunteer_tshirt_options'): del self.fields['shirt_size'] del self.fields['shirt_type'] elif not Tag.getTag('volunteer_tshirt_type_selection'): del self.fields['shirt_type'] if not Tag.getTag('volunteer_allow_comments'): del self.fields['comments']
def __init__(self, *args, **kwargs): super(TeacherInfoForm, self).__init__(*args, **kwargs) if not Tag.getTag('teacherinfo_reimbursement_options', default=False): reimbursement_fields = [ 'full_legal_name', 'university_email', 'student_id', 'mail_reimbursement' ] for field_name in reimbursement_fields: del self.fields[field_name] if Tag.getTag('teacherinfo_shirt_options') == 'False': del self.fields['shirt_size'] del self.fields['shirt_type'] elif Tag.getTag('teacherinfo_shirt_type_selection') == 'False': del self.fields['shirt_type'] if Tag.getTag('teacherinfo_shirt_size_required'): self.fields['shirt_size'].required = True self.fields['shirt_size'].widget.attrs['class'] = 'required' if Tag.getTag('teacherinfo_reimbursement_checks') == 'False': del self.fields['mail_reimbursement']
def clear_theme(self, theme_name=None): if theme_name is None: theme_name = self.get_current_theme() # Remove template overrides matching the theme name if themes_settings.THEME_DEBUG: print 'Clearing theme: %s' % theme_name for template_name in self.get_template_names(theme_name): TemplateOverride.objects.filter(name=template_name).delete() if themes_settings.THEME_DEBUG: print '-- Removed template override: %s' % template_name # Clear template override cache TemplateOverrideLoader.get_template_hash.delete_all() # Remove images and script files from the active theme directory if os.path.exists(settings.MEDIA_ROOT + 'images/theme'): distutils.dir_util.remove_tree(settings.MEDIA_ROOT + 'images/theme') if os.path.exists(settings.MEDIA_ROOT + 'scripts/theme'): distutils.dir_util.remove_tree(settings.MEDIA_ROOT + 'scripts/theme') # Remove compiled CSS file if os.path.exists(self.css_filename): os.remove(self.css_filename) Tag.unSetTag('current_theme_name') Tag.unSetTag('current_theme_params') Tag.unSetTag('current_theme_palette') self.unset_current_customization()
def testTagWithTarget(self): '''Test getting and setting of tags with targets.''' # Delete any existing tags that might interfere Tag.objects.filter(key="test").delete() # Dump any existing Tag cache Tag._getTag.delete_all() user, created = User.objects.get_or_create(username="******", email="*****@*****.**", password="") self.assertFalse( Tag.getTag("test", user), "Retrieved a tag for key 'test' target '%s', but we haven't set one yet!" % (user)) Tag.setTag("test", user, "frobbed again") self.assertEqual(Tag.getTag("test", user), "frobbed again") Tag.setTag("test", user) self.assertEqual(Tag.getTag("test", user), Tag.EMPTY_TAG) Tag.unSetTag("test", user) self.assertFalse(Tag.getTag("test", user), "unSetTag() didn't work for per-row tags!")
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 get_template_settings(self): """ Get the current template settings. The base settings are the initial values of the configuration form fields, which are overriden by values in the theme_template_control Tag. """ form_class = self.get_config_form_class(self.get_current_theme()) if form_class is not None: data = form_class.initial_data() else: data = {} data.update(json.loads(Tag.getTag('theme_template_control', default='{}'))) data['theme_name'] = self.get_current_theme() return data
def get_palette(self): palette_base = json.loads(Tag.getTag('current_theme_palette', default='[]')) # Augment with the colors from any global LESS variables palette = set(palette_base) base_vars = self.find_less_variables() for varset in base_vars.values(): for val in varset.values(): if isinstance(val, basestring) and val.startswith('#'): palette.add(val) palette = list(palette) palette.sort() return palette
def prepare(self, context={}): """ prepare returns the context for the main teacherreg page. """ context['can_edit'] = self.deadline_met('/Classes/Edit') context['can_create'] = self.any_reg_is_open() context['can_create_class'] = self.class_reg_is_open() context['can_create_open_class'] = self.open_class_reg_is_open() context['crmi'] = self.crmi context['clslist'] = self.clslist(get_current_request().user) context['friendly_times_with_date'] = Tag.getBooleanTag( 'friendly_times_with_date', self.program, False) context[ 'open_class_category'] = self.program.open_class_category.category return context
def isCompleted(self): """ Make sure that they have indicated sufficient availability for all classes they have signed up to teach. """ available_slots = get_current_request().user.getAvailableTimes( self.program, ignore_classes=True) # Check number of timeslots against Tag-specified minimum if Tag.getTag('min_available_timeslots'): min_ts_count = int(Tag.getTag('min_available_timeslots')) if len(available_slots) < min_ts_count: return False # Round durations of both classes and timeslots to nearest 30 minutes total_time = get_current_request().user.getTaughtTime( self.program, include_scheduled=True, round_to=0.5) available_time = timedelta() for a in available_slots: available_time = available_time + timedelta( seconds=1800 * round(a.duration().seconds / 1800.0)) if (total_time > available_time) or (available_time == timedelta()): return False else: return True
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 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 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 test_grade_range_popup(self): # Login the teacher self.assertTrue(self.client.login(username=self.teacher.username, password='******'), "Couldn't log in as teacher %s" % self.teacher.username) # Try editing the class response = self.client.get('%smakeaclass' % self.program.get_teach_url()) self.assertTrue("grade_range_popup" in response.content) # Add a tag that specifically removes this functionality Tag.setTag('grade_range_popup', self.program, 'False') # Try editing the class response = self.client.get('%smakeaclass' % self.program.get_teach_url()) self.assertTrue(not "grade_range_popup" in response.content) # Change the grade range of the program and reset the tag self.program.grade_min = 7 self.program.grade_max = 8 self.program.save() Tag.setTag('grade_range_popup', self.program, 'True') # Try editing the class response = self.client.get('%smakeaclass' % self.program.get_teach_url()) self.assertTrue(not "check_grade_range" in response.content)
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 user_registration_phase2(request): """Displays the second part of account creation, and when that form is submitted, call a function to handle the actual validation and creation.""" if request.method == 'POST': return user_registration_validate(request) if not Tag.getBooleanTag("ask_about_duplicate_accounts",default=False): return HttpResponseRedirect(reverse("users.views.user_registration_phase1")) try: email = urllib.unquote(request.GET['email']) except MultiValueDictKeyError: return HttpResponseRedirect(reverse("users.views.user_registration_phase1")) form = UserRegForm(initial={'email':email,'confirm_email':email}) return render_to_response('registration/newuser.html', request, {'form':form, 'email':email})
def render_class_teacher_list_row(cls): """Render a class for the teacher list of classes in teacherreg.""" return { 'cls': cls, 'program': cls.parent_program, 'crmi': cls.parent_program.classregmoduleinfo, 'friendly_times_with_date': Tag.getBooleanTag('friendly_times_with_date', cls.parent_program, False), 'email_host_sender': settings.EMAIL_HOST_SENDER }
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 _checkTeacher(moduleObj, request, *args, **kwargs): allowed_teacher_types = Tag.getTag("allowed_teacher_types", moduleObj.program, default='').split(",") if not_logged_in(request): return HttpResponseRedirect('%s?%s=%s' % (LOGIN_URL, REDIRECT_FIELD_NAME, quote(request.get_full_path()))) if not request.user.isTeacher() and not request.user.isAdmin( moduleObj.program) and not (set(request.user.getUserTypes()) & set(allowed_teacher_types)): return render_to_response('errors/program/notateacher.html', request, {}) return method(moduleObj, request, *args, **kwargs)
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 _checkStudent(moduleObj, request, *args, **kwargs): if not_logged_in(request): return HttpResponseRedirect('%s?%s=%s' % (LOGIN_URL, REDIRECT_FIELD_NAME, quote(request.get_full_path()))) if not request.user.isStudent() and not request.user.isAdmin( moduleObj.program): allowed_student_types = Tag.getTag("allowed_student_types", moduleObj.program, default='') matching_user_types = any( x in request.user.groups.all().values_list("name", flat=True) for x in allowed_student_types.split(",")) if not matching_user_types: return render_to_response('errors/program/notastudent.html', request, {}) return method(moduleObj, request, *args, **kwargs)
def clean(self): super(UserContactForm, self).clean() if self.user.isTeacher() or Tag.getBooleanTag( 'request_student_phonenum', default=True): if self.cleaned_data.get('phone_day', '') == '' and self.cleaned_data.get( 'phone_cell', '') == '': raise forms.ValidationError( "Please provide either a day phone or cell phone number in your personal contact information." ) if self.cleaned_data.get('receive_txt_message', None) and self.cleaned_data.get( 'phone_cell', '') == '': raise forms.ValidationError( "Please specify your cellphone number if you ask to receive text messages." ) return self.cleaned_data
def user_registration_checkemail(request): """Method to handle the first phase of registration when submitted as a form. The method user_registration_phase1 calls this function when it's given a POST request. When the form isn't valid, re-render the same template but with the form errors. When there are already accounts with this email address (depending on some tags), give the user information about them before proceeding. """ form = EmailUserRegForm(request.POST) if form.is_valid(): ## First, check to see if we have any users with the same e-mail if not 'do_reg_no_really' in request.POST and Tag.getTag( 'ask_about_duplicate_accounts', default='false').lower() != 'false': existing_accounts = ESPUser.objects.filter( email=form.cleaned_data['email'], is_active=True).exclude(password='******') awaiting_activation_accounts = ESPUser.objects.filter( email=form.cleaned_data['email']).filter( is_active=False, password__regex='\$(.*)_').exclude(password='******') if len(existing_accounts) + len(awaiting_activation_accounts) != 0: #they have accounts. go back to the same page, but ask them #if they want to try to log in return render_to_response( 'registration/newuser_phase1.html', request, request.get_node('Q/Web/myesp'), { 'accounts': existing_accounts, 'awaitings': awaiting_activation_accounts, 'email': form.cleaned_data['email'], 'site': Site.objects.get_current(), 'form': form }) #form is valid, and not caring about multiple accounts email = urllib.quote_plus(form.cleaned_data['email']) return HttpResponseRedirect( reverse('users.views.user_registration_phase2') + '?email=' + email) else: #form is not valid return render_to_response('registration/newuser_phase1.html', request, request.get_node('Q/Web/myesp'), { 'form': form, 'site': Site.objects.get_current() })
def render_class_core(cls): """Render non-user-specific parts of a class for the catalog.""" prog = cls.parent_program scrmi = prog.studentclassregmoduleinfo colorstring = prog.getColor() if colorstring is not None: colorstring = ' background-color:#' + colorstring + ';' # Allow tag configuration of whether class descriptions get collapsed # when the class is full (default: yes) collapse_full = Tag.getBooleanTag('collapse_full_classes', prog, True) return {'class': cls, 'collapse_full': collapse_full, 'colorstring': colorstring, 'show_enrollment': scrmi.visible_enrollments, 'show_emailcodes': scrmi.show_emailcodes, 'show_meeting_times': scrmi.visible_meeting_times}
def registration_redirect(request): """ A view which returns: - A redirect to the currently open registration if exactly one registration is open - A list of open registration links otherwise """ from esp.users.models import ESPUser from esp.program.models import Program user = request.user # prepare the rendered page so it points them to open student/teacher reg's ctxt = {} userrole = {} regperm = None if user.isStudent(): userrole['name'] = 'Student' userrole['base'] = 'learn' userrole['reg'] = 'studentreg' regperm = 'Student/Classes' elif user.isTeacher(): userrole['name'] = 'Teacher' userrole['base'] = 'teach' userrole['reg'] = 'teacherreg' regperm = 'Teacher/Classes' ctxt['userrole'] = userrole if regperm: progs = list(Permission.program_by_perm(user,regperm)) else: progs = [] # If we have 1 program, automatically redirect to registration for that program. # Most chapters will want this, but it can be disabled by a Tag. if len(progs) == 1 and Tag.getBooleanTag('automatic_registration_redirect', default=True): ctxt['prog'] = progs[0] return HttpResponseRedirect(u'/%s/%s/%s' % (userrole['base'], progs[0].getUrlBase(), userrole['reg'])) else: if len(progs) > 0: # Sort available programs newest first progs.sort(key=lambda x: -x.id) ctxt['progs'] = progs ctxt['prog'] = progs[0] return render_to_response('users/profile_complete.html', request, ctxt)
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 ajax_login(request, *args, **kwargs): import simplejson as json from django.contrib.auth import authenticate from django.template.loader import render_to_string username = None password = None if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] username = filter_username(username, password) user = authenticate(username=username, password=password) if user is not None: if user.is_active: result_str = 'Login successful' user, forwarded = UserForwarder.follow(ESPUser(user)) if forwarded: result_str = 'Logged in as "%s" ("%s" is marked as a duplicate account)' % ( user.username, username) auth_login(request, user) else: result_str = 'Account disabled' else: result_str = 'Invalid username or password' request.user = ESPUser(user) content = render_to_string( 'users/loginbox_content.html', RequestContext(request, { 'request': request, 'login_result': result_str })) result_dict = {'loginbox_html': content} if request.user.isAdministrator(): admin_home_url = Tag.getTag('admin_home_page') if admin_home_url: result_dict['script'] = render_to_string( 'users/loginbox_redirect.js', {'target': admin_home_url}) return HttpResponse(json.dumps(result_dict))
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 __init__(self, *args, **kwargs): # Get tag data in the form of a dictionary: # field name -> tag to look up for initial value if 'tag_map' in kwargs: tag_map = kwargs['tag_map'] tag_defaults = {} for field_name in tag_map: # Check for existence of tag tag_data = Tag.getTag(tag_map[field_name]) # Use tag data as initial value if the tag was found if tag_data: tag_defaults[field_name] = tag_data if 'initial' not in kwargs: kwargs['initial'] = {} # Apply defaults to form quietly (don't override provided values) for key in tag_defaults: if key not in kwargs['initial']: kwargs['initial'][key] = tag_defaults[key] # Remove the tag_map so as not to confuse other functions del kwargs['tag_map'] super(FormWithTagInitialValues, self).__init__(*args, **kwargs)
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 phase_2(self): """Testing phase 2, where user provides info, and we make the account""" url = "/myesp/register/" if Tag.getBooleanTag("ask_about_duplicate_accounts", default=False): url+="information/" response = self.client.post(url, data={"username":"******", "password":"******", "confirm_password":"******", "first_name":"first", "last_name":"last", "email":"*****@*****.**", "confirm_email":"*****@*****.**", "initial_role":"Teacher"}) #test that the user was created properly try: u=ESPUser.objects.get(username="******", first_name="first", last_name="last", email="*****@*****.**") except ESPUser.DoesNotExist, ESPUser.MultipleObjectsReturned: self.fail("User not created correctly or created multiple times")
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 __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 __init__(self, *args, **kwargs): super(TeacherProfileForm, self).__init__(*args, **kwargs) for field_name in Tag.getTag('teacher_profile_hide_fields', default='').split(','): if field_name in self.fields: del self.fields[field_name]
def __init__(self, *args, **kwargs): super(UserContactForm, self).__init__(*args, **kwargs) if not Tag.getBooleanTag('request_student_phonenum', default=True): del self.fields['phone_day'] if not Tag.getBooleanTag('text_messages_to_students'): del self.fields['receive_txt_message']