class EditPageForm(MarkupContentMixin(field_name='markup_content'), EditPageFileForm): title = forms.CharField(max_length=60, widget=forms.TextInput(attrs={'size':50})) markup_content = MarkupContentField(label='Content', with_wysiwyg=True) comment = CommentField() def __init__(self, instance=None, *args, **kwargs): if instance: # push the initial values into the page object, to make MarkupContentMixin happy version = instance.current_version() instance.markup_content = version.wikitext instance.markup = version.markup() instance.math = version.math() super(EditPageForm, self).__init__(instance=instance, *args, **kwargs) @transaction.atomic def save(self, editor, *args, **kwargs): # create the PageVersion object: distribute the self.cleaned_data values appropriately wikitext = self.cleaned_data['markup_content'] comment = self.cleaned_data['comment'] title = self.cleaned_data['title'] pv = PageVersion(title=title, wikitext=wikitext, comment=comment, editor=editor) pv.set_markup(self.cleaned_data['_markup']) pv.set_math(self.cleaned_data['_math']) self.instance.offering = self.offering pg = super(EditPageForm, self).save(*args, **kwargs) pv.page=self.instance pv.save() return pg
class AdvisorNoteForm(MarkupContentMixin(field_name='text'), forms.ModelForm): text = MarkupContentField(label="Content", default_markup='plain', allow_math=False, restricted=False, with_wysiwyg=True) email_student = forms.BooleanField( required=False, help_text="Should the student be emailed the contents of this note?") def __init__(self, student, *args, **kwargs): # Only needed for the clean_email_student below, so that we may check for an email and display a validation # error if needed. The view handles sending the actual email afterwards. self.student = student super().__init__(*args, **kwargs) def clean_email_student(self): email = self.cleaned_data['email_student'] if email and not self.student.email(): raise ValidationError( "We don't have an email address for this student: cannot email them here." ) return email class Meta: model = AdvisorNote exclude = ('hidden', 'emailed', 'created_at', 'config')
class _DiscussionTopicForm(MarkupContentMixin(field_name='content'), forms.ModelForm): title = forms.CharField(widget=TextInput(attrs={'size': 60}), help_text="What is this topic about?") content = MarkupContentField(label='Content', with_wysiwyg=True, restricted=True, rows=10) class Meta: model = DiscussionTopic exclude = ('offering', 'last_activity_at', 'created_at', 'message_count', 'author', 'config', 'status', 'pinned')
class DiscussionMessageForm(MarkupContentMixin(field_name='content'), forms.ModelForm): content = MarkupContentField(label='Content', with_wysiwyg=True, restricted=True, rows=10) class Meta: model = DiscussionMessage exclude = ('topic', 'created_at', 'modified_at', 'status', 'author', 'config')
class MessageForm(MarkupContentMixin(), forms.ModelForm): content = MarkupContentField(rows=10, with_wysiwyg=False, default_markup='textile', allow_math=False, restricted=True) class Meta: model = NewsItem # these fields are decided from the request at the time the form is submitted exclude = [ 'user', 'author', 'published', 'updated', 'source_app', 'course', 'read', 'config' ]
class AnnouncementForm(MarkupContentMixin(field_name='message'), forms.ModelForm): message = MarkupContentField(default_markup='plain', allow_math=False, restricted=False, with_wysiwyg=True) class Meta: model = Announcement exclude = ('hidden', 'author', 'created_at', 'config') def __init__(self, units: Iterable[Unit], *args, **kwargs): super().__init__(*args, **kwargs) # force unit choice to be as specified: self.fields['unit'].queryset = Unit.objects.filter( id__in=(u.id for u in units)) self.fields['unit'].empty_label = None
class QuizForm(MarkupContentMixin(field_name='intro'), QuizTimeBaseForm): grace = forms.IntegerField(required=True, min_value=0, max_value=3600, initial=300, label='Grace time', help_text=mark_safe('Number of seconds after the “true” end of the quiz that ' 'students may submit their answers (but not reload the quiz to continue working).')) honour_code = forms.BooleanField(required=False, initial=True, help_text="Require students to agree to the honour code before they can proceed with the quiz?") photo_verification = forms.BooleanField(required=False, initial=True, help_text="Require students to take a photo with their webcam when submitting the quiz?") intro = MarkupContentField(required=False, label='Introductory Text (displayed at the top of the quiz, optional)', default_markup=DEFAULT_QUIZ_MARKUP, with_wysiwyg=True) review = forms.ChoiceField(required=True, label='Student Review', initial='none', choices=REVIEW_CHOICES, help_text="Allow students to review the quiz?") honour_code_text = MarkupContentField(required=False, label='Honour Code Text', initial=(HONOUR_CODE_DEFAULT, DEFAULT_QUIZ_MARKUP, False), default_markup=DEFAULT_QUIZ_MARKUP, with_wysiwyg=True, allow_math=False) class Meta: model = Quiz fields = ['start', 'end'] widgets = {} def __init__(self, activity: Activity, instance: Optional[Quiz] = None, *args, **kwargs): self.activity = activity super().__init__(instance=instance, *args, **kwargs) if instance: self.initial['grace'] = instance.grace self.initial['honour_code'] = instance.honour_code self.initial['photo_verification'] = instance.photos self.initial['review'] = instance.review self.initial['honour_code_text'] = instance.honour_code_text, instance.honour_code_markup, instance.honour_code_math def clean(self): cleaned_data = super().clean() # all Quiz instances must have the activity where we're editing self.instance.activity = self.activity self.instance.grace = cleaned_data['grace'] self.instance.honour_code = cleaned_data['honour_code'] self.instance.photos = cleaned_data['photo_verification'] self.instance.review = cleaned_data['review'] hc_text, hc_markup, hc_math = cleaned_data['honour_code_text'] if self.instance.honour_code and not hc_text: self.add_error('honour_code_text', 'Must give text for honour code if that functionality is enabled.') self.instance.honour_code_text = hc_text self.instance.honour_code_markup = hc_markup self.instance.honour_code_math = hc_math return cleaned_data
class ReminderForm(MarkupContentMixin(), forms.ModelForm): content = MarkupContentField(allow_math=False, restricted=True) role_unit = forms.ChoiceField(label='Role', choices=[], required=False) # choices filled by __init__ def __init__(self, person, *args, **kwargs): self.person = person courses_set = Reminder.relevant_courses(person) courses = sorted(list(courses_set)) course_choices = [(c.id, str(c)) for c in courses] role_unit_choices = [('%s %s' % (r.role, r.unit_id), '%s(s) in %s' % (ROLES[r.role], r.unit.label)) for r in Role.objects_fresh.filter(person=person)] super().__init__(*args, **kwargs) # set initial for the role_unit field if 'role' in self.initial and self.initial[ 'role'] and 'unit' in self.initial and self.initial['unit']: self.initial['role_unit'] = '%s %i' % (self.initial['role'], self.initial['unit']) else: self.initial['role_unit'] = None self.fields['course'].choices = [(None, '\u2014')] + course_choices # don't show nulls, or INST if user isn't an instructor of anything self.fields['reminder_type'].choices = [ (k, v) for k, v in self.fields['reminder_type'].choices if k and (courses_set or k != 'INST') ] self.fields['date_type'].choices = [ (k, v) for k, v in self.fields['date_type'].choices if k ] self.fields['role_unit'].choices = role_unit_choices # reorder fields... painfully. role_unit = self.fields['role_unit'] new_order = OrderedDict() for n, f in self.fields.items(): if n in ['role_unit', 'role', 'unit']: continue elif n == 'course': new_order['role_unit'] = role_unit new_order[n] = f self.fields = new_order class Meta: model = Reminder exclude = ['person', 'config', 'status'] widgets = { 'reminder_type': forms.RadioSelect, 'date_type': forms.RadioSelect, } def clean_week(self): week = self.cleaned_data['week'] if week is not None and week < 0: raise forms.ValidationError('Week number must be positive.') if week is not None and week > 16: raise forms.ValidationError('Week number can be no more than 16.') return week def require_null(self, cleaned_data, fields): """ Make sure the field is null. Should only be an issue if the form is fiddled with: UI hides these fields. """ for f in fields: cleaned_data[f] = None def require_non_null(self, cleaned_data, fields): """ Make sure these situationally-required fields are non-null. """ for f in fields: if f not in cleaned_data or not bool(cleaned_data[f]): self.add_error(f, 'This field is required.') def clean(self): cleaned_data = super().clean() # instructor reminders can only be semesterly if 'reminder_type' in cleaned_data and cleaned_data['reminder_type'] == 'INST' \ and 'date_type' in cleaned_data and cleaned_data['date_type'] != 'SEM': self.add_error( 'date_type', 'Course-teaching reminders can only be semesterly.') # make sure the right fields are null/non-null for the various reminder_types and date_types if 'reminder_type' in cleaned_data: if cleaned_data['reminder_type'] == 'PERS': self.require_null(cleaned_data, ['role_unit', 'course']) elif cleaned_data['reminder_type'] == 'INST': self.require_null(cleaned_data, ['role_unit']) self.require_non_null(cleaned_data, ['course']) elif cleaned_data['reminder_type'] == 'ROLE': self.require_null(cleaned_data, ['course']) self.require_non_null(cleaned_data, ['role_unit']) else: raise forms.ValidationError('Unknown reminder type') if 'date_type' in cleaned_data: if cleaned_data['date_type'] == 'SEM': self.require_null(cleaned_data, ['month', 'day']) self.require_non_null(cleaned_data, ['week', 'weekday']) elif cleaned_data['date_type'] == 'YEAR': self.require_null(cleaned_data, ['week', 'weekday']) self.require_non_null(cleaned_data, ['month', 'day']) else: raise forms.ValidationError('Unknown date type') if 'role_unit' in cleaned_data and cleaned_data[ 'role_unit'] is not None: # fill role and unit from role_unit role_unit = cleaned_data['role_unit'] role_name, unit_id = role_unit.split(' ') unit = Unit.objects.get(id=unit_id) cleaned_data['unit'] = unit cleaned_data['role'] = role_name else: cleaned_data['unit'] = None cleaned_data['role'] = None # make sure month/day forms a valid date if 'month' in cleaned_data and cleaned_data['month'] is not None \ and 'day' in cleaned_data and cleaned_data['day'] is not None: try: # poor Feb 29, never getting the respect it deserves. datetime.date(year=2001, month=int(cleaned_data['month']), day=cleaned_data['day']) except ValueError: self.add_error('day', 'Not a valid day in that month.') return cleaned_data