Statistics
| Branch: | Tag: | Revision:

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

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

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

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

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