]> git.ozlabs.org Git - patchwork/blob - apps/patchwork/forms.py
views: Refactor generic_list() to make it less complicated
[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 from registration.forms import RegistrationFormUniqueEmail
26 from registration.models import RegistrationProfile
27
28 class RegistrationForm(RegistrationFormUniqueEmail):
29     first_name = forms.CharField(max_length = 30, required = False)
30     last_name = forms.CharField(max_length = 30, required = False)
31     username = forms.CharField(max_length=30, label=u'Username')
32     email = forms.EmailField(max_length=100, label=u'Email address')
33     password = forms.CharField(widget=forms.PasswordInput(),
34                                 label='Password')
35     password1 = forms.BooleanField(required = False)
36     password2 = forms.BooleanField(required = False)
37
38     def save(self, profile_callback = None):
39         user = RegistrationProfile.objects.create_inactive_user( \
40                 username = self.cleaned_data['username'],
41                 password = self.cleaned_data['password'],
42                 email = self.cleaned_data['email'],
43                 profile_callback = profile_callback)
44         user.first_name = self.cleaned_data.get('first_name', '')
45         user.last_name = self.cleaned_data.get('last_name', '')
46         user.save()
47
48         # saving the userprofile causes the firstname/lastname to propagate
49         # to the person objects.
50         user.get_profile().save()
51
52         return user
53
54     def clean(self):
55         return self.cleaned_data
56
57 class LoginForm(forms.Form):
58     username = forms.CharField(max_length = 30)
59     password = forms.CharField(widget = forms.PasswordInput)
60
61 class BundleForm(forms.ModelForm):
62     class Meta:
63         model = Bundle
64         fields = ['name', 'public']
65
66 class CreateBundleForm(forms.ModelForm):
67     def __init__(self, *args, **kwargs):
68         super(CreateBundleForm, self).__init__(*args, **kwargs)
69
70     class Meta:
71         model = Bundle
72         fields = ['name']
73
74     def clean_name(self):
75         name = self.cleaned_data['name']
76         count = Bundle.objects.filter(owner = self.instance.owner, \
77                 name = name).count()
78         if count > 0:
79             raise forms.ValidationError('A bundle called %s already exists' \
80                     % name)
81         return name
82
83 class DeleteBundleForm(forms.Form):
84     name = 'deletebundleform'
85     form_name = forms.CharField(initial = name, widget = forms.HiddenInput)
86     bundle_id = forms.IntegerField(widget = forms.HiddenInput)
87
88 class DelegateField(forms.ModelChoiceField):
89     def __init__(self, project, *args, **kwargs):
90         queryset = User.objects.filter(userprofile__in = \
91                 UserProfile.objects \
92                         .filter(maintainer_projects = project) \
93                         .values('pk').query)
94         super(DelegateField, self).__init__(queryset, *args, **kwargs)
95
96
97 class PatchForm(forms.ModelForm):
98     def __init__(self, instance = None, project = None, *args, **kwargs):
99         if (not project) and instance:
100             project = instance.project
101         if not project:
102             raise Exception("meep")
103         super(PatchForm, self).__init__(instance = instance, *args, **kwargs)
104         self.fields['delegate'] = DelegateField(project, required = False)
105
106     class Meta:
107         model = Patch
108         fields = ['state', 'archived', 'delegate']
109
110 class UserProfileForm(forms.ModelForm):
111     class Meta:
112         model = UserProfile
113         fields = ['primary_project', 'patches_per_page']
114
115 class OptionalDelegateField(DelegateField):
116     no_change_choice = ('*', 'no change')
117     to_field_name = None
118
119     def __init__(self, no_change_choice = None, *args, **kwargs):
120         self.filter = None
121         if (no_change_choice):
122             self.no_change_choice = no_change_choice
123         super(OptionalDelegateField, self). \
124             __init__(initial = self.no_change_choice[0], *args, **kwargs)
125
126     def _get_choices(self):
127         choices = list(
128                 super(OptionalDelegateField, self)._get_choices())
129         choices.append(self.no_change_choice)
130         return choices
131
132     choices = property(_get_choices, forms.ChoiceField._set_choices)
133
134     def is_no_change(self, value):
135         return value == self.no_change_choice[0]
136
137     def clean(self, value):
138         if value == self.no_change_choice[0]:
139             return value
140         return super(OptionalDelegateField, self).clean(value)
141
142 class OptionalModelChoiceField(forms.ModelChoiceField):
143     no_change_choice = ('*', 'no change')
144     to_field_name = None
145
146     def __init__(self, no_change_choice = None, *args, **kwargs):
147         self.filter = None
148         if (no_change_choice):
149             self.no_change_choice = no_change_choice
150         super(OptionalModelChoiceField, self). \
151             __init__(initial = self.no_change_choice[0], *args, **kwargs)
152
153     def _get_choices(self):
154         choices = list(
155                 super(OptionalModelChoiceField, self)._get_choices())
156         choices.append(self.no_change_choice)
157         return choices
158
159     choices = property(_get_choices, forms.ChoiceField._set_choices)
160
161     def is_no_change(self, value):
162         return value == self.no_change_choice[0]
163
164     def clean(self, value):
165         if value == self.no_change_choice[0]:
166             return value
167         return super(OptionalModelChoiceField, self).clean(value)
168
169 class MultipleBooleanField(forms.ChoiceField):
170     no_change_choice = ('*', 'no change')
171     def __init__(self, *args, **kwargs):
172         super(MultipleBooleanField, self).__init__(*args, **kwargs)
173         self.choices = [self.no_change_choice] + \
174                 [(True, 'Archived'), (False, 'Unarchived')]
175
176     def is_no_change(self, value):
177         return value == self.no_change_choice[0]
178
179     # TODO: Check whether it'd be worth to use a TypedChoiceField here; I
180     # think that'd allow us to get rid of the custom valid_value() and
181     # to_python() methods.
182     def valid_value(self, value):
183         if value in [v1 for (v1, v2) in self.choices]:
184             return True
185         return False
186
187     def to_python(self, value):
188         if self.is_no_change(value):
189             return value
190         elif value == 'True':
191             return True
192         elif value == 'False':
193             return False
194         else:
195             raise ValueError('Unknown value: %s' % value)
196
197 class MultiplePatchForm(forms.Form):
198     action = 'update'
199     state = OptionalModelChoiceField(queryset = State.objects.all())
200     archived = MultipleBooleanField()
201
202     def __init__(self, project, *args, **kwargs):
203         super(MultiplePatchForm, self).__init__(*args, **kwargs)
204         self.fields['delegate'] = OptionalDelegateField(project = project,
205                 required = False)
206
207     def save(self, instance, commit = True):
208         opts = instance.__class__._meta
209         if self.errors:
210             raise ValueError("The %s could not be changed because the data "
211                     "didn't validate." % opts.object_name)
212         data = self.cleaned_data
213         # Update the instance
214         for f in opts.fields:
215             if not f.name in data:
216                 continue
217
218             field = self.fields.get(f.name, None)
219             if not field:
220                 continue
221
222             if field.is_no_change(data[f.name]):
223                 continue
224
225             setattr(instance, f.name, data[f.name])
226
227         if commit:
228             instance.save()
229         return instance
230
231 class UserPersonLinkForm(forms.Form):
232     email = forms.EmailField(max_length = 200)