Revision 43332a76

b/snf-astakos-app/astakos/im/forms.py
69 69
from astakos.im.functions import (
70 70
    send_change_email, submit_application, do_accept_membership_checks)
71 71

  
72
from astakos.im.util import reserved_email, get_query, model_to_dict
72
from astakos.im.util import reserved_email, reserved_verified_email, \
73
                            get_query, model_to_dict
73 74
from astakos.im import auth_providers
74 75

  
75 76
import astakos.im.messages as astakos_messages
......
87 88

  
88 89
class StoreUserMixin(object):
89 90

  
90
    @transaction.commit_on_success
91 91
    def store_user(self, user, request):
92
        """
93
        WARNING: this should be wrapped inside a transactional view/method.
94
        """
92 95
        user.save()
93 96
        self.post_store_user(user, request)
94 97
        return user
......
150 153
        email = self.cleaned_data['email']
151 154
        if not email:
152 155
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
153
        if reserved_email(email):
156
        if reserved_verified_email(email):
154 157
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
155 158
        return email
156 159

  
......
236 239
        widget=forms.HiddenInput(),
237 240
        label=''
238 241
    )
242

  
239 243
    class Meta:
240 244
        model = AstakosUser
241 245
        fields = ['id', 'email', 'third_party_identifier', 'first_name', 'last_name']
......
269 273
        email = self.cleaned_data['email']
270 274
        if not email:
271 275
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
272
        if reserved_email(email):
276
        if reserved_verified_email(email):
273 277
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
274 278
        return email
275 279

  
......
283 287
        pending = PendingThirdPartyUser.objects.get(
284 288
                                token=request.POST.get('third_party_token'),
285 289
                                third_party_identifier= \
286
            self.cleaned_data.get('third_party_identifier'))
290
                            self.cleaned_data.get('third_party_identifier'))
287 291
        return user.add_pending_auth_provider(pending)
288 292

  
289

  
290 293
    def save(self, commit=True):
291 294
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
292 295
        user.set_unusable_password()
......
525 528

  
526 529
    def clean_new_email_address(self):
527 530
        addr = self.cleaned_data['new_email_address']
528
        if AstakosUser.objects.filter(email__iexact=addr):
531
        if reserved_verified_email(addr):
529 532
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
530 533
        return addr
531 534

  
......
847 850
            self.project = Project.objects.get(application__id=application_id)
848 851
        self.request_user = kwargs.pop('request_user', None)
849 852
        super(AddProjectMembersForm, self).__init__(*args, **kwargs)
850
        
853

  
851 854
    def clean(self):
852 855
        try:
853 856
            do_accept_membership_checks(self.project, self.request_user)
b/snf-astakos-app/astakos/im/models.py
219 219
        )
220 220
    return _default_quota
221 221

  
222

  
222 223
class AstakosUserManager(UserManager):
223 224

  
224 225
    def get_auth_provider_user(self, provider, **kwargs):
......
242 243
    def user_exists(self, email_or_username, **kwargs):
243 244
        qemail = Q(email__iexact=email_or_username)
244 245
        qusername = Q(username__iexact=email_or_username)
245
        return self.filter(qemail | qusername).exists()
246
        qextra = Q(**kwargs)
247
        return self.filter((qemail | qusername) & qextra).exists()
248

  
249
    def verified_user_exists(self, email_or_username):
250
        return self.user_exists(email_or_username, email_verified=True)
251

  
252
    def verified(self):
253
        return self.filter(email_verified=True)
246 254

  
247 255

  
248 256
class AstakosUser(User):
b/snf-astakos-app/astakos/im/templates/im/activation_email.txt
19 19
To activate the account, please use the link: {{ url }}
20 20
{% endblock %}
21 21

  
22
{% block en_note %} {% endblock%}
22
{% block en_note %} {% endblock%}
/dev/null
1
{% extends 'im/base.html' %}
2

  
3
{% block page.title %}Signup complete{% endblock %}
4

  
5
{% block body %}
6
    <div class='header'>
7
        <div class="mainlogo">
8
            <h1>Signup complete</h1>
9
        </div>
10
    </div>
11

  
12
<div class="section">
13
    <form action="{% url signup %}" method="post" class="login innerlabels">{% csrf_token %}
14
                {% with thirdparty_signup_form as form %}
15
                {% include "im/form_render.html" %}
16
                {% endwith %}
17
                <input type="hidden" name="next" value="{{ next }}">
18
                <input type="hidden" name="provider" value="{{ provider }}">
19
                <div class="form-row submit">
20
                    <input type="submit" class="submit altcol" value="SUBMIT" />
21
                </div>
22
        </form>
23
{% endblock body %}
b/snf-astakos-app/astakos/im/urls.py
45 45
    url(r'^login/?$', 'index', {}, name='login'),
46 46
    url(r'^profile/?$','edit_profile', {}, name='edit_profile'),
47 47
    url(r'^feedback/?$', 'feedback', {}, name='feedback'),
48
    url(r'^signup/?$', 'signup', {'on_success': 'im/login.html', 'extra_context': {'login_form': LoginForm()}}, name='signup'),
48
    url(r'^signup/?$', 'signup', {'on_success': 'index', 'extra_context': {'login_form': LoginForm()}}, name='signup'),
49 49
    url(r'^logout/?$', 'logout', {'template': 'im/login.html', 'extra_context': {'login_form': LoginForm()}}, name='logout'),
50 50
    url(r'^activate/?$', 'activate', {}, name='activate'),
51 51
    url(r'^approval_terms/?$', 'approval_terms', {}, name='latest_terms'),
......
66 66
    url(r'^projects/(?P<application_id>\d+)/(?P<user_id>\d+)/accept/?$', 'project_accept_member', {}, name='project_accept_member'),
67 67
    url(r'^projects/(?P<application_id>\d+)/(?P<user_id>\d+)/reject/?$', 'project_reject_member', {}, name='project_reject_member'),
68 68
    url(r'^projects/(?P<application_id>\d+)/(?P<user_id>\d+)/remove/?$', 'project_remove_member', {}, name='project_remove_member'),
69
    
69

  
70 70
    url(r'^projects/how_it_works/?$', 'how_it_works', {}, name='how_it_works'),
71 71
    url(r'^remove_auth_provider/(?P<pk>\d+)?$', 'remove_auth_provider', {}, name='remove_auth_provider'),
72 72
)
b/snf-astakos-app/astakos/im/util.py
212 212
    return AstakosUser.objects.user_exists(email)
213 213

  
214 214

  
215
def reserved_verified_email(email):
216
    return AstakosUser.objects.verified_user_exists(email)
217

  
218

  
215 219
def get_query(request):
216 220
    try:
217 221
        return request.__getattribute__(request.method)
b/snf-astakos-app/astakos/im/views.py
410 410

  
411 411
@transaction.commit_manually
412 412
@require_http_methods(["GET", "POST"])
413
def signup(request, template_name='im/signup.html', on_success='im/signup_complete.html', extra_context=None, backend=None):
413
def signup(request, template_name='im/signup.html', on_success='index', extra_context=None, backend=None):
414 414
    """
415 415
    Allows a user to create a local account.
416 416

  
......
433 433
        A custom template to render. This is optional;
434 434
        if not specified, this will default to ``im/signup.html``.
435 435

  
436
    ``on_success``
437
        A custom template to render in case of success. This is optional;
438
        if not specified, this will default to ``im/signup_complete.html``.
439

  
440 436
    ``extra_context``
441 437
        An dictionary of variables to add to the template context.
442 438

  
439
    ``on_success``
440
        Resolvable view name to redirect on registration success.
441

  
443 442
    **Template:**
444 443

  
445 444
    im/signup.html or ``template_name`` keyword argument.
446
    im/signup_complete.html or ``on_success`` keyword argument.
447 445
    """
448 446
    extra_context = extra_context or {}
449 447
    if request.user.is_authenticated():
......
476 474
    if request.method == 'POST':
477 475
        if form.is_valid():
478 476
            user = form.save(commit=False)
477

  
478
            # delete previously unverified accounts
479
            if AstakosUser.objects.user_exists(user.email):
480
                AstakosUser.objects.get_by_identifier(user.email).delete()
481

  
479 482
            try:
480 483
                result = backend.handle_activation(user)
481 484
                status = messages.SUCCESS
......
492 495
                            user.email
493 496
                        )
494 497
                        logger._log(LOGGING_LEVEL, msg, [])
498

  
495 499
                if user and user.is_active:
496 500
                    next = request.POST.get('next', '')
497 501
                    response = prepare_response(request, user, next=next)
498 502
                    transaction.commit()
499 503
                    return response
500
                messages.add_message(request, status, message)
504

  
501 505
                transaction.commit()
502
                return render_response(
503
                    on_success,
504
                    context_instance=get_context(
505
                        request,
506
                        extra_context
507
                    )
508
                )
506
                messages.add_message(request, status, message)
507
                return HttpResponseRedirect(reverse(on_success))
508

  
509 509
            except SendMailError, e:
510 510
                logger.exception(e)
511 511
                status = messages.ERROR
......
518 518
                messages.error(request, message)
519 519
                logger.exception(e)
520 520
                transaction.rollback()
521

  
521 522
    return render_response(template_name,
522 523
                           signup_form=form,
523 524
                           third_party_token=third_party_token,

Also available in: Unified diff