Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / functions.py @ 1cbce16f

History | View | Annotate | Download (11.1 kB)

1
# Copyright 2011 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
import logging
35
import socket
36

    
37
from django.utils.translation import ugettext as _
38
from django.template.loader import render_to_string
39
from django.core.mail import send_mail
40
from django.core.urlresolvers import reverse
41
from django.core.exceptions import ValidationError
42
from django.template import Context, loader
43
from django.contrib.auth import login as auth_login, logout as auth_logout
44
from django.http import HttpRequest
45
from django.conf import settings
46

    
47
from urllib import quote
48
from urlparse import urljoin
49
from smtplib import SMTPException
50
from datetime import datetime
51
from functools import wraps
52

    
53
from astakos.im.settings import (DEFAULT_CONTACT_EMAIL, SITENAME, BASEURL,
54
    LOGGING_LEVEL
55
)
56
from astakos.im.models import AstakosUser
57

    
58
logger = logging.getLogger(__name__)
59

    
60
def logged(func, msg):
61
    @wraps(func)
62
    def with_logging(*args, **kwargs):
63
        email = ''
64
        user = None
65
        if len(args) == 2 and isinstance(args[1], AstakosUser):
66
            user = args[1]
67
        elif len(args) == 1 and isinstance(args[0], HttpRequest):
68
            request = args[0]
69
            user = request.user
70
        email = user.email if user and user.is_authenticated() else ''
71
        r = func(*args, **kwargs)
72
        if LOGGING_LEVEL:
73
            logger.log(LOGGING_LEVEL, msg % email)
74
        return r
75
    return with_logging
76

    
77
login = logged(auth_login, '%s logged in.')
78
logout = logged(auth_logout, '%s logged out.')
79

    
80
def send_verification(user, template_name='im/activation_email.txt'):
81
    """
82
    Send email to user to verify his/her email and activate his/her account.
83
    
84
    Raises SendVerificationError
85
    """
86
    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('activate')),
87
                                    quote(user.auth_token),
88
                                    quote(urljoin(BASEURL, reverse('index'))))
89
    message = render_to_string(template_name, {
90
            'user': user,
91
            'url': url,
92
            'baseurl': BASEURL,
93
            'site_name': SITENAME,
94
            'support': DEFAULT_CONTACT_EMAIL})
95
    sender = settings.SERVER_EMAIL
96
    try:
97
        send_mail('%s alpha2 testing account activation is needed' % SITENAME, message, sender, [user.email])
98
    except (SMTPException, socket.error) as e:
99
        logger.exception(e)
100
        raise SendVerificationError()
101
    else:
102
        msg = 'Sent activation %s' % user.email
103
        logger.log(LOGGING_LEVEL, msg)
104

    
105
def send_activation(user, template_name='im/activation_email.txt'):
106
    send_verification(user, template_name)
107
    user.activation_sent = datetime.now()
108
    user.save()
109

    
110
def send_admin_notification(template_name,
111
    dictionary=None,
112
    subject='alpha2 testing notification',
113
):
114
    """
115
    Send notification email to settings.ADMINS.
116
    
117
    Raises SendNotificationError
118
    """
119
    if not settings.ADMINS:
120
        return
121
    dictionary = dictionary or {}
122
    message = render_to_string(template_name, dictionary)
123
    sender = settings.SERVER_EMAIL
124
    try:
125
        send_mail(subject, message, sender, [i[1] for i in settings.ADMINS])
126
    except (SMTPException, socket.error) as e:
127
        logger.exception(e)
128
        raise SendNotificationError()
129
    else:
130
        msg = 'Sent admin notification for user %s' % dictionary
131
        logger.log(LOGGING_LEVEL, msg)
132

    
133
def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
134
    """
135
    Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
136
    
137
    Raises SendNotificationError
138
    """
139
    if not DEFAULT_CONTACT_EMAIL:
140
        return
141
    message = render_to_string(
142
        template_name,
143
        {'user': user}
144
    )
145
    sender = settings.SERVER_EMAIL
146
    try:
147
        send_mail(
148
            '%s alpha2 testing account activated' % SITENAME,
149
            message,
150
            sender,
151
            [DEFAULT_CONTACT_EMAIL]
152
        )
153
    except (SMTPException, socket.error) as e:
154
        logger.exception(e)
155
        raise SendNotificationError()
156
    else:
157
        msg = 'Sent helpdesk admin notification for %s' % user.email
158
        logger.log(LOGGING_LEVEL, msg)
159

    
160
def send_invitation(invitation, template_name='im/invitation.txt'):
161
    """
162
    Send invitation email.
163
    
164
    Raises SendInvitationError
165
    """
166
    subject = _('Invitation to %s alpha2 testing' % SITENAME)
167
    url = '%s?code=%d' % (urljoin(BASEURL, reverse('index')), invitation.code)
168
    message = render_to_string(template_name, {
169
                'invitation': invitation,
170
                'url': url,
171
                'baseurl': BASEURL,
172
                'site_name': SITENAME,
173
                'support': DEFAULT_CONTACT_EMAIL})
174
    sender = settings.SERVER_EMAIL
175
    try:
176
        send_mail(subject, message, sender, [invitation.username])
177
    except (SMTPException, socket.error) as e:
178
        logger.exception(e)
179
        raise SendInvitationError()
180
    else:
181
        msg = 'Sent invitation %s' % invitation
182
        logger.log(LOGGING_LEVEL, msg)
183

    
184
def send_greeting(user, email_template_name='im/welcome_email.txt'):
185
    """
186
    Send welcome email.
187
    
188
    Raises SMTPException, socket.error
189
    """
190
    subject = _('Welcome to %s alpha2 testing' % SITENAME)
191
    message = render_to_string(email_template_name, {
192
                'user': user,
193
                'url': urljoin(BASEURL, reverse('index')),
194
                'baseurl': BASEURL,
195
                'site_name': SITENAME,
196
                'support': DEFAULT_CONTACT_EMAIL})
197
    sender = settings.SERVER_EMAIL
198
    try:
199
        send_mail(subject, message, sender, [user.email])
200
    except (SMTPException, socket.error) as e:
201
        logger.exception(e)
202
        raise SendGreetingError()
203
    else:
204
        msg = 'Sent greeting %s' % user.email
205
        logger.log(LOGGING_LEVEL, msg)
206

    
207
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
208
    subject = _("Feedback from %s alpha2 testing" % SITENAME)
209
    from_email = user.email
210
    recipient_list = [DEFAULT_CONTACT_EMAIL]
211
    content = render_to_string(email_template_name, {
212
        'message': msg,
213
        'data': data,
214
        'user': user})
215
    try:
216
        send_mail(subject, content, from_email, recipient_list)
217
    except (SMTPException, socket.error) as e:
218
        logger.exception(e)
219
        raise SendFeedbackError()
220
    else:
221
        msg = 'Sent feedback from %s' % user.email
222
        logger.log(LOGGING_LEVEL, msg)
223

    
224
def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
225
    try:
226
        url = reverse('email_change_confirm',
227
                      kwargs={'activation_key':ec.activation_key})
228
        url = request.build_absolute_uri(url)
229
        t = loader.get_template(email_template_name)
230
        c = {'url': url, 'site_name': SITENAME}
231
        from_email = settings.SERVER_EMAIL
232
        send_mail(_("Email change on %s alpha2 testing") % SITENAME,
233
            t.render(Context(c)), from_email, [ec.new_email_address])
234
    except (SMTPException, socket.error) as e:
235
        logger.exception(e)
236
        raise ChangeEmailError()
237
    else:
238
        msg = 'Sent change email for %s' % ec.user.email
239
        logger.log(LOGGING_LEVEL, msg)
240

    
241
def activate(user, email_template_name='im/welcome_email.txt',
242
                helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
243
    """
244
    Activates the specific user and sends email.
245
    
246
    Raises SendGreetingError, ValidationError
247
    """
248
    user.is_active = True
249
    if verify_email:
250
        user.email_verified = True
251
    user.save()
252
    send_helpdesk_notification(user, helpdesk_email_template_name)
253
    send_greeting(user, email_template_name)
254

    
255
def switch_account_to_shibboleth(user, local_user, greeting_template_name='im/welcome_email.txt'):
256
    if not user or not isinstance(user, AstakosUser):
257
        return
258
    
259
    if not local_user or not isinstance(user, AstakosUser):
260
        return
261
    
262
    if not user.provider == 'shibboleth':
263
        return
264
    
265
    user.delete()
266
    local_user.provider = 'shibboleth'
267
    local_user.third_party_identifier = user.third_party_identifier
268
    local_user.save()
269
    send_greeting(local_user, greeting_template_name)
270
    return local_user
271

    
272
def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
273
    """
274
    Send an invitation email and upon success reduces inviter's invitation by one.
275
    
276
    Raises SendInvitationError
277
    """
278
    invitation.inviter = inviter
279
    invitation.save()
280
    send_invitation(invitation, email_template_name)
281
    inviter.invitations = max(0, inviter.invitations - 1)
282
    inviter.save()
283

    
284
class SendMailError(Exception):
285
    pass
286

    
287
class SendAdminNotificationError(SendMailError):
288
    def __init__(self):
289
        self.message = _('Failed to send notification')
290
        super(SendAdminNotificationError, self).__init__()
291

    
292
class SendVerificationError(SendMailError):
293
    def __init__(self):
294
        self.message = _('Failed to send verification')
295
        super(SendVerificationError, self).__init__()
296

    
297
class SendInvitationError(SendMailError):
298
    def __init__(self):
299
        self.message = _('Failed to send invitation')
300
        super(SendInvitationError, self).__init__()
301

    
302
class SendGreetingError(SendMailError):
303
    def __init__(self):
304
        self.message = _('Failed to send greeting')
305
        super(SendGreetingError, self).__init__()
306

    
307
class SendFeedbackError(SendMailError):
308
    def __init__(self):
309
        self.message = _('Failed to send feedback')
310
        super(SendFeedbackError, self).__init__()
311

    
312
class ChangeEmailError(SendMailError):
313
    def __init__(self):
314
        self.message = _('Failed to send change email')
315
        super(ChangeEmailError, self).__init__()
316

    
317
class SendNotificationError(SendMailError):
318
    def __init__(self):
319
        self.message = _('Failed to send notification email')
320
        super(SendNotificationError, self).__init__()