Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 116e778a

History | View | Annotate | Download (31.6 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 64cd4730 Antony Chazapis
36 64cd4730 Antony Chazapis
from django import forms
37 64cd4730 Antony Chazapis
from django.utils.translation import ugettext as _
38 e1a80257 Sofia Papagiannaki
from django.contrib.auth.forms import (
39 e1a80257 Sofia Papagiannaki
    UserCreationForm, AuthenticationForm,
40 e1a80257 Sofia Papagiannaki
    PasswordResetForm, PasswordChangeForm,
41 73fbaec4 Sofia Papagiannaki
    SetPasswordForm)
42 e2125441 Sofia Papagiannaki
from django.core.mail import send_mail
43 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
44 e2125441 Sofia Papagiannaki
from django.template import Context, loader
45 e2125441 Sofia Papagiannaki
from django.utils.http import int_to_base36
46 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
47 18ffbee1 Sofia Papagiannaki
from django.utils.safestring import mark_safe
48 49790d9d Sofia Papagiannaki
from django.utils.encoding import smart_str
49 1cbce16f Sofia Papagiannaki
from django.conf import settings
50 678b2236 Sofia Papagiannaki
from django.forms.models import fields_for_model
51 d2633501 Kostas Papadimitriou
from django.db import transaction
52 caf70869 Sofia Papagiannaki
from django.utils.encoding import smart_unicode
53 caf70869 Sofia Papagiannaki
from django.core import validators
54 e1a80257 Sofia Papagiannaki
from django.contrib.auth.models import AnonymousUser
55 5ed6816e Sofia Papagiannaki
56 678b2236 Sofia Papagiannaki
from astakos.im.models import (
57 73fbaec4 Sofia Papagiannaki
    AstakosUser, EmailChange, Invitation,
58 e1a80257 Sofia Papagiannaki
    Resource, PendingThirdPartyUser, get_latest_terms, RESOURCE_SEPARATOR,
59 272cf735 Sofia Papagiannaki
    ProjectApplication)
60 c0b26605 Sofia Papagiannaki
from astakos.im.settings import (
61 c0b26605 Sofia Papagiannaki
    INVITATIONS_PER_LEVEL, BASEURL, SITENAME, RECAPTCHA_PRIVATE_KEY,
62 c0b26605 Sofia Papagiannaki
    RECAPTCHA_ENABLED, DEFAULT_CONTACT_EMAIL, LOGGING_LEVEL,
63 2e90e3ec Kostas Papadimitriou
    PASSWORD_RESET_EMAIL_SUBJECT, NEWPASSWD_INVALIDATE_TOKEN,
64 272cf735 Sofia Papagiannaki
    MODERATION_ENABLED, PROJECT_MEMBER_JOIN_POLICIES,
65 272cf735 Sofia Papagiannaki
    PROJECT_MEMBER_LEAVE_POLICIES)
66 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
67 73fbaec4 Sofia Papagiannaki
from astakos.im.functions import send_change_email, submit_application
68 270dd48d Sofia Papagiannaki
69 6556e514 Sofia Papagiannaki
from astakos.im.util import reserved_email, get_query, model_to_dict
70 c4b1a172 Kostas Papadimitriou
from astakos.im import auth_providers
71 64cd4730 Antony Chazapis
72 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
73 64cd4730 Antony Chazapis
74 3bf924ec Sofia Papagiannaki
import logging
75 49790d9d Sofia Papagiannaki
import hashlib
76 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
77 caf70869 Sofia Papagiannaki
import re
78 64cd4730 Antony Chazapis
79 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
80 e015e9e6 Sofia Papagiannaki
81 caf70869 Sofia Papagiannaki
DOMAIN_VALUE_REGEX = re.compile(
82 892410d3 Sofia Papagiannaki
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
83 73fbaec4 Sofia Papagiannaki
    re.IGNORECASE)
84 d2633501 Kostas Papadimitriou
85 caf70869 Sofia Papagiannaki
class StoreUserMixin(object):
86 e5966bd9 Kostas Papadimitriou
87 d2633501 Kostas Papadimitriou
    @transaction.commit_on_success
88 d2633501 Kostas Papadimitriou
    def store_user(self, user, request):
89 d2633501 Kostas Papadimitriou
        user.save()
90 d2633501 Kostas Papadimitriou
        self.post_store_user(user, request)
91 d2633501 Kostas Papadimitriou
        return user
92 d2633501 Kostas Papadimitriou
93 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
94 d2633501 Kostas Papadimitriou
        """
95 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
96 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
97 d2633501 Kostas Papadimitriou
        """
98 d2633501 Kostas Papadimitriou
        pass
99 d2633501 Kostas Papadimitriou
100 d2633501 Kostas Papadimitriou
101 d2633501 Kostas Papadimitriou
class LocalUserCreationForm(UserCreationForm, StoreUserMixin):
102 890b0eaf Sofia Papagiannaki
    """
103 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
104 18ffbee1 Sofia Papagiannaki

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

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

473 dd5f8f4d Kostas Papadimitriou
    save method: to pass a custom from_email in send_mail.
474 dd5f8f4d Kostas Papadimitriou
    clean_email: to handle local auth provider checks
475 e2125441 Sofia Papagiannaki
    """
476 23c271b3 Sofia Papagiannaki
    def clean_email(self):
477 23c271b3 Sofia Papagiannaki
        email = super(ExtendedPasswordResetForm, self).clean_email()
478 23c271b3 Sofia Papagiannaki
        try:
479 dd5f8f4d Kostas Papadimitriou
            user = AstakosUser.objects.get_by_identifier(email)
480 dd5f8f4d Kostas Papadimitriou
481 dd5f8f4d Kostas Papadimitriou
            if not user.is_active:
482 dd5f8f4d Kostas Papadimitriou
                raise forms.ValidationError(_(astakos_messages.ACCOUNT_INACTIVE))
483 dd5f8f4d Kostas Papadimitriou
484 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
485 ae497612 Olga Brani
                raise forms.ValidationError(_(astakos_messages.UNUSABLE_PASSWORD))
486 d2633501 Kostas Papadimitriou
487 d2633501 Kostas Papadimitriou
            if not user.can_change_password():
488 dd5f8f4d Kostas Papadimitriou
                raise forms.ValidationError(_(astakos_messages.AUTH_PROVIDER_CANNOT_CHANGE_PASSWORD))
489 23c271b3 Sofia Papagiannaki
        except AstakosUser.DoesNotExist, e:
490 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
491 23c271b3 Sofia Papagiannaki
        return email
492 ab8bfb29 Kostas Papadimitriou
493 5ce3ce4f Sofia Papagiannaki
    def save(
494 5ce3ce4f Sofia Papagiannaki
        self, domain_override=None, email_template_name='registration/password_reset_email.html',
495 5ce3ce4f Sofia Papagiannaki
            use_https=False, token_generator=default_token_generator, request=None):
496 e2125441 Sofia Papagiannaki
        """
497 e2125441 Sofia Papagiannaki
        Generates a one-use only link for resetting password and sends to the user.
498 e2125441 Sofia Papagiannaki
        """
499 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
500 d2633501 Kostas Papadimitriou
            url = user.astakosuser.get_password_reset_url(token_generator)
501 a53b19da Sofia Papagiannaki
            url = urljoin(BASEURL, url)
502 e2125441 Sofia Papagiannaki
            t = loader.get_template(email_template_name)
503 e2125441 Sofia Papagiannaki
            c = {
504 e2125441 Sofia Papagiannaki
                'email': user.email,
505 8f378756 Sofia Papagiannaki
                'url': url,
506 374611bc Sofia Papagiannaki
                'site_name': SITENAME,
507 e2125441 Sofia Papagiannaki
                'user': user,
508 a53b19da Sofia Papagiannaki
                'baseurl': BASEURL,
509 09122dd8 Sofia Papagiannaki
                'support': DEFAULT_CONTACT_EMAIL
510 e2125441 Sofia Papagiannaki
            }
511 1cbce16f Sofia Papagiannaki
            from_email = settings.SERVER_EMAIL
512 1fcf4a99 Kostas Papadimitriou
            send_mail(_(PASSWORD_RESET_EMAIL_SUBJECT),
513 5ce3ce4f Sofia Papagiannaki
                      t.render(Context(c)), from_email, [user.email])
514 5ce3ce4f Sofia Papagiannaki
515 270dd48d Sofia Papagiannaki
516 49790d9d Sofia Papagiannaki
class EmailChangeForm(forms.ModelForm):
517 34a76cdb Kostas Papadimitriou
518 49790d9d Sofia Papagiannaki
    class Meta:
519 49790d9d Sofia Papagiannaki
        model = EmailChange
520 49790d9d Sofia Papagiannaki
        fields = ('new_email_address',)
521 ab8bfb29 Kostas Papadimitriou
522 49790d9d Sofia Papagiannaki
    def clean_new_email_address(self):
523 49790d9d Sofia Papagiannaki
        addr = self.cleaned_data['new_email_address']
524 49790d9d Sofia Papagiannaki
        if AstakosUser.objects.filter(email__iexact=addr):
525 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
526 49790d9d Sofia Papagiannaki
        return addr
527 ab8bfb29 Kostas Papadimitriou
528 49790d9d Sofia Papagiannaki
    def save(self, email_template_name, request, commit=True):
529 49790d9d Sofia Papagiannaki
        ec = super(EmailChangeForm, self).save(commit=False)
530 49790d9d Sofia Papagiannaki
        ec.user = request.user
531 5ce3ce4f Sofia Papagiannaki
        activation_key = hashlib.sha1(
532 5ce3ce4f Sofia Papagiannaki
            str(random()) + smart_str(ec.new_email_address))
533 5ce3ce4f Sofia Papagiannaki
        ec.activation_key = activation_key.hexdigest()
534 49790d9d Sofia Papagiannaki
        if commit:
535 49790d9d Sofia Papagiannaki
            ec.save()
536 49790d9d Sofia Papagiannaki
        send_change_email(ec, request, email_template_name=email_template_name)
537 49790d9d Sofia Papagiannaki
538 5ce3ce4f Sofia Papagiannaki
539 270dd48d Sofia Papagiannaki
class SignApprovalTermsForm(forms.ModelForm):
540 34a76cdb Kostas Papadimitriou
541 270dd48d Sofia Papagiannaki
    class Meta:
542 270dd48d Sofia Papagiannaki
        model = AstakosUser
543 270dd48d Sofia Papagiannaki
        fields = ("has_signed_terms",)
544 18ffbee1 Sofia Papagiannaki
545 270dd48d Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
546 270dd48d Sofia Papagiannaki
        super(SignApprovalTermsForm, self).__init__(*args, **kwargs)
547 18ffbee1 Sofia Papagiannaki
548 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
549 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
550 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
551 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
552 270dd48d Sofia Papagiannaki
        return has_signed_terms
553 8f5a3a06 Sofia Papagiannaki
554 5ce3ce4f Sofia Papagiannaki
555 8f5a3a06 Sofia Papagiannaki
class InvitationForm(forms.ModelForm):
556 34a76cdb Kostas Papadimitriou
557 8f5a3a06 Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
558 ab8bfb29 Kostas Papadimitriou
559 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
560 18ffbee1 Sofia Papagiannaki
        super(InvitationForm, self).__init__(*args, **kwargs)
561 ab8bfb29 Kostas Papadimitriou
562 8f5a3a06 Sofia Papagiannaki
    class Meta:
563 8f5a3a06 Sofia Papagiannaki
        model = Invitation
564 8f5a3a06 Sofia Papagiannaki
        fields = ('username', 'realname')
565 ab8bfb29 Kostas Papadimitriou
566 8f5a3a06 Sofia Papagiannaki
    def clean_username(self):
567 8f5a3a06 Sofia Papagiannaki
        username = self.cleaned_data['username']
568 8f5a3a06 Sofia Papagiannaki
        try:
569 5ce3ce4f Sofia Papagiannaki
            Invitation.objects.get(username=username)
570 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.INVITATION_EMAIL_EXISTS))
571 8f5a3a06 Sofia Papagiannaki
        except Invitation.DoesNotExist:
572 8f5a3a06 Sofia Papagiannaki
            pass
573 18ffbee1 Sofia Papagiannaki
        return username
574 1039bab1 Sofia Papagiannaki
575 5ce3ce4f Sofia Papagiannaki
576 1039bab1 Sofia Papagiannaki
class ExtendedPasswordChangeForm(PasswordChangeForm):
577 1039bab1 Sofia Papagiannaki
    """
578 1039bab1 Sofia Papagiannaki
    Extends PasswordChangeForm by enabling user
579 1039bab1 Sofia Papagiannaki
    to optionally renew also the token.
580 1039bab1 Sofia Papagiannaki
    """
581 ee210d1d Sofia Papagiannaki
    if not NEWPASSWD_INVALIDATE_TOKEN:
582 48e9f076 Sofia Papagiannaki
        renew = forms.BooleanField(label='Renew token', required=False,
583 48e9f076 Sofia Papagiannaki
                                   initial=True,
584 48e9f076 Sofia Papagiannaki
                                   help_text='Unsetting this may result in security risk.')
585 ab8bfb29 Kostas Papadimitriou
586 1039bab1 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
587 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
588 1039bab1 Sofia Papagiannaki
        super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
589 ab8bfb29 Kostas Papadimitriou
590 1039bab1 Sofia Papagiannaki
    def save(self, commit=True):
591 bf0c6de5 Sofia Papagiannaki
        try:
592 bf0c6de5 Sofia Papagiannaki
            if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
593 bf0c6de5 Sofia Papagiannaki
                self.user.renew_token()
594 bf0c6de5 Sofia Papagiannaki
            self.user.flush_sessions(current_key=self.session_key)
595 bf0c6de5 Sofia Papagiannaki
        except AttributeError:
596 bf0c6de5 Sofia Papagiannaki
            # if user model does has not such methods
597 bf0c6de5 Sofia Papagiannaki
            pass
598 53161dd8 Sofia Papagiannaki
        return super(ExtendedPasswordChangeForm, self).save(commit=commit)
599 48e9f076 Sofia Papagiannaki
600 48e9f076 Sofia Papagiannaki
class ExtendedSetPasswordForm(SetPasswordForm):
601 48e9f076 Sofia Papagiannaki
    """
602 48e9f076 Sofia Papagiannaki
    Extends SetPasswordForm by enabling user
603 48e9f076 Sofia Papagiannaki
    to optionally renew also the token.
604 48e9f076 Sofia Papagiannaki
    """
605 ee210d1d Sofia Papagiannaki
    if not NEWPASSWD_INVALIDATE_TOKEN:
606 bf0c6de5 Sofia Papagiannaki
        renew = forms.BooleanField(
607 bf0c6de5 Sofia Papagiannaki
            label='Renew token',
608 bf0c6de5 Sofia Papagiannaki
            required=False,
609 bf0c6de5 Sofia Papagiannaki
            initial=True,
610 47b77c8b Sofia Papagiannaki
            help_text='Unsetting this may result in security risk.')
611 2e90e3ec Kostas Papadimitriou
612 48e9f076 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
613 48e9f076 Sofia Papagiannaki
        super(ExtendedSetPasswordForm, self).__init__(user, *args, **kwargs)
614 d2633501 Kostas Papadimitriou
615 d2633501 Kostas Papadimitriou
    @transaction.commit_on_success()
616 48e9f076 Sofia Papagiannaki
    def save(self, commit=True):
617 bf0c6de5 Sofia Papagiannaki
        try:
618 bf0c6de5 Sofia Papagiannaki
            self.user = AstakosUser.objects.get(id=self.user.id)
619 bf0c6de5 Sofia Papagiannaki
            if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
620 53161dd8 Sofia Papagiannaki
                self.user.renew_token()
621 d2633501 Kostas Papadimitriou
            #self.user.flush_sessions()
622 d2633501 Kostas Papadimitriou
            if not self.user.has_auth_provider('local'):
623 d2633501 Kostas Papadimitriou
                self.user.add_auth_provider('local', auth_backend='astakos')
624 d2633501 Kostas Papadimitriou
625 bf0c6de5 Sofia Papagiannaki
        except BaseException, e:
626 bf0c6de5 Sofia Papagiannaki
            logger.exception(e)
627 53161dd8 Sofia Papagiannaki
        return super(ExtendedSetPasswordForm, self).save(commit=commit)
628 e1a80257 Sofia Papagiannaki
629 e1a80257 Sofia Papagiannaki
630 67980f56 Georgios D. Tsoukalas
631 67980f56 Georgios D. Tsoukalas
632 67980f56 Georgios D. Tsoukalas
app_name_label       =  "Project name"
633 67980f56 Georgios D. Tsoukalas
app_name_placeholder = _("myproject.mylab.ntua.gr")
634 67980f56 Georgios D. Tsoukalas
app_name_validator   =  validators.RegexValidator(
635 67980f56 Georgios D. Tsoukalas
                            DOMAIN_VALUE_REGEX,
636 67980f56 Georgios D. Tsoukalas
                            _(astakos_messages.DOMAIN_VALUE_ERR),
637 67980f56 Georgios D. Tsoukalas
                            'invalid')
638 67980f56 Georgios D. Tsoukalas
app_name_help        =  _("""
639 67980f56 Georgios D. Tsoukalas
        The Project's name should be in a domain format.
640 67980f56 Georgios D. Tsoukalas
        The domain shouldn't neccessarily exist in the real
641 67980f56 Georgios D. Tsoukalas
        world but is helpful to imply a structure.
642 67980f56 Georgios D. Tsoukalas
        e.g.: myproject.mylab.ntua.gr or
643 67980f56 Georgios D. Tsoukalas
        myservice.myteam.myorganization""")
644 67980f56 Georgios D. Tsoukalas
app_name_widget      =  forms.TextInput(
645 67980f56 Georgios D. Tsoukalas
                            attrs={'placeholder': app_name_placeholder})
646 67980f56 Georgios D. Tsoukalas
647 67980f56 Georgios D. Tsoukalas
648 67980f56 Georgios D. Tsoukalas
app_home_label       =  "Homepage URL"
649 67980f56 Georgios D. Tsoukalas
app_home_placeholder =  'http://myteam.myinstitution.org/myproject/'
650 67980f56 Georgios D. Tsoukalas
app_home_help        =  _("""
651 67980f56 Georgios D. Tsoukalas
        URL pointing at your project's site.
652 67980f56 Georgios D. Tsoukalas
        e.g.: http://myteam.myinstitution.org/myproject.
653 67980f56 Georgios D. Tsoukalas
        Leave blank if there is no website.""")
654 67980f56 Georgios D. Tsoukalas
app_home_widget      =  forms.TextInput(
655 67980f56 Georgios D. Tsoukalas
                            attrs={'placeholder': app_home_placeholder})
656 67980f56 Georgios D. Tsoukalas
657 67980f56 Georgios D. Tsoukalas
app_desc_label       =  _("Description")
658 67980f56 Georgios D. Tsoukalas
app_desc_help        =  _("""
659 67980f56 Georgios D. Tsoukalas
        Please provide a short but descriptive abstract of your Project,
660 67980f56 Georgios D. Tsoukalas
        so that anyone searching can quickly understand
661 67980f56 Georgios D. Tsoukalas
        what this Project is about.""")
662 67980f56 Georgios D. Tsoukalas
663 67980f56 Georgios D. Tsoukalas
app_comment_label    =  _("Comments for review (private)")
664 67980f56 Georgios D. Tsoukalas
app_comment_help     =  _("""
665 67980f56 Georgios D. Tsoukalas
        Write down any comments you may have for the reviewer
666 67980f56 Georgios D. Tsoukalas
        of this application (e.g. background and rationale to
667 67980f56 Georgios D. Tsoukalas
        support your request).
668 67980f56 Georgios D. Tsoukalas
        The comments are strictly for the review process
669 67980f56 Georgios D. Tsoukalas
        and will not be published.""")
670 67980f56 Georgios D. Tsoukalas
671 67980f56 Georgios D. Tsoukalas
app_start_date_label =  _("Start date")
672 67980f56 Georgios D. Tsoukalas
app_start_date_help  =  _("""
673 67980f56 Georgios D. Tsoukalas
        Provide a date when your need your project to be created,
674 67980f56 Georgios D. Tsoukalas
        and members to be able to join and get resources.
675 67980f56 Georgios D. Tsoukalas
        This date is only a hint to help prioritize reviews.""")
676 67980f56 Georgios D. Tsoukalas
677 67980f56 Georgios D. Tsoukalas
app_end_date_label   =  _("Termination date")
678 67980f56 Georgios D. Tsoukalas
app_end_date_help    =  _("""
679 67980f56 Georgios D. Tsoukalas
        At this date, the project will be automatically terminated
680 67980f56 Georgios D. Tsoukalas
        and its resource grants revoked from all members.
681 67980f56 Georgios D. Tsoukalas
        Unless you know otherwise,
682 67980f56 Georgios D. Tsoukalas
        it is best to start with a conservative estimation.
683 67980f56 Georgios D. Tsoukalas
        You can always re-apply for an extension, if you need.""")
684 67980f56 Georgios D. Tsoukalas
685 67980f56 Georgios D. Tsoukalas
join_policy_label    =  _("Joining policy")
686 67980f56 Georgios D. Tsoukalas
leave_policy_label   =  _("Leaving policy")
687 67980f56 Georgios D. Tsoukalas
688 67980f56 Georgios D. Tsoukalas
max_members_label    =  _("Maximum member count")
689 67980f56 Georgios D. Tsoukalas
max_members_help     =  _("""
690 67980f56 Georgios D. Tsoukalas
        Specify the maximum number of members this project may have,
691 67980f56 Georgios D. Tsoukalas
        including the owner. Beyond this number, no new members
692 67980f56 Georgios D. Tsoukalas
        may join the project and be granted the project resources.
693 67980f56 Georgios D. Tsoukalas
        Unless you certainly for otherwise,
694 67980f56 Georgios D. Tsoukalas
        it is best to start with a conservative limit.
695 67980f56 Georgios D. Tsoukalas
        You can always request a raise when you need it.""")
696 67980f56 Georgios D. Tsoukalas
697 67980f56 Georgios D. Tsoukalas
join_policies = PROJECT_MEMBER_JOIN_POLICIES.iteritems()
698 67980f56 Georgios D. Tsoukalas
leave_policies = PROJECT_MEMBER_LEAVE_POLICIES.iteritems()
699 67980f56 Georgios D. Tsoukalas
700 e1a80257 Sofia Papagiannaki
class ProjectApplicationForm(forms.ModelForm):
701 67980f56 Georgios D. Tsoukalas
702 e1a80257 Sofia Papagiannaki
    name = forms.CharField(
703 67980f56 Georgios D. Tsoukalas
        label     = app_name_label,
704 67980f56 Georgios D. Tsoukalas
        help_text = app_name_help,
705 67980f56 Georgios D. Tsoukalas
        widget    = app_name_widget,
706 67980f56 Georgios D. Tsoukalas
        validators = [app_name_validator])
707 67980f56 Georgios D. Tsoukalas
708 52784759 Olga Brani
    homepage = forms.URLField(
709 67980f56 Georgios D. Tsoukalas
        label     = app_home_label,
710 67980f56 Georgios D. Tsoukalas
        help_text = app_home_help,   
711 67980f56 Georgios D. Tsoukalas
        widget    = app_home_widget,
712 67980f56 Georgios D. Tsoukalas
        required  = False)
713 67980f56 Georgios D. Tsoukalas
714 67980f56 Georgios D. Tsoukalas
    description = forms.CharField(
715 67980f56 Georgios D. Tsoukalas
        label     = app_desc_label,
716 67980f56 Georgios D. Tsoukalas
        help_text = app_desc_help,
717 67980f56 Georgios D. Tsoukalas
        widget    = forms.Textarea,
718 67980f56 Georgios D. Tsoukalas
        required  = False)
719 67980f56 Georgios D. Tsoukalas
720 67980f56 Georgios D. Tsoukalas
    comments = forms.CharField(
721 67980f56 Georgios D. Tsoukalas
        label     = app_comment_label,
722 67980f56 Georgios D. Tsoukalas
        help_text = app_comment_help,
723 67980f56 Georgios D. Tsoukalas
        widget    = forms.Textarea,
724 67980f56 Georgios D. Tsoukalas
        required  = False)
725 67980f56 Georgios D. Tsoukalas
726 67980f56 Georgios D. Tsoukalas
    start_date = forms.DateTimeField(
727 67980f56 Georgios D. Tsoukalas
        label     = app_start_date_label,
728 67980f56 Georgios D. Tsoukalas
        help_text = app_start_date_help,
729 67980f56 Georgios D. Tsoukalas
        required  = False)
730 67980f56 Georgios D. Tsoukalas
731 67980f56 Georgios D. Tsoukalas
    end_date = forms.DateTimeField(
732 67980f56 Georgios D. Tsoukalas
        label     = app_end_date_label,
733 67980f56 Georgios D. Tsoukalas
        help_text = app_end_date_help)
734 67980f56 Georgios D. Tsoukalas
735 67980f56 Georgios D. Tsoukalas
    member_join_policy  = forms.ChoiceField(
736 67980f56 Georgios D. Tsoukalas
        label     = join_policy_label,
737 67980f56 Georgios D. Tsoukalas
        choices   = join_policies)
738 dd5f8f4d Kostas Papadimitriou
739 272cf735 Sofia Papagiannaki
    member_leave_policy = forms.ChoiceField(
740 67980f56 Georgios D. Tsoukalas
        label     = leave_policy_label,
741 67980f56 Georgios D. Tsoukalas
        choices   = leave_policies)
742 67980f56 Georgios D. Tsoukalas
743 67980f56 Georgios D. Tsoukalas
    limit_on_members_number = forms.IntegerField(
744 67980f56 Georgios D. Tsoukalas
        label     = max_members_label,
745 67980f56 Georgios D. Tsoukalas
        help_text = max_members_help,
746 67980f56 Georgios D. Tsoukalas
        required  = False)
747 dd5f8f4d Kostas Papadimitriou
748 e1a80257 Sofia Papagiannaki
    class Meta:
749 73fbaec4 Sofia Papagiannaki
        model = ProjectApplication
750 67980f56 Georgios D. Tsoukalas
        #include = ( 'name', 'homepage', 'description',
751 67980f56 Georgios D. Tsoukalas
        #            'start_date', 'end_date', 'comments')
752 73fbaec4 Sofia Papagiannaki
753 c82bd52b Kostas Papadimitriou
        fields = ( 'name', 'homepage', 'description',
754 c82bd52b Kostas Papadimitriou
                    'start_date', 'end_date', 'comments',
755 c82bd52b Kostas Papadimitriou
                    'member_join_policy', 'member_leave_policy',
756 c82bd52b Kostas Papadimitriou
                    'limit_on_members_number')
757 c82bd52b Kostas Papadimitriou
758 40b52116 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
759 40b52116 Sofia Papagiannaki
        self.precursor_application = kwargs.get('instance')
760 40b52116 Sofia Papagiannaki
        super(ProjectApplicationForm, self).__init__(*args, **kwargs)
761 dd5f8f4d Kostas Papadimitriou
762 e1a80257 Sofia Papagiannaki
    def clean(self):
763 185b2190 Sofia Papagiannaki
        userid = self.data.get('user', None)
764 e1a80257 Sofia Papagiannaki
        self.user = None
765 e1a80257 Sofia Papagiannaki
        if userid:
766 e1a80257 Sofia Papagiannaki
            try:
767 e1a80257 Sofia Papagiannaki
                self.user = AstakosUser.objects.get(id=userid)
768 e1a80257 Sofia Papagiannaki
            except AstakosUser.DoesNotExist:
769 e1a80257 Sofia Papagiannaki
                pass
770 e1a80257 Sofia Papagiannaki
        if not self.user:
771 e1a80257 Sofia Papagiannaki
            raise forms.ValidationError(_(astakos_messages.NO_APPLICANT))
772 e1a80257 Sofia Papagiannaki
        super(ProjectApplicationForm, self).clean()
773 e1a80257 Sofia Papagiannaki
        return self.cleaned_data
774 dd5f8f4d Kostas Papadimitriou
775 f3342849 Sofia Papagiannaki
    @property
776 f3342849 Sofia Papagiannaki
    def resource_policies(self):
777 e1a80257 Sofia Papagiannaki
        policies = []
778 e1a80257 Sofia Papagiannaki
        append = policies.append
779 f3342849 Sofia Papagiannaki
        for name, value in self.data.iteritems():
780 f3342849 Sofia Papagiannaki
            if not value:
781 f3342849 Sofia Papagiannaki
                continue
782 56eb807c Sofia Papagiannaki
            uplimit = value
783 56eb807c Sofia Papagiannaki
            if name.endswith('_uplimit'):
784 56eb807c Sofia Papagiannaki
                subs = name.split('_uplimit')
785 e1a80257 Sofia Papagiannaki
                prefix, suffix = subs
786 e1a80257 Sofia Papagiannaki
                s, sep, r = prefix.partition(RESOURCE_SEPARATOR)
787 e1a80257 Sofia Papagiannaki
                resource = Resource.objects.get(service__name=s, name=r)
788 e1a80257 Sofia Papagiannaki
789 e1a80257 Sofia Papagiannaki
                # keep only resource limits for selected resource groups
790 30dd9e0e Olga Brani
                if self.data.get(
791 30dd9e0e Olga Brani
                    'is_selected_%s' % resource.group, "0"
792 30dd9e0e Olga Brani
                 ) == "1":
793 6556e514 Sofia Papagiannaki
                    d = model_to_dict(resource)
794 30dd9e0e Olga Brani
                    if uplimit:
795 6556e514 Sofia Papagiannaki
                        d.update(dict(service=s, resource=r, uplimit=uplimit))
796 30dd9e0e Olga Brani
                    else:
797 6556e514 Sofia Papagiannaki
                        d.update(dict(service=s, resource=r, uplimit=None))
798 6556e514 Sofia Papagiannaki
                    append(d)
799 dd5f8f4d Kostas Papadimitriou
800 e1a80257 Sofia Papagiannaki
        return policies
801 dd5f8f4d Kostas Papadimitriou
802 e1a80257 Sofia Papagiannaki
803 e1a80257 Sofia Papagiannaki
    def save(self, commit=True):
804 73fbaec4 Sofia Papagiannaki
        application = super(ProjectApplicationForm, self).save(commit=False)
805 e1a80257 Sofia Papagiannaki
        applicant = self.user
806 e1a80257 Sofia Papagiannaki
        comments = self.cleaned_data.pop('comments', None)
807 73fbaec4 Sofia Papagiannaki
        return submit_application(
808 73fbaec4 Sofia Papagiannaki
            application,
809 ccab6eb5 Sofia Papagiannaki
            self.resource_policies,
810 e1a80257 Sofia Papagiannaki
            applicant,
811 e1a80257 Sofia Papagiannaki
            comments,
812 40b52116 Sofia Papagiannaki
            self.precursor_application
813 e1a80257 Sofia Papagiannaki
        )
814 8327782d Sofia Papagiannaki
815 8327782d Sofia Papagiannaki
class ProjectSortForm(forms.Form):
816 8327782d Sofia Papagiannaki
    sorting = forms.ChoiceField(
817 8327782d Sofia Papagiannaki
        label='Sort by',
818 73fbaec4 Sofia Papagiannaki
        choices=(('name', 'Sort by Name'),
819 8327782d Sofia Papagiannaki
                 ('issue_date', 'Sort by Issue date'),
820 73fbaec4 Sofia Papagiannaki
                 ('start_date', 'Sort by Start Date'),
821 73fbaec4 Sofia Papagiannaki
                 ('end_date', 'Sort by End Date'),
822 8327782d Sofia Papagiannaki
#                  ('approved_members_num', 'Sort by Participants'),
823 d6a162d3 Sofia Papagiannaki
                 ('state', 'Sort by Status'),
824 73fbaec4 Sofia Papagiannaki
                 ('member_join_policy__description', 'Sort by Member Join Policy'),
825 7592e3e2 Sofia Papagiannaki
                 ('member_leave_policy__description', 'Sort by Member Leave Policy'),
826 7592e3e2 Sofia Papagiannaki
                 ('-name', 'Sort by Name'),
827 7592e3e2 Sofia Papagiannaki
                 ('-issue_date', 'Sort by Issue date'),
828 7592e3e2 Sofia Papagiannaki
                 ('-start_date', 'Sort by Start Date'),
829 7592e3e2 Sofia Papagiannaki
                 ('-end_date', 'Sort by End Date'),
830 7592e3e2 Sofia Papagiannaki
#                  ('-approved_members_num', 'Sort by Participants'),
831 7592e3e2 Sofia Papagiannaki
                 ('-state', 'Sort by Status'),
832 7592e3e2 Sofia Papagiannaki
                 ('-member_join_policy__description', 'Sort by Member Join Policy'),
833 7592e3e2 Sofia Papagiannaki
                 ('-member_leave_policy__description', 'Sort by Member Leave Policy')
834 8327782d Sofia Papagiannaki
        ),
835 8327782d Sofia Papagiannaki
        required=True
836 ccab6eb5 Sofia Papagiannaki
    )
837 ccab6eb5 Sofia Papagiannaki
838 ccab6eb5 Sofia Papagiannaki
class AddProjectMembersForm(forms.Form):
839 ccab6eb5 Sofia Papagiannaki
    q = forms.CharField(
840 ccab6eb5 Sofia Papagiannaki
        max_length=800, widget=forms.Textarea, label=_('Add members'),
841 ccab6eb5 Sofia Papagiannaki
        help_text=_(astakos_messages.ADD_PROJECT_MEMBERS_Q_HELP),
842 ccab6eb5 Sofia Papagiannaki
        required=True)
843 ccab6eb5 Sofia Papagiannaki
844 ccab6eb5 Sofia Papagiannaki
    def clean(self):
845 ccab6eb5 Sofia Papagiannaki
        q = self.cleaned_data.get('q') or ''
846 ccab6eb5 Sofia Papagiannaki
        users = q.split(',')
847 ccab6eb5 Sofia Papagiannaki
        users = list(u.strip() for u in users if u)
848 ccab6eb5 Sofia Papagiannaki
        db_entries = AstakosUser.objects.filter(email__in=users)
849 ccab6eb5 Sofia Papagiannaki
        unknown = list(set(users) - set(u.email for u in db_entries))
850 ccab6eb5 Sofia Papagiannaki
        if unknown:
851 ccab6eb5 Sofia Papagiannaki
            raise forms.ValidationError(_(astakos_messages.UNKNOWN_USERS) % ','.join(unknown))
852 ccab6eb5 Sofia Papagiannaki
        self.valid_users = db_entries
853 ccab6eb5 Sofia Papagiannaki
        return self.cleaned_data
854 ccab6eb5 Sofia Papagiannaki
855 ccab6eb5 Sofia Papagiannaki
    def get_valid_users(self):
856 ccab6eb5 Sofia Papagiannaki
        """Should be called after form cleaning"""
857 ccab6eb5 Sofia Papagiannaki
        try:
858 ccab6eb5 Sofia Papagiannaki
            return self.valid_users
859 ccab6eb5 Sofia Papagiannaki
        except:
860 bfe23b13 Sofia Papagiannaki
            return ()
861 bfe23b13 Sofia Papagiannaki
862 bfe23b13 Sofia Papagiannaki
class ProjectMembersSortForm(forms.Form):
863 bfe23b13 Sofia Papagiannaki
    sorting = forms.ChoiceField(
864 bfe23b13 Sofia Papagiannaki
        label='Sort by',
865 bfe23b13 Sofia Papagiannaki
        choices=(('person__email', 'User Id'),
866 bfe23b13 Sofia Papagiannaki
                 ('person__first_name', 'Name'),
867 bfe23b13 Sofia Papagiannaki
                 ('acceptance_date', 'Acceptance date')
868 bfe23b13 Sofia Papagiannaki
        ),
869 bfe23b13 Sofia Papagiannaki
        required=True
870 bfe23b13 Sofia Papagiannaki
    )
871 bfe23b13 Sofia Papagiannaki
872 6dadd24a Sofia Papagiannaki
class ProjectSearchForm(forms.Form):
873 85d444db Sofia Papagiannaki
    q = forms.CharField(max_length=200, label='Search project', required=False)