Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 28f4439f

History | View | Annotate | Download (39 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 18ffbee1 Sofia Papagiannaki
#
3 64cd4730 Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 64cd4730 Antony Chazapis
# without modification, are permitted provided that the following
5 64cd4730 Antony Chazapis
# conditions are met:
6 18ffbee1 Sofia Papagiannaki
#
7 64cd4730 Antony Chazapis
#   1. Redistributions of source code must retain the above
8 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
9 64cd4730 Antony Chazapis
#      disclaimer.
10 18ffbee1 Sofia Papagiannaki
#
11 64cd4730 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 64cd4730 Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 64cd4730 Antony Chazapis
#      provided with the distribution.
15 18ffbee1 Sofia Papagiannaki
#
16 64cd4730 Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64cd4730 Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64cd4730 Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64cd4730 Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64cd4730 Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64cd4730 Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64cd4730 Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64cd4730 Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64cd4730 Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64cd4730 Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64cd4730 Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64cd4730 Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 18ffbee1 Sofia Papagiannaki
#
29 64cd4730 Antony Chazapis
# The views and conclusions contained in the software and
30 64cd4730 Antony Chazapis
# documentation are those of the authors and should not be
31 64cd4730 Antony Chazapis
# interpreted as representing official policies, either expressed
32 64cd4730 Antony Chazapis
# or implied, of GRNET S.A.
33 8f378756 Sofia Papagiannaki
from urlparse import urljoin
34 caf70869 Sofia Papagiannaki
from random import random
35 69b26576 Sofia Papagiannaki
from datetime import datetime, timedelta
36 64cd4730 Antony Chazapis
37 64cd4730 Antony Chazapis
from django import forms
38 64cd4730 Antony Chazapis
from django.utils.translation import ugettext as _
39 e1a80257 Sofia Papagiannaki
from django.contrib.auth.forms import (
40 e1a80257 Sofia Papagiannaki
    UserCreationForm, AuthenticationForm,
41 e1a80257 Sofia Papagiannaki
    PasswordResetForm, PasswordChangeForm,
42 73fbaec4 Sofia Papagiannaki
    SetPasswordForm)
43 f9224cc0 Sofia Papagiannaki
from django.core.mail import send_mail, get_connection
44 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
45 e2125441 Sofia Papagiannaki
from django.template import Context, loader
46 e2125441 Sofia Papagiannaki
from django.utils.http import int_to_base36
47 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
48 18ffbee1 Sofia Papagiannaki
from django.utils.safestring import mark_safe
49 49790d9d Sofia Papagiannaki
from django.utils.encoding import smart_str
50 1cbce16f Sofia Papagiannaki
from django.conf import settings
51 678b2236 Sofia Papagiannaki
from django.forms.models import fields_for_model
52 d2633501 Kostas Papadimitriou
from django.db import transaction
53 caf70869 Sofia Papagiannaki
from django.utils.encoding import smart_unicode
54 caf70869 Sofia Papagiannaki
from django.core import validators
55 e1a80257 Sofia Papagiannaki
from django.contrib.auth.models import AnonymousUser
56 e47fb17a Sofia Papagiannaki
from django.core.exceptions import PermissionDenied
57 5ed6816e Sofia Papagiannaki
58 678b2236 Sofia Papagiannaki
from astakos.im.models import (
59 73fbaec4 Sofia Papagiannaki
    AstakosUser, EmailChange, Invitation,
60 e1a80257 Sofia Papagiannaki
    Resource, PendingThirdPartyUser, get_latest_terms, RESOURCE_SEPARATOR,
61 e47fb17a Sofia Papagiannaki
    ProjectApplication, Project)
62 c0b26605 Sofia Papagiannaki
from astakos.im.settings import (
63 c0b26605 Sofia Papagiannaki
    INVITATIONS_PER_LEVEL, BASEURL, SITENAME, RECAPTCHA_PRIVATE_KEY,
64 c0b26605 Sofia Papagiannaki
    RECAPTCHA_ENABLED, DEFAULT_CONTACT_EMAIL, LOGGING_LEVEL,
65 2e90e3ec Kostas Papadimitriou
    PASSWORD_RESET_EMAIL_SUBJECT, NEWPASSWD_INVALIDATE_TOKEN,
66 272cf735 Sofia Papagiannaki
    MODERATION_ENABLED, PROJECT_MEMBER_JOIN_POLICIES,
67 17ad5d37 Kostas Papadimitriou
    PROJECT_MEMBER_LEAVE_POLICIES, EMAILCHANGE_ENABLED)
68 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
69 e47fb17a Sofia Papagiannaki
from astakos.im.functions import (
70 ff67242a Giorgos Korfiatis
    send_change_email, submit_application, accept_membership_checks)
71 270dd48d Sofia Papagiannaki
72 43332a76 Kostas Papadimitriou
from astakos.im.util import reserved_email, reserved_verified_email, \
73 43332a76 Kostas Papadimitriou
                            get_query, model_to_dict
74 c4b1a172 Kostas Papadimitriou
from astakos.im import auth_providers
75 64cd4730 Antony Chazapis
76 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
77 64cd4730 Antony Chazapis
78 3bf924ec Sofia Papagiannaki
import logging
79 49790d9d Sofia Papagiannaki
import hashlib
80 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
81 caf70869 Sofia Papagiannaki
import re
82 64cd4730 Antony Chazapis
83 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
84 e015e9e6 Sofia Papagiannaki
85 caf70869 Sofia Papagiannaki
DOMAIN_VALUE_REGEX = re.compile(
86 892410d3 Sofia Papagiannaki
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
87 73fbaec4 Sofia Papagiannaki
    re.IGNORECASE)
88 d2633501 Kostas Papadimitriou
89 caf70869 Sofia Papagiannaki
class StoreUserMixin(object):
90 e5966bd9 Kostas Papadimitriou
91 d2633501 Kostas Papadimitriou
    def store_user(self, user, request):
92 43332a76 Kostas Papadimitriou
        """
93 43332a76 Kostas Papadimitriou
        WARNING: this should be wrapped inside a transactional view/method.
94 43332a76 Kostas Papadimitriou
        """
95 d2633501 Kostas Papadimitriou
        user.save()
96 d2633501 Kostas Papadimitriou
        self.post_store_user(user, request)
97 d2633501 Kostas Papadimitriou
        return user
98 d2633501 Kostas Papadimitriou
99 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
100 d2633501 Kostas Papadimitriou
        """
101 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
102 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
103 d2633501 Kostas Papadimitriou
        """
104 d2633501 Kostas Papadimitriou
        pass
105 d2633501 Kostas Papadimitriou
106 d2633501 Kostas Papadimitriou
107 d2633501 Kostas Papadimitriou
class LocalUserCreationForm(UserCreationForm, StoreUserMixin):
108 890b0eaf Sofia Papagiannaki
    """
109 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
110 18ffbee1 Sofia Papagiannaki

111 e47fb17a Sofia Papagiannaki
    * Adds email, first_name, last_name, recaptcha_challenge_field,
112 e47fb17a Sofia Papagiannaki
    * recaptcha_response_field field.
113 5ed6816e Sofia Papagiannaki
    * The username field isn't visible and it is assigned a generated id.
114 18ffbee1 Sofia Papagiannaki
    * User created is not active.
115 890b0eaf Sofia Papagiannaki
    """
116 db7fecd9 Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
117 5ce3ce4f Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(
118 5ce3ce4f Sofia Papagiannaki
        widget=RecaptchaWidget, label='')
119 18ffbee1 Sofia Papagiannaki
120 794852f2 Sofia Papagiannaki
    class Meta:
121 794852f2 Sofia Papagiannaki
        model = AstakosUser
122 5ce3ce4f Sofia Papagiannaki
        fields = ("email", "first_name", "last_name",
123 5ce3ce4f Sofia Papagiannaki
                  "has_signed_terms", "has_signed_terms")
124 18ffbee1 Sofia Papagiannaki
125 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
126 64cd4730 Antony Chazapis
        """
127 890b0eaf Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
128 64cd4730 Antony Chazapis
        """
129 bf0c6de5 Sofia Papagiannaki
        request = kwargs.pop('request', None)
130 672d445a Sofia Papagiannaki
        if request:
131 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
132 672d445a Sofia Papagiannaki
                                       request.META.get('HTTP_X_REAL_IP', None))
133 ab8bfb29 Kostas Papadimitriou
134 15efc749 Sofia Papagiannaki
        super(LocalUserCreationForm, self).__init__(*args, **kwargs)
135 890b0eaf Sofia Papagiannaki
        self.fields.keyOrder = ['email', 'first_name', 'last_name',
136 d8f63346 Sofia Papagiannaki
                                'password1', 'password2']
137 1b3398a0 Olga Brani
138 53bf2659 Sofia Papagiannaki
        if RECAPTCHA_ENABLED:
139 53bf2659 Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
140 5ce3ce4f Sofia Papagiannaki
                                         'recaptcha_response_field', ])
141 1b3398a0 Olga Brani
        if get_latest_terms():
142 1b3398a0 Olga Brani
            self.fields.keyOrder.append('has_signed_terms')
143 18ffbee1 Sofia Papagiannaki
144 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
145 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
146 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
147 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
148 5ce3ce4f Sofia Papagiannaki
                % (reverse('latest_terms'), _("the terms"))
149 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
150 5ce3ce4f Sofia Papagiannaki
                mark_safe("I agree with %s" % terms_link_html)
151 18ffbee1 Sofia Papagiannaki
152 af4eb974 Sofia Papagiannaki
    def clean_email(self):
153 e5966bd9 Kostas Papadimitriou
        email = self.cleaned_data['email']
154 881c856c Sofia Papagiannaki
        if not email:
155 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
156 43332a76 Kostas Papadimitriou
        if reserved_verified_email(email):
157 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
158 0a569195 Sofia Papagiannaki
        return email
159 18ffbee1 Sofia Papagiannaki
160 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
161 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
162 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
163 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
164 270dd48d Sofia Papagiannaki
        return has_signed_terms
165 18ffbee1 Sofia Papagiannaki
166 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
167 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
168 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
169 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
170 db7fecd9 Sofia Papagiannaki
171 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
172 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
173 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
174 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
175 db7fecd9 Sofia Papagiannaki
176 db7fecd9 Sofia Papagiannaki
    def validate_captcha(self):
177 db7fecd9 Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
178 db7fecd9 Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
179 db7fecd9 Sofia Papagiannaki
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
180 db7fecd9 Sofia Papagiannaki
        if not check.is_valid:
181 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.CAPTCHA_VALIDATION_ERR))
182 18ffbee1 Sofia Papagiannaki
183 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
184 d2633501 Kostas Papadimitriou
        """
185 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
186 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
187 d2633501 Kostas Papadimitriou
        """
188 d2633501 Kostas Papadimitriou
        user.add_auth_provider('local', auth_backend='astakos')
189 d2633501 Kostas Papadimitriou
        user.set_password(self.cleaned_data['password1'])
190 d2633501 Kostas Papadimitriou
191 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
192 64cd4730 Antony Chazapis
        """
193 890b0eaf Sofia Papagiannaki
        Saves the email, first_name and last_name properties, after the normal
194 890b0eaf Sofia Papagiannaki
        save behavior is complete.
195 890b0eaf Sofia Papagiannaki
        """
196 15efc749 Sofia Papagiannaki
        user = super(LocalUserCreationForm, self).save(commit=False)
197 d2633501 Kostas Papadimitriou
        user.renew_token()
198 9fb8e808 Sofia Papagiannaki
        if commit:
199 9fb8e808 Sofia Papagiannaki
            user.save()
200 aab4d540 Sofia Papagiannaki
            logger.log(LOGGING_LEVEL, 'Created user %s' % user.email)
201 890b0eaf Sofia Papagiannaki
        return user
202 64cd4730 Antony Chazapis
203 5ce3ce4f Sofia Papagiannaki
204 15efc749 Sofia Papagiannaki
class InvitedLocalUserCreationForm(LocalUserCreationForm):
205 890b0eaf Sofia Papagiannaki
    """
206 062c970c Sofia Papagiannaki
    Extends the LocalUserCreationForm: email is readonly.
207 890b0eaf Sofia Papagiannaki
    """
208 794852f2 Sofia Papagiannaki
    class Meta:
209 794852f2 Sofia Papagiannaki
        model = AstakosUser
210 270dd48d Sofia Papagiannaki
        fields = ("email", "first_name", "last_name", "has_signed_terms")
211 18ffbee1 Sofia Papagiannaki
212 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
213 64cd4730 Antony Chazapis
        """
214 3bf924ec Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
215 64cd4730 Antony Chazapis
        """
216 15efc749 Sofia Papagiannaki
        super(InvitedLocalUserCreationForm, self).__init__(*args, **kwargs)
217 18ffbee1 Sofia Papagiannaki
218 64cd4730 Antony Chazapis
        #set readonly form fields
219 062c970c Sofia Papagiannaki
        ro = ('email', 'username',)
220 4e30244e Sofia Papagiannaki
        for f in ro:
221 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
222 ab8bfb29 Kostas Papadimitriou
223 9fb8e808 Sofia Papagiannaki
    def save(self, commit=True):
224 15efc749 Sofia Papagiannaki
        user = super(InvitedLocalUserCreationForm, self).save(commit=False)
225 74836e50 Sofia Papagiannaki
        user.set_invitations_level()
226 8316698a Sofia Papagiannaki
        user.email_verified = True
227 9fb8e808 Sofia Papagiannaki
        if commit:
228 9fb8e808 Sofia Papagiannaki
            user.save()
229 9fb8e808 Sofia Papagiannaki
        return user
230 5ed6816e Sofia Papagiannaki
231 d2633501 Kostas Papadimitriou
232 d2633501 Kostas Papadimitriou
class ThirdPartyUserCreationForm(forms.ModelForm, StoreUserMixin):
233 6c8a3f7c Sofia Papagiannaki
    id = forms.CharField(
234 6c8a3f7c Sofia Papagiannaki
        widget=forms.HiddenInput(),
235 6c8a3f7c Sofia Papagiannaki
        label='',
236 6c8a3f7c Sofia Papagiannaki
        required=False
237 6c8a3f7c Sofia Papagiannaki
    )
238 ef20ea07 Sofia Papagiannaki
    third_party_identifier = forms.CharField(
239 ef20ea07 Sofia Papagiannaki
        widget=forms.HiddenInput(),
240 ef20ea07 Sofia Papagiannaki
        label=''
241 ef20ea07 Sofia Papagiannaki
    )
242 1177e91b Olga Brani
    email = forms.EmailField(
243 1177e91b Olga Brani
        label='Contact email',
244 835e2ee3 Olga Brani
        help_text = 'This is needed for contact purposes. It doesn&#39;t need to be the same with the one you provided to login previously. '
245 1177e91b Olga Brani
    )
246 43332a76 Kostas Papadimitriou
247 8f5a3a06 Sofia Papagiannaki
    class Meta:
248 8f5a3a06 Sofia Papagiannaki
        model = AstakosUser
249 a1d151a8 Kostas Papadimitriou
        fields = ['id', 'email', 'third_party_identifier',
250 a1d151a8 Kostas Papadimitriou
                  'first_name', 'last_name', 'has_signed_terms']
251 ab8bfb29 Kostas Papadimitriou
252 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
253 8f5a3a06 Sofia Papagiannaki
        """
254 8f5a3a06 Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
255 8f5a3a06 Sofia Papagiannaki
        """
256 0a569195 Sofia Papagiannaki
        self.request = kwargs.get('request', None)
257 0a569195 Sofia Papagiannaki
        if self.request:
258 0a569195 Sofia Papagiannaki
            kwargs.pop('request')
259 2e90e3ec Kostas Papadimitriou
260 8f5a3a06 Sofia Papagiannaki
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
261 2e90e3ec Kostas Papadimitriou
262 4a13d054 Kostas Papadimitriou
        if not get_latest_terms():
263 4a13d054 Kostas Papadimitriou
            del self.fields['has_signed_terms']
264 4a13d054 Kostas Papadimitriou
265 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
266 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
267 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
268 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
269 5ce3ce4f Sofia Papagiannaki
                % (reverse('latest_terms'), _("the terms"))
270 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
271 18ffbee1 Sofia Papagiannaki
                    mark_safe("I agree with %s" % terms_link_html)
272 2e90e3ec Kostas Papadimitriou
273 18ffbee1 Sofia Papagiannaki
    def clean_email(self):
274 e5966bd9 Kostas Papadimitriou
        email = self.cleaned_data['email']
275 18ffbee1 Sofia Papagiannaki
        if not email:
276 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
277 43332a76 Kostas Papadimitriou
        if reserved_verified_email(email):
278 564a2292 Kostas Papadimitriou
            provider = auth_providers.get_provider(self.request.REQUEST.get('provider', 'local'))
279 564a2292 Kostas Papadimitriou
            extra_message = _(astakos_messages.EXISTING_EMAIL_THIRD_PARTY_NOTIFICATION) % \
280 564a2292 Kostas Papadimitriou
                    (provider.get_title_display, reverse('edit_profile'))
281 564a2292 Kostas Papadimitriou
282 564a2292 Kostas Papadimitriou
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED) + ' ' + \
283 564a2292 Kostas Papadimitriou
                                        extra_message)
284 0a569195 Sofia Papagiannaki
        return email
285 ab8bfb29 Kostas Papadimitriou
286 18ffbee1 Sofia Papagiannaki
    def clean_has_signed_terms(self):
287 18ffbee1 Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
288 18ffbee1 Sofia Papagiannaki
        if not has_signed_terms:
289 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
290 18ffbee1 Sofia Papagiannaki
        return has_signed_terms
291 ab8bfb29 Kostas Papadimitriou
292 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
293 d2633501 Kostas Papadimitriou
        pending = PendingThirdPartyUser.objects.get(
294 d2633501 Kostas Papadimitriou
                                token=request.POST.get('third_party_token'),
295 d2633501 Kostas Papadimitriou
                                third_party_identifier= \
296 43332a76 Kostas Papadimitriou
                            self.cleaned_data.get('third_party_identifier'))
297 d2633501 Kostas Papadimitriou
        return user.add_pending_auth_provider(pending)
298 d2633501 Kostas Papadimitriou
299 8f5a3a06 Sofia Papagiannaki
    def save(self, commit=True):
300 8f5a3a06 Sofia Papagiannaki
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
301 8f5a3a06 Sofia Papagiannaki
        user.set_unusable_password()
302 d2633501 Kostas Papadimitriou
        user.renew_token()
303 8f5a3a06 Sofia Papagiannaki
        if commit:
304 8f5a3a06 Sofia Papagiannaki
            user.save()
305 aab4d540 Sofia Papagiannaki
            logger.log(LOGGING_LEVEL, 'Created user %s' % user.email)
306 8f5a3a06 Sofia Papagiannaki
        return user
307 8f5a3a06 Sofia Papagiannaki
308 5ce3ce4f Sofia Papagiannaki
309 8f5a3a06 Sofia Papagiannaki
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
310 4e30244e Sofia Papagiannaki
    """
311 062c970c Sofia Papagiannaki
    Extends the ThirdPartyUserCreationForm: email is readonly.
312 4e30244e Sofia Papagiannaki
    """
313 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
314 4e30244e Sofia Papagiannaki
        """
315 4e30244e Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
316 4e30244e Sofia Papagiannaki
        """
317 5ce3ce4f Sofia Papagiannaki
        super(
318 5ce3ce4f Sofia Papagiannaki
            InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
319 4e30244e Sofia Papagiannaki
320 8f5a3a06 Sofia Papagiannaki
        #set readonly form fields
321 062c970c Sofia Papagiannaki
        ro = ('email',)
322 4e30244e Sofia Papagiannaki
        for f in ro:
323 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
324 ab8bfb29 Kostas Papadimitriou
325 4e30244e Sofia Papagiannaki
    def save(self, commit=True):
326 4e30244e Sofia Papagiannaki
        user = super(InvitedThirdPartyUserCreationForm, self).save(commit=False)
327 d2633501 Kostas Papadimitriou
        user.set_invitation_level()
328 4e30244e Sofia Papagiannaki
        user.email_verified = True
329 4e30244e Sofia Papagiannaki
        if commit:
330 4e30244e Sofia Papagiannaki
            user.save()
331 4e30244e Sofia Papagiannaki
        return user
332 8f5a3a06 Sofia Papagiannaki
333 5ce3ce4f Sofia Papagiannaki
334 18ffbee1 Sofia Papagiannaki
class ShibbolethUserCreationForm(ThirdPartyUserCreationForm):
335 5ce3ce4f Sofia Papagiannaki
    additional_email = forms.CharField(
336 5ce3ce4f Sofia Papagiannaki
        widget=forms.HiddenInput(), label='', required=False)
337 ab8bfb29 Kostas Papadimitriou
338 ca828a10 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
339 ca828a10 Sofia Papagiannaki
        super(ShibbolethUserCreationForm, self).__init__(*args, **kwargs)
340 ca828a10 Sofia Papagiannaki
        # copy email value to additional_mail in case user will change it
341 ca828a10 Sofia Papagiannaki
        name = 'email'
342 ca828a10 Sofia Papagiannaki
        field = self.fields[name]
343 ca828a10 Sofia Papagiannaki
        self.initial['additional_email'] = self.initial.get(name, field.initial)
344 ef20ea07 Sofia Papagiannaki
        self.initial['email'] = None
345 d2633501 Kostas Papadimitriou
346 4e30244e Sofia Papagiannaki
347 9a06d96f Olga Brani
class InvitedShibbolethUserCreationForm(ShibbolethUserCreationForm,
348 9a06d96f Olga Brani
                                        InvitedThirdPartyUserCreationForm):
349 4e30244e Sofia Papagiannaki
    pass
350 ab8bfb29 Kostas Papadimitriou
351 5ce3ce4f Sofia Papagiannaki
352 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
353 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
354 672d445a Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
355 5ce3ce4f Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(
356 5ce3ce4f Sofia Papagiannaki
        widget=RecaptchaWidget, label='')
357 ab8bfb29 Kostas Papadimitriou
358 672d445a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
359 672d445a Sofia Papagiannaki
        was_limited = kwargs.get('was_limited', False)
360 672d445a Sofia Papagiannaki
        request = kwargs.get('request', None)
361 672d445a Sofia Papagiannaki
        if request:
362 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
363 672d445a Sofia Papagiannaki
                                       request.META.get('HTTP_X_REAL_IP', None))
364 ab8bfb29 Kostas Papadimitriou
365 672d445a Sofia Papagiannaki
        t = ('request', 'was_limited')
366 672d445a Sofia Papagiannaki
        for elem in t:
367 672d445a Sofia Papagiannaki
            if elem in kwargs.keys():
368 672d445a Sofia Papagiannaki
                kwargs.pop(elem)
369 672d445a Sofia Papagiannaki
        super(LoginForm, self).__init__(*args, **kwargs)
370 ab8bfb29 Kostas Papadimitriou
371 672d445a Sofia Papagiannaki
        self.fields.keyOrder = ['username', 'password']
372 672d445a Sofia Papagiannaki
        if was_limited and RECAPTCHA_ENABLED:
373 672d445a Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
374 5ce3ce4f Sofia Papagiannaki
                                         'recaptcha_response_field', ])
375 9a06d96f Olga Brani
376 9a06d96f Olga Brani
    def clean_username(self):
377 4bdd7e3d Kostas Papadimitriou
        return self.cleaned_data['username'].lower()
378 ab8bfb29 Kostas Papadimitriou
379 672d445a Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
380 672d445a Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
381 672d445a Sofia Papagiannaki
            self.validate_captcha()
382 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
383 672d445a Sofia Papagiannaki
384 672d445a Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
385 672d445a Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
386 672d445a Sofia Papagiannaki
            self.validate_captcha()
387 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
388 672d445a Sofia Papagiannaki
389 672d445a Sofia Papagiannaki
    def validate_captcha(self):
390 672d445a Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
391 672d445a Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
392 672d445a Sofia Papagiannaki
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
393 672d445a Sofia Papagiannaki
        if not check.is_valid:
394 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.CAPTCHA_VALIDATION_ERR))
395 2e90e3ec Kostas Papadimitriou
396 eedb3923 Sofia Papagiannaki
    def clean(self):
397 1f3b4b39 Sofia Papagiannaki
        """
398 1f3b4b39 Sofia Papagiannaki
        Override default behavior in order to check user's activation later
399 1f3b4b39 Sofia Papagiannaki
        """
400 c4b1a172 Kostas Papadimitriou
        username = self.cleaned_data.get('username')
401 c4b1a172 Kostas Papadimitriou
402 bea8a810 Kostas Papadimitriou
        if username:
403 bea8a810 Kostas Papadimitriou
            try:
404 bea8a810 Kostas Papadimitriou
                user = AstakosUser.objects.get_by_identifier(username)
405 bea8a810 Kostas Papadimitriou
                if not user.has_auth_provider('local'):
406 bea8a810 Kostas Papadimitriou
                    provider = auth_providers.get_provider('local')
407 bea8a810 Kostas Papadimitriou
                    raise forms.ValidationError(
408 bea8a810 Kostas Papadimitriou
                        _(provider.get_message('NOT_ACTIVE_FOR_USER')))
409 bea8a810 Kostas Papadimitriou
            except AstakosUser.DoesNotExist:
410 bea8a810 Kostas Papadimitriou
                pass
411 c4b1a172 Kostas Papadimitriou
412 1f3b4b39 Sofia Papagiannaki
        try:
413 1f3b4b39 Sofia Papagiannaki
            super(LoginForm, self).clean()
414 1f3b4b39 Sofia Papagiannaki
        except forms.ValidationError, e:
415 c4b1a172 Kostas Papadimitriou
            if self.user_cache is None:
416 c4b1a172 Kostas Papadimitriou
                raise
417 c4b1a172 Kostas Papadimitriou
            if not self.user_cache.is_active:
418 c4b1a172 Kostas Papadimitriou
                raise forms.ValidationError(self.user_cache.get_inactive_message())
419 1f3b4b39 Sofia Papagiannaki
            if self.request:
420 1f3b4b39 Sofia Papagiannaki
                if not self.request.session.test_cookie_worked():
421 1f3b4b39 Sofia Papagiannaki
                    raise
422 eedb3923 Sofia Papagiannaki
        return self.cleaned_data
423 64cd4730 Antony Chazapis
424 5ce3ce4f Sofia Papagiannaki
425 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
426 890b0eaf Sofia Papagiannaki
    """
427 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
428 9a06d96f Olga Brani
    Most of the fields are readonly since the user is not allowed to change
429 9a06d96f Olga Brani
    them.
430 18ffbee1 Sofia Papagiannaki

431 9a06d96f Olga Brani
    The class defines a save method which sets ``is_verified`` to True so as the
432 9a06d96f Olga Brani
    user during the next login will not to be redirected to profile page.
433 890b0eaf Sofia Papagiannaki
    """
434 c301698f Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
435 18ffbee1 Sofia Papagiannaki
436 890b0eaf Sofia Papagiannaki
    class Meta:
437 890b0eaf Sofia Papagiannaki
        model = AstakosUser
438 5ce3ce4f Sofia Papagiannaki
        fields = ('email', 'first_name', 'last_name', 'auth_token',
439 5ce3ce4f Sofia Papagiannaki
                  'auth_token_expires')
440 18ffbee1 Sofia Papagiannaki
441 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
442 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
443 890b0eaf Sofia Papagiannaki
        super(ProfileForm, self).__init__(*args, **kwargs)
444 890b0eaf Sofia Papagiannaki
        instance = getattr(self, 'instance', None)
445 0a569195 Sofia Papagiannaki
        ro_fields = ('email', 'auth_token', 'auth_token_expires')
446 890b0eaf Sofia Papagiannaki
        if instance and instance.id:
447 890b0eaf Sofia Papagiannaki
            for field in ro_fields:
448 890b0eaf Sofia Papagiannaki
                self.fields[field].widget.attrs['readonly'] = True
449 18ffbee1 Sofia Papagiannaki
450 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
451 890b0eaf Sofia Papagiannaki
        user = super(ProfileForm, self).save(commit=False)
452 890b0eaf Sofia Papagiannaki
        user.is_verified = True
453 c301698f Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
454 bf0c6de5 Sofia Papagiannaki
            user.renew_token(
455 bf0c6de5 Sofia Papagiannaki
                flush_sessions=True,
456 bf0c6de5 Sofia Papagiannaki
                current_key=self.session_key
457 bf0c6de5 Sofia Papagiannaki
            )
458 890b0eaf Sofia Papagiannaki
        if commit:
459 890b0eaf Sofia Papagiannaki
            user.save()
460 890b0eaf Sofia Papagiannaki
        return user
461 64cd4730 Antony Chazapis
462 5ce3ce4f Sofia Papagiannaki
463 f7400729 Kostas Papadimitriou
464 890b0eaf Sofia Papagiannaki
class FeedbackForm(forms.Form):
465 890b0eaf Sofia Papagiannaki
    """
466 890b0eaf Sofia Papagiannaki
    Form for writing feedback.
467 890b0eaf Sofia Papagiannaki
    """
468 0a569195 Sofia Papagiannaki
    feedback_msg = forms.CharField(widget=forms.Textarea, label=u'Message')
469 8f5a3a06 Sofia Papagiannaki
    feedback_data = forms.CharField(widget=forms.HiddenInput(), label='',
470 8f5a3a06 Sofia Papagiannaki
                                    required=False)
471 5ed6816e Sofia Papagiannaki
472 5ce3ce4f Sofia Papagiannaki
473 5ed6816e Sofia Papagiannaki
class SendInvitationForm(forms.Form):
474 5ed6816e Sofia Papagiannaki
    """
475 5ed6816e Sofia Papagiannaki
    Form for sending an invitations
476 5ed6816e Sofia Papagiannaki
    """
477 18ffbee1 Sofia Papagiannaki
478 5ce3ce4f Sofia Papagiannaki
    email = forms.EmailField(required=True, label='Email address')
479 5ce3ce4f Sofia Papagiannaki
    first_name = forms.EmailField(label='First name')
480 5ce3ce4f Sofia Papagiannaki
    last_name = forms.EmailField(label='Last name')
481 5ce3ce4f Sofia Papagiannaki
482 e2125441 Sofia Papagiannaki
483 e2125441 Sofia Papagiannaki
class ExtendedPasswordResetForm(PasswordResetForm):
484 e2125441 Sofia Papagiannaki
    """
485 dd5f8f4d Kostas Papadimitriou
    Extends PasswordResetForm by overriding
486 18ffbee1 Sofia Papagiannaki

487 dd5f8f4d Kostas Papadimitriou
    save method: to pass a custom from_email in send_mail.
488 dd5f8f4d Kostas Papadimitriou
    clean_email: to handle local auth provider checks
489 e2125441 Sofia Papagiannaki
    """
490 23c271b3 Sofia Papagiannaki
    def clean_email(self):
491 23c271b3 Sofia Papagiannaki
        email = super(ExtendedPasswordResetForm, self).clean_email()
492 23c271b3 Sofia Papagiannaki
        try:
493 dd5f8f4d Kostas Papadimitriou
            user = AstakosUser.objects.get_by_identifier(email)
494 dd5f8f4d Kostas Papadimitriou
495 dd5f8f4d Kostas Papadimitriou
            if not user.is_active:
496 dd5f8f4d Kostas Papadimitriou
                raise forms.ValidationError(_(astakos_messages.ACCOUNT_INACTIVE))
497 dd5f8f4d Kostas Papadimitriou
498 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
499 260f1021 Kostas Papadimitriou
                provider = auth_providers.get_provider('local')
500 260f1021 Kostas Papadimitriou
                available_providers = user.auth_providers.all()
501 260f1021 Kostas Papadimitriou
                available_providers = ",".join(p.settings.get_title_display for p in \
502 260f1021 Kostas Papadimitriou
                                                   available_providers)
503 260f1021 Kostas Papadimitriou
                message = astakos_messages.UNUSABLE_PASSWORD % \
504 260f1021 Kostas Papadimitriou
                    (provider.get_method_prompt_display, available_providers)
505 260f1021 Kostas Papadimitriou
                raise forms.ValidationError(message)
506 d2633501 Kostas Papadimitriou
507 d2633501 Kostas Papadimitriou
            if not user.can_change_password():
508 dd5f8f4d Kostas Papadimitriou
                raise forms.ValidationError(_(astakos_messages.AUTH_PROVIDER_CANNOT_CHANGE_PASSWORD))
509 23c271b3 Sofia Papagiannaki
        except AstakosUser.DoesNotExist, e:
510 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
511 23c271b3 Sofia Papagiannaki
        return email
512 ab8bfb29 Kostas Papadimitriou
513 5ce3ce4f Sofia Papagiannaki
    def save(
514 5ce3ce4f Sofia Papagiannaki
        self, domain_override=None, email_template_name='registration/password_reset_email.html',
515 5ce3ce4f Sofia Papagiannaki
            use_https=False, token_generator=default_token_generator, request=None):
516 e2125441 Sofia Papagiannaki
        """
517 e2125441 Sofia Papagiannaki
        Generates a one-use only link for resetting password and sends to the user.
518 e2125441 Sofia Papagiannaki
        """
519 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
520 d2633501 Kostas Papadimitriou
            url = user.astakosuser.get_password_reset_url(token_generator)
521 a53b19da Sofia Papagiannaki
            url = urljoin(BASEURL, url)
522 e2125441 Sofia Papagiannaki
            t = loader.get_template(email_template_name)
523 e2125441 Sofia Papagiannaki
            c = {
524 e2125441 Sofia Papagiannaki
                'email': user.email,
525 8f378756 Sofia Papagiannaki
                'url': url,
526 374611bc Sofia Papagiannaki
                'site_name': SITENAME,
527 e2125441 Sofia Papagiannaki
                'user': user,
528 a53b19da Sofia Papagiannaki
                'baseurl': BASEURL,
529 09122dd8 Sofia Papagiannaki
                'support': DEFAULT_CONTACT_EMAIL
530 e2125441 Sofia Papagiannaki
            }
531 1cbce16f Sofia Papagiannaki
            from_email = settings.SERVER_EMAIL
532 1fcf4a99 Kostas Papadimitriou
            send_mail(_(PASSWORD_RESET_EMAIL_SUBJECT),
533 f9224cc0 Sofia Papagiannaki
                      t.render(Context(c)),
534 f9224cc0 Sofia Papagiannaki
                      from_email,
535 f9224cc0 Sofia Papagiannaki
                      [user.email],
536 28f4439f Sofia Papagiannaki
                      connection=get_connection())
537 5ce3ce4f Sofia Papagiannaki
538 270dd48d Sofia Papagiannaki
539 49790d9d Sofia Papagiannaki
class EmailChangeForm(forms.ModelForm):
540 34a76cdb Kostas Papadimitriou
541 49790d9d Sofia Papagiannaki
    class Meta:
542 49790d9d Sofia Papagiannaki
        model = EmailChange
543 49790d9d Sofia Papagiannaki
        fields = ('new_email_address',)
544 ab8bfb29 Kostas Papadimitriou
545 49790d9d Sofia Papagiannaki
    def clean_new_email_address(self):
546 49790d9d Sofia Papagiannaki
        addr = self.cleaned_data['new_email_address']
547 43332a76 Kostas Papadimitriou
        if reserved_verified_email(addr):
548 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
549 49790d9d Sofia Papagiannaki
        return addr
550 ab8bfb29 Kostas Papadimitriou
551 3fbf7863 Kostas Papadimitriou
    def save(self, request, email_template_name='registration/email_change_email.txt', commit=True):
552 49790d9d Sofia Papagiannaki
        ec = super(EmailChangeForm, self).save(commit=False)
553 49790d9d Sofia Papagiannaki
        ec.user = request.user
554 3fbf7863 Kostas Papadimitriou
        # delete pending email changes
555 3fbf7863 Kostas Papadimitriou
        request.user.emailchanges.all().delete()
556 3fbf7863 Kostas Papadimitriou
557 5ce3ce4f Sofia Papagiannaki
        activation_key = hashlib.sha1(
558 5ce3ce4f Sofia Papagiannaki
            str(random()) + smart_str(ec.new_email_address))
559 5ce3ce4f Sofia Papagiannaki
        ec.activation_key = activation_key.hexdigest()
560 49790d9d Sofia Papagiannaki
        if commit:
561 49790d9d Sofia Papagiannaki
            ec.save()
562 49790d9d Sofia Papagiannaki
        send_change_email(ec, request, email_template_name=email_template_name)
563 49790d9d Sofia Papagiannaki
564 5ce3ce4f Sofia Papagiannaki
565 270dd48d Sofia Papagiannaki
class SignApprovalTermsForm(forms.ModelForm):
566 34a76cdb Kostas Papadimitriou
567 270dd48d Sofia Papagiannaki
    class Meta:
568 270dd48d Sofia Papagiannaki
        model = AstakosUser
569 270dd48d Sofia Papagiannaki
        fields = ("has_signed_terms",)
570 18ffbee1 Sofia Papagiannaki
571 270dd48d Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
572 270dd48d Sofia Papagiannaki
        super(SignApprovalTermsForm, self).__init__(*args, **kwargs)
573 18ffbee1 Sofia Papagiannaki
574 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
575 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
576 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
577 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
578 270dd48d Sofia Papagiannaki
        return has_signed_terms
579 8f5a3a06 Sofia Papagiannaki
580 5ce3ce4f Sofia Papagiannaki
581 8f5a3a06 Sofia Papagiannaki
class InvitationForm(forms.ModelForm):
582 34a76cdb Kostas Papadimitriou
583 8f5a3a06 Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
584 ab8bfb29 Kostas Papadimitriou
585 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
586 18ffbee1 Sofia Papagiannaki
        super(InvitationForm, self).__init__(*args, **kwargs)
587 ab8bfb29 Kostas Papadimitriou
588 8f5a3a06 Sofia Papagiannaki
    class Meta:
589 8f5a3a06 Sofia Papagiannaki
        model = Invitation
590 8f5a3a06 Sofia Papagiannaki
        fields = ('username', 'realname')
591 ab8bfb29 Kostas Papadimitriou
592 8f5a3a06 Sofia Papagiannaki
    def clean_username(self):
593 8f5a3a06 Sofia Papagiannaki
        username = self.cleaned_data['username']
594 8f5a3a06 Sofia Papagiannaki
        try:
595 5ce3ce4f Sofia Papagiannaki
            Invitation.objects.get(username=username)
596 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.INVITATION_EMAIL_EXISTS))
597 8f5a3a06 Sofia Papagiannaki
        except Invitation.DoesNotExist:
598 8f5a3a06 Sofia Papagiannaki
            pass
599 18ffbee1 Sofia Papagiannaki
        return username
600 1039bab1 Sofia Papagiannaki
601 5ce3ce4f Sofia Papagiannaki
602 1039bab1 Sofia Papagiannaki
class ExtendedPasswordChangeForm(PasswordChangeForm):
603 1039bab1 Sofia Papagiannaki
    """
604 1039bab1 Sofia Papagiannaki
    Extends PasswordChangeForm by enabling user
605 1039bab1 Sofia Papagiannaki
    to optionally renew also the token.
606 1039bab1 Sofia Papagiannaki
    """
607 ee210d1d Sofia Papagiannaki
    if not NEWPASSWD_INVALIDATE_TOKEN:
608 48e9f076 Sofia Papagiannaki
        renew = forms.BooleanField(label='Renew token', required=False,
609 48e9f076 Sofia Papagiannaki
                                   initial=True,
610 48e9f076 Sofia Papagiannaki
                                   help_text='Unsetting this may result in security risk.')
611 ab8bfb29 Kostas Papadimitriou
612 1039bab1 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
613 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
614 1039bab1 Sofia Papagiannaki
        super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
615 ab8bfb29 Kostas Papadimitriou
616 1039bab1 Sofia Papagiannaki
    def save(self, commit=True):
617 bf0c6de5 Sofia Papagiannaki
        try:
618 bf0c6de5 Sofia Papagiannaki
            if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
619 bf0c6de5 Sofia Papagiannaki
                self.user.renew_token()
620 bf0c6de5 Sofia Papagiannaki
            self.user.flush_sessions(current_key=self.session_key)
621 bf0c6de5 Sofia Papagiannaki
        except AttributeError:
622 bf0c6de5 Sofia Papagiannaki
            # if user model does has not such methods
623 bf0c6de5 Sofia Papagiannaki
            pass
624 53161dd8 Sofia Papagiannaki
        return super(ExtendedPasswordChangeForm, self).save(commit=commit)
625 48e9f076 Sofia Papagiannaki
626 48e9f076 Sofia Papagiannaki
class ExtendedSetPasswordForm(SetPasswordForm):
627 48e9f076 Sofia Papagiannaki
    """
628 48e9f076 Sofia Papagiannaki
    Extends SetPasswordForm by enabling user
629 48e9f076 Sofia Papagiannaki
    to optionally renew also the token.
630 48e9f076 Sofia Papagiannaki
    """
631 ee210d1d Sofia Papagiannaki
    if not NEWPASSWD_INVALIDATE_TOKEN:
632 bf0c6de5 Sofia Papagiannaki
        renew = forms.BooleanField(
633 bf0c6de5 Sofia Papagiannaki
            label='Renew token',
634 bf0c6de5 Sofia Papagiannaki
            required=False,
635 bf0c6de5 Sofia Papagiannaki
            initial=True,
636 47b77c8b Sofia Papagiannaki
            help_text='Unsetting this may result in security risk.')
637 2e90e3ec Kostas Papadimitriou
638 48e9f076 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
639 48e9f076 Sofia Papagiannaki
        super(ExtendedSetPasswordForm, self).__init__(user, *args, **kwargs)
640 d2633501 Kostas Papadimitriou
641 d2633501 Kostas Papadimitriou
    @transaction.commit_on_success()
642 48e9f076 Sofia Papagiannaki
    def save(self, commit=True):
643 bf0c6de5 Sofia Papagiannaki
        try:
644 bf0c6de5 Sofia Papagiannaki
            self.user = AstakosUser.objects.get(id=self.user.id)
645 bf0c6de5 Sofia Papagiannaki
            if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
646 53161dd8 Sofia Papagiannaki
                self.user.renew_token()
647 d2633501 Kostas Papadimitriou
            #self.user.flush_sessions()
648 d2633501 Kostas Papadimitriou
            if not self.user.has_auth_provider('local'):
649 d2633501 Kostas Papadimitriou
                self.user.add_auth_provider('local', auth_backend='astakos')
650 d2633501 Kostas Papadimitriou
651 bf0c6de5 Sofia Papagiannaki
        except BaseException, e:
652 bf0c6de5 Sofia Papagiannaki
            logger.exception(e)
653 53161dd8 Sofia Papagiannaki
        return super(ExtendedSetPasswordForm, self).save(commit=commit)
654 e1a80257 Sofia Papagiannaki
655 e1a80257 Sofia Papagiannaki
656 67980f56 Georgios D. Tsoukalas
657 67980f56 Georgios D. Tsoukalas
658 67980f56 Georgios D. Tsoukalas
app_name_label       =  "Project name"
659 67980f56 Georgios D. Tsoukalas
app_name_placeholder = _("myproject.mylab.ntua.gr")
660 67980f56 Georgios D. Tsoukalas
app_name_validator   =  validators.RegexValidator(
661 67980f56 Georgios D. Tsoukalas
                            DOMAIN_VALUE_REGEX,
662 67980f56 Georgios D. Tsoukalas
                            _(astakos_messages.DOMAIN_VALUE_ERR),
663 67980f56 Georgios D. Tsoukalas
                            'invalid')
664 67980f56 Georgios D. Tsoukalas
app_name_help        =  _("""
665 67980f56 Georgios D. Tsoukalas
        The Project's name should be in a domain format.
666 67980f56 Georgios D. Tsoukalas
        The domain shouldn't neccessarily exist in the real
667 67980f56 Georgios D. Tsoukalas
        world but is helpful to imply a structure.
668 67980f56 Georgios D. Tsoukalas
        e.g.: myproject.mylab.ntua.gr or
669 67980f56 Georgios D. Tsoukalas
        myservice.myteam.myorganization""")
670 67980f56 Georgios D. Tsoukalas
app_name_widget      =  forms.TextInput(
671 67980f56 Georgios D. Tsoukalas
                            attrs={'placeholder': app_name_placeholder})
672 67980f56 Georgios D. Tsoukalas
673 67980f56 Georgios D. Tsoukalas
674 67980f56 Georgios D. Tsoukalas
app_home_label       =  "Homepage URL"
675 3ff82dca Olga Brani
app_home_placeholder =  'myinstitution.org/myproject/'
676 67980f56 Georgios D. Tsoukalas
app_home_help        =  _("""
677 67980f56 Georgios D. Tsoukalas
        URL pointing at your project's site.
678 3ff82dca Olga Brani
        e.g.: myinstitution.org/myproject/.
679 67980f56 Georgios D. Tsoukalas
        Leave blank if there is no website.""")
680 67980f56 Georgios D. Tsoukalas
app_home_widget      =  forms.TextInput(
681 67980f56 Georgios D. Tsoukalas
                            attrs={'placeholder': app_home_placeholder})
682 67980f56 Georgios D. Tsoukalas
683 67980f56 Georgios D. Tsoukalas
app_desc_label       =  _("Description")
684 67980f56 Georgios D. Tsoukalas
app_desc_help        =  _("""
685 67980f56 Georgios D. Tsoukalas
        Please provide a short but descriptive abstract of your Project,
686 67980f56 Georgios D. Tsoukalas
        so that anyone searching can quickly understand
687 67980f56 Georgios D. Tsoukalas
        what this Project is about.""")
688 67980f56 Georgios D. Tsoukalas
689 67980f56 Georgios D. Tsoukalas
app_comment_label    =  _("Comments for review (private)")
690 67980f56 Georgios D. Tsoukalas
app_comment_help     =  _("""
691 67980f56 Georgios D. Tsoukalas
        Write down any comments you may have for the reviewer
692 67980f56 Georgios D. Tsoukalas
        of this application (e.g. background and rationale to
693 67980f56 Georgios D. Tsoukalas
        support your request).
694 67980f56 Georgios D. Tsoukalas
        The comments are strictly for the review process
695 67980f56 Georgios D. Tsoukalas
        and will not be published.""")
696 67980f56 Georgios D. Tsoukalas
697 67980f56 Georgios D. Tsoukalas
app_start_date_label =  _("Start date")
698 67980f56 Georgios D. Tsoukalas
app_start_date_help  =  _("""
699 67980f56 Georgios D. Tsoukalas
        Provide a date when your need your project to be created,
700 67980f56 Georgios D. Tsoukalas
        and members to be able to join and get resources.
701 67980f56 Georgios D. Tsoukalas
        This date is only a hint to help prioritize reviews.""")
702 67980f56 Georgios D. Tsoukalas
703 67980f56 Georgios D. Tsoukalas
app_end_date_label   =  _("Termination date")
704 67980f56 Georgios D. Tsoukalas
app_end_date_help    =  _("""
705 67980f56 Georgios D. Tsoukalas
        At this date, the project will be automatically terminated
706 67980f56 Georgios D. Tsoukalas
        and its resource grants revoked from all members.
707 67980f56 Georgios D. Tsoukalas
        Unless you know otherwise,
708 67980f56 Georgios D. Tsoukalas
        it is best to start with a conservative estimation.
709 67980f56 Georgios D. Tsoukalas
        You can always re-apply for an extension, if you need.""")
710 67980f56 Georgios D. Tsoukalas
711 67980f56 Georgios D. Tsoukalas
join_policy_label    =  _("Joining policy")
712 b87429e1 Olga Brani
app_member_join_policy_help    =  _("""
713 b87429e1 Olga Brani
        Text fo member_join_policy.""")
714 67980f56 Georgios D. Tsoukalas
leave_policy_label   =  _("Leaving policy")
715 b87429e1 Olga Brani
app_member_leave_policy_help    =  _("""
716 b87429e1 Olga Brani
        Text fo member_leave_policy.""")
717 67980f56 Georgios D. Tsoukalas
718 67980f56 Georgios D. Tsoukalas
max_members_label    =  _("Maximum member count")
719 67980f56 Georgios D. Tsoukalas
max_members_help     =  _("""
720 67980f56 Georgios D. Tsoukalas
        Specify the maximum number of members this project may have,
721 67980f56 Georgios D. Tsoukalas
        including the owner. Beyond this number, no new members
722 67980f56 Georgios D. Tsoukalas
        may join the project and be granted the project resources.
723 67980f56 Georgios D. Tsoukalas
        Unless you certainly for otherwise,
724 67980f56 Georgios D. Tsoukalas
        it is best to start with a conservative limit.
725 67980f56 Georgios D. Tsoukalas
        You can always request a raise when you need it.""")
726 67980f56 Georgios D. Tsoukalas
727 67980f56 Georgios D. Tsoukalas
join_policies = PROJECT_MEMBER_JOIN_POLICIES.iteritems()
728 67980f56 Georgios D. Tsoukalas
leave_policies = PROJECT_MEMBER_LEAVE_POLICIES.iteritems()
729 67980f56 Georgios D. Tsoukalas
730 e1a80257 Sofia Papagiannaki
class ProjectApplicationForm(forms.ModelForm):
731 67980f56 Georgios D. Tsoukalas
732 e1a80257 Sofia Papagiannaki
    name = forms.CharField(
733 67980f56 Georgios D. Tsoukalas
        label     = app_name_label,
734 67980f56 Georgios D. Tsoukalas
        help_text = app_name_help,
735 67980f56 Georgios D. Tsoukalas
        widget    = app_name_widget,
736 67980f56 Georgios D. Tsoukalas
        validators = [app_name_validator])
737 67980f56 Georgios D. Tsoukalas
738 52784759 Olga Brani
    homepage = forms.URLField(
739 67980f56 Georgios D. Tsoukalas
        label     = app_home_label,
740 80da92f0 Kostas Papadimitriou
        help_text = app_home_help,
741 67980f56 Georgios D. Tsoukalas
        widget    = app_home_widget,
742 67980f56 Georgios D. Tsoukalas
        required  = False)
743 67980f56 Georgios D. Tsoukalas
744 67980f56 Georgios D. Tsoukalas
    description = forms.CharField(
745 67980f56 Georgios D. Tsoukalas
        label     = app_desc_label,
746 67980f56 Georgios D. Tsoukalas
        help_text = app_desc_help,
747 67980f56 Georgios D. Tsoukalas
        widget    = forms.Textarea,
748 67980f56 Georgios D. Tsoukalas
        required  = False)
749 67980f56 Georgios D. Tsoukalas
750 67980f56 Georgios D. Tsoukalas
    comments = forms.CharField(
751 67980f56 Georgios D. Tsoukalas
        label     = app_comment_label,
752 67980f56 Georgios D. Tsoukalas
        help_text = app_comment_help,
753 67980f56 Georgios D. Tsoukalas
        widget    = forms.Textarea,
754 67980f56 Georgios D. Tsoukalas
        required  = False)
755 67980f56 Georgios D. Tsoukalas
756 67980f56 Georgios D. Tsoukalas
    start_date = forms.DateTimeField(
757 67980f56 Georgios D. Tsoukalas
        label     = app_start_date_label,
758 67980f56 Georgios D. Tsoukalas
        help_text = app_start_date_help,
759 67980f56 Georgios D. Tsoukalas
        required  = False)
760 67980f56 Georgios D. Tsoukalas
761 67980f56 Georgios D. Tsoukalas
    end_date = forms.DateTimeField(
762 67980f56 Georgios D. Tsoukalas
        label     = app_end_date_label,
763 67980f56 Georgios D. Tsoukalas
        help_text = app_end_date_help)
764 67980f56 Georgios D. Tsoukalas
765 80da92f0 Kostas Papadimitriou
    member_join_policy  = forms.TypedChoiceField(
766 67980f56 Georgios D. Tsoukalas
        label     = join_policy_label,
767 b87429e1 Olga Brani
        help_text = app_member_join_policy_help,
768 80da92f0 Kostas Papadimitriou
        initial   = 2,
769 80da92f0 Kostas Papadimitriou
        coerce    = int,
770 67980f56 Georgios D. Tsoukalas
        choices   = join_policies)
771 dd5f8f4d Kostas Papadimitriou
772 80da92f0 Kostas Papadimitriou
    member_leave_policy = forms.TypedChoiceField(
773 67980f56 Georgios D. Tsoukalas
        label     = leave_policy_label,
774 b87429e1 Olga Brani
        help_text = app_member_leave_policy_help,
775 80da92f0 Kostas Papadimitriou
        coerce    = int,
776 67980f56 Georgios D. Tsoukalas
        choices   = leave_policies)
777 67980f56 Georgios D. Tsoukalas
778 67980f56 Georgios D. Tsoukalas
    limit_on_members_number = forms.IntegerField(
779 67980f56 Georgios D. Tsoukalas
        label     = max_members_label,
780 67980f56 Georgios D. Tsoukalas
        help_text = max_members_help,
781 67980f56 Georgios D. Tsoukalas
        required  = False)
782 dd5f8f4d Kostas Papadimitriou
783 e1a80257 Sofia Papagiannaki
    class Meta:
784 73fbaec4 Sofia Papagiannaki
        model = ProjectApplication
785 c82bd52b Kostas Papadimitriou
        fields = ( 'name', 'homepage', 'description',
786 c82bd52b Kostas Papadimitriou
                    'start_date', 'end_date', 'comments',
787 c82bd52b Kostas Papadimitriou
                    'member_join_policy', 'member_leave_policy',
788 c82bd52b Kostas Papadimitriou
                    'limit_on_members_number')
789 c82bd52b Kostas Papadimitriou
790 40b52116 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
791 2ef98527 Sofia Papagiannaki
        instance = kwargs.get('instance')
792 2ef98527 Sofia Papagiannaki
        self.precursor_application = instance
793 40b52116 Sofia Papagiannaki
        super(ProjectApplicationForm, self).__init__(*args, **kwargs)
794 f568d0f4 Sofia Papagiannaki
        # in case of new application remove closed join policy
795 2ef98527 Sofia Papagiannaki
        if not instance:
796 2ef98527 Sofia Papagiannaki
            policies = PROJECT_MEMBER_JOIN_POLICIES.copy()
797 2ef98527 Sofia Papagiannaki
            policies.pop('3')
798 2ef98527 Sofia Papagiannaki
            self.fields['member_join_policy'].choices = policies.iteritems()
799 dd5f8f4d Kostas Papadimitriou
800 69b26576 Sofia Papagiannaki
    def clean_start_date(self):
801 69b26576 Sofia Papagiannaki
        start_date = self.cleaned_data.get('start_date')
802 f568d0f4 Sofia Papagiannaki
        if not self.precursor_application:
803 8172d87d Sofia Papagiannaki
            today = datetime.now()
804 8172d87d Sofia Papagiannaki
            today = datetime(today.year, today.month, today.day)
805 01223f04 Sofia Papagiannaki
            if start_date and (start_date - today).days < 0:
806 f568d0f4 Sofia Papagiannaki
                raise forms.ValidationError(
807 69b26576 Sofia Papagiannaki
                _(astakos_messages.INVALID_PROJECT_START_DATE))
808 69b26576 Sofia Papagiannaki
        return start_date
809 69b26576 Sofia Papagiannaki
810 69b26576 Sofia Papagiannaki
    def clean_end_date(self):
811 69b26576 Sofia Papagiannaki
        start_date = self.cleaned_data.get('start_date')
812 69b26576 Sofia Papagiannaki
        end_date = self.cleaned_data.get('end_date')
813 8172d87d Sofia Papagiannaki
        today = datetime.now()
814 8172d87d Sofia Papagiannaki
        today = datetime(today.year, today.month, today.day)
815 01223f04 Sofia Papagiannaki
        if end_date and (end_date - today).days < 0:
816 69b26576 Sofia Papagiannaki
            raise forms.ValidationError(
817 69b26576 Sofia Papagiannaki
                _(astakos_messages.INVALID_PROJECT_END_DATE))
818 f03b9ba6 Sofia Papagiannaki
        if start_date and (end_date - start_date).days <= 0:
819 69b26576 Sofia Papagiannaki
            raise forms.ValidationError(
820 69b26576 Sofia Papagiannaki
                _(astakos_messages.INCONSISTENT_PROJECT_DATES))
821 69b26576 Sofia Papagiannaki
        return end_date
822 69b26576 Sofia Papagiannaki
823 e1a80257 Sofia Papagiannaki
    def clean(self):
824 185b2190 Sofia Papagiannaki
        userid = self.data.get('user', None)
825 e1a80257 Sofia Papagiannaki
        self.user = None
826 e1a80257 Sofia Papagiannaki
        if userid:
827 e1a80257 Sofia Papagiannaki
            try:
828 e1a80257 Sofia Papagiannaki
                self.user = AstakosUser.objects.get(id=userid)
829 e1a80257 Sofia Papagiannaki
            except AstakosUser.DoesNotExist:
830 e1a80257 Sofia Papagiannaki
                pass
831 e1a80257 Sofia Papagiannaki
        if not self.user:
832 e1a80257 Sofia Papagiannaki
            raise forms.ValidationError(_(astakos_messages.NO_APPLICANT))
833 e1a80257 Sofia Papagiannaki
        super(ProjectApplicationForm, self).clean()
834 e1a80257 Sofia Papagiannaki
        return self.cleaned_data
835 dd5f8f4d Kostas Papadimitriou
836 f3342849 Sofia Papagiannaki
    @property
837 f3342849 Sofia Papagiannaki
    def resource_policies(self):
838 e1a80257 Sofia Papagiannaki
        policies = []
839 e1a80257 Sofia Papagiannaki
        append = policies.append
840 f3342849 Sofia Papagiannaki
        for name, value in self.data.iteritems():
841 f3342849 Sofia Papagiannaki
            if not value:
842 f3342849 Sofia Papagiannaki
                continue
843 56eb807c Sofia Papagiannaki
            uplimit = value
844 56eb807c Sofia Papagiannaki
            if name.endswith('_uplimit'):
845 56eb807c Sofia Papagiannaki
                subs = name.split('_uplimit')
846 e1a80257 Sofia Papagiannaki
                prefix, suffix = subs
847 e1a80257 Sofia Papagiannaki
                s, sep, r = prefix.partition(RESOURCE_SEPARATOR)
848 e1a80257 Sofia Papagiannaki
                resource = Resource.objects.get(service__name=s, name=r)
849 e1a80257 Sofia Papagiannaki
850 e1a80257 Sofia Papagiannaki
                # keep only resource limits for selected resource groups
851 30dd9e0e Olga Brani
                if self.data.get(
852 30dd9e0e Olga Brani
                    'is_selected_%s' % resource.group, "0"
853 30dd9e0e Olga Brani
                 ) == "1":
854 6556e514 Sofia Papagiannaki
                    d = model_to_dict(resource)
855 30dd9e0e Olga Brani
                    if uplimit:
856 6556e514 Sofia Papagiannaki
                        d.update(dict(service=s, resource=r, uplimit=uplimit))
857 30dd9e0e Olga Brani
                    else:
858 6556e514 Sofia Papagiannaki
                        d.update(dict(service=s, resource=r, uplimit=None))
859 6556e514 Sofia Papagiannaki
                    append(d)
860 dd5f8f4d Kostas Papadimitriou
861 e1a80257 Sofia Papagiannaki
        return policies
862 dd5f8f4d Kostas Papadimitriou
863 e1a80257 Sofia Papagiannaki
    def save(self, commit=True):
864 15ca2bea Giorgos Korfiatis
        data = dict(self.cleaned_data)
865 69c822cc Giorgos Korfiatis
        data['precursor_application'] = self.instance.id
866 69c822cc Giorgos Korfiatis
        data['owner'] = self.user
867 69c822cc Giorgos Korfiatis
        data['resource_policies'] = self.resource_policies
868 ee4aa6eb Giorgos Korfiatis
        submit_application(data, request_user=self.user)
869 8327782d Sofia Papagiannaki
870 8327782d Sofia Papagiannaki
class ProjectSortForm(forms.Form):
871 8327782d Sofia Papagiannaki
    sorting = forms.ChoiceField(
872 8327782d Sofia Papagiannaki
        label='Sort by',
873 73fbaec4 Sofia Papagiannaki
        choices=(('name', 'Sort by Name'),
874 8327782d Sofia Papagiannaki
                 ('issue_date', 'Sort by Issue date'),
875 73fbaec4 Sofia Papagiannaki
                 ('start_date', 'Sort by Start Date'),
876 73fbaec4 Sofia Papagiannaki
                 ('end_date', 'Sort by End Date'),
877 8327782d Sofia Papagiannaki
#                  ('approved_members_num', 'Sort by Participants'),
878 d6a162d3 Sofia Papagiannaki
                 ('state', 'Sort by Status'),
879 73fbaec4 Sofia Papagiannaki
                 ('member_join_policy__description', 'Sort by Member Join Policy'),
880 7592e3e2 Sofia Papagiannaki
                 ('member_leave_policy__description', 'Sort by Member Leave Policy'),
881 7592e3e2 Sofia Papagiannaki
                 ('-name', 'Sort by Name'),
882 7592e3e2 Sofia Papagiannaki
                 ('-issue_date', 'Sort by Issue date'),
883 7592e3e2 Sofia Papagiannaki
                 ('-start_date', 'Sort by Start Date'),
884 7592e3e2 Sofia Papagiannaki
                 ('-end_date', 'Sort by End Date'),
885 7592e3e2 Sofia Papagiannaki
#                  ('-approved_members_num', 'Sort by Participants'),
886 7592e3e2 Sofia Papagiannaki
                 ('-state', 'Sort by Status'),
887 7592e3e2 Sofia Papagiannaki
                 ('-member_join_policy__description', 'Sort by Member Join Policy'),
888 7592e3e2 Sofia Papagiannaki
                 ('-member_leave_policy__description', 'Sort by Member Leave Policy')
889 8327782d Sofia Papagiannaki
        ),
890 8327782d Sofia Papagiannaki
        required=True
891 ccab6eb5 Sofia Papagiannaki
    )
892 ccab6eb5 Sofia Papagiannaki
893 ccab6eb5 Sofia Papagiannaki
class AddProjectMembersForm(forms.Form):
894 ccab6eb5 Sofia Papagiannaki
    q = forms.CharField(
895 ccab6eb5 Sofia Papagiannaki
        max_length=800, widget=forms.Textarea, label=_('Add members'),
896 e47fb17a Sofia Papagiannaki
        help_text=_(astakos_messages.ADD_PROJECT_MEMBERS_Q_HELP), required=True)
897 ccab6eb5 Sofia Papagiannaki
898 e47fb17a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
899 ff67242a Giorgos Korfiatis
        chain_id = kwargs.pop('chain_id', None)
900 ff67242a Giorgos Korfiatis
        if chain_id:
901 ff67242a Giorgos Korfiatis
            self.project = Project.objects.get(id=chain_id)
902 e47fb17a Sofia Papagiannaki
        self.request_user = kwargs.pop('request_user', None)
903 e47fb17a Sofia Papagiannaki
        super(AddProjectMembersForm, self).__init__(*args, **kwargs)
904 43332a76 Kostas Papadimitriou
905 ccab6eb5 Sofia Papagiannaki
    def clean(self):
906 e47fb17a Sofia Papagiannaki
        try:
907 ff67242a Giorgos Korfiatis
            accept_membership_checks(self.project, self.request_user)
908 e47fb17a Sofia Papagiannaki
        except PermissionDenied, e:
909 e47fb17a Sofia Papagiannaki
            raise forms.ValidationError(e)
910 e47fb17a Sofia Papagiannaki
911 ccab6eb5 Sofia Papagiannaki
        q = self.cleaned_data.get('q') or ''
912 ccab6eb5 Sofia Papagiannaki
        users = q.split(',')
913 ccab6eb5 Sofia Papagiannaki
        users = list(u.strip() for u in users if u)
914 ccab6eb5 Sofia Papagiannaki
        db_entries = AstakosUser.objects.filter(email__in=users)
915 ccab6eb5 Sofia Papagiannaki
        unknown = list(set(users) - set(u.email for u in db_entries))
916 ccab6eb5 Sofia Papagiannaki
        if unknown:
917 e47fb17a Sofia Papagiannaki
            raise forms.ValidationError(
918 e47fb17a Sofia Papagiannaki
                _(astakos_messages.UNKNOWN_USERS) % ','.join(unknown))
919 ccab6eb5 Sofia Papagiannaki
        self.valid_users = db_entries
920 ccab6eb5 Sofia Papagiannaki
        return self.cleaned_data
921 ccab6eb5 Sofia Papagiannaki
922 ccab6eb5 Sofia Papagiannaki
    def get_valid_users(self):
923 ccab6eb5 Sofia Papagiannaki
        """Should be called after form cleaning"""
924 ccab6eb5 Sofia Papagiannaki
        try:
925 ccab6eb5 Sofia Papagiannaki
            return self.valid_users
926 ccab6eb5 Sofia Papagiannaki
        except:
927 bfe23b13 Sofia Papagiannaki
            return ()
928 bfe23b13 Sofia Papagiannaki
929 bfe23b13 Sofia Papagiannaki
class ProjectMembersSortForm(forms.Form):
930 bfe23b13 Sofia Papagiannaki
    sorting = forms.ChoiceField(
931 bfe23b13 Sofia Papagiannaki
        label='Sort by',
932 bfe23b13 Sofia Papagiannaki
        choices=(('person__email', 'User Id'),
933 bfe23b13 Sofia Papagiannaki
                 ('person__first_name', 'Name'),
934 bfe23b13 Sofia Papagiannaki
                 ('acceptance_date', 'Acceptance date')
935 bfe23b13 Sofia Papagiannaki
        ),
936 bfe23b13 Sofia Papagiannaki
        required=True
937 bfe23b13 Sofia Papagiannaki
    )
938 bfe23b13 Sofia Papagiannaki
939 f7400729 Kostas Papadimitriou
940 6dadd24a Sofia Papagiannaki
class ProjectSearchForm(forms.Form):
941 85d444db Sofia Papagiannaki
    q = forms.CharField(max_length=200, label='Search project', required=False)
942 5550bcfb Kostas Papadimitriou
943 f7400729 Kostas Papadimitriou
944 f7400729 Kostas Papadimitriou
class ExtendedProfileForm(ProfileForm):
945 f7400729 Kostas Papadimitriou
    """
946 f7400729 Kostas Papadimitriou
    Profile form that combines `email change` and `password change` user
947 f7400729 Kostas Papadimitriou
    actions by propagating submited data to internal EmailChangeForm
948 f7400729 Kostas Papadimitriou
    and ExtendedPasswordChangeForm objects.
949 f7400729 Kostas Papadimitriou
    """
950 f7400729 Kostas Papadimitriou
951 f7400729 Kostas Papadimitriou
    password_change_form = None
952 f7400729 Kostas Papadimitriou
    email_change_form = None
953 17ad5d37 Kostas Papadimitriou
954 3fbf7863 Kostas Papadimitriou
    password_change = False
955 17ad5d37 Kostas Papadimitriou
    email_change = False
956 17ad5d37 Kostas Papadimitriou
957 f7400729 Kostas Papadimitriou
    extra_forms_fields = {
958 f7400729 Kostas Papadimitriou
        'email': ['new_email_address'],
959 f7400729 Kostas Papadimitriou
        'password': ['old_password', 'new_password1', 'new_password2']
960 f7400729 Kostas Papadimitriou
    }
961 f7400729 Kostas Papadimitriou
962 d0632ab1 Olga Brani
    fields = ('email')
963 f7400729 Kostas Papadimitriou
    change_password = forms.BooleanField(initial=False, required=False)
964 f7400729 Kostas Papadimitriou
    change_email = forms.BooleanField(initial=False, required=False)
965 c55e39e7 Kostas Papadimitriou
966 2da6f56b Kostas Papadimitriou
    email_changed = False
967 2da6f56b Kostas Papadimitriou
    password_changed = False
968 f7400729 Kostas Papadimitriou
969 f7400729 Kostas Papadimitriou
    def __init__(self, *args, **kwargs):
970 95cb469b Kostas Papadimitriou
        session_key = kwargs.get('session_key', None)
971 c55e39e7 Kostas Papadimitriou
        self.fields_list = [
972 c55e39e7 Kostas Papadimitriou
                'email',
973 c55e39e7 Kostas Papadimitriou
                'new_email_address',
974 c55e39e7 Kostas Papadimitriou
                'first_name',
975 c55e39e7 Kostas Papadimitriou
                'last_name',
976 c55e39e7 Kostas Papadimitriou
                'auth_token',
977 c55e39e7 Kostas Papadimitriou
                'auth_token_expires',
978 c55e39e7 Kostas Papadimitriou
                'old_password',
979 c55e39e7 Kostas Papadimitriou
                'new_password1',
980 c55e39e7 Kostas Papadimitriou
                'new_password2',
981 c55e39e7 Kostas Papadimitriou
                'change_email',
982 c55e39e7 Kostas Papadimitriou
                'change_password',
983 c55e39e7 Kostas Papadimitriou
        ]
984 c55e39e7 Kostas Papadimitriou
985 f7400729 Kostas Papadimitriou
        super(ExtendedProfileForm, self).__init__(*args, **kwargs)
986 95cb469b Kostas Papadimitriou
        self.session_key = session_key
987 3fbf7863 Kostas Papadimitriou
        if self.instance.can_change_password():
988 3fbf7863 Kostas Papadimitriou
            self.password_change = True
989 3fbf7863 Kostas Papadimitriou
        else:
990 2b7a87d7 Olga Brani
            self.fields_list.remove('old_password')
991 2b7a87d7 Olga Brani
            self.fields_list.remove('new_password1')
992 2b7a87d7 Olga Brani
            self.fields_list.remove('new_password2')
993 2b7a87d7 Olga Brani
            self.fields_list.remove('change_password')
994 3fbf7863 Kostas Papadimitriou
            del self.fields['change_password']
995 3fbf7863 Kostas Papadimitriou
996 c55e39e7 Kostas Papadimitriou
997 649f2d36 Kostas Papadimitriou
        if EMAILCHANGE_ENABLED and self.instance.can_change_email():
998 17ad5d37 Kostas Papadimitriou
            self.email_change = True
999 17ad5d37 Kostas Papadimitriou
        else:
1000 d0632ab1 Olga Brani
            self.fields_list.remove('new_email_address')
1001 2b7a87d7 Olga Brani
            self.fields_list.remove('change_email')
1002 17ad5d37 Kostas Papadimitriou
            del self.fields['change_email']
1003 17ad5d37 Kostas Papadimitriou
1004 f7400729 Kostas Papadimitriou
        self._init_extra_forms()
1005 f7400729 Kostas Papadimitriou
        self.save_extra_forms = []
1006 f7400729 Kostas Papadimitriou
        self.success_messages = []
1007 d0632ab1 Olga Brani
        self.fields.keyOrder = self.fields_list
1008 c55e39e7 Kostas Papadimitriou
1009 c55e39e7 Kostas Papadimitriou
1010 f7400729 Kostas Papadimitriou
    def _init_extra_form_fields(self):
1011 17ad5d37 Kostas Papadimitriou
        if self.email_change:
1012 17ad5d37 Kostas Papadimitriou
            self.fields.update(self.email_change_form.fields)
1013 17ad5d37 Kostas Papadimitriou
            self.fields['new_email_address'].required = False
1014 3fbf7863 Kostas Papadimitriou
1015 3fbf7863 Kostas Papadimitriou
        if self.password_change:
1016 3fbf7863 Kostas Papadimitriou
            self.fields.update(self.password_change_form.fields)
1017 3fbf7863 Kostas Papadimitriou
            self.fields['old_password'].required = False
1018 003d8fcf Olga Brani
            self.fields['old_password'].label = _('Password')
1019 861458fd Kostas Papadimitriou
            self.fields['old_password'].initial = 'password'
1020 3fbf7863 Kostas Papadimitriou
            self.fields['new_password1'].required = False
1021 3fbf7863 Kostas Papadimitriou
            self.fields['new_password2'].required = False
1022 f7400729 Kostas Papadimitriou
1023 f7400729 Kostas Papadimitriou
    def _update_extra_form_errors(self):
1024 f7400729 Kostas Papadimitriou
        if self.cleaned_data.get('change_password'):
1025 f7400729 Kostas Papadimitriou
            self.errors.update(self.password_change_form.errors)
1026 f7400729 Kostas Papadimitriou
        if self.cleaned_data.get('change_email'):
1027 f7400729 Kostas Papadimitriou
            self.errors.update(self.email_change_form.errors)
1028 f7400729 Kostas Papadimitriou
1029 f7400729 Kostas Papadimitriou
    def _init_extra_forms(self):
1030 f7400729 Kostas Papadimitriou
        self.email_change_form = EmailChangeForm(self.data)
1031 f7400729 Kostas Papadimitriou
        self.password_change_form = ExtendedPasswordChangeForm(user=self.instance,
1032 95cb469b Kostas Papadimitriou
                                   data=self.data, session_key=self.session_key)
1033 f7400729 Kostas Papadimitriou
        self._init_extra_form_fields()
1034 f7400729 Kostas Papadimitriou
1035 f7400729 Kostas Papadimitriou
    def is_valid(self):
1036 f7400729 Kostas Papadimitriou
        password, email = True, True
1037 f7400729 Kostas Papadimitriou
        profile = super(ExtendedProfileForm, self).is_valid()
1038 3fbf7863 Kostas Papadimitriou
        if profile and self.cleaned_data.get('change_password', None):
1039 e9e692be Kostas Papadimitriou
1040 f7400729 Kostas Papadimitriou
            password = self.password_change_form.is_valid()
1041 3fbf7863 Kostas Papadimitriou
            self.save_extra_forms.append('password')
1042 f7400729 Kostas Papadimitriou
        if profile and self.cleaned_data.get('change_email'):
1043 7b4ca7fe Olga Brani
            self.fields['new_email_address'].required = True
1044 f7400729 Kostas Papadimitriou
            email = self.email_change_form.is_valid()
1045 3fbf7863 Kostas Papadimitriou
            self.save_extra_forms.append('email')
1046 f7400729 Kostas Papadimitriou
1047 f7400729 Kostas Papadimitriou
        if not password or not email:
1048 f7400729 Kostas Papadimitriou
            self._update_extra_form_errors()
1049 f7400729 Kostas Papadimitriou
1050 f7400729 Kostas Papadimitriou
        return all([profile, password, email])
1051 f7400729 Kostas Papadimitriou
1052 3fbf7863 Kostas Papadimitriou
    def save(self, request, *args, **kwargs):
1053 f7400729 Kostas Papadimitriou
        if 'email' in self.save_extra_forms:
1054 3fbf7863 Kostas Papadimitriou
            self.email_change_form.save(request, *args, **kwargs)
1055 2da6f56b Kostas Papadimitriou
            self.email_changed = True
1056 f7400729 Kostas Papadimitriou
        if 'password' in self.save_extra_forms:
1057 f7400729 Kostas Papadimitriou
            self.password_change_form.save(*args, **kwargs)
1058 2da6f56b Kostas Papadimitriou
            self.password_changed = True
1059 f7400729 Kostas Papadimitriou
        return super(ExtendedProfileForm, self).save(*args, **kwargs)