[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/getpatchwork/patchwork/main/patchwork/forms.py [Back]  [Original]

# Patchwork - automated patch tracking system
# Copyright (C) 2008 Jeremy Kerr 
#
# SPDX-License-Identifier: GPL-2.0-or-later

from django.contrib.auth.models import User
from django import forms
from django.forms import renderers
from django.db.models import Q
from django.db.utils import ProgrammingError
from django.template.backends import django as django_template_backend

from patchwork.models import Bundle
from patchwork.models import Patch
from patchwork.models import State
from patchwork.models import UserProfile


class PatchworkTableRenderer(renderers.EngineMixin, renderers.BaseRenderer):
    backend = django_template_backend.DjangoTemplates
    form_template_name = 'django/forms/table.html'
    formset_template_name = 'django/forms/formsets/table.html'


class RegistrationForm(forms.Form):
    first_name = forms.CharField(max_length=30, required=False)
    last_name = forms.CharField(max_length=30, required=False)
    username = forms.RegexField(
        regex=r'^\w+$',
        max_length=30,
        label='Username',
    )
    email = forms.EmailField(max_length=100, label='Email address')
    password = forms.CharField(widget=forms.PasswordInput(), label='Password')

    def clean_username(self):
        value = self.cleaned_data['username']
        try:
            User.objects.get(username__iexact=value)
        except User.DoesNotExist:
            return self.cleaned_data['username']
        raise forms.ValidationError(
            'This username is already taken. Please choose another.'
        )

    def clean_email(self):
        value = self.cleaned_data['email']
        try:
            user = User.objects.get(email__iexact=value)
        except User.DoesNotExist:
            return self.cleaned_data['email']
        raise forms.ValidationError(
            'This email address is already in use '
            'for the account "%s".\n' % user.username
        )

    def clean(self):
        return self.cleaned_data


class BundleForm(forms.ModelForm):
    name = forms.RegexField(
        regex=r'^[^/]+$',
        min_length=1,
        max_length=50,
        required=False,
        error_messages={'invalid': "Bundle names can't contain slashes"},
        widget=forms.TextInput(
            attrs={'class': 'create-bundle', 'placeholder': 'Bundle name'}
        ),
    )

    class Meta:
        model = Bundle
        fields = ['name', 'public']


class CreateBundleForm(BundleForm):
    def clean_name(self):
        name = self.cleaned_data['name']
        if not name:
            raise forms.ValidationError(
                'No bundle name was specified', code='invalid'
            )

        count = Bundle.objects.filter(
            owner=self.instance.owner, name=name
        ).count()
        if count > 0:
            raise forms.ValidationError(
                'A bundle called %(name)s already exists',
                code='invalid',
                params={'name': name},
            )
        return name

    class Meta:
        model = Bundle
        fields = ['name']


class DeleteBundleForm(forms.Form):
    name = 'deletebundleform'
    form_name = forms.CharField(initial=name, widget=forms.HiddenInput)
    bundle_id = forms.IntegerField(widget=forms.HiddenInput)


class EmailForm(forms.Form):
    email = forms.EmailField(max_length=200)


class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['items_per_page', 'show_ids']
        labels = {'show_ids': 'Show Patch IDs:'}


def _get_delegate_qs(project, instance=None):
    if instance and not project:
        project = instance.project

    if not project:
        raise ValueError('Expected a project')

    q = Q(
        profile__in=UserProfile.objects.filter(maintainer_projects=project)
        .values('pk')
        .query
    )
    if instance and instance.delegate:
        q = q | Q(username=instance.delegate)

    return User.objects.complex_filter(q)


class PatchForm(forms.ModelForm):
    def __init__(self, instance=None, project=None, *args, **kwargs):
        super(PatchForm, self).__init__(instance=instance, *args, **kwargs)
        self.fields['delegate'] = forms.ModelChoiceField(
            queryset=_get_delegate_qs(project, instance),
            widget=forms.Select(attrs={'class': 'change-property-delegate'}),
            required=False,
        )

    class Meta:
        model = Patch
        fields = ['state', 'archived', 'delegate']
        widgets = {
            'state': forms.Select(attrs={'class': 'change-property-state'}),
            'archived': forms.CheckboxInput(
                attrs={'class': 'archive-patch-check'}
            ),
        }


class OptionalModelChoiceField(forms.ModelChoiceField):
    no_change_choice = ('*', 'No change')
    to_field_name = None

    def __init__(self, *args, placeholder, className, **kwargs):
        self.no_change_choice = ('*', placeholder)
        self.widget = forms.Select(attrs={'class': className})
        super(OptionalModelChoiceField, self).__init__(
            initial=self.no_change_choice[0], *args, **kwargs
        )

    def _get_choices(self):
        # _get_choices queries the database, which can fail if the db
        # hasn't been initialised yet. catch that and give an empty
        # set of choices for now.
        try:
            choices = list(
                super(OptionalModelChoiceField, self)._get_choices()
            )
        except ProgrammingError:
            choices = []
        choices.append(self.no_change_choice)
        return choices

    choices = property(_get_choices, forms.ChoiceField.choices.fset)

    def is_no_change(self, value):
        return value == self.no_change_choice[0]

    def clean(self, value):
        if value == self.no_change_choice[0]:
            return value
        return super(OptionalModelChoiceField, self).clean(value)


class OptionalBooleanField(forms.TypedChoiceField):
    def __init__(self, className, *args, **kwargs):
        self.widget = forms.Select(attrs={'class': className})
        super(OptionalBooleanField, self).__init__(*args, **kwargs)

    def is_no_change(self, value):
        return value == self.empty_value


class MultiplePatchForm(forms.Form):
    action = 'update'
    archived = OptionalBooleanField(
        className='archive-patch-select',
        choices=[
            ('*', 'No change'),
            ('True', 'Archive'),
            ('False', 'Unarchive'),
        ],
        coerce=lambda x: x == 'True',
        empty_value='*',
        label='Archived',
    )

    def __init__(self, project, *args, **kwargs):
        super(MultiplePatchForm, self).__init__(*args, **kwargs)
        self.fields['delegate'] = OptionalModelChoiceField(
            queryset=_get_delegate_qs(project=project),
            placeholder='Delegate to',
            className='change-property-delegate',
            label='Delegate to',
            required=False,
        )
        self.fields['state'] = OptionalModelChoiceField(
            queryset=State.objects.all(),
            placeholder='Change state',
            className='change-property-state',
            label='Change state',
        )

    def save(self, instance, commit=True):
        opts = instance.__class__._meta
        if self.errors:
            raise ValueError(
                'The %s could not be changed because the data '
                "didn't validate." % opts.object_name
            )
        data = self.cleaned_data
        # Update the instance
        for f in opts.fields:
            if f.name not in data:
                continue

            field = self.fields.get(f.name, None)
            if not field:
                continue

            if field.is_no_change(data[f.name]):
                continue

            setattr(instance, f.name, data[f.name])

        if commit:
            instance.save()
        return instance

Web Proxy Viewer  |  New URL  |  Original Page