Statistics
| Branch: | Tag: | Revision:

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

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.template import Context, loader
42
from django.contrib.auth import (
43
    login as auth_login,
44
    logout as auth_logout
45
)
46
from django.conf import settings
47
from django.contrib.auth.models import AnonymousUser
48

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

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

    
64
logger = logging.getLogger(__name__)
65

    
66

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

    
83

    
84
def login(request, user):
85
    auth_login(request, user)
86
    from astakos.im.models import SessionCatalog
87
    SessionCatalog(
88
        session_key=request.session.session_key,
89
        user=user
90
    ).save()
91

    
92
login = logged(login, '%s logged in.')
93
logout = logged(auth_logout, '%s logged out.')
94

    
95

    
96
def send_verification(user, template_name='im/activation_email.txt'):
97
    """
98
    Send email to user to verify his/her email and activate his/her account.
99

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

    
121

    
122
def send_activation(user, template_name='im/activation_email.txt'):
123
    send_verification(user, template_name)
124
    user.activation_sent = datetime.now()
125
    user.save()
126

    
127

    
128
def _send_admin_notification(template_name,
129
                             dictionary=None,
130
                             subject='alpha2 testing notification',):
131
    """
132
    Send notification email to settings.ADMINS.
133

134
    Raises SendNotificationError
135
    """
136
    if not settings.ADMINS:
137
        return
138
    dictionary = dictionary or {}
139
    message = render_to_string(template_name, dictionary)
140
    sender = settings.SERVER_EMAIL
141
    try:
142
        send_mail(subject,
143
                  message, sender, [i[1] for i in settings.ADMINS])
144
    except (SMTPException, socket.error) as e:
145
        logger.exception(e)
146
        raise SendNotificationError()
147
    else:
148
        msg = 'Sent admin notification for user %s' % dictionary
149
        logger.log(LOGGING_LEVEL, msg)
150

    
151

    
152
def send_account_creation_notification(template_name, dictionary=None):
153
    user = dictionary.get('user', AnonymousUser())
154
    subject = _(ACCOUNT_CREATION_SUBJECT) % {'user':user.get('email', '')}
155
    return _send_admin_notification(template_name, dictionary, subject=subject)
156

    
157

    
158
def send_group_creation_notification(template_name, dictionary=None):
159
    group = dictionary.get('group')
160
    if not group:
161
        return
162
    subject = _(GROUP_CREATION_SUBJECT) % {'group':group.get('name', '')}
163
    return _send_admin_notification(template_name, dictionary, subject=subject)
164

    
165

    
166
def send_helpdesk_notification(user, template_name='im/helpdesk_notification.txt'):
167
    """
168
    Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
169

170
    Raises SendNotificationError
171
    """
172
    if not DEFAULT_CONTACT_EMAIL:
173
        return
174
    message = render_to_string(
175
        template_name,
176
        {'user': user}
177
    )
178
    sender = settings.SERVER_EMAIL
179
    try:
180
        send_mail(
181
            _(HELPDESK_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email},
182
            message, sender, [DEFAULT_CONTACT_EMAIL])
183
    except (SMTPException, socket.error) as e:
184
        logger.exception(e)
185
        raise SendNotificationError()
186
    else:
187
        msg = 'Sent helpdesk admin notification for %s' % user.email
188
        logger.log(LOGGING_LEVEL, msg)
189

    
190

    
191
def send_invitation(invitation, template_name='im/invitation.txt'):
192
    """
193
    Send invitation email.
194

195
    Raises SendInvitationError
196
    """
197
    subject = _(INVITATION_EMAIL_SUBJECT)
198
    url = '%s?code=%d' % (urljoin(BASEURL, reverse('index')), invitation.code)
199
    message = render_to_string(template_name, {
200
                               'invitation': invitation,
201
                               'url': url,
202
                               'baseurl': BASEURL,
203
                               'site_name': SITENAME,
204
                               'support': DEFAULT_CONTACT_EMAIL})
205
    sender = settings.SERVER_EMAIL
206
    try:
207
        send_mail(subject, message, sender, [invitation.username])
208
    except (SMTPException, socket.error) as e:
209
        logger.exception(e)
210
        raise SendInvitationError()
211
    else:
212
        msg = 'Sent invitation %s' % invitation
213
        logger.log(LOGGING_LEVEL, msg)
214
        invitation.inviter.invitations = max(0, invitation.inviter.invitations - 1)
215
        invitation.inviter.save()
216

    
217

    
218
def send_greeting(user, email_template_name='im/welcome_email.txt'):
219
    """
220
    Send welcome email.
221

222
    Raises SMTPException, socket.error
223
    """
224
    subject = _(GREETING_EMAIL_SUBJECT)
225
    message = render_to_string(email_template_name, {
226
                               'user': user,
227
                               'url': urljoin(BASEURL, reverse('index')),
228
                               'baseurl': BASEURL,
229
                               'site_name': SITENAME,
230
                               'support': DEFAULT_CONTACT_EMAIL})
231
    sender = settings.SERVER_EMAIL
232
    try:
233
        send_mail(subject, message, sender, [user.email])
234
    except (SMTPException, socket.error) as e:
235
        logger.exception(e)
236
        raise SendGreetingError()
237
    else:
238
        msg = 'Sent greeting %s' % user.email
239
        logger.log(LOGGING_LEVEL, msg)
240

    
241

    
242
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
243
    subject = _(FEEDBACK_EMAIL_SUBJECT)
244
    from_email = user.email
245
    recipient_list = [DEFAULT_CONTACT_EMAIL]
246
    content = render_to_string(email_template_name, {
247
        'message': msg,
248
        'data': data,
249
        'user': user})
250
    try:
251
        send_mail(subject, content, from_email, recipient_list)
252
    except (SMTPException, socket.error) as e:
253
        logger.exception(e)
254
        raise SendFeedbackError()
255
    else:
256
        msg = 'Sent feedback from %s' % user.email
257
        logger.log(LOGGING_LEVEL, msg)
258

    
259

    
260
def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
261
    try:
262
        url = reverse('email_change_confirm',
263
                      kwargs={'activation_key': ec.activation_key})
264
        url = request.build_absolute_uri(url)
265
        t = loader.get_template(email_template_name)
266
        c = {'url': url, 'site_name': SITENAME}
267
        from_email = settings.SERVER_EMAIL
268
        send_mail(_(EMAIL_CHANGE_EMAIL_SUBJECT),
269
                  t.render(Context(c)), from_email, [ec.new_email_address])
270
    except (SMTPException, socket.error) as e:
271
        logger.exception(e)
272
        raise ChangeEmailError()
273
    else:
274
        msg = 'Sent change email for %s' % ec.user.email
275
        logger.log(LOGGING_LEVEL, msg)
276

    
277

    
278
def activate(
279
    user,
280
    email_template_name='im/welcome_email.txt',
281
    helpdesk_email_template_name='im/helpdesk_notification.txt',
282
    verify_email=False
283
):
284
    """
285
    Activates the specific user and sends email.
286

287
    Raises SendGreetingError, ValidationError
288
    """
289
    user.is_active = True
290
    if verify_email:
291
        user.email_verified = True
292
    user.save()
293
    send_helpdesk_notification(user, helpdesk_email_template_name)
294
    send_greeting(user, email_template_name)
295

    
296

    
297
def switch_account_to_shibboleth(user, local_user,
298
                                 greeting_template_name='im/welcome_email.txt'):
299
    try:
300
        provider = user.provider
301
    except AttributeError:
302
        return
303
    else:
304
        if not provider == 'shibboleth':
305
            return
306
        user.delete()
307
        local_user.provider = 'shibboleth'
308
        local_user.third_party_identifier = user.third_party_identifier
309
        local_user.save()
310
        send_greeting(local_user, greeting_template_name)
311
        return local_user
312

    
313

    
314
class SendMailError(Exception):
315
    pass
316

    
317

    
318
class SendAdminNotificationError(SendMailError):
319
    def __init__(self):
320
        self.message = _(astakos_messages.ADMIN_NOTIFICATION_SEND_ERR)
321
        super(SendAdminNotificationError, self).__init__()
322

    
323

    
324
class SendVerificationError(SendMailError):
325
    def __init__(self):
326
        self.message = _(astakos_messages.VERIFICATION_SEND_ERR)
327
        super(SendVerificationError, self).__init__()
328

    
329

    
330
class SendInvitationError(SendMailError):
331
    def __init__(self):
332
        self.message = _(astakos_messages.INVITATION_SEND_ERR)
333
        super(SendInvitationError, self).__init__()
334

    
335

    
336
class SendGreetingError(SendMailError):
337
    def __init__(self):
338
        self.message = _(astakos_messages.GREETING_SEND_ERR)
339
        super(SendGreetingError, self).__init__()
340

    
341

    
342
class SendFeedbackError(SendMailError):
343
    def __init__(self):
344
        self.message = _(astakos_messages.FEEDBACK_SEND_ERR)
345
        super(SendFeedbackError, self).__init__()
346

    
347

    
348
class ChangeEmailError(SendMailError):
349
    def __init__(self):
350
        self.message = _(astakos_messages.CHANGE_EMAIL_SEND_ERR)
351
        super(ChangeEmailError, self).__init__()
352

    
353

    
354
class SendNotificationError(SendMailError):
355
    def __init__(self):
356
        self.message = _(astakos_messages.NOTIFICATION_SEND_ERR)
357
        super(SendNotificationError, self).__init__()