Statistics
| Branch: | Tag: | Revision:

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

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
    user.email_verified = True
291
    if not user.activation_sent:
292
        user.activation_sent = datetime.now()
293
    user.save()
294
    send_helpdesk_notification(user, helpdesk_email_template_name)
295
    send_greeting(user, email_template_name)
296

    
297

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

    
314

    
315
class SendMailError(Exception):
316
    pass
317

    
318

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

    
324

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

    
330

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

    
336

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

    
342

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

    
348

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

    
354

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