Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / functions.py @ ed2f0452

History | View | Annotate | Download (11.9 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
from django.contrib.auth.models import AnonymousUser
47

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

    
54
from astakos.im.settings import (DEFAULT_CONTACT_EMAIL, SITENAME, BASEURL,
55
                                 LOGGING_LEVEL, VERIFICATION_EMAIL_SUBJECT,
56
                                 ACCOUNT_CREATION_SUBJECT,
57
                                 GROUP_CREATION_SUBJECT,
58
                                 HELPDESK_NOTIFICATION_EMAIL_SUBJECT,
59
                                 INVITATION_EMAIL_SUBJECT,
60
                                 GREETING_EMAIL_SUBJECT,
61
                                 FEEDBACK_EMAIL_SUBJECT,
62
                                 EMAIL_CHANGE_EMAIL_SUBJECT)
63
import astakos.im.models
64

    
65
logger = logging.getLogger(__name__)
66

    
67

    
68
def logged(func, msg):
69
    @wraps(func)
70
    def with_logging(*args, **kwargs):
71
        email = ''
72
        user = None
73
        try:
74
            request = args[0]
75
            email = request.user.email
76
        except (KeyError, AttributeError), e:
77
            email = ''
78
        r = func(*args, **kwargs)
79
        if LOGGING_LEVEL:
80
            logger.log(LOGGING_LEVEL, msg % email)
81
        return r
82
    return with_logging
83

    
84
login = logged(auth_login, '%s logged in.')
85
logout = logged(auth_logout, '%s logged out.')
86

    
87

    
88
def send_verification(user, template_name='im/activation_email.txt'):
89
    """
90
    Send email to user to verify his/her email and activate his/her account.
91

92
    Raises SendVerificationError
93
    """
94
    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('activate')),
95
                                  quote(user.auth_token),
96
                                  quote(urljoin(BASEURL, reverse('index'))))
97
    message = render_to_string(template_name, {
98
                               'user': user,
99
                               'url': url,
100
                               'baseurl': BASEURL,
101
                               'site_name': SITENAME,
102
                               'support': DEFAULT_CONTACT_EMAIL})
103
    sender = settings.SERVER_EMAIL
104
    try:
105
        send_mail(_(VERIFICATION_EMAIL_SUBJECT), message, sender, [user.email])
106
    except (SMTPException, socket.error) as e:
107
        logger.exception(e)
108
        raise SendVerificationError()
109
    else:
110
        msg = 'Sent activation %s' % user.email
111
        logger.log(LOGGING_LEVEL, msg)
112

    
113

    
114
def send_activation(user, template_name='im/activation_email.txt'):
115
    send_verification(user, template_name)
116
    user.activation_sent = datetime.now()
117
    user.save()
118

    
119

    
120
def _send_admin_notification(template_name,
121
                             dictionary=None,
122
                             subject='alpha2 testing notification',):
123
    """
124
    Send notification email to settings.ADMINS.
125

126
    Raises SendNotificationError
127
    """
128
    if not settings.ADMINS:
129
        return
130
    dictionary = dictionary or {}
131
    message = render_to_string(template_name, dictionary)
132
    sender = settings.SERVER_EMAIL
133
    try:
134
        send_mail(subject,
135
                  message, sender, [i[1] for i in settings.ADMINS])
136
    except (SMTPException, socket.error) as e:
137
        logger.exception(e)
138
        raise SendNotificationError()
139
    else:
140
        msg = 'Sent admin notification for user %s' % dictionary
141
        logger.log(LOGGING_LEVEL, msg)
142

    
143

    
144
def send_account_creation_notification(template_name, dictionary=None):
145
    user = dictionary.get('user', AnonymousUser())
146
    subject = _(ACCOUNT_CREATION_SUBJECT) % {'user': user.email}
147
    return _send_admin_notification(template_name, dictionary, subject=subject)
148

    
149

    
150
def send_group_creation_notification(template_name, dictionary=None):
151
    group = dictionary.get('group', astakos.im.models.AstakosGroup())
152
    subject = _(GROUP_CREATION_SUBJECT) % {'group': group.name}
153
    return _send_admin_notification(template_name, dictionary, subject=subject)
154

    
155

    
156
def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
157
    """
158
    Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
159

160
    Raises SendNotificationError
161
    """
162
    if not DEFAULT_CONTACT_EMAIL:
163
        return
164
    message = render_to_string(
165
        template_name,
166
        {'user': user}
167
    )
168
    sender = settings.SERVER_EMAIL
169
    try:
170
        send_mail(
171
            _(HELPDESK_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email},
172
            message, sender, [DEFAULT_CONTACT_EMAIL])
173
    except (SMTPException, socket.error) as e:
174
        logger.exception(e)
175
        raise SendNotificationError()
176
    else:
177
        msg = 'Sent helpdesk admin notification for %s' % user.email
178
        logger.log(LOGGING_LEVEL, msg)
179

    
180

    
181
def send_invitation(invitation, template_name='im/invitation.txt'):
182
    """
183
    Send invitation email.
184

185
    Raises SendInvitationError
186
    """
187
    subject = _(INVITATION_EMAIL_SUBJECT)
188
    url = '%s?code=%d' % (urljoin(BASEURL, reverse('index')), invitation.code)
189
    message = render_to_string(template_name, {
190
                               'invitation': invitation,
191
                               'url': url,
192
                               'baseurl': BASEURL,
193
                               'site_name': SITENAME,
194
                               'support': DEFAULT_CONTACT_EMAIL})
195
    sender = settings.SERVER_EMAIL
196
    try:
197
        send_mail(subject, message, sender, [invitation.username])
198
    except (SMTPException, socket.error) as e:
199
        logger.exception(e)
200
        raise SendInvitationError()
201
    else:
202
        msg = 'Sent invitation %s' % invitation
203
        logger.log(LOGGING_LEVEL, msg)
204
        invitation.inviter.invitations = max(0, self.invitations - 1)
205
        invitation.inviter.save()
206

    
207

    
208
def send_greeting(user, email_template_name='im/welcome_email.txt'):
209
    """
210
    Send welcome email.
211

212
    Raises SMTPException, socket.error
213
    """
214
    subject = _(GREETING_EMAIL_SUBJECT)
215
    message = render_to_string(email_template_name, {
216
                               'user': user,
217
                               'url': urljoin(BASEURL, reverse('index')),
218
                               'baseurl': BASEURL,
219
                               'site_name': SITENAME,
220
                               'support': DEFAULT_CONTACT_EMAIL})
221
    sender = settings.SERVER_EMAIL
222
    try:
223
        send_mail(subject, message, sender, [user.email])
224
    except (SMTPException, socket.error) as e:
225
        logger.exception(e)
226
        raise SendGreetingError()
227
    else:
228
        msg = 'Sent greeting %s' % user.email
229
        logger.log(LOGGING_LEVEL, msg)
230

    
231

    
232
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
233
    subject = _(FEEDBACK_EMAIL_SUBJECT)
234
    from_email = user.email
235
    recipient_list = [DEFAULT_CONTACT_EMAIL]
236
    content = render_to_string(email_template_name, {
237
        'message': msg,
238
        'data': data,
239
        'user': user})
240
    try:
241
        send_mail(subject, content, from_email, recipient_list)
242
    except (SMTPException, socket.error) as e:
243
        logger.exception(e)
244
        raise SendFeedbackError()
245
    else:
246
        msg = 'Sent feedback from %s' % user.email
247
        logger.log(LOGGING_LEVEL, msg)
248

    
249

    
250
def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
251
    try:
252
        url = reverse('email_change_confirm',
253
                      kwargs={'activation_key': ec.activation_key})
254
        url = request.build_absolute_uri(url)
255
        t = loader.get_template(email_template_name)
256
        c = {'url': url, 'site_name': SITENAME}
257
        from_email = settings.SERVER_EMAIL
258
        send_mail(_(EMAIL_CHANGE_EMAIL_SUBJECT),
259
                  t.render(Context(c)), from_email, [ec.new_email_address])
260
    except (SMTPException, socket.error) as e:
261
        logger.exception(e)
262
        raise ChangeEmailError()
263
    else:
264
        msg = 'Sent change email for %s' % ec.user.email
265
        logger.log(LOGGING_LEVEL, msg)
266

    
267

    
268
def activate(user, email_template_name='im/welcome_email.txt',
269
             helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
270
    """
271
    Activates the specific user and sends email.
272

273
    Raises SendGreetingError, ValidationError
274
    """
275
    user.is_active = True
276
    if verify_email:
277
        user.email_verified = True
278
    user.save()
279
    send_helpdesk_notification(user, helpdesk_email_template_name)
280
    send_greeting(user, email_template_name)
281

    
282

    
283
def switch_account_to_shibboleth(user, local_user,
284
                                 greeting_template_name='im/welcome_email.txt'):
285
    try:
286
        provider = user.provider
287
    except AttributeError:
288
        return
289
    else:
290
        if not provider == 'shibboleth':
291
            return
292
        user.delete()
293
        local_user.provider = 'shibboleth'
294
        local_user.third_party_identifier = user.third_party_identifier
295
        local_user.save()
296
        send_greeting(local_user, greeting_template_name)
297
        return local_user
298

    
299

    
300
class SendMailError(Exception):
301
    pass
302

    
303

    
304
class SendAdminNotificationError(SendMailError):
305
    def __init__(self):
306
        self.message = _('Failed to send notification')
307
        super(SendAdminNotificationError, self).__init__()
308

    
309

    
310
class SendVerificationError(SendMailError):
311
    def __init__(self):
312
        self.message = _('Failed to send verification')
313
        super(SendVerificationError, self).__init__()
314

    
315

    
316
class SendInvitationError(SendMailError):
317
    def __init__(self):
318
        self.message = _('Failed to send invitation')
319
        super(SendInvitationError, self).__init__()
320

    
321

    
322
class SendGreetingError(SendMailError):
323
    def __init__(self):
324
        self.message = _('Failed to send greeting')
325
        super(SendGreetingError, self).__init__()
326

    
327

    
328
class SendFeedbackError(SendMailError):
329
    def __init__(self):
330
        self.message = _('Failed to send feedback')
331
        super(SendFeedbackError, self).__init__()
332

    
333

    
334
class ChangeEmailError(SendMailError):
335
    def __init__(self):
336
        self.message = _('Failed to send change email')
337
        super(ChangeEmailError, self).__init__()
338

    
339

    
340
class SendNotificationError(SendMailError):
341
    def __init__(self):
342
        self.message = _('Failed to send notification email')
343
        super(SendNotificationError, self).__init__()