Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ bb528b2e

History | View | Annotate | Download (41.3 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 caf70869 Sofia Papagiannaki
from random import random
34 3e0a032d Sofia Papagiannaki
from datetime import datetime
35 64cd4730 Antony Chazapis
36 64cd4730 Antony Chazapis
from django import forms
37 64cd4730 Antony Chazapis
from django.utils.translation import ugettext as _
38 3e0a032d Sofia Papagiannaki
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, \
39 3e0a032d Sofia Papagiannaki
    PasswordResetForm, PasswordChangeForm, SetPasswordForm
40 f9224cc0 Sofia Papagiannaki
from django.core.mail import send_mail, get_connection
41 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
42 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
43 18ffbee1 Sofia Papagiannaki
from django.utils.safestring import mark_safe
44 49790d9d Sofia Papagiannaki
from django.utils.encoding import smart_str
45 d2633501 Kostas Papadimitriou
from django.db import transaction
46 caf70869 Sofia Papagiannaki
from django.core import validators
47 5ed6816e Sofia Papagiannaki
48 3e87075a Giorgos Korfiatis
from synnefo.util import units
49 734107ef Kostas Papadimitriou
from synnefo_branding.utils import render_to_string
50 d2c9adac Christos Stavrakakis
from synnefo.lib import join_urls
51 3e0a032d Sofia Papagiannaki
from astakos.im.models import AstakosUser, EmailChange, Invitation, Resource, \
52 3e0a032d Sofia Papagiannaki
    PendingThirdPartyUser, get_latest_terms, ProjectApplication, Project
53 75380308 Kostas Papadimitriou
from astakos.im import presentation
54 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
55 3e0a032d Sofia Papagiannaki
from astakos.im.functions import send_change_email, submit_application, \
56 f12bcb3d Giorgos Korfiatis
    accept_membership_project_checks, ProjectError
57 270dd48d Sofia Papagiannaki
58 3e0a032d Sofia Papagiannaki
from astakos.im.util import reserved_verified_email, model_to_dict
59 c4b1a172 Kostas Papadimitriou
from astakos.im import auth_providers
60 8998f09a Sofia Papagiannaki
from astakos.im import settings
61 64cd4730 Antony Chazapis
62 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
63 64cd4730 Antony Chazapis
64 3bf924ec Sofia Papagiannaki
import logging
65 49790d9d Sofia Papagiannaki
import hashlib
66 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
67 caf70869 Sofia Papagiannaki
import re
68 64cd4730 Antony Chazapis
69 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
70 e015e9e6 Sofia Papagiannaki
71 caf70869 Sofia Papagiannaki
DOMAIN_VALUE_REGEX = re.compile(
72 892410d3 Sofia Papagiannaki
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
73 73fbaec4 Sofia Papagiannaki
    re.IGNORECASE)
74 d2633501 Kostas Papadimitriou
75 e7cb4085 Kostas Papadimitriou
76 caf70869 Sofia Papagiannaki
class StoreUserMixin(object):
77 e5966bd9 Kostas Papadimitriou
78 e7cb4085 Kostas Papadimitriou
    def store_user(self, user, request=None):
79 43332a76 Kostas Papadimitriou
        """
80 43332a76 Kostas Papadimitriou
        WARNING: this should be wrapped inside a transactional view/method.
81 43332a76 Kostas Papadimitriou
        """
82 d2633501 Kostas Papadimitriou
        user.save()
83 d2633501 Kostas Papadimitriou
        self.post_store_user(user, request)
84 d2633501 Kostas Papadimitriou
        return user
85 d2633501 Kostas Papadimitriou
86 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
87 d2633501 Kostas Papadimitriou
        """
88 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
89 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
90 d2633501 Kostas Papadimitriou
        """
91 d2633501 Kostas Papadimitriou
        pass
92 d2633501 Kostas Papadimitriou
93 d2633501 Kostas Papadimitriou
94 d2633501 Kostas Papadimitriou
class LocalUserCreationForm(UserCreationForm, StoreUserMixin):
95 890b0eaf Sofia Papagiannaki
    """
96 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
97 18ffbee1 Sofia Papagiannaki

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

442 8fb8d0cf Giorgos Korfiatis
    The class defines a save method which sets ``is_verified`` to True so as
443 8fb8d0cf Giorgos Korfiatis
    the user during the next login will not to be redirected to profile page.
444 890b0eaf Sofia Papagiannaki
    """
445 8fb8d0cf Giorgos Korfiatis
    email = forms.EmailField(label='E-mail address',
446 8fb8d0cf Giorgos Korfiatis
                             help_text='E-mail address')
447 c301698f Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
448 18ffbee1 Sofia Papagiannaki
449 890b0eaf Sofia Papagiannaki
    class Meta:
450 890b0eaf Sofia Papagiannaki
        model = AstakosUser
451 bebd2649 Kostas Papadimitriou
        fields = ('email', 'first_name', 'last_name')
452 18ffbee1 Sofia Papagiannaki
453 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
454 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
455 890b0eaf Sofia Papagiannaki
        super(ProfileForm, self).__init__(*args, **kwargs)
456 890b0eaf Sofia Papagiannaki
        instance = getattr(self, 'instance', None)
457 bebd2649 Kostas Papadimitriou
        ro_fields = ('email',)
458 890b0eaf Sofia Papagiannaki
        if instance and instance.id:
459 890b0eaf Sofia Papagiannaki
            for field in ro_fields:
460 890b0eaf Sofia Papagiannaki
                self.fields[field].widget.attrs['readonly'] = True
461 18ffbee1 Sofia Papagiannaki
462 98b84806 Kostas Papadimitriou
    def clean_email(self):
463 98b84806 Kostas Papadimitriou
        return self.instance.email
464 98b84806 Kostas Papadimitriou
465 0eb1f53a Ilias Tsitsimpis
    def save(self, commit=True, **kwargs):
466 0eb1f53a Ilias Tsitsimpis
        user = super(ProfileForm, self).save(commit=False, **kwargs)
467 890b0eaf Sofia Papagiannaki
        user.is_verified = True
468 c301698f Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
469 bf0c6de5 Sofia Papagiannaki
            user.renew_token(
470 bf0c6de5 Sofia Papagiannaki
                flush_sessions=True,
471 bf0c6de5 Sofia Papagiannaki
                current_key=self.session_key
472 bf0c6de5 Sofia Papagiannaki
            )
473 890b0eaf Sofia Papagiannaki
        if commit:
474 0eb1f53a Ilias Tsitsimpis
            user.save(**kwargs)
475 890b0eaf Sofia Papagiannaki
        return user
476 64cd4730 Antony Chazapis
477 5ce3ce4f Sofia Papagiannaki
478 890b0eaf Sofia Papagiannaki
class FeedbackForm(forms.Form):
479 890b0eaf Sofia Papagiannaki
    """
480 890b0eaf Sofia Papagiannaki
    Form for writing feedback.
481 890b0eaf Sofia Papagiannaki
    """
482 0a569195 Sofia Papagiannaki
    feedback_msg = forms.CharField(widget=forms.Textarea, label=u'Message')
483 8f5a3a06 Sofia Papagiannaki
    feedback_data = forms.CharField(widget=forms.HiddenInput(), label='',
484 8f5a3a06 Sofia Papagiannaki
                                    required=False)
485 5ed6816e Sofia Papagiannaki
486 5ce3ce4f Sofia Papagiannaki
487 5ed6816e Sofia Papagiannaki
class SendInvitationForm(forms.Form):
488 5ed6816e Sofia Papagiannaki
    """
489 5ed6816e Sofia Papagiannaki
    Form for sending an invitations
490 5ed6816e Sofia Papagiannaki
    """
491 18ffbee1 Sofia Papagiannaki
492 5ce3ce4f Sofia Papagiannaki
    email = forms.EmailField(required=True, label='Email address')
493 5ce3ce4f Sofia Papagiannaki
    first_name = forms.EmailField(label='First name')
494 5ce3ce4f Sofia Papagiannaki
    last_name = forms.EmailField(label='Last name')
495 5ce3ce4f Sofia Papagiannaki
496 e2125441 Sofia Papagiannaki
497 e2125441 Sofia Papagiannaki
class ExtendedPasswordResetForm(PasswordResetForm):
498 e2125441 Sofia Papagiannaki
    """
499 dd5f8f4d Kostas Papadimitriou
    Extends PasswordResetForm by overriding
500 18ffbee1 Sofia Papagiannaki

501 dd5f8f4d Kostas Papadimitriou
    save method: to pass a custom from_email in send_mail.
502 dd5f8f4d Kostas Papadimitriou
    clean_email: to handle local auth provider checks
503 e2125441 Sofia Papagiannaki
    """
504 23c271b3 Sofia Papagiannaki
    def clean_email(self):
505 9d20fe23 Kostas Papadimitriou
        # we override the default django auth clean_email to provide more
506 9d20fe23 Kostas Papadimitriou
        # detailed messages in case of inactive users
507 9d20fe23 Kostas Papadimitriou
        email = self.cleaned_data['email']
508 23c271b3 Sofia Papagiannaki
        try:
509 dd5f8f4d Kostas Papadimitriou
            user = AstakosUser.objects.get_by_identifier(email)
510 9d20fe23 Kostas Papadimitriou
            self.users_cache = [user]
511 dd5f8f4d Kostas Papadimitriou
            if not user.is_active:
512 e7cb4085 Kostas Papadimitriou
                msg = mark_safe(user.get_inactive_message('local'))
513 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(msg)
514 dd5f8f4d Kostas Papadimitriou
515 9d20fe23 Kostas Papadimitriou
            provider = auth_providers.get_provider('local', user)
516 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
517 9d20fe23 Kostas Papadimitriou
                msg = provider.get_unusable_password_msg
518 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(mark_safe(msg))
519 d2633501 Kostas Papadimitriou
520 d2633501 Kostas Papadimitriou
            if not user.can_change_password():
521 9d20fe23 Kostas Papadimitriou
                msg = provider.get_cannot_change_password_msg
522 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(mark_safe(msg))
523 9d20fe23 Kostas Papadimitriou
524 9d20fe23 Kostas Papadimitriou
        except AstakosUser.DoesNotExist:
525 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
526 23c271b3 Sofia Papagiannaki
        return email
527 ab8bfb29 Kostas Papadimitriou
528 8fb8d0cf Giorgos Korfiatis
    def save(self, domain_override=None,
529 8fb8d0cf Giorgos Korfiatis
             email_template_name='registration/password_reset_email.html',
530 8fb8d0cf Giorgos Korfiatis
             use_https=False, token_generator=default_token_generator,
531 0eb1f53a Ilias Tsitsimpis
             request=None, **kwargs):
532 e2125441 Sofia Papagiannaki
        """
533 8fb8d0cf Giorgos Korfiatis
        Generates a one-use only link for resetting password and sends to the
534 8fb8d0cf Giorgos Korfiatis
        user.
535 0a70d2c5 Christos Stavrakakis

536 e2125441 Sofia Papagiannaki
        """
537 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
538 d2633501 Kostas Papadimitriou
            url = user.astakosuser.get_password_reset_url(token_generator)
539 95d49da0 Sofia Papagiannaki
            url = join_urls(settings.BASE_HOST, url)
540 e2125441 Sofia Papagiannaki
            c = {
541 e2125441 Sofia Papagiannaki
                'email': user.email,
542 8f378756 Sofia Papagiannaki
                'url': url,
543 8998f09a Sofia Papagiannaki
                'site_name': settings.SITENAME,
544 e2125441 Sofia Papagiannaki
                'user': user,
545 6c7af65c Georgios D. Tsoukalas
                'baseurl': settings.BASE_URL,
546 8998f09a Sofia Papagiannaki
                'support': settings.CONTACT_EMAIL
547 e2125441 Sofia Papagiannaki
            }
548 734107ef Kostas Papadimitriou
            message = render_to_string(email_template_name, c)
549 1cbce16f Sofia Papagiannaki
            from_email = settings.SERVER_EMAIL
550 cfb7dd4f Giorgos Korfiatis
            send_mail(_(astakos_messages.PASSWORD_RESET_EMAIL_SUBJECT),
551 734107ef Kostas Papadimitriou
                      message,
552 f9224cc0 Sofia Papagiannaki
                      from_email,
553 f9224cc0 Sofia Papagiannaki
                      [user.email],
554 28f4439f Sofia Papagiannaki
                      connection=get_connection())
555 5ce3ce4f Sofia Papagiannaki
556 270dd48d Sofia Papagiannaki
557 49790d9d Sofia Papagiannaki
class EmailChangeForm(forms.ModelForm):
558 34a76cdb Kostas Papadimitriou
559 49790d9d Sofia Papagiannaki
    class Meta:
560 49790d9d Sofia Papagiannaki
        model = EmailChange
561 49790d9d Sofia Papagiannaki
        fields = ('new_email_address',)
562 ab8bfb29 Kostas Papadimitriou
563 49790d9d Sofia Papagiannaki
    def clean_new_email_address(self):
564 49790d9d Sofia Papagiannaki
        addr = self.cleaned_data['new_email_address']
565 43332a76 Kostas Papadimitriou
        if reserved_verified_email(addr):
566 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
567 49790d9d Sofia Papagiannaki
        return addr
568 ab8bfb29 Kostas Papadimitriou
569 8fb8d0cf Giorgos Korfiatis
    def save(self, request,
570 8fb8d0cf Giorgos Korfiatis
             email_template_name='registration/email_change_email.txt',
571 0eb1f53a Ilias Tsitsimpis
             commit=True, **kwargs):
572 0eb1f53a Ilias Tsitsimpis
        ec = super(EmailChangeForm, self).save(commit=False, **kwargs)
573 49790d9d Sofia Papagiannaki
        ec.user = request.user
574 3fbf7863 Kostas Papadimitriou
        # delete pending email changes
575 3fbf7863 Kostas Papadimitriou
        request.user.emailchanges.all().delete()
576 3fbf7863 Kostas Papadimitriou
577 5ce3ce4f Sofia Papagiannaki
        activation_key = hashlib.sha1(
578 5ce3ce4f Sofia Papagiannaki
            str(random()) + smart_str(ec.new_email_address))
579 5ce3ce4f Sofia Papagiannaki
        ec.activation_key = activation_key.hexdigest()
580 49790d9d Sofia Papagiannaki
        if commit:
581 0eb1f53a Ilias Tsitsimpis
            ec.save(**kwargs)
582 49790d9d Sofia Papagiannaki
        send_change_email(ec, request, email_template_name=email_template_name)
583 49790d9d Sofia Papagiannaki
584 5ce3ce4f Sofia Papagiannaki
585 270dd48d Sofia Papagiannaki
class SignApprovalTermsForm(forms.ModelForm):
586 34a76cdb Kostas Papadimitriou
587 270dd48d Sofia Papagiannaki
    class Meta:
588 270dd48d Sofia Papagiannaki
        model = AstakosUser
589 270dd48d Sofia Papagiannaki
        fields = ("has_signed_terms",)
590 18ffbee1 Sofia Papagiannaki
591 270dd48d Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
592 270dd48d Sofia Papagiannaki
        super(SignApprovalTermsForm, self).__init__(*args, **kwargs)
593 18ffbee1 Sofia Papagiannaki
594 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
595 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
596 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
597 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
598 270dd48d Sofia Papagiannaki
        return has_signed_terms
599 8f5a3a06 Sofia Papagiannaki
600 0eb1f53a Ilias Tsitsimpis
    def save(self, commit=True, **kwargs):
601 0eb1f53a Ilias Tsitsimpis
        user = super(SignApprovalTermsForm, self).save(commit=commit, **kwargs)
602 e7cb4085 Kostas Papadimitriou
        user.date_signed_terms = datetime.now()
603 e7cb4085 Kostas Papadimitriou
        if commit:
604 0eb1f53a Ilias Tsitsimpis
            user.save(**kwargs)
605 e7cb4085 Kostas Papadimitriou
        return user
606 e7cb4085 Kostas Papadimitriou
607 5ce3ce4f Sofia Papagiannaki
608 8f5a3a06 Sofia Papagiannaki
class InvitationForm(forms.ModelForm):
609 34a76cdb Kostas Papadimitriou
610 8f5a3a06 Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
611 ab8bfb29 Kostas Papadimitriou
612 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
613 18ffbee1 Sofia Papagiannaki
        super(InvitationForm, self).__init__(*args, **kwargs)
614 ab8bfb29 Kostas Papadimitriou
615 8f5a3a06 Sofia Papagiannaki
    class Meta:
616 8f5a3a06 Sofia Papagiannaki
        model = Invitation
617 8f5a3a06 Sofia Papagiannaki
        fields = ('username', 'realname')
618 ab8bfb29 Kostas Papadimitriou
619 8f5a3a06 Sofia Papagiannaki
    def clean_username(self):
620 8f5a3a06 Sofia Papagiannaki
        username = self.cleaned_data['username']
621 8f5a3a06 Sofia Papagiannaki
        try:
622 5ce3ce4f Sofia Papagiannaki
            Invitation.objects.get(username=username)
623 8fb8d0cf Giorgos Korfiatis
            raise forms.ValidationError(
624 8fb8d0cf Giorgos Korfiatis
                _(astakos_messages.INVITATION_EMAIL_EXISTS))
625 8f5a3a06 Sofia Papagiannaki
        except Invitation.DoesNotExist:
626 8f5a3a06 Sofia Papagiannaki
            pass
627 18ffbee1 Sofia Papagiannaki
        return username
628 1039bab1 Sofia Papagiannaki
629 5ce3ce4f Sofia Papagiannaki
630 1039bab1 Sofia Papagiannaki
class ExtendedPasswordChangeForm(PasswordChangeForm):
631 1039bab1 Sofia Papagiannaki
    """
632 1039bab1 Sofia Papagiannaki
    Extends PasswordChangeForm by enabling user
633 1039bab1 Sofia Papagiannaki
    to optionally renew also the token.
634 1039bab1 Sofia Papagiannaki
    """
635 8998f09a Sofia Papagiannaki
    if not settings.NEWPASSWD_INVALIDATE_TOKEN:
636 8fb8d0cf Giorgos Korfiatis
        renew = forms.BooleanField(
637 8fb8d0cf Giorgos Korfiatis
            label='Renew token', required=False,
638 8fb8d0cf Giorgos Korfiatis
            initial=True,
639 8fb8d0cf Giorgos Korfiatis
            help_text='Unsetting this may result in security risk.')
640 ab8bfb29 Kostas Papadimitriou
641 1039bab1 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
642 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
643 1039bab1 Sofia Papagiannaki
        super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
644 ab8bfb29 Kostas Papadimitriou
645 0eb1f53a Ilias Tsitsimpis
    def save(self, commit=True, **kwargs):
646 bf0c6de5 Sofia Papagiannaki
        try:
647 8998f09a Sofia Papagiannaki
            if settings.NEWPASSWD_INVALIDATE_TOKEN or \
648 8998f09a Sofia Papagiannaki
                    self.cleaned_data.get('renew'):
649 bf0c6de5 Sofia Papagiannaki
                self.user.renew_token()
650 bf0c6de5 Sofia Papagiannaki
            self.user.flush_sessions(current_key=self.session_key)
651 bf0c6de5 Sofia Papagiannaki
        except AttributeError:
652 bf0c6de5 Sofia Papagiannaki
            # if user model does has not such methods
653 bf0c6de5 Sofia Papagiannaki
            pass
654 60b59fed Ilias Tsitsimpis
        return super(ExtendedPasswordChangeForm, self).save(commit=commit,
655 0eb1f53a Ilias Tsitsimpis
                                                            **kwargs)
656 48e9f076 Sofia Papagiannaki
657 8fb8d0cf Giorgos Korfiatis
658 48e9f076 Sofia Papagiannaki
class ExtendedSetPasswordForm(SetPasswordForm):
659 48e9f076 Sofia Papagiannaki
    """
660 48e9f076 Sofia Papagiannaki
    Extends SetPasswordForm by enabling user
661 48e9f076 Sofia Papagiannaki
    to optionally renew also the token.
662 48e9f076 Sofia Papagiannaki
    """
663 8998f09a Sofia Papagiannaki
    if not settings.NEWPASSWD_INVALIDATE_TOKEN:
664 bf0c6de5 Sofia Papagiannaki
        renew = forms.BooleanField(
665 bf0c6de5 Sofia Papagiannaki
            label='Renew token',
666 bf0c6de5 Sofia Papagiannaki
            required=False,
667 bf0c6de5 Sofia Papagiannaki
            initial=True,
668 47b77c8b Sofia Papagiannaki
            help_text='Unsetting this may result in security risk.')
669 2e90e3ec Kostas Papadimitriou
670 48e9f076 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
671 48e9f076 Sofia Papagiannaki
        super(ExtendedSetPasswordForm, self).__init__(user, *args, **kwargs)
672 d2633501 Kostas Papadimitriou
673 d2633501 Kostas Papadimitriou
    @transaction.commit_on_success()
674 0eb1f53a Ilias Tsitsimpis
    def save(self, commit=True, **kwargs):
675 bf0c6de5 Sofia Papagiannaki
        try:
676 bf0c6de5 Sofia Papagiannaki
            self.user = AstakosUser.objects.get(id=self.user.id)
677 8998f09a Sofia Papagiannaki
            if settings.NEWPASSWD_INVALIDATE_TOKEN or \
678 8998f09a Sofia Papagiannaki
                    self.cleaned_data.get('renew'):
679 53161dd8 Sofia Papagiannaki
                self.user.renew_token()
680 9d20fe23 Kostas Papadimitriou
681 9d20fe23 Kostas Papadimitriou
            provider = auth_providers.get_provider('local', self.user)
682 9d20fe23 Kostas Papadimitriou
            if provider.get_add_policy:
683 9d20fe23 Kostas Papadimitriou
                provider.add_to_user()
684 d2633501 Kostas Papadimitriou
685 bf0c6de5 Sofia Papagiannaki
        except BaseException, e:
686 bf0c6de5 Sofia Papagiannaki
            logger.exception(e)
687 60b59fed Ilias Tsitsimpis
        return super(ExtendedSetPasswordForm, self).save(commit=commit,
688 0eb1f53a Ilias Tsitsimpis
                                                         **kwargs)
689 e1a80257 Sofia Papagiannaki
690 e1a80257 Sofia Papagiannaki
691 8fb8d0cf Giorgos Korfiatis
app_name_label = "Project name"
692 67980f56 Georgios D. Tsoukalas
app_name_placeholder = _("myproject.mylab.ntua.gr")
693 8fb8d0cf Giorgos Korfiatis
app_name_validator = validators.RegexValidator(
694 8fb8d0cf Giorgos Korfiatis
    DOMAIN_VALUE_REGEX,
695 8fb8d0cf Giorgos Korfiatis
    _(astakos_messages.DOMAIN_VALUE_ERR),
696 8fb8d0cf Giorgos Korfiatis
    'invalid')
697 8fb8d0cf Giorgos Korfiatis
app_name_help = _("""
698 c9a6e558 Constantinos Venetsanopoulos
        The project's name should be in a domain format.
699 67980f56 Georgios D. Tsoukalas
        The domain shouldn't neccessarily exist in the real
700 67980f56 Georgios D. Tsoukalas
        world but is helpful to imply a structure.
701 67980f56 Georgios D. Tsoukalas
        e.g.: myproject.mylab.ntua.gr or
702 67980f56 Georgios D. Tsoukalas
        myservice.myteam.myorganization""")
703 8fb8d0cf Giorgos Korfiatis
app_name_widget = forms.TextInput(
704 8fb8d0cf Giorgos Korfiatis
    attrs={'placeholder': app_name_placeholder})
705 67980f56 Georgios D. Tsoukalas
706 67980f56 Georgios D. Tsoukalas
707 8fb8d0cf Giorgos Korfiatis
app_home_label = "Homepage URL"
708 8fb8d0cf Giorgos Korfiatis
app_home_placeholder = 'myinstitution.org/myproject/'
709 8fb8d0cf Giorgos Korfiatis
app_home_help = _("""
710 67980f56 Georgios D. Tsoukalas
        URL pointing at your project's site.
711 3ff82dca Olga Brani
        e.g.: myinstitution.org/myproject/.
712 67980f56 Georgios D. Tsoukalas
        Leave blank if there is no website.""")
713 8fb8d0cf Giorgos Korfiatis
app_home_widget = forms.TextInput(
714 8fb8d0cf Giorgos Korfiatis
    attrs={'placeholder': app_home_placeholder})
715 67980f56 Georgios D. Tsoukalas
716 8fb8d0cf Giorgos Korfiatis
app_desc_label = _("Description")
717 8fb8d0cf Giorgos Korfiatis
app_desc_help = _("""
718 c53afd76 Georgios D. Tsoukalas
        Please provide a short but descriptive abstract of your
719 c9a6e558 Constantinos Venetsanopoulos
        project, so that anyone searching can quickly understand
720 c9a6e558 Constantinos Venetsanopoulos
        what this project is about.""")
721 67980f56 Georgios D. Tsoukalas
722 8fb8d0cf Giorgos Korfiatis
app_comment_label = _("Comments for review (private)")
723 8fb8d0cf Giorgos Korfiatis
app_comment_help = _("""
724 67980f56 Georgios D. Tsoukalas
        Write down any comments you may have for the reviewer
725 67980f56 Georgios D. Tsoukalas
        of this application (e.g. background and rationale to
726 67980f56 Georgios D. Tsoukalas
        support your request).
727 67980f56 Georgios D. Tsoukalas
        The comments are strictly for the review process
728 c53afd76 Georgios D. Tsoukalas
        and will not be made public.""")
729 67980f56 Georgios D. Tsoukalas
730 8fb8d0cf Giorgos Korfiatis
app_start_date_label = _("Start date")
731 8fb8d0cf Giorgos Korfiatis
app_start_date_help = _("""
732 67980f56 Georgios D. Tsoukalas
        Provide a date when your need your project to be created,
733 67980f56 Georgios D. Tsoukalas
        and members to be able to join and get resources.
734 67980f56 Georgios D. Tsoukalas
        This date is only a hint to help prioritize reviews.""")
735 67980f56 Georgios D. Tsoukalas
736 8fb8d0cf Giorgos Korfiatis
app_end_date_label = _("Termination date")
737 8fb8d0cf Giorgos Korfiatis
app_end_date_help = _("""
738 67980f56 Georgios D. Tsoukalas
        At this date, the project will be automatically terminated
739 c53afd76 Georgios D. Tsoukalas
        and its resource grants revoked from all members. If you are
740 c53afd76 Georgios D. Tsoukalas
        not certain, it is best to start with a conservative estimation.
741 67980f56 Georgios D. Tsoukalas
        You can always re-apply for an extension, if you need.""")
742 67980f56 Georgios D. Tsoukalas
743 8fb8d0cf Giorgos Korfiatis
join_policy_label = _("Joining policy")
744 8fb8d0cf Giorgos Korfiatis
app_member_join_policy_help = _("""
745 c53afd76 Georgios D. Tsoukalas
        Select how new members are accepted into the project.""")
746 8fb8d0cf Giorgos Korfiatis
leave_policy_label = _("Leaving policy")
747 8fb8d0cf Giorgos Korfiatis
app_member_leave_policy_help = _("""
748 c53afd76 Georgios D. Tsoukalas
        Select how new members can leave the project.""")
749 67980f56 Georgios D. Tsoukalas
750 8fb8d0cf Giorgos Korfiatis
max_members_label = _("Maximum member count")
751 8fb8d0cf Giorgos Korfiatis
max_members_help = _("""
752 67980f56 Georgios D. Tsoukalas
        Specify the maximum number of members this project may have,
753 67980f56 Georgios D. Tsoukalas
        including the owner. Beyond this number, no new members
754 67980f56 Georgios D. Tsoukalas
        may join the project and be granted the project resources.
755 c53afd76 Georgios D. Tsoukalas
        If you are not certain, it is best to start with a conservative
756 c53afd76 Georgios D. Tsoukalas
        limit. You can always request a raise when you need it.""")
757 67980f56 Georgios D. Tsoukalas
758 251b83be Giorgos Korfiatis
join_policies = presentation.PROJECT_MEMBER_JOIN_POLICIES.items()
759 251b83be Giorgos Korfiatis
leave_policies = presentation.PROJECT_MEMBER_LEAVE_POLICIES.items()
760 67980f56 Georgios D. Tsoukalas
761 8fb8d0cf Giorgos Korfiatis
762 e1a80257 Sofia Papagiannaki
class ProjectApplicationForm(forms.ModelForm):
763 67980f56 Georgios D. Tsoukalas
764 e1a80257 Sofia Papagiannaki
    name = forms.CharField(
765 8fb8d0cf Giorgos Korfiatis
        label=app_name_label,
766 8fb8d0cf Giorgos Korfiatis
        help_text=app_name_help,
767 8fb8d0cf Giorgos Korfiatis
        widget=app_name_widget,
768 8fb8d0cf Giorgos Korfiatis
        validators=[app_name_validator])
769 67980f56 Georgios D. Tsoukalas
770 52784759 Olga Brani
    homepage = forms.URLField(
771 8fb8d0cf Giorgos Korfiatis
        label=app_home_label,
772 8fb8d0cf Giorgos Korfiatis
        help_text=app_home_help,
773 8fb8d0cf Giorgos Korfiatis
        widget=app_home_widget,
774 8fb8d0cf Giorgos Korfiatis
        required=False)
775 67980f56 Georgios D. Tsoukalas
776 67980f56 Georgios D. Tsoukalas
    description = forms.CharField(
777 8fb8d0cf Giorgos Korfiatis
        label=app_desc_label,
778 8fb8d0cf Giorgos Korfiatis
        help_text=app_desc_help,
779 8fb8d0cf Giorgos Korfiatis
        widget=forms.Textarea,
780 8fb8d0cf Giorgos Korfiatis
        required=False)
781 67980f56 Georgios D. Tsoukalas
782 67980f56 Georgios D. Tsoukalas
    comments = forms.CharField(
783 8fb8d0cf Giorgos Korfiatis
        label=app_comment_label,
784 8fb8d0cf Giorgos Korfiatis
        help_text=app_comment_help,
785 8fb8d0cf Giorgos Korfiatis
        widget=forms.Textarea,
786 8fb8d0cf Giorgos Korfiatis
        required=False)
787 67980f56 Georgios D. Tsoukalas
788 67980f56 Georgios D. Tsoukalas
    start_date = forms.DateTimeField(
789 8fb8d0cf Giorgos Korfiatis
        label=app_start_date_label,
790 8fb8d0cf Giorgos Korfiatis
        help_text=app_start_date_help,
791 8fb8d0cf Giorgos Korfiatis
        required=False)
792 67980f56 Georgios D. Tsoukalas
793 67980f56 Georgios D. Tsoukalas
    end_date = forms.DateTimeField(
794 8fb8d0cf Giorgos Korfiatis
        label=app_end_date_label,
795 8fb8d0cf Giorgos Korfiatis
        help_text=app_end_date_help)
796 67980f56 Georgios D. Tsoukalas
797 8fb8d0cf Giorgos Korfiatis
    member_join_policy = forms.TypedChoiceField(
798 8fb8d0cf Giorgos Korfiatis
        label=join_policy_label,
799 8fb8d0cf Giorgos Korfiatis
        help_text=app_member_join_policy_help,
800 8fb8d0cf Giorgos Korfiatis
        initial=2,
801 8fb8d0cf Giorgos Korfiatis
        coerce=int,
802 8fb8d0cf Giorgos Korfiatis
        choices=join_policies)
803 dd5f8f4d Kostas Papadimitriou
804 80da92f0 Kostas Papadimitriou
    member_leave_policy = forms.TypedChoiceField(
805 8fb8d0cf Giorgos Korfiatis
        label=leave_policy_label,
806 8fb8d0cf Giorgos Korfiatis
        help_text=app_member_leave_policy_help,
807 8fb8d0cf Giorgos Korfiatis
        coerce=int,
808 8fb8d0cf Giorgos Korfiatis
        choices=leave_policies)
809 67980f56 Georgios D. Tsoukalas
810 67980f56 Georgios D. Tsoukalas
    limit_on_members_number = forms.IntegerField(
811 8fb8d0cf Giorgos Korfiatis
        label=max_members_label,
812 8fb8d0cf Giorgos Korfiatis
        help_text=max_members_help,
813 8fb8d0cf Giorgos Korfiatis
        min_value=0,
814 e98239db Giorgos Korfiatis
        required=True)
815 dd5f8f4d Kostas Papadimitriou
816 e1a80257 Sofia Papagiannaki
    class Meta:
817 73fbaec4 Sofia Papagiannaki
        model = ProjectApplication
818 8fb8d0cf Giorgos Korfiatis
        fields = ('name', 'homepage', 'description',
819 8fb8d0cf Giorgos Korfiatis
                  'start_date', 'end_date', 'comments',
820 8fb8d0cf Giorgos Korfiatis
                  'member_join_policy', 'member_leave_policy',
821 8fb8d0cf Giorgos Korfiatis
                  'limit_on_members_number')
822 c82bd52b Kostas Papadimitriou
823 40b52116 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
824 2ef98527 Sofia Papagiannaki
        instance = kwargs.get('instance')
825 2ef98527 Sofia Papagiannaki
        self.precursor_application = instance
826 40b52116 Sofia Papagiannaki
        super(ProjectApplicationForm, self).__init__(*args, **kwargs)
827 f568d0f4 Sofia Papagiannaki
        # in case of new application remove closed join policy
828 2ef98527 Sofia Papagiannaki
        if not instance:
829 251b83be Giorgos Korfiatis
            policies = presentation.PROJECT_MEMBER_JOIN_POLICIES.copy()
830 251b83be Giorgos Korfiatis
            policies.pop(3)
831 2ef98527 Sofia Papagiannaki
            self.fields['member_join_policy'].choices = policies.iteritems()
832 dd5f8f4d Kostas Papadimitriou
833 69b26576 Sofia Papagiannaki
    def clean_start_date(self):
834 69b26576 Sofia Papagiannaki
        start_date = self.cleaned_data.get('start_date')
835 f568d0f4 Sofia Papagiannaki
        if not self.precursor_application:
836 8172d87d Sofia Papagiannaki
            today = datetime.now()
837 8172d87d Sofia Papagiannaki
            today = datetime(today.year, today.month, today.day)
838 01223f04 Sofia Papagiannaki
            if start_date and (start_date - today).days < 0:
839 f568d0f4 Sofia Papagiannaki
                raise forms.ValidationError(
840 8fb8d0cf Giorgos Korfiatis
                    _(astakos_messages.INVALID_PROJECT_START_DATE))
841 69b26576 Sofia Papagiannaki
        return start_date
842 69b26576 Sofia Papagiannaki
843 69b26576 Sofia Papagiannaki
    def clean_end_date(self):
844 69b26576 Sofia Papagiannaki
        start_date = self.cleaned_data.get('start_date')
845 69b26576 Sofia Papagiannaki
        end_date = self.cleaned_data.get('end_date')
846 8172d87d Sofia Papagiannaki
        today = datetime.now()
847 8172d87d Sofia Papagiannaki
        today = datetime(today.year, today.month, today.day)
848 01223f04 Sofia Papagiannaki
        if end_date and (end_date - today).days < 0:
849 69b26576 Sofia Papagiannaki
            raise forms.ValidationError(
850 69b26576 Sofia Papagiannaki
                _(astakos_messages.INVALID_PROJECT_END_DATE))
851 f03b9ba6 Sofia Papagiannaki
        if start_date and (end_date - start_date).days <= 0:
852 69b26576 Sofia Papagiannaki
            raise forms.ValidationError(
853 69b26576 Sofia Papagiannaki
                _(astakos_messages.INCONSISTENT_PROJECT_DATES))
854 69b26576 Sofia Papagiannaki
        return end_date
855 69b26576 Sofia Papagiannaki
856 e1a80257 Sofia Papagiannaki
    def clean(self):
857 185b2190 Sofia Papagiannaki
        userid = self.data.get('user', None)
858 51db2da2 Giorgos Korfiatis
        self.resource_policies
859 e1a80257 Sofia Papagiannaki
        self.user = None
860 e1a80257 Sofia Papagiannaki
        if userid:
861 e1a80257 Sofia Papagiannaki
            try:
862 e1a80257 Sofia Papagiannaki
                self.user = AstakosUser.objects.get(id=userid)
863 e1a80257 Sofia Papagiannaki
            except AstakosUser.DoesNotExist:
864 e1a80257 Sofia Papagiannaki
                pass
865 e1a80257 Sofia Papagiannaki
        if not self.user:
866 e1a80257 Sofia Papagiannaki
            raise forms.ValidationError(_(astakos_messages.NO_APPLICANT))
867 e1a80257 Sofia Papagiannaki
        super(ProjectApplicationForm, self).clean()
868 e1a80257 Sofia Papagiannaki
        return self.cleaned_data
869 dd5f8f4d Kostas Papadimitriou
870 f3342849 Sofia Papagiannaki
    @property
871 f3342849 Sofia Papagiannaki
    def resource_policies(self):
872 e1a80257 Sofia Papagiannaki
        policies = []
873 e1a80257 Sofia Papagiannaki
        append = policies.append
874 f3342849 Sofia Papagiannaki
        for name, value in self.data.iteritems():
875 f3342849 Sofia Papagiannaki
            if not value:
876 f3342849 Sofia Papagiannaki
                continue
877 56eb807c Sofia Papagiannaki
            uplimit = value
878 56eb807c Sofia Papagiannaki
            if name.endswith('_uplimit'):
879 56eb807c Sofia Papagiannaki
                subs = name.split('_uplimit')
880 e1a80257 Sofia Papagiannaki
                prefix, suffix = subs
881 37d59b27 Kostas Papadimitriou
                try:
882 37d59b27 Kostas Papadimitriou
                    resource = Resource.objects.get(name=prefix)
883 37d59b27 Kostas Papadimitriou
                except Resource.DoesNotExist:
884 37d59b27 Kostas Papadimitriou
                    raise forms.ValidationError("Resource %s does not exist" %
885 37d59b27 Kostas Papadimitriou
                                                resource.name)
886 e1a80257 Sofia Papagiannaki
                # keep only resource limits for selected resource groups
887 8fb8d0cf Giorgos Korfiatis
                if self.data.get('is_selected_%s' %
888 8fb8d0cf Giorgos Korfiatis
                                 resource.group, "0") == "1":
889 37d59b27 Kostas Papadimitriou
                    if not resource.allow_in_projects:
890 37d59b27 Kostas Papadimitriou
                        raise forms.ValidationError("Invalid resource %s" %
891 37d59b27 Kostas Papadimitriou
                                                    resource.name)
892 6556e514 Sofia Papagiannaki
                    d = model_to_dict(resource)
893 3e87075a Giorgos Korfiatis
                    try:
894 3e87075a Giorgos Korfiatis
                        uplimit = long(uplimit)
895 3e87075a Giorgos Korfiatis
                    except ValueError:
896 3e87075a Giorgos Korfiatis
                        m = "Limit should be an integer"
897 3e87075a Giorgos Korfiatis
                        raise forms.ValidationError(m)
898 3e87075a Giorgos Korfiatis
                    display = units.show(uplimit, resource.unit)
899 3e87075a Giorgos Korfiatis
                    d.update(dict(resource=prefix, uplimit=uplimit,
900 3e87075a Giorgos Korfiatis
                                  display_uplimit=display))
901 6556e514 Sofia Papagiannaki
                    append(d)
902 dd5f8f4d Kostas Papadimitriou
903 75380308 Kostas Papadimitriou
        ordered_keys = presentation.RESOURCES['resources_order']
904 8fb8d0cf Giorgos Korfiatis
905 37d59b27 Kostas Papadimitriou
        def resource_order(r):
906 37d59b27 Kostas Papadimitriou
            if r['str_repr'] in ordered_keys:
907 37d59b27 Kostas Papadimitriou
                return ordered_keys.index(r['str_repr'])
908 37d59b27 Kostas Papadimitriou
            else:
909 37d59b27 Kostas Papadimitriou
                return -1
910 37d59b27 Kostas Papadimitriou
911 37d59b27 Kostas Papadimitriou
        policies = sorted(policies, key=resource_order)
912 e1a80257 Sofia Papagiannaki
        return policies
913 dd5f8f4d Kostas Papadimitriou
914 eee9ec4d Giorgos Korfiatis
    def cleaned_resource_policies(self):
915 b2369828 Giorgos Korfiatis
        policies = {}
916 b2369828 Giorgos Korfiatis
        for d in self.resource_policies:
917 b2369828 Giorgos Korfiatis
            policies[d["name"]] = {
918 b2369828 Giorgos Korfiatis
                "project_capacity": None,
919 b2369828 Giorgos Korfiatis
                "member_capacity": d["uplimit"]
920 b2369828 Giorgos Korfiatis
            }
921 b2369828 Giorgos Korfiatis
922 b2369828 Giorgos Korfiatis
        return policies
923 eee9ec4d Giorgos Korfiatis
924 0eb1f53a Ilias Tsitsimpis
    def save(self, commit=True, **kwargs):
925 15ca2bea Giorgos Korfiatis
        data = dict(self.cleaned_data)
926 42732c26 Giorgos Korfiatis
        is_new = self.instance.id is None
927 c4028837 Giorgos Korfiatis
        data['project_id'] = self.instance.chain.id if not is_new else None
928 42732c26 Giorgos Korfiatis
        data['owner'] = self.user if is_new else self.instance.owner
929 b2369828 Giorgos Korfiatis
        data['resources'] = self.cleaned_resource_policies()
930 6da04174 Giorgos Korfiatis
        data['request_user'] = self.user
931 6da04174 Giorgos Korfiatis
        submit_application(**data)
932 6da04174 Giorgos Korfiatis
933 8327782d Sofia Papagiannaki
934 8327782d Sofia Papagiannaki
class ProjectSortForm(forms.Form):
935 8327782d Sofia Papagiannaki
    sorting = forms.ChoiceField(
936 8327782d Sofia Papagiannaki
        label='Sort by',
937 73fbaec4 Sofia Papagiannaki
        choices=(('name', 'Sort by Name'),
938 8327782d Sofia Papagiannaki
                 ('issue_date', 'Sort by Issue date'),
939 73fbaec4 Sofia Papagiannaki
                 ('start_date', 'Sort by Start Date'),
940 73fbaec4 Sofia Papagiannaki
                 ('end_date', 'Sort by End Date'),
941 8fb8d0cf Giorgos Korfiatis
                 # ('approved_members_num', 'Sort by Participants'),
942 d6a162d3 Sofia Papagiannaki
                 ('state', 'Sort by Status'),
943 8fb8d0cf Giorgos Korfiatis
                 ('member_join_policy__description',
944 8fb8d0cf Giorgos Korfiatis
                  'Sort by Member Join Policy'),
945 8fb8d0cf Giorgos Korfiatis
                 ('member_leave_policy__description',
946 8fb8d0cf Giorgos Korfiatis
                  'Sort by Member Leave Policy'),
947 7592e3e2 Sofia Papagiannaki
                 ('-name', 'Sort by Name'),
948 7592e3e2 Sofia Papagiannaki
                 ('-issue_date', 'Sort by Issue date'),
949 7592e3e2 Sofia Papagiannaki
                 ('-start_date', 'Sort by Start Date'),
950 7592e3e2 Sofia Papagiannaki
                 ('-end_date', 'Sort by End Date'),
951 8fb8d0cf Giorgos Korfiatis
                 # ('-approved_members_num', 'Sort by Participants'),
952 7592e3e2 Sofia Papagiannaki
                 ('-state', 'Sort by Status'),
953 8fb8d0cf Giorgos Korfiatis
                 ('-member_join_policy__description',
954 8fb8d0cf Giorgos Korfiatis
                  'Sort by Member Join Policy'),
955 8fb8d0cf Giorgos Korfiatis
                 ('-member_leave_policy__description',
956 8fb8d0cf Giorgos Korfiatis
                  'Sort by Member Leave Policy')
957 8fb8d0cf Giorgos Korfiatis
                 ),
958 8327782d Sofia Papagiannaki
        required=True
959 ccab6eb5 Sofia Papagiannaki
    )
960 ccab6eb5 Sofia Papagiannaki
961 8fb8d0cf Giorgos Korfiatis
962 ccab6eb5 Sofia Papagiannaki
class AddProjectMembersForm(forms.Form):
963 ccab6eb5 Sofia Papagiannaki
    q = forms.CharField(
964 8fb8d0cf Giorgos Korfiatis
        widget=forms.Textarea(
965 8fb8d0cf Giorgos Korfiatis
            attrs={
966 8fb8d0cf Giorgos Korfiatis
                'placeholder':
967 8fb8d0cf Giorgos Korfiatis
                astakos_messages.ADD_PROJECT_MEMBERS_Q_PLACEHOLDER}),
968 3f3dc4b7 Olga Brani
        label=_('Add members'),
969 b6e2252e Kostas Papadimitriou
        help_text=_(astakos_messages.ADD_PROJECT_MEMBERS_Q_HELP),
970 3f3dc4b7 Olga Brani
        required=True,)
971 ccab6eb5 Sofia Papagiannaki
972 e47fb17a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
973 ff67242a Giorgos Korfiatis
        chain_id = kwargs.pop('chain_id', None)
974 ff67242a Giorgos Korfiatis
        if chain_id:
975 ff67242a Giorgos Korfiatis
            self.project = Project.objects.get(id=chain_id)
976 e47fb17a Sofia Papagiannaki
        self.request_user = kwargs.pop('request_user', None)
977 e47fb17a Sofia Papagiannaki
        super(AddProjectMembersForm, self).__init__(*args, **kwargs)
978 43332a76 Kostas Papadimitriou
979 ccab6eb5 Sofia Papagiannaki
    def clean(self):
980 e47fb17a Sofia Papagiannaki
        try:
981 866e5768 Giorgos Korfiatis
            accept_membership_project_checks(self.project, self.request_user)
982 f12bcb3d Giorgos Korfiatis
        except ProjectError as e:
983 e47fb17a Sofia Papagiannaki
            raise forms.ValidationError(e)
984 e47fb17a Sofia Papagiannaki
985 ccab6eb5 Sofia Papagiannaki
        q = self.cleaned_data.get('q') or ''
986 ccab6eb5 Sofia Papagiannaki
        users = q.split(',')
987 ccab6eb5 Sofia Papagiannaki
        users = list(u.strip() for u in users if u)
988 97e93991 Kostas Papadimitriou
        db_entries = AstakosUser.objects.verified().filter(email__in=users)
989 ccab6eb5 Sofia Papagiannaki
        unknown = list(set(users) - set(u.email for u in db_entries))
990 ccab6eb5 Sofia Papagiannaki
        if unknown:
991 e47fb17a Sofia Papagiannaki
            raise forms.ValidationError(
992 e47fb17a Sofia Papagiannaki
                _(astakos_messages.UNKNOWN_USERS) % ','.join(unknown))
993 ccab6eb5 Sofia Papagiannaki
        self.valid_users = db_entries
994 ccab6eb5 Sofia Papagiannaki
        return self.cleaned_data
995 ccab6eb5 Sofia Papagiannaki
996 ccab6eb5 Sofia Papagiannaki
    def get_valid_users(self):
997 ccab6eb5 Sofia Papagiannaki
        """Should be called after form cleaning"""
998 ccab6eb5 Sofia Papagiannaki
        try:
999 ccab6eb5 Sofia Papagiannaki
            return self.valid_users
1000 ccab6eb5 Sofia Papagiannaki
        except:
1001 bfe23b13 Sofia Papagiannaki
            return ()
1002 bfe23b13 Sofia Papagiannaki
1003 8fb8d0cf Giorgos Korfiatis
1004 bfe23b13 Sofia Papagiannaki
class ProjectMembersSortForm(forms.Form):
1005 bfe23b13 Sofia Papagiannaki
    sorting = forms.ChoiceField(
1006 bfe23b13 Sofia Papagiannaki
        label='Sort by',
1007 bfe23b13 Sofia Papagiannaki
        choices=(('person__email', 'User Id'),
1008 bfe23b13 Sofia Papagiannaki
                 ('person__first_name', 'Name'),
1009 bfe23b13 Sofia Papagiannaki
                 ('acceptance_date', 'Acceptance date')
1010 8fb8d0cf Giorgos Korfiatis
                 ),
1011 bfe23b13 Sofia Papagiannaki
        required=True
1012 bfe23b13 Sofia Papagiannaki
    )
1013 bfe23b13 Sofia Papagiannaki
1014 f7400729 Kostas Papadimitriou
1015 6dadd24a Sofia Papagiannaki
class ProjectSearchForm(forms.Form):
1016 85d444db Sofia Papagiannaki
    q = forms.CharField(max_length=200, label='Search project', required=False)
1017 5550bcfb Kostas Papadimitriou
1018 f7400729 Kostas Papadimitriou
1019 f7400729 Kostas Papadimitriou
class ExtendedProfileForm(ProfileForm):
1020 f7400729 Kostas Papadimitriou
    """
1021 f7400729 Kostas Papadimitriou
    Profile form that combines `email change` and `password change` user
1022 f7400729 Kostas Papadimitriou
    actions by propagating submited data to internal EmailChangeForm
1023 f7400729 Kostas Papadimitriou
    and ExtendedPasswordChangeForm objects.
1024 f7400729 Kostas Papadimitriou
    """
1025 f7400729 Kostas Papadimitriou
1026 f7400729 Kostas Papadimitriou
    password_change_form = None
1027 f7400729 Kostas Papadimitriou
    email_change_form = None
1028 17ad5d37 Kostas Papadimitriou
1029 3fbf7863 Kostas Papadimitriou
    password_change = False
1030 17ad5d37 Kostas Papadimitriou
    email_change = False
1031 17ad5d37 Kostas Papadimitriou
1032 f7400729 Kostas Papadimitriou
    extra_forms_fields = {
1033 f7400729 Kostas Papadimitriou
        'email': ['new_email_address'],
1034 f7400729 Kostas Papadimitriou
        'password': ['old_password', 'new_password1', 'new_password2']
1035 f7400729 Kostas Papadimitriou
    }
1036 f7400729 Kostas Papadimitriou
1037 d0632ab1 Olga Brani
    fields = ('email')
1038 f7400729 Kostas Papadimitriou
    change_password = forms.BooleanField(initial=False, required=False)
1039 f7400729 Kostas Papadimitriou
    change_email = forms.BooleanField(initial=False, required=False)
1040 c55e39e7 Kostas Papadimitriou
1041 2da6f56b Kostas Papadimitriou
    email_changed = False
1042 2da6f56b Kostas Papadimitriou
    password_changed = False
1043 f7400729 Kostas Papadimitriou
1044 f7400729 Kostas Papadimitriou
    def __init__(self, *args, **kwargs):
1045 95cb469b Kostas Papadimitriou
        session_key = kwargs.get('session_key', None)
1046 c55e39e7 Kostas Papadimitriou
        self.fields_list = [
1047 8fb8d0cf Giorgos Korfiatis
            'email',
1048 8fb8d0cf Giorgos Korfiatis
            'new_email_address',
1049 8fb8d0cf Giorgos Korfiatis
            'first_name',
1050 8fb8d0cf Giorgos Korfiatis
            'last_name',
1051 8fb8d0cf Giorgos Korfiatis
            'old_password',
1052 8fb8d0cf Giorgos Korfiatis
            'new_password1',
1053 8fb8d0cf Giorgos Korfiatis
            'new_password2',
1054 8fb8d0cf Giorgos Korfiatis
            'change_email',
1055 8fb8d0cf Giorgos Korfiatis
            'change_password',
1056 c55e39e7 Kostas Papadimitriou
        ]
1057 c55e39e7 Kostas Papadimitriou
1058 f7400729 Kostas Papadimitriou
        super(ExtendedProfileForm, self).__init__(*args, **kwargs)
1059 95cb469b Kostas Papadimitriou
        self.session_key = session_key
1060 3fbf7863 Kostas Papadimitriou
        if self.instance.can_change_password():
1061 3fbf7863 Kostas Papadimitriou
            self.password_change = True
1062 3fbf7863 Kostas Papadimitriou
        else:
1063 2b7a87d7 Olga Brani
            self.fields_list.remove('old_password')
1064 2b7a87d7 Olga Brani
            self.fields_list.remove('new_password1')
1065 2b7a87d7 Olga Brani
            self.fields_list.remove('new_password2')
1066 2b7a87d7 Olga Brani
            self.fields_list.remove('change_password')
1067 3fbf7863 Kostas Papadimitriou
            del self.fields['change_password']
1068 3fbf7863 Kostas Papadimitriou
1069 8998f09a Sofia Papagiannaki
        if settings.EMAILCHANGE_ENABLED and self.instance.can_change_email():
1070 17ad5d37 Kostas Papadimitriou
            self.email_change = True
1071 17ad5d37 Kostas Papadimitriou
        else:
1072 d0632ab1 Olga Brani
            self.fields_list.remove('new_email_address')
1073 2b7a87d7 Olga Brani
            self.fields_list.remove('change_email')
1074 17ad5d37 Kostas Papadimitriou
            del self.fields['change_email']
1075 17ad5d37 Kostas Papadimitriou
1076 f7400729 Kostas Papadimitriou
        self._init_extra_forms()
1077 f7400729 Kostas Papadimitriou
        self.save_extra_forms = []
1078 f7400729 Kostas Papadimitriou
        self.success_messages = []
1079 d0632ab1 Olga Brani
        self.fields.keyOrder = self.fields_list
1080 c55e39e7 Kostas Papadimitriou
1081 f7400729 Kostas Papadimitriou
    def _init_extra_form_fields(self):
1082 17ad5d37 Kostas Papadimitriou
        if self.email_change:
1083 17ad5d37 Kostas Papadimitriou
            self.fields.update(self.email_change_form.fields)
1084 17ad5d37 Kostas Papadimitriou
            self.fields['new_email_address'].required = False
1085 8fb8d0cf Giorgos Korfiatis
            self.fields['email'].help_text = _(
1086 8fb8d0cf Giorgos Korfiatis
                'Change the email associated with '
1087 8fb8d0cf Giorgos Korfiatis
                'your account. This email will '
1088 8fb8d0cf Giorgos Korfiatis
                'remain active until you verify '
1089 8fb8d0cf Giorgos Korfiatis
                'your new one.')
1090 3fbf7863 Kostas Papadimitriou
1091 3fbf7863 Kostas Papadimitriou
        if self.password_change:
1092 3fbf7863 Kostas Papadimitriou
            self.fields.update(self.password_change_form.fields)
1093 3fbf7863 Kostas Papadimitriou
            self.fields['old_password'].required = False
1094 003d8fcf Olga Brani
            self.fields['old_password'].label = _('Password')
1095 c9a6e558 Constantinos Venetsanopoulos
            self.fields['old_password'].help_text = _('Change your password.')
1096 861458fd Kostas Papadimitriou
            self.fields['old_password'].initial = 'password'
1097 3fbf7863 Kostas Papadimitriou
            self.fields['new_password1'].required = False
1098 3fbf7863 Kostas Papadimitriou
            self.fields['new_password2'].required = False
1099 f7400729 Kostas Papadimitriou
1100 f7400729 Kostas Papadimitriou
    def _update_extra_form_errors(self):
1101 f7400729 Kostas Papadimitriou
        if self.cleaned_data.get('change_password'):
1102 f7400729 Kostas Papadimitriou
            self.errors.update(self.password_change_form.errors)
1103 f7400729 Kostas Papadimitriou
        if self.cleaned_data.get('change_email'):
1104 f7400729 Kostas Papadimitriou
            self.errors.update(self.email_change_form.errors)
1105 f7400729 Kostas Papadimitriou
1106 f7400729 Kostas Papadimitriou
    def _init_extra_forms(self):
1107 f7400729 Kostas Papadimitriou
        self.email_change_form = EmailChangeForm(self.data)
1108 8fb8d0cf Giorgos Korfiatis
        self.password_change_form = ExtendedPasswordChangeForm(
1109 8fb8d0cf Giorgos Korfiatis
            user=self.instance,
1110 8fb8d0cf Giorgos Korfiatis
            data=self.data, session_key=self.session_key)
1111 f7400729 Kostas Papadimitriou
        self._init_extra_form_fields()
1112 f7400729 Kostas Papadimitriou
1113 f7400729 Kostas Papadimitriou
    def is_valid(self):
1114 f7400729 Kostas Papadimitriou
        password, email = True, True
1115 f7400729 Kostas Papadimitriou
        profile = super(ExtendedProfileForm, self).is_valid()
1116 3fbf7863 Kostas Papadimitriou
        if profile and self.cleaned_data.get('change_password', None):
1117 36f1eabb Kostas Papadimitriou
            self.password_change_form.fields['new_password1'].required = True
1118 36f1eabb Kostas Papadimitriou
            self.password_change_form.fields['new_password2'].required = True
1119 f7400729 Kostas Papadimitriou
            password = self.password_change_form.is_valid()
1120 3fbf7863 Kostas Papadimitriou
            self.save_extra_forms.append('password')
1121 f7400729 Kostas Papadimitriou
        if profile and self.cleaned_data.get('change_email'):
1122 7b4ca7fe Olga Brani
            self.fields['new_email_address'].required = True
1123 f7400729 Kostas Papadimitriou
            email = self.email_change_form.is_valid()
1124 3fbf7863 Kostas Papadimitriou
            self.save_extra_forms.append('email')
1125 f7400729 Kostas Papadimitriou
1126 f7400729 Kostas Papadimitriou
        if not password or not email:
1127 f7400729 Kostas Papadimitriou
            self._update_extra_form_errors()
1128 f7400729 Kostas Papadimitriou
1129 f7400729 Kostas Papadimitriou
        return all([profile, password, email])
1130 f7400729 Kostas Papadimitriou
1131 3fbf7863 Kostas Papadimitriou
    def save(self, request, *args, **kwargs):
1132 f7400729 Kostas Papadimitriou
        if 'email' in self.save_extra_forms:
1133 3fbf7863 Kostas Papadimitriou
            self.email_change_form.save(request, *args, **kwargs)
1134 2da6f56b Kostas Papadimitriou
            self.email_changed = True
1135 f7400729 Kostas Papadimitriou
        if 'password' in self.save_extra_forms:
1136 f7400729 Kostas Papadimitriou
            self.password_change_form.save(*args, **kwargs)
1137 2da6f56b Kostas Papadimitriou
            self.password_changed = True
1138 f7400729 Kostas Papadimitriou
        return super(ExtendedProfileForm, self).save(*args, **kwargs)