Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / functions.py @ 7233d542

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
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

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

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

    
94

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

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

    
120

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

    
126

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

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

    
150

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

    
156

    
157
def send_group_creation_notification(template_name, dictionary=None):
158
    group = dictionary.get('group', astakos.im.models.AstakosGroup())
159
    subject = _(GROUP_CREATION_SUBJECT) % {'group':group.get('name', '')}
160
    return _send_admin_notification(template_name, dictionary, subject=subject)
161

    
162

    
163
def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
164
    """
165
    Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
166

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

    
187

    
188
def send_invitation(invitation, template_name='im/invitation.txt'):
189
    """
190
    Send invitation email.
191

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

    
214

    
215
def send_greeting(user, email_template_name='im/welcome_email.txt'):
216
    """
217
    Send welcome email.
218

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

    
238

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

    
256

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

    
274

    
275
def activate(user, email_template_name='im/welcome_email.txt',
276
             helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
277
    """
278
    Activates the specific user and sends email.
279

280
    Raises SendGreetingError, ValidationError
281
    """
282
    user.is_active = True
283
    if verify_email:
284
        user.email_verified = True
285
    user.save()
286
    send_helpdesk_notification(user, helpdesk_email_template_name)
287
    send_greeting(user, email_template_name)
288

    
289

    
290
def switch_account_to_shibboleth(user, local_user,
291
                                 greeting_template_name='im/welcome_email.txt'):
292
    try:
293
        provider = user.provider
294
    except AttributeError:
295
        return
296
    else:
297
        if not provider == 'shibboleth':
298
            return
299
        user.delete()
300
        local_user.provider = 'shibboleth'
301
        local_user.third_party_identifier = user.third_party_identifier
302
        local_user.save()
303
        send_greeting(local_user, greeting_template_name)
304
        return local_user
305

    
306

    
307
class SendMailError(Exception):
308
    pass
309

    
310

    
311
class SendAdminNotificationError(SendMailError):
312
    def __init__(self):
313
        self.message = _(astakos_messages.ADMIN_NOTIFICATION_SEND_ERR)
314
        super(SendAdminNotificationError, self).__init__()
315

    
316

    
317
class SendVerificationError(SendMailError):
318
    def __init__(self):
319
        self.message = _(astakos_messages.VERIFICATION_SEND_ERR)
320
        super(SendVerificationError, self).__init__()
321

    
322

    
323
class SendInvitationError(SendMailError):
324
    def __init__(self):
325
        self.message = _(astakos_messages.INVITATION_SEND_ERR)
326
        super(SendInvitationError, self).__init__()
327

    
328

    
329
class SendGreetingError(SendMailError):
330
    def __init__(self):
331
        self.message = _(astakos_messages.GREETING_SEND_ERR)
332
        super(SendGreetingError, self).__init__()
333

    
334

    
335
class SendFeedbackError(SendMailError):
336
    def __init__(self):
337
        self.message = _(astakos_messages.FEEDBACK_SEND_ERR)
338
        super(SendFeedbackError, self).__init__()
339

    
340

    
341
class ChangeEmailError(SendMailError):
342
    def __init__(self):
343
        self.message = self.message = _(astakos_messages.CHANGE_EMAIL_SEND_ERR)
344
        super(ChangeEmailError, self).__init__()
345

    
346

    
347
class SendNotificationError(SendMailError):
348
    def __init__(self):
349
        self.message = _(astakos_messages.NOTIFICATION_SEND_ERR)
350
        super(SendNotificationError, self).__init__()