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