]> git.ozlabs.org Git - patchwork/blob - apps/patchwork/forms.py
03279588a1ef40d045bb02982a49dbed17d6c24e
[patchwork] / apps / patchwork / forms.py
1 # Patchwork - automated patch tracking system
2 # Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
3 #
4 # This file is part of the Patchwork package.
5 #
6 # Patchwork is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # Patchwork is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Patchwork; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20
21 from django.contrib.auth.models import User
22 from django import forms
23
24 from patchwork.models import Patch, State, Bundle, UserProfile
25
26 class RegistrationForm(forms.Form):
27     first_name = forms.CharField(max_length = 30, required = False)
28     last_name = forms.CharField(max_length = 30, required = False)
29     username = forms.RegexField(regex = r'^\w+$', max_length=30,
30                                 label=u'Username')
31     email = forms.EmailField(max_length=100, label=u'Email address')
32     password = forms.CharField(widget=forms.PasswordInput(),
33                                 label='Password')
34
35     def clean_username(self):
36         value = self.cleaned_data['username']
37         try:
38             user = User.objects.get(username__iexact = value)
39         except User.DoesNotExist:
40             return self.cleaned_data['username']
41         raise forms.ValidationError('This username is already taken. ' + \
42                                     'Please choose another.')
43
44     def clean_email(self):
45         value = self.cleaned_data['email']
46         try:
47             user = User.objects.get(email__iexact = value)
48         except User.DoesNotExist:
49             return self.cleaned_data['email']
50         raise forms.ValidationError('This email address is already in use ' + \
51                                     'for the account "%s".\n' % user.username)
52
53     def clean(self):
54         return self.cleaned_data
55
56 class LoginForm(forms.Form):
57     username = forms.CharField(max_length = 30)
58     password = forms.CharField(widget = forms.PasswordInput)
59
60 class BundleForm(forms.ModelForm):
61     name = forms.RegexField(regex = r'^[^/]+$', max_length=50, label=u'Name',
62             error_messages = {'invalid': 'Bundle names can\'t contain slashes'})
63
64     class Meta:
65         model = Bundle
66         fields = ['name', 'public']
67
68 class CreateBundleForm(BundleForm):
69     def __init__(self, *args, **kwargs):
70         super(CreateBundleForm, self).__init__(*args, **kwargs)
71
72     class Meta:
73         model = Bundle
74         fields = ['name']
75
76     def clean_name(self):
77         name = self.cleaned_data['name']
78         count = Bundle.objects.filter(owner = self.instance.owner, \
79                 name = name).count()
80         if count > 0:
81             raise forms.ValidationError('A bundle called %s already exists' \
82                     % name)
83         return name
84
85 class DeleteBundleForm(forms.Form):
86     name = 'deletebundleform'
87     form_name = forms.CharField(initial = name, widget = forms.HiddenInput)
88     bundle_id = forms.IntegerField(widget = forms.HiddenInput)
89
90 class DelegateField(forms.ModelChoiceField):
91     def __init__(self, project, *args, **kwargs):
92         queryset = User.objects.filter(profile__in = \
93                 UserProfile.objects \
94                         .filter(maintainer_projects = project) \
95                         .values('pk').query)
96         super(DelegateField, self).__init__(queryset, *args, **kwargs)
97
98
99 class PatchForm(forms.ModelForm):
100     def __init__(self, instance = None, project = None, *args, **kwargs):
101         if (not project) and instance:
102             project = instance.project
103         if not project:
104             raise Exception("meep")
105         super(PatchForm, self).__init__(instance = instance, *args, **kwargs)
106         self.fields['delegate'] = DelegateField(project, required = False)
107
108     class Meta:
109         model = Patch
110         fields = ['state', 'archived', 'delegate']
111
112 class UserProfileForm(forms.ModelForm):
113     class Meta:
114         model = UserProfile
115         fields = ['primary_project', 'patches_per_page']
116
117 class OptionalDelegateField(DelegateField):
118     no_change_choice = ('*', 'no change')
119     to_field_name = None
120
121     def __init__(self, no_change_choice = None, *args, **kwargs):
122         self.filter = None
123         if (no_change_choice):
124             self.no_change_choice = no_change_choice
125         super(OptionalDelegateField, self). \
126             __init__(initial = self.no_change_choice[0], *args, **kwargs)
127
128     def _get_choices(self):
129         choices = list(
130                 super(OptionalDelegateField, self)._get_choices())
131         choices.append(self.no_change_choice)
132         return choices
133
134     choices = property(_get_choices, forms.ChoiceField._set_choices)
135
136     def is_no_change(self, value):
137         return value == self.no_change_choice[0]
138
139     def clean(self, value):
140         if value == self.no_change_choice[0]:
141             return value
142         return super(OptionalDelegateField, self).clean(value)
143
144 class OptionalModelChoiceField(forms.ModelChoiceField):
145     no_change_choice = ('*', 'no change')
146     to_field_name = None
147
148     def __init__(self, no_change_choice = None, *args, **kwargs):
149         self.filter = None
150         if (no_change_choice):
151             self.no_change_choice = no_change_choice
152         super(OptionalModelChoiceField, self). \
153             __init__(initial = self.no_change_choice[0], *args, **kwargs)
154
155     def _get_choices(self):
156         choices = list(
157                 super(OptionalModelChoiceField, self)._get_choices())
158         choices.append(self.no_change_choice)
159         return choices
160
161     choices = property(_get_choices, forms.ChoiceField._set_choices)
162
163     def is_no_change(self, value):
164         return value == self.no_change_choice[0]
165
166     def clean(self, value):
167         if value == self.no_change_choice[0]:
168             return value
169         return super(OptionalModelChoiceField, self).clean(value)
170
171 class MultipleBooleanField(forms.ChoiceField):
172     no_change_choice = ('*', 'no change')
173     def __init__(self, *args, **kwargs):
174         super(MultipleBooleanField, self).__init__(*args, **kwargs)
175         self.choices = [self.no_change_choice] + \
176                 [(True, 'Archived'), (False, 'Unarchived')]
177
178     def is_no_change(self, value):
179         return value == self.no_change_choice[0]
180
181     # TODO: Check whether it'd be worth to use a TypedChoiceField here; I
182     # think that'd allow us to get rid of the custom valid_value() and
183     # to_python() methods.
184     def valid_value(self, value):
185         if value in [v1 for (v1, v2) in self.choices]:
186             return True
187         return False
188
189     def to_python(self, value):
190         if value is None or self.is_no_change(value):
191             return self.no_change_choice[0]
192         elif value == 'True':
193             return True
194         elif value == 'False':
195             return False
196         else:
197             raise ValueError('Unknown value: %s' % value)
198
199 class MultiplePatchForm(forms.Form):
200     action = 'update'
201     state = OptionalModelChoiceField(queryset = State.objects.all())
202     archived = MultipleBooleanField()
203
204     def __init__(self, project, *args, **kwargs):
205         super(MultiplePatchForm, self).__init__(*args, **kwargs)
206         self.fields['delegate'] = OptionalDelegateField(project = project,
207                 required = False)
208
209     def save(self, instance, commit = True):
210         opts = instance.__class__._meta
211         if self.errors:
212             raise ValueError("The %s could not be changed because the data "
213                     "didn't validate." % opts.object_name)
214         data = self.cleaned_data
215         # Update the instance
216         for f in opts.fields:
217             if not f.name in data:
218                 continue
219
220             field = self.fields.get(f.name, None)
221             if not field:
222                 continue
223
224             if field.is_no_change(data[f.name]):
225                 continue
226
227             setattr(instance, f.name, data[f.name])
228
229         if commit:
230             instance.save()
231         return instance
232
233 class EmailForm(forms.Form):
234     email = forms.EmailField(max_length = 200)
235
236 UserPersonLinkForm = EmailForm
237 OptinoutRequestForm = EmailForm