Exemplo n.º 1
0
class RevisionDashboardForm(forms.Form):

    locale = forms.ChoiceField(
        choices=LANG_CHOICES,
        # Required for non-translations, which is
        # enforced in Document.clean().
        required=False,
        label=_lazy(u'Locale:'))

    user = StrippedCharField(min_length=1,
                             max_length=255,
                             required=False,
                             label=_lazy(u'User:'******'Topic:'))

    start_date = forms.DateField(
        required=False,
        label=_lazy(u'Start Date:'),
        input_formats=['%m/%d/%Y'],
        widget=forms.TextInput(attrs={'pattern': '\d{1,2}/\d{1,2}/\d{4}'}))

    end_date = forms.DateField(
        required=False,
        label=_lazy(u'End Date:'),
        input_formats=['%m/%d/%Y'],
        widget=forms.TextInput(attrs={'pattern': '\d{1,2}/\d{1,2}/\d{4}'}))
Exemplo n.º 2
0
class TreeMoveForm(forms.Form):
    title = StrippedCharField(
        min_length=1,
        max_length=255,
        required=False,
        widget=forms.TextInput(attrs={'placeholder': TITLE_PLACEHOLDER}),
        label=_lazy(u'Title:'),
        help_text=_lazy(u'Title of article'),
        error_messages={
            'required': TITLE_REQUIRED,
            'min_length': TITLE_SHORT,
            'max_length': TITLE_LONG
        })
    slug = StrippedCharField(min_length=1,
                             max_length=255,
                             widget=forms.TextInput(),
                             label=_lazy(u'New slug:'),
                             help_text=_lazy(u'New article URL'),
                             error_messages={
                                 'required': SLUG_REQUIRED,
                                 'min_length': SLUG_SHORT,
                                 'max_length': SLUG_LONG
                             })

    def clean_slug(self):
        # Removes leading slash and {locale/docs/} if necessary
        # IMPORTANT: This exact same regex is used on the client side, so
        # update both if doing so
        self.cleaned_data['slug'] = re.sub(re.compile(SLUG_CLEANSING_REGEX),
                                           '', self.cleaned_data['slug'])

        return self.cleaned_data['slug']
Exemplo n.º 3
0
class ExampleForm(forms.Form):
    """Example form to test a bunch of Django fields."""
    char = forms.CharField(max_length=10)
    char_optional = forms.CharField(required=False, widget=forms.TextInput())
    file = forms.FileField(max_length=10)
    choice = forms.ChoiceField(choices=((1, 1), (2, 2)))
    stripped_char = StrippedCharField(max_length=10)
    bool = forms.BooleanField()
    textarea = StrippedCharField(widget=forms.Textarea())
    email = forms.EmailField()
    url = forms.URLField(required=False, verify_exists=False)
    date = forms.DateField()
    time = forms.TimeField()
Exemplo n.º 4
0
class TreeMoveForm(forms.Form):
    title = StrippedCharField(
        min_length=1,
        max_length=255,
        required=False,
        widget=forms.TextInput(attrs={'placeholder': TITLE_PLACEHOLDER}),
        label=_lazy(u'Title:'),
        help_text=_lazy(u'Title of article'),
        error_messages={
            'required': TITLE_REQUIRED,
            'min_length': TITLE_SHORT,
            'max_length': TITLE_LONG
        })
    slug = StrippedCharField(min_length=1,
                             max_length=255,
                             widget=forms.TextInput(),
                             label=_lazy(u'New slug:'),
                             help_text=_lazy(u'New article URL'),
                             error_messages={
                                 'required': SLUG_REQUIRED,
                                 'min_length': SLUG_SHORT,
                                 'max_length': SLUG_LONG
                             })
    locale = StrippedCharField(min_length=2,
                               max_length=5,
                               widget=forms.HiddenInput())

    def clean_slug(self):
        # We only want the slug here; inputting a full URL would lead
        # to disaster.
        if '://' in self.cleaned_data['slug']:
            raise forms.ValidationError('Please enter only the slug to move '
                                        'to, not the full URL.')

        # Removes leading slash and {locale/docs/} if necessary
        # IMPORTANT: This exact same regex is used on the client side, so
        # update both if doing so
        self.cleaned_data['slug'] = re.sub(re.compile(SLUG_CLEANSING_REGEX),
                                           '', self.cleaned_data['slug'])

        return self.cleaned_data['slug']

    def clean(self):
        cleaned_data = super(TreeMoveForm, self).clean()
        if set(['slug', 'locale']).issubset(cleaned_data):
            slug, locale = cleaned_data['slug'], cleaned_data['locale']
            try:
                valid_slug_parent(slug, locale)
            except Exception, e:
                raise forms.ValidationError(e.args[0])
        return cleaned_data
Exemplo n.º 5
0
class NewThreadForm(forms.Form):
    """Form to start a new thread."""
    title = StrippedCharField(min_length=5, max_length=255,
                              label=_lazy('Title:'),
                              widget=forms.TextInput(attrs={'size': 80}),
                              error_messages={'required': MSG_TITLE_REQUIRED,
                                              'min_length': MSG_TITLE_SHORT,
                                              'max_length': MSG_TITLE_LONG})
    content = StrippedCharField(
                label=_lazy('Content:'),
                min_length=5,
                max_length=10000,
                widget=forms.Textarea(attrs={'rows': 30, 'cols': 76}),
                error_messages={'required': MSG_CONTENT_REQUIRED,
                                'min_length': MSG_CONTENT_SHORT,
                                'max_length': MSG_CONTENT_LONG})
Exemplo n.º 6
0
class ReviewForm(forms.Form):
    comment = StrippedCharField(max_length=2000, widget=forms.Textarea(),
                                required=False, label=_lazy(u'Comment:'),
                                error_messages={'max_length': COMMENT_LONG})

    _widget = forms.RadioSelect(renderer=RadioFieldRendererWithHelpText)
    significance = forms.ChoiceField(
                    label=_lazy(u'Significance:'),
                    choices=SIGNIFICANCES,
                    initial=SIGNIFICANCES[1][0],
                    required=False, widget=_widget)

    is_ready_for_localization = forms.BooleanField(
        initial=False,
        label=_lazy(u'Ready for localization'),
        required=False)

    needs_change = forms.BooleanField(
        label=_lazy(u'Needs change'),
        initial=False,
        required=False)

    needs_change_comment = forms.CharField(
        label=_lazy(u'Comment:'),
        widget=forms.Textarea(),
        required=False)
Exemplo n.º 7
0
Arquivo: forms.py Projeto: psbots/kuma
class ReviewForm(forms.Form):
    comment = StrippedCharField(max_length=255, widget=forms.Textarea(),
                                required=False, label=_lazy(u'Comment:'),
                                error_messages={'max_length': COMMENT_LONG})

    significance = forms.ChoiceField(
                    label=_lazy(u'Significance:'),
                    choices=SIGNIFICANCES, initial=SIGNIFICANCES[0][0],
                    required=False, widget=forms.RadioSelect())
Exemplo n.º 8
0
class EditThreadForm(forms.ModelForm):
    """Form to start a new thread."""
    title = StrippedCharField(min_length=5, max_length=255,
                              label=_lazy('Title:'),
                              widget=forms.TextInput(attrs={'size': 80}),
                              error_messages={'required': MSG_TITLE_REQUIRED,
                                              'min_length': MSG_TITLE_SHORT,
                                              'max_length': MSG_TITLE_LONG})

    class Meta:
        model = Thread
        fields = ('title',)
Exemplo n.º 9
0
class ReplyForm(forms.ModelForm):
    """Reply form for forum threads."""
    content = StrippedCharField(
                label=_lazy('Content:'),
                min_length=5,
                max_length=10000,
                widget=forms.Textarea(attrs={'rows': 10, 'cols': 80}),
                error_messages={'required': MSG_CONTENT_REQUIRED,
                                'min_length': MSG_CONTENT_SHORT,
                                'max_length': MSG_CONTENT_LONG})

    class Meta:
        model = Post
        fields = ('content', )
Exemplo n.º 10
0
class TreeMoveForm(forms.Form):
    title = StrippedCharField(
        min_length=1,
        max_length=255,
        required=False,
        widget=forms.TextInput(attrs={'placeholder': TITLE_PLACEHOLDER}),
        label=_lazy(u'Title:'),
        help_text=_lazy(u'Title of article'),
        error_messages={
            'required': TITLE_REQUIRED,
            'min_length': TITLE_SHORT,
            'max_length': TITLE_LONG
        })
    slug = StrippedCharField(min_length=1,
                             max_length=255,
                             widget=forms.TextInput(),
                             label=_lazy(u'New slug:'),
                             help_text=_lazy(u'New article URL'),
                             error_messages={
                                 'required': SLUG_REQUIRED,
                                 'min_length': SLUG_SHORT,
                                 'max_length': SLUG_LONG
                             })
Exemplo n.º 11
0
class EditPostForm(forms.Form):
    """Form to edit an existing post."""
    content = StrippedCharField(
            label=_lazy('Content:'),
            min_length=5,
            max_length=10000,
            widget=forms.Textarea(attrs={'rows': 30, 'cols': 76}),
            error_messages={'required': MSG_CONTENT_REQUIRED,
                            'min_length': MSG_CONTENT_SHORT,
                            'max_length': MSG_CONTENT_LONG})

    class Meta:
        model = Post
        exclude = ('thread', 'author', 'updated', 'created', 'updated_by')
Exemplo n.º 12
0
class MediaForm(forms.ModelForm):
    """Common abstractions for Image and Video forms."""
    locale = forms.ChoiceField(required=False,
                               label=_lazy(u'Locale'),
                               choices=[(k, LOCALES[k].native)
                                        for k in settings.SUMO_LANGUAGES],
                               initial=settings.WIKI_DEFAULT_LANGUAGE)
    title = StrippedCharField(required=False,
                              label=_lazy(u'Title'),
                              help_text=TITLE_HELP_TEXT % {'type': u'Image'},
                              min_length=5,
                              max_length=255,
                              error_messages={
                                  'required': MSG_TITLE_REQUIRED,
                                  'min_length': MSG_TITLE_SHORT,
                                  'max_length': MSG_TITLE_LONG
                              })
    description = StrippedCharField(required=False,
                                    label=_lazy(u'Description'),
                                    help_text=DESCRIPTION_HELP_TEXT,
                                    max_length=10000,
                                    widget=forms.Textarea(),
                                    error_messages={
                                        'required': MSG_DESCRIPTION_REQUIRED,
                                        'max_length': MSG_DESCRIPTION_LONG
                                    })

    def __init__(self, *args, **kwargs):
        self.is_ajax = kwargs.pop('is_ajax', True)
        super(MediaForm, self).__init__(*args, **kwargs)
        if not self.is_ajax:
            self.fields['locale'].required = True
            self.fields['title'].required = True
            self.fields['description'].required = True

    def save(self, update_user=None, is_draft=True, **kwargs):
        return save_form(self, update_user, is_draft=is_draft, **kwargs)
Exemplo n.º 13
0
class MarketplaceAaqForm(forms.Form):
    """AAQ Form for Marketplace."""
    def __init__(self, user, *args, **kwargs):
        super(MarketplaceAaqForm, self).__init__(*args, **kwargs)

        # Add email field for users not logged in.
        if not user.is_authenticated():
            email = forms.EmailField(
                label=_lazy(u'Email:'),
                widget=forms.TextInput(
                    attrs={'placeholder': EMAIL_PLACEHOLDER}))
            self.fields['email'] = email

    subject = StrippedCharField(
        label=_lazy(u'Subject:'),
        min_length=4,
        max_length=255,
        widget=forms.TextInput(attrs={'placeholder': SUBJECT_PLACEHOLDER}),
        error_messages={
            'required': SUBJECT_CONTENT_REQUIRED,
            'min_length': SUBJECT_CONTENT_SHORT,
            'max_length': SUBJECT_CONTENT_LONG
        })

    body = StrippedCharField(
        label=_lazy(u'Body:'),
        min_length=5,
        max_length=10000,
        widget=forms.Textarea(attrs={'placeholder': BODY_PLACEHOLDER}),
        error_messages={
            'required': BODY_CONTENT_REQUIRED,
            'min_length': BODY_CONTENT_SHORT,
            'max_length': BODY_CONTENT_LONG
        })

    category = forms.ChoiceField(label=_lazy(u'Category:'),
                                 choices=CATEGORY_CHOICES)
Exemplo n.º 14
0
class AnswerForm(forms.Form):
    """Form for replying to a question."""
    content = StrippedCharField(
        label=_lazy('Content:'),
        min_length=5,
        max_length=10000,
        widget=forms.Textarea(attrs={'placeholder': REPLY_PLACEHOLDER}),
        error_messages={
            'required': MSG_CONTENT_REQUIRED,
            'min_length': MSG_CONTENT_SHORT,
            'max_length': MSG_CONTENT_LONG
        })

    class Meta:
        model = Answer
        fields = ('content', )
Exemplo n.º 15
0
class ReplyForm(forms.ModelForm):
    """Reply form for forum threads."""
    content = StrippedCharField(min_length=5,
                                max_length=10000,
                                widget=forms.Textarea(attrs={
                                    'rows': 10,
                                    'cols': 80
                                }),
                                error_messages={
                                    'required': MSG_CONTENT_REQUIRED,
                                    'min_length': MSG_CONTENT_SHORT,
                                    'max_length': MSG_CONTENT_LONG
                                })

    class Meta:
        model = Post
        exclude = ('thread', 'author', 'created', 'updated', 'updated_by')
Exemplo n.º 16
0
class RevisionForm(forms.ModelForm):
    """Form to create new revisions."""

    title = StrippedCharField(
        min_length=1,
        max_length=255,
        required=False,
        widget=forms.TextInput(attrs={'placeholder': TITLE_PLACEHOLDER}),
        label=_lazy(u'Title:'),
        help_text=_lazy(u'Title of article'),
        error_messages={
            'required': TITLE_REQUIRED,
            'min_length': TITLE_SHORT,
            'max_length': TITLE_LONG
        })
    slug = StrippedCharField(min_length=1,
                             max_length=255,
                             required=False,
                             widget=forms.TextInput(),
                             label=_lazy(u'Slug:'),
                             help_text=_lazy(u'Article URL'),
                             error_messages={
                                 'required': SLUG_REQUIRED,
                                 'min_length': SLUG_SHORT,
                                 'max_length': SLUG_LONG
                             })

    tags = StrippedCharField(required=False, label=_lazy(u'Tags:'))

    keywords = StrippedCharField(required=False,
                                 label=_lazy(u'Keywords:'),
                                 help_text=_lazy(u'Affects search results'))

    summary = StrippedCharField(
        required=False,
        min_length=5,
        max_length=1000,
        widget=forms.Textarea(),
        label=_lazy(u'Search result summary:'),
        help_text=_lazy(u'Only displayed on search results page'),
        error_messages={
            'required': SUMMARY_REQUIRED,
            'min_length': SUMMARY_SHORT,
            'max_length': SUMMARY_LONG
        })

    content = StrippedCharField(min_length=5,
                                max_length=300000,
                                label=_lazy(u'Content:'),
                                widget=forms.Textarea(),
                                error_messages={
                                    'required': CONTENT_REQUIRED,
                                    'min_length': CONTENT_SHORT,
                                    'max_length': CONTENT_LONG
                                })

    comment = StrippedCharField(required=False, label=_lazy(u'Comment:'))

    review_tags = forms.MultipleChoiceField(
        label=_("Tag this revision for review?"),
        widget=CheckboxSelectMultiple,
        required=False,
        choices=REVIEW_FLAG_TAGS)

    localization_tags = forms.MultipleChoiceField(
        label=_("Tag this revision for localization?"),
        widget=CheckboxSelectMultiple,
        required=False,
        choices=LOCALIZATION_FLAG_TAGS)

    current_rev = forms.CharField(required=False, widget=forms.HiddenInput())

    class Meta(object):
        model = Revision
        fields = ('title', 'slug', 'tags', 'keywords', 'summary', 'content',
                  'comment', 'based_on', 'toc_depth', 'render_max_age')

    def __init__(self, *args, **kwargs):

        # Snag some optional kwargs and delete them before calling
        # super-constructor.
        for n in ('section_id', 'is_iframe_target'):
            if n not in kwargs:
                setattr(self, n, None)
            else:
                setattr(self, n, kwargs[n])
                del kwargs[n]

        super(RevisionForm, self).__init__(*args, **kwargs)
        self.fields['based_on'].widget = forms.HiddenInput()

        if self.instance and self.instance.pk:

            # Ensure both title and slug are populated from parent document, if
            # last revision didn't have them
            if not self.instance.title:
                self.initial['title'] = self.instance.document.title
            if not self.instance.slug:
                self.initial['slug'] = self.instance.document.slug

            content = self.instance.content
            if not self.instance.document.is_template:
                tool = wiki.content.parse(content)
                tool.injectSectionIDs()
                if self.section_id:
                    tool.extractSection(self.section_id)
                tool.filterEditorSafety()
                content = tool.serialize()
            self.initial['content'] = content

            self.initial['review_tags'] = [
                x.name for x in self.instance.review_tags.all()
            ]
            self.initial['localization_tags'] = [
                x.name for x in self.instance.localization_tags.all()
            ]

        if self.section_id:
            self.fields['toc_depth'].required = False

    def _clean_collidable(self, name):
        value = self.cleaned_data[name]

        if self.is_iframe_target:
            # Since these collidables can change the URL of the page, changes
            # to them are ignored for an iframe submission
            return getattr(self.instance.document, name)

        error_message = {'slug': SLUG_COLLIDES}.get(name, OTHER_COLLIDES)
        try:
            existing_doc = Document.objects.get(
                locale=self.instance.document.locale, **{name: value})
            if self.instance and self.instance.document:
                if (not existing_doc.redirect_url()
                        and existing_doc.pk != self.instance.document.pk):
                    # There's another document with this value,
                    # and we're not a revision of it.
                    raise forms.ValidationError(error_message)
            else:
                # This document-and-revision doesn't exist yet, so there
                # shouldn't be any collisions at all.
                raise forms.ValidationError(error_message)

        except Document.DoesNotExist:
            # No existing document for this value, so we're good here.
            pass

        return value

    def clean_slug(self):
        # TODO: move this check somewhere else?
        # edits can come in without a slug, so default to the current doc slug
        if not self.cleaned_data['slug']:
            existing_slug = self.instance.document.slug
            self.cleaned_data['slug'] = self.instance.slug = existing_slug
        cleaned_slug = self._clean_collidable('slug')
        return cleaned_slug

    def clean_content(self):
        """Validate the content, performing any section editing if necessary"""
        content = self.cleaned_data['content']

        # If we're editing a section, we need to replace the section content
        # from the current revision.
        if self.section_id and self.instance and self.instance.document:
            # Make sure we start with content form the latest revision.
            full_content = self.instance.document.current_revision.content
            # Replace the section content with the form content.
            tool = wiki.content.parse(full_content)
            tool.replaceSection(self.section_id, content)
            content = tool.serialize()

        return content

    def clean_current_rev(self):
        """If a current revision is supplied in the form, compare it against
        what the document claims is the current revision. If there's a
        difference, then an edit has occurred since the form was constructed
        and we treat it as a mid-air collision."""
        current_rev = self.cleaned_data.get('current_rev', None)

        if not current_rev:
            # If there's no current_rev, just bail.
            return current_rev

        try:
            doc_current_rev = self.instance.document.current_revision.id
            if unicode(current_rev) != unicode(doc_current_rev):

                if (self.section_id and self.instance
                        and self.instance.document):
                    # This is a section edit. So, even though the revision has
                    # changed, it still might not be a collision if the section
                    # in particular hasn't changed.
                    orig_ct = (Revision.objects.get(
                        pk=current_rev).get_section_content(self.section_id))
                    curr_ct = (self.instance.document.current_revision.
                               get_section_content(self.section_id))
                    if orig_ct != curr_ct:
                        # Oops. Looks like the section did actually get
                        # changed, so yeah this is a collision.
                        raise forms.ValidationError(MIDAIR_COLLISION)

                    return current_rev

                else:
                    # No section edit, so this is a flat-out collision.
                    raise forms.ValidationError(MIDAIR_COLLISION)

        except Document.DoesNotExist:
            # If there's no document yet, just bail.
            return current_rev

    def save_section(self, creator, document, **kwargs):
        """Save a section edit."""
        # This is separate because the logic is slightly different and
        # may need to evolve over time; a section edit doesn't submit
        # all the fields, and we need to account for that when we
        # construct the new Revision.

        old_rev = Document.objects.get(
            pk=self.instance.document.id).current_revision
        new_rev = super(RevisionForm, self).save(commit=False, **kwargs)
        new_rev.document = document
        new_rev.creator = creator
        new_rev.toc_depth = old_rev.toc_depth
        new_rev.save()
        new_rev.review_tags.set(*[t.name for t in old_rev.review_tags.all()])
        return new_rev

    def save(self, creator, document, **kwargs):
        """Persist me, and return the saved Revision.

        Take several other necessary pieces of data that aren't from the
        form.

        """
        if self.section_id and self.instance and \
           self.instance.document:
            return self.save_section(creator, document, **kwargs)
        # Throws a TypeError if somebody passes in a commit kwarg:
        new_rev = super(RevisionForm, self).save(commit=False, **kwargs)

        new_rev.document = document
        new_rev.creator = creator
        new_rev.toc_depth = self.cleaned_data['toc_depth']
        new_rev.save()
        new_rev.review_tags.set(*self.cleaned_data['review_tags'])
        new_rev.localization_tags.set(*self.cleaned_data['localization_tags'])
        return new_rev
Exemplo n.º 17
0
class DocumentForm(forms.ModelForm):
    """Form to create/edit a document."""

    title = StrippedCharField(
        min_length=1,
        max_length=255,
        widget=forms.TextInput(attrs={'placeholder': TITLE_PLACEHOLDER}),
        label=_lazy(u'Title:'),
        help_text=_lazy(u'Title of article'),
        error_messages={
            'required': TITLE_REQUIRED,
            'min_length': TITLE_SHORT,
            'max_length': TITLE_LONG
        })
    slug = StrippedCharField(min_length=1,
                             max_length=255,
                             widget=forms.TextInput(),
                             label=_lazy(u'Slug:'),
                             help_text=_lazy(u'Article URL'),
                             error_messages={
                                 'required': SLUG_REQUIRED,
                                 'min_length': SLUG_SHORT,
                                 'max_length': SLUG_LONG
                             })

    firefox_versions = forms.MultipleChoiceField(
        label=_lazy(u'Firefox version:'),
        choices=[(v.id, v.long) for v in FIREFOX_VERSIONS],
        initial=[v.id for v in GROUPED_FIREFOX_VERSIONS[0][1]],
        required=False,
        widget=forms.CheckboxSelectMultiple())

    operating_systems = forms.MultipleChoiceField(
        label=_lazy(u'Operating systems:'),
        choices=[(o.id, o.name) for o in OPERATING_SYSTEMS],
        initial=[o.id for o in GROUPED_OPERATING_SYSTEMS[0][1]],
        required=False,
        widget=forms.CheckboxSelectMultiple())

    category = forms.ChoiceField(
        choices=CATEGORIES,
        initial=10,
        # Required for non-translations, which is
        # enforced in Document.clean().
        required=False,
        label=_lazy(u'Category:'),
        help_text=_lazy(u'Type of article'),
        widget=forms.HiddenInput())

    parent_topic = forms.ModelChoiceField(queryset=Document.objects.all(),
                                          required=False,
                                          label=_lazy(u'Parent:'))

    locale = forms.CharField(widget=forms.HiddenInput())

    def clean_slug(self):
        slug = self.cleaned_data['slug']
        if slug == '':
            # Default to the title, if missing.
            slug = self.cleaned_data['title']
        # "?" disallowed in slugs altogether
        if '?' in slug:
            raise forms.ValidationError(SLUG_INVALID)
        # Pattern copied from urls.py
        if not re.compile(r'^[^\$]+$').match(slug):
            raise forms.ValidationError(SLUG_INVALID)
        # Guard against slugs that match urlpatterns
        for pat in RESERVED_SLUGS:
            if re.compile(pat).match(slug):
                raise forms.ValidationError(SLUG_INVALID)
        return slug

    def clean_firefox_versions(self):
        data = self.cleaned_data['firefox_versions']
        return [FirefoxVersion(item_id=int(x)) for x in data]

    def clean_operating_systems(self):
        data = self.cleaned_data['operating_systems']
        return [OperatingSystem(item_id=int(x)) for x in data]

    class Meta:
        model = Document
        fields = ('title', 'slug', 'category', 'locale')

    def save(self, parent_doc, **kwargs):
        """Persist the Document form, and return the saved Document."""
        doc = super(DocumentForm, self).save(commit=False, **kwargs)
        doc.parent = parent_doc
        if 'parent_topic' in self.cleaned_data:
            doc.parent_topic = self.cleaned_data['parent_topic']
        doc.save()
        self.save_m2m()  # not strictly necessary since we didn't change
        # any m2m data since we instantiated the doc

        if not parent_doc:
            ffv = self.cleaned_data['firefox_versions']
            doc.firefox_versions.all().delete()
            doc.firefox_versions = ffv
            os = self.cleaned_data['operating_systems']
            doc.operating_systems.all().delete()
            doc.operating_systems = os

        return doc
Exemplo n.º 18
0
    def __init__(self, product=None, category=None, *args, **kwargs):
        """Init the form.

        We are adding fields here and not declaratively because the
        form fields to include depend on the selected product/category.
        """
        super(EditQuestionForm, self).__init__(*args, **kwargs)

        #  Extra fields required by product/category selected
        extra_fields = []

        if product:
            extra_fields += product.get('extra_fields', [])
        if category:
            extra_fields += category.get('extra_fields', [])

        #  Add the fields to the form
        error_messages = {
            'required': MSG_TITLE_REQUIRED,
            'min_length': MSG_TITLE_SHORT,
            'max_length': MSG_TITLE_LONG
        }
        field = StrippedCharField(label=TITLE_LABEL,
                                  min_length=5,
                                  max_length=255,
                                  widget=forms.TextInput(),
                                  error_messages=error_messages)
        self.fields['title'] = field

        error_messages = {
            'required': MSG_CONTENT_REQUIRED,
            'min_length': MSG_CONTENT_SHORT,
            'max_length': MSG_CONTENT_LONG
        }
        field = StrippedCharField(label=CONTENT_LABEL,
                                  help_text=CONTENT_HELP,
                                  min_length=5,
                                  max_length=10000,
                                  widget=forms.Textarea(),
                                  error_messages=error_messages)
        self.fields['content'] = field

        if 'sites_affected' in extra_fields:
            field = StrippedCharField(label=SITE_AFFECTED_LABEL,
                                      initial='http://',
                                      required=False,
                                      max_length=255,
                                      widget=forms.TextInput())
            self.fields['sites_affected'] = field

        if 'crash_id' in extra_fields:
            field = StrippedCharField(label=CRASH_ID_LABEL,
                                      help_text=CRASH_ID_HELP,
                                      required=False,
                                      max_length=255,
                                      widget=forms.TextInput())
            self.fields['crash_id'] = field

        if 'frequency' in extra_fields:
            field = forms.ChoiceField(label=FREQUENCY_LABEL,
                                      choices=FREQUENCY_CHOICES,
                                      required=False)
            self.fields['frequency'] = field

        if 'started' in extra_fields:
            field = StrippedCharField(label=STARTED_LABEL,
                                      required=False,
                                      max_length=255,
                                      widget=forms.TextInput())
            self.fields['started'] = field

        if 'addon' in extra_fields:
            field = StrippedCharField(label=ADDON_LABEL,
                                      required=False,
                                      max_length=255,
                                      widget=forms.TextInput())
            self.fields['addon'] = field

        if 'troubleshooting' in extra_fields:
            widget = forms.Textarea(attrs={'class': 'troubleshooting'})
            field = StrippedCharField(label=TROUBLESHOOTING_LABEL,
                                      help_text=TROUBLESHOOTING_HELP,
                                      required=False,
                                      max_length=30000,
                                      widget=widget)
            self.fields['troubleshooting'] = field

        if 'ff_version' in extra_fields:
            field = StrippedCharField(label=FF_VERSION_LABEL, required=False)
            self.fields['ff_version'] = field

        if 'os' in extra_fields:
            self.fields['os'] = StrippedCharField(label=OS_LABEL,
                                                  required=False)

        if 'plugins' in extra_fields:
            widget = forms.Textarea(attrs={'class': 'plugins'})
            self.fields['plugins'] = StrippedCharField(label=PLUGINS_LABEL,
                                                       required=False,
                                                       widget=widget)
Exemplo n.º 19
0
class RevisionForm(forms.ModelForm):
    """Form to create new revisions."""
    keywords = StrippedCharField(required=False,
                                 label=_lazy(u'Keywords:'),
                                 help_text=_lazy(u'Affects search results'))

    summary = StrippedCharField(
                min_length=5, max_length=1000, widget=forms.Textarea(),
                label=_lazy(u'Search result summary:'),
                help_text=_lazy(u'Only displayed on search results page'),
                error_messages={'required': SUMMARY_REQUIRED,
                                'min_length': SUMMARY_SHORT,
                                'max_length': SUMMARY_LONG})

    showfor_data = {
        'oses': [(smart_str(c[0][0]), [(o.slug, smart_str(o.name)) for
                                    o in c[1]]) for
                 c in GROUPED_OPERATING_SYSTEMS],
        'versions': [(smart_str(c[0][0]), [(v.slug, smart_str(v.name)) for
                                        v in c[1] if v.show_in_ui]) for
                     c in GROUPED_FIREFOX_VERSIONS]}
    content = StrippedCharField(
                min_length=5, max_length=100000,
                label=_lazy(u'Content:'),
                widget=forms.Textarea(attrs={'data-showfor':
                                             json.dumps(showfor_data)}),
                error_messages={'required': CONTENT_REQUIRED,
                                'min_length': CONTENT_SHORT,
                                'max_length': CONTENT_LONG})

    comment = StrippedCharField(required=False, label=_lazy(u'Comment:'))

    class Meta(object):
        model = Revision
        fields = ('keywords', 'summary', 'content', 'comment', 'based_on')

    def __init__(self, *args, **kwargs):
        super(RevisionForm, self).__init__(*args, **kwargs)
        self.fields['based_on'].widget = forms.HiddenInput()
        self.fields['comment'].widget = forms.TextInput(
            attrs={'maxlength': MAX_REVISION_COMMENT_LENGTH})

    def save(self, creator, document, based_on_id=None, base_rev=None,
             **kwargs):
        """Persist me, and return the saved Revision.

        Take several other necessary pieces of data that aren't from the
        form.

        """
        # Throws a TypeError if somebody passes in a commit kwarg:
        new_rev = super(RevisionForm, self).save(commit=False, **kwargs)

        new_rev.document = document
        new_rev.creator = creator

        if based_on_id:
            new_rev.based_on_id = based_on_id

        # If the user doesn't have edit keywords permission, don't change.
        if base_rev and not creator.has_perm('wiki.edit_keywords'):
            new_rev.keywords = base_rev.keywords

        new_rev.save()
        return new_rev
Exemplo n.º 20
0
class DocumentForm(forms.ModelForm):
    """Form to create/edit a document."""
    def __init__(self, *args, **kwargs):
        # Quasi-kwargs:
        can_archive = kwargs.pop('can_archive', False)
        initial_title = kwargs.pop('initial_title', '')

        super(DocumentForm, self).__init__(*args, **kwargs)

        title_field = self.fields['title']
        title_field.initial = initial_title

        slug_field = self.fields['slug']
        slug_field.initial = slugify(initial_title)

        topics_field = self.fields['topics']
        topics_field.choices = Topic.objects.values_list('id', 'title')

        products_field = self.fields['products']
        products_field.choices = Product.objects.values_list('id', 'title')

        # If user hasn't permission to frob is_archived, remove the field. This
        # causes save() to skip it as well.
        if not can_archive:
            del self.fields['is_archived']

    title = StrippedCharField(
        min_length=5, max_length=255,
        widget=forms.TextInput(),
        label=_lazy(u'Title:'),
        help_text=_lazy(u'Title of article'),
        error_messages={'required': TITLE_REQUIRED,
                        'min_length': TITLE_SHORT,
                        'max_length': TITLE_LONG})

    # We don't use forms.SlugField because it is too strict in
    # what it allows (English/Roman alpha-numeric characters and dashes).
    # Instead, we do custom validation in `clean_slug` below.
    slug = StrippedCharField(
        min_length=3, max_length=255,
        widget=forms.TextInput(),
        label=_lazy(u'Slug:'),
        help_text=_lazy(u'Article URL'),
        error_messages={'required': SLUG_REQUIRED,
                        'min_length': SLUG_SHORT,
                        'max_length': SLUG_LONG})

    products = forms.MultipleChoiceField(
        label=_lazy(u'Relevant to:'),
        required=False,
        widget=forms.CheckboxSelectMultiple())

    is_localizable = forms.BooleanField(
        initial=True,
        label=_lazy(u'Allow translations:'),
        required=False)

    is_archived = forms.BooleanField(
        label=_lazy(u'Obsolete:'),
        required=False)

    allow_discussion = forms.BooleanField(
        label=_lazy(u'Allow discussion on this article?'),
        initial=True,
        required=False)

    category = forms.ChoiceField(
        choices=CATEGORIES,
        # Required for non-translations, which is
        # enforced in Document.clean().
        required=False,
        label=_lazy(u'Category:'),
        help_text=_lazy(u'Type of article'))

    topics = forms.MultipleChoiceField(
        label=_lazy(u'Topics:'),
        required=False,
        widget=forms.CheckboxSelectMultiple())

    locale = forms.CharField(widget=forms.HiddenInput())

    needs_change = forms.BooleanField(
        label=_lazy(u'Needs change:'),
        initial=False,
        required=False)

    needs_change_comment = forms.CharField(
        label=_lazy(u'Comment:'),
        widget=forms.Textarea(),
        required=False)

    def clean_slug(self):
        slug = self.cleaned_data['slug']
        # Blacklist /, ? and +
        if not re.compile(r'^[^/^\+^\?]+$').match(slug):
            raise forms.ValidationError(SLUG_INVALID)
        return slug

    def clean(self):
        c = super(DocumentForm, self).clean()
        locale = c.get('locale')

        # Products are required for en-US
        products = c.get('products')
        if (locale == settings.WIKI_DEFAULT_LANGUAGE and
            (not products or len(products) < 1)):
            raise forms.ValidationError(PRODUCT_REQUIRED)

        # Topics are required for en-US
        topics = c.get('topics')
        if (locale == settings.WIKI_DEFAULT_LANGUAGE and
            (not topics or len(topics) < 1)):
            raise forms.ValidationError(TOPIC_REQUIRED)

        return c

    class Meta:
        model = Document
        fields = ('title', 'slug', 'category', 'is_localizable', 'products',
                  'topics', 'locale', 'is_archived', 'allow_discussion',
                  'needs_change', 'needs_change_comment')

    def save(self, parent_doc, **kwargs):
        """Persist the Document form, and return the saved Document."""
        doc = super(DocumentForm, self).save(commit=False, **kwargs)
        doc.parent = parent_doc

        # If document doesn't need change, clear out the comment.
        if not doc.needs_change:
            doc.needs_change_comment = ''

        doc.save()
        self.save_m2m()

        if parent_doc:
            # Products are not set on translations.
            doc.products.remove(*[p for p in doc.products.all()])

        return doc
Exemplo n.º 21
0
class DocumentForm(forms.ModelForm):
    """Form to create/edit a document."""

    title = StrippedCharField(
        min_length=1,
        max_length=255,
        widget=forms.TextInput(attrs={'placeholder': TITLE_PLACEHOLDER}),
        label=_lazy(u'Title:'),
        help_text=_lazy(u'Title of article'),
        error_messages={
            'required': TITLE_REQUIRED,
            'min_length': TITLE_SHORT,
            'max_length': TITLE_LONG
        })

    slug = StrippedCharField(min_length=1,
                             max_length=255,
                             widget=forms.TextInput(),
                             label=_lazy(u'Slug:'),
                             help_text=_lazy(u'Article URL'),
                             error_messages={
                                 'required': SLUG_REQUIRED,
                                 'min_length': SLUG_SHORT,
                                 'max_length': SLUG_LONG
                             })

    category = forms.ChoiceField(
        choices=Document.CATEGORIES,
        initial=10,
        # Required for non-translations, which is
        # enforced in Document.clean().
        required=False,
        label=_lazy(u'Category:'),
        help_text=_lazy(u'Type of article'),
        widget=forms.HiddenInput())

    parent_topic = forms.ModelChoiceField(queryset=Document.objects.all(),
                                          required=False,
                                          label=_lazy(u'Parent:'))

    locale = forms.CharField(widget=forms.HiddenInput())

    def clean_slug(self):
        slug = self.cleaned_data['slug']
        if slug == '':
            # Default to the title, if missing.
            slug = self.cleaned_data['title']
        # "?", " ", quote disallowed in slugs altogether
        if '?' in slug or ' ' in slug or '"' in slug or "'" in slug:
            raise forms.ValidationError(SLUG_INVALID)
        # Pattern copied from urls.py
        if not re.compile(r'^[^\$]+$').match(slug):
            raise forms.ValidationError(SLUG_INVALID)
        # Guard against slugs that match urlpatterns
        for pat in RESERVED_SLUGS:
            if re.compile(pat).match(slug):
                raise forms.ValidationError(SLUG_INVALID)
        return slug

    class Meta:
        model = Document
        fields = ('title', 'slug', 'category', 'locale')

    def save(self, parent_doc, **kwargs):
        """Persist the Document form, and return the saved Document."""
        doc = super(DocumentForm, self).save(commit=False, **kwargs)
        doc.parent = parent_doc
        if 'parent_topic' in self.cleaned_data:
            doc.parent_topic = self.cleaned_data['parent_topic']
        doc.save()
        # not strictly necessary since we didn't change
        # any m2m data since we instantiated the doc
        self.save_m2m()
        return doc
Exemplo n.º 22
0
class DocumentForm(forms.ModelForm):
    """Form to create/edit a document."""
    def __init__(self, *args, **kwargs):
        # Quasi-kwargs:
        can_create_tags = kwargs.pop('can_create_tags', False)
        can_archive = kwargs.pop('can_archive', False)

        super(DocumentForm, self).__init__(*args, **kwargs)

        # Set up tags field, which is instantiated deep within taggit:
        tags_field = self.fields['tags']
        tags_field.widget.can_create_tags = can_create_tags

        # If user hasn't permission to frob is_archived, remove the field. This
        # causes save() to skip it as well.
        if not can_archive:
            del self.fields['is_archived']

    title = StrippedCharField(min_length=5,
                              max_length=255,
                              widget=forms.TextInput(),
                              label=_lazy(u'Title:'),
                              help_text=_lazy(u'Title of article'),
                              error_messages={
                                  'required': TITLE_REQUIRED,
                                  'min_length': TITLE_SHORT,
                                  'max_length': TITLE_LONG
                              })

    # We don't use forms.SlugField because it is too strict in
    # what it allows (English/Roman alpha-numeric characters and dashes).
    # Instead, we do custom validation in `clean_slug` below.
    slug = StrippedCharField(min_length=3,
                             max_length=255,
                             widget=forms.TextInput(),
                             label=_lazy(u'Slug:'),
                             help_text=_lazy(u'Article URL'),
                             error_messages={
                                 'required': SLUG_REQUIRED,
                                 'min_length': SLUG_SHORT,
                                 'max_length': SLUG_LONG
                             })

    products = forms.MultipleChoiceField(label=_lazy(u'Relevant to:'),
                                         choices=PRODUCTS,
                                         initial=[PRODUCTS[0][0]],
                                         required=False,
                                         widget=forms.CheckboxSelectMultiple())

    is_localizable = forms.BooleanField(initial=True,
                                        label=_lazy(u'Allow translations:'),
                                        required=False)

    is_archived = forms.BooleanField(label=_lazy(u'Obsolete:'), required=False)

    allow_discussion = forms.BooleanField(
        label=_lazy(u'Allow discussion on this article?'),
        initial=True,
        required=False)

    category = forms.ChoiceField(
        choices=CATEGORIES,
        # Required for non-translations, which is
        # enforced in Document.clean().
        required=False,
        label=_lazy(u'Category:'),
        help_text=_lazy(u'Type of article'))

    tags = tag_forms.TagField(
        required=False,
        label=_lazy(u'Topics:'),
        help_text=_lazy(u'Popular articles in each topic are displayed on the '
                        'front page'))

    locale = forms.CharField(widget=forms.HiddenInput())

    needs_change = forms.BooleanField(label=_lazy(u'Needs change:'),
                                      initial=False,
                                      required=False)

    needs_change_comment = forms.CharField(label=_lazy(u'Comment:'),
                                           widget=forms.Textarea(),
                                           required=False)

    def clean_slug(self):
        slug = self.cleaned_data['slug']
        # Blacklist /, ? and +
        if not re.compile(r'^[^/^\+^\?]+$').match(slug):
            raise forms.ValidationError(SLUG_INVALID)
        return slug

    class Meta:
        model = Document
        fields = ('title', 'slug', 'category', 'is_localizable', 'products',
                  'tags', 'locale', 'is_archived', 'allow_discussion',
                  'needs_change', 'needs_change_comment')

    def save(self, parent_doc, **kwargs):
        """Persist the Document form, and return the saved Document."""
        doc = super(DocumentForm, self).save(commit=False, **kwargs)
        doc.parent = parent_doc

        # If document doesn't need change, clear out the comment.
        if not doc.needs_change:
            doc.needs_change_comment = ''

        doc.save()
        self.save_m2m()  # not strictly necessary since we didn't change
        # any m2m data since we instantiated the doc

        if not parent_doc:
            # Set the products as tags.
            # products are not set on the translations.
            prods = self.cleaned_data['products']
            doc.tags.add(*prods)
            doc.tags.remove(*[p for p in PRODUCT_TAGS if p not in prods])

        return doc