Revision 683cf244

b/snf-astakos-app/astakos/im/backends.py
42 42
from django.core.urlresolvers import reverse
43 43

  
44 44
from smtplib import SMTPException
45
from urllib import quote
46 45
from urlparse import urljoin
47 46

  
48 47
from astakos.im.models import AstakosUser, Invitation
49 48
from astakos.im.forms import *
50 49
from astakos.im.util import get_invitation
50
from astakos.im.functions import send_verification, send_notification, activate
51 51
from astakos.im.settings import INVITATIONS_ENABLED, DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, MODERATION_ENABLED, SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL, RE_USER_EMAIL_PATTERNS
52 52

  
53 53
import socket
......
157 157
        return False
158 158

  
159 159
    @transaction.commit_manually
160
    def signup(self, form, email_template_name='im/activation_email.txt', admin_email_template_name='im/admin_notification.txt'):
160
    def signup(self, form, verification_template_name='im/activation_email.txt', greeting_template_name='im/welcome_email.txt', admin_email_template_name='im/admin_notification.txt'):
161 161
        """
162 162
        Initially creates an inactive user account. If the user is preaccepted
163 163
        (has a valid invitation code) the user is activated and if the request
......
172 172
            user = form.save()
173 173
            if self._is_preaccepted(user):
174 174
                if user.email_verified:
175
                    user.is_active = True
176
                    user.save()
177
                    message = _('Registration completed. You can now login.')
175
                    try:
176
                        activate(user, greeting_template_name)
177
                        message = _('Registration completed. You can now login.')
178
                    except (SMTPException, socket.error) as e:
179
                        status = messages.ERROR
180
                        name = 'strerror'
181
                        message = getattr(e, 'name') if hasattr(e, 'name') else e
178 182
                else:
179 183
                    try:
180
                        _send_verification(self.request, user, email_template_name)
184
                        send_verification(user, verification_template_name)
181 185
                        message = _('Verification sent to %s' % user.email)
182 186
                    except (SMTPException, socket.error) as e:
183 187
                        status = messages.ERROR
184 188
                        name = 'strerror'
185
                        message = getattr(e, name) if hasattr(e, name) else e
189
                        message = getattr(e, 'name') if hasattr(e, 'name') else e
186 190
            else:
187
                _send_notification(user, admin_email_template_name)
188
                message = _('Your request for an account was successfully sent \
189
                            and pending approval from our administrators. You \
190
                            will be notified by email the next days. \
191
                            Thanks for being patient, the GRNET team')
191
                send_notification(user, admin_email_template_name)
192
                message = _('Your request for an account was successfully received and is now pending \
193
                            approval. You will be notified by email in the next few days. Thanks for \
194
                            your interest in ~okeanos! The GRNET team.')
192 195
            status = messages.SUCCESS
193 196
        except Invitation.DoesNotExist, e:
194 197
            status = messages.ERROR
......
264 267
        status = messages.SUCCESS
265 268
        if not self._is_preaccepted(user):
266 269
            try:
267
                _send_notification(user, admin_email_template_name)
268
                message = _('Your request for an account was successfully sent \
269
                            and pending approval from our administrators. You \
270
                            will be notified by email the next days. \
271
                            Thanks for being patient, the GRNET team')
270
                send_notification(user, admin_email_template_name)
271
                message = _('Your request for an account was successfully received and is now pending \
272
                            approval. You will be notified by email in the next few days. Thanks for \
273
                            your interest in ~okeanos! The GRNET team.')
272 274
            except (SMTPException, socket.error) as e:
273 275
                status = messages.ERROR
274 276
                name = 'strerror'
275
                message = getattr(e, name) if hasattr(e, name) else e
277
                message = getattr(e, 'name') if hasattr(e, 'name') else e
276 278
        else:
277 279
            try:
278
                _send_verification(self.request, user, email_template_name)
280
                send_verification(user, email_template_name)
279 281
                message = _('Verification sent to %s' % user.email)
280 282
            except (SMTPException, socket.error) as e:
281 283
                status = messages.ERROR
282 284
                name = 'strerror'
283
                message = getattr(e, name) if hasattr(e, name) else e
285
                message = getattr(e, 'name') if hasattr(e, 'name') else e
284 286

  
285 287
        # rollback in case of error
286 288
        if status == messages.ERROR:
......
288 290
        else:
289 291
            transaction.commit()
290 292
        return status, message, user
291

  
292
def _send_verification(request, user, template_name):
293
    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('astakos.im.views.activate')),
294
                                    quote(user.auth_token),
295
                                    quote(BASEURL))
296
    message = render_to_string(template_name, {
297
            'user': user,
298
            'url': url,
299
            'baseurl': BASEURL,
300
            'site_name': SITENAME,
301
            'support': DEFAULT_CONTACT_EMAIL})
302
    sender = DEFAULT_FROM_EMAIL
303
    send_mail('%s  alpha2 testing account activation' % SITENAME, message, sender, [user.email])
304
    logger.info('Sent activation %s', user)
305

  
306
def _send_notification(user, template_name):
307
    if not DEFAULT_ADMIN_EMAIL:
308
        return
309
    message = render_to_string(template_name, {
310
            'user': user,
311
            'baseurl': BASEURL,
312
            'site_name': SITENAME,
313
            'support': DEFAULT_CONTACT_EMAIL})
314
    sender = DEFAULT_FROM_EMAIL
315
    send_mail('%s  alpha2 testing account notification' % SITENAME, message, sender, [DEFAULT_ADMIN_EMAIL])
316
    logger.info('Sent admin notification for user %s', user)
b/snf-astakos-app/astakos/im/functions.py
37 37
from django.template.loader import render_to_string
38 38
from django.core.mail import send_mail
39 39
from django.core.urlresolvers import reverse
40
from urllib import quote
40 41
from urlparse import urljoin
41 42
from random import randint
42 43

  
43
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, SITENAME, BASEURL
44
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL
44 45
from astakos.im.models import Invitation
45 46

  
46 47
logger = logging.getLogger(__name__)
47 48

  
48
def activate(user, email_template_name='im/welcome_email.txt'):
49
def send_verification(user, template_name='im/activation_email.txt'):
49 50
    """
50
    Activates the specific user and sends email.
51
    Send email to user to verify his/her email and activate his/her account.
52
    
53
    Raises SMTPException, socket.error
54
    """
55
    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('astakos.im.views.activate')),
56
                                    quote(user.auth_token),
57
                                    quote(BASEURL))
58
    message = render_to_string(template_name, {
59
            'user': user,
60
            'url': url,
61
            'baseurl': BASEURL,
62
            'site_name': SITENAME,
63
            'support': DEFAULT_CONTACT_EMAIL})
64
    sender = DEFAULT_FROM_EMAIL
65
    send_mail('%s  alpha2 testing account activation' % SITENAME, message, sender, [user.email])
66
    logger.info('Sent activation %s', user)
67

  
68
def send_notification(user, template_name='im/admin_notification.txt'):
69
    """
70
    Send email to DEFAULT_ADMIN_EMAIL to notify for a new user registration.
71
    
72
    Raises SMTPException, socket.error
73
    """
74
    if not DEFAULT_ADMIN_EMAIL:
75
        return
76
    message = render_to_string(template_name, {
77
            'user': user,
78
            'baseurl': BASEURL,
79
            'site_name': SITENAME,
80
            'support': DEFAULT_CONTACT_EMAIL})
81
    sender = DEFAULT_FROM_EMAIL
82
    send_mail('%s  alpha2 testing account notification' % SITENAME, message, sender, [DEFAULT_ADMIN_EMAIL])
83
    logger.info('Sent admin notification for user %s', user)
84

  
85
def send_invitation(invitation, template_name='im/invitation.txt'):
86
    """
87
    Send invitation email.
88
    
89
    Raises SMTPException, socket.error
90
    """
91
    subject = _('Invitation to %s alpha2 testing' % SITENAME)
92
    url = '%s?code=%d' % (urljoin(BASEURL, reverse('astakos.im.views.signup')), invitation.code)
93
    message = render_to_string('im/invitation.txt', {
94
                'invitation': invitation,
95
                'url': url,
96
                'baseurl': BASEURL,
97
                'site_name': SITENAME,
98
                'support': DEFAULT_CONTACT_EMAIL})
99
    sender = DEFAULT_FROM_EMAIL
100
    send_mail(subject, message, sender, [invitation.username])
101
    logger.info('Sent invitation %s', invitation)
102

  
103
def send_greeting(user, email_template_name='im/welcome_email.txt'):
104
    """
105
    Send welcome email.
51 106
    
52 107
    Raises SMTPException, socket.error
53 108
    """
54
    user.is_active = True
55
    user.save()
56 109
    subject = _('Welcome to %s alpha2 testing' % SITENAME)
57 110
    message = render_to_string(email_template_name, {
58 111
                'user': user,
......
64 117
    send_mail(subject, message, sender, [user.email])
65 118
    logger.info('Sent greeting %s', user)
66 119

  
120
def activate(user, email_template_name='im/welcome_email.txt'):
121
    """
122
    Activates the specific user and sends email.
123
    
124
    Raises SMTPException, socket.error
125
    """
126
    user.is_active = True
127
    user.save()
128
    send_greeting(user, email_template_name)
129

  
67 130
def _generate_invitation_code():
68 131
    while True:
69 132
        code = randint(1, 2L**63 - 1)
......
73 136
        except Invitation.DoesNotExist:
74 137
            return code
75 138

  
76
def invite(inviter, username, realname):
139
def invite(inviter, username, realname, email_template_name='im/welcome_email.txt'):
77 140
    """
78 141
    Send an invitation email and upon success reduces inviter's invitation by one.
79 142
    
......
85 148
                            code=code,
86 149
                            realname=realname)
87 150
    invitation.save()
88
    subject = _('Invitation to %s alpha2 testing' % SITENAME)
89
    url = '%s?code=%d' % (urljoin(BASEURL, reverse('astakos.im.views.signup')), code)
90
    message = render_to_string('im/invitation.txt', {
91
                'invitation': invitation,
92
                'url': url,
93
                'baseurl': BASEURL,
94
                'service': SITENAME,
95
                'support': DEFAULT_CONTACT_EMAIL})
96
    sender = DEFAULT_FROM_EMAIL
97
    send_mail(subject, message, sender, [invitation.username])
98
    logger.info('Sent invitation %s', invitation)
151
    send_invitation(invitation, email_template_name)
99 152
    inviter.invitations = max(0, inviter.invitations - 1)
100 153
    inviter.save()
/dev/null
1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34
from django.core.management.base import BaseCommand, CommandError
35
from django.db import transaction
36

  
37
from astakos.im.functions import activate
38

  
39
from ._common import get_user
40
    
41

  
42
class Command(BaseCommand):
43
    args = "<user ID or email> [user ID or email] ..."
44
    help = "Activates one or more users"
45
    
46
    @transaction.commit_manually
47
    def handle(self, *args, **options):
48
        if not args:
49
            raise CommandError("No user was given")
50
        
51
        for email_or_id in args:
52
            user = get_user(email_or_id)
53
            if not user:
54
                self.stderr.write("Unknown user '%s'\n" % (email_or_id,))
55
                continue
56
            
57
            if user.is_active:
58
                msg = "User '%s' already active\n" % (user.email,)
59
                self.stderr.write(msg)
60
                continue
61
            
62
            try:
63
                activate(user)
64
                transaction.commit()
65
            except Exception, e:
66
                transaction.rollback()
67
                raise e
68
            
69
            self.stdout.write("Activated '%s'\n" % (user.email,))
b/snf-astakos-app/astakos/im/management/commands/sendactivation.py
1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34
from django.core.management.base import BaseCommand, CommandError
35
from django.db import transaction
36

  
37
from astakos.im.functions import send_verification
38

  
39
from ._common import get_user
40
    
41

  
42
class Command(BaseCommand):
43
    args = "<user ID or email> [user ID or email] ..."
44
    help = "Sends an activation email to one or more users"
45
    
46
    def handle(self, *args, **options):
47
        if not args:
48
            raise CommandError("No user was given")
49
        
50
        for email_or_id in args:
51
            user = get_user(email_or_id)
52
            if not user:
53
                self.stderr.write("Unknown user '%s'\n" % (email_or_id,))
54
                continue
55
            
56
            if user.is_active:
57
                msg = "User '%s' already active\n" % (user.email,)
58
                self.stderr.write(msg)
59
                continue
60
            
61
            send_verification(user)
62
            
63
            self.stdout.write("Activated '%s'\n" % (user.email,))
b/snf-astakos-app/astakos/im/views.py
49 49
from django.db import transaction
50 50
from django.contrib.auth import logout as auth_logout
51 51
from django.utils.http import urlencode
52
from django.http import HttpResponseRedirect
52
from django.http import HttpResponseRedirect, HttpResponseBadRequest
53 53
from django.db.utils import IntegrityError
54 54

  
55 55
from astakos.im.models import AstakosUser, Invitation
56 56
from astakos.im.backends import get_backend
57 57
from astakos.im.util import get_context, prepare_response, set_cookie
58 58
from astakos.im.forms import *
59
from astakos.im.functions import send_greeting
59 60
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, BASEURL, LOGOUT_NEXT
60 61
from astakos.im.functions import invite as invite_func
61 62

  
......
396 397
    response.write(render_to_string(template, context_instance=context))
397 398
    return response
398 399

  
399
def activate(request):
400
@transaction.commit_manually
401
def activate(request, email_template_name='im/welcome_email.txt', on_failure=''):
400 402
    """
401
    Activates the user identified by the ``auth`` request parameter
403
    Activates the user identified by the ``auth`` request parameter, sends a welcome email
404
    and renews the user token.
405
    
406
    The view uses commit_manually decorator in order to ensure the user state will be updated
407
    only if the email will be send successfully.
402 408
    """
403 409
    token = request.GET.get('auth')
404 410
    next = request.GET.get('next')
405 411
    try:
406 412
        user = AstakosUser.objects.get(auth_token=token)
407 413
    except AstakosUser.DoesNotExist:
408
        return HttpResponseBadRequest('No such user')
414
        return HttpResponseBadRequest(_('No such user'))
409 415
    
410 416
    user.is_active = True
411 417
    user.email_verified = True
412 418
    user.save()
413
    return prepare_response(request, user, next, renew=True)
419
    try:
420
        send_greeting(user, email_template_name)
421
        response = prepare_response(request, user, next, renew=True)
422
        transaction.commit()
423
        return response
424
    except (SMTPException, socket.error) as e:
425
        message = getattr(e, 'name') if hasattr(e, 'name') else e
426
        messages.add_message(request, messages.ERROR, message)
427
        transaction.rollback()
428
        return signup(request, on_failure='im/signup.html')

Also available in: Unified diff