Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / functions.py @ 5ce3ce4f

History | View | Annotate | Download (11.4 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

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

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

    
81

    
82
def send_verification(user, template_name='im/activation_email.txt'):
83
    """
84
    Send email to user to verify his/her email and activate his/her account.
85

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

    
108

    
109
def send_activation(user, template_name='im/activation_email.txt'):
110
    send_verification(user, template_name)
111
    user.activation_sent = datetime.now()
112
    user.save()
113

    
114

    
115
def send_admin_notification(template_name,
116
                            dictionary=None,
117
                            subject='alpha2 testing notification',
118
                            ):
119
    """
120
    Send notification email to settings.ADMINS.
121

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

    
138

    
139
def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
140
    """
141
    Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
142

143
    Raises SendNotificationError
144
    """
145
    if not DEFAULT_CONTACT_EMAIL:
146
        return
147
    message = render_to_string(
148
        template_name,
149
        {'user': user}
150
    )
151
    sender = settings.SERVER_EMAIL
152
    try:
153
        send_mail(
154
            '%s alpha2 testing account activated' % SITENAME,
155
            message,
156
            sender,
157
            [DEFAULT_CONTACT_EMAIL]
158
        )
159
    except (SMTPException, socket.error) as e:
160
        logger.exception(e)
161
        raise SendNotificationError()
162
    else:
163
        msg = 'Sent helpdesk admin notification for %s' % user.email
164
        logger.log(LOGGING_LEVEL, msg)
165

    
166

    
167
def send_invitation(invitation, template_name='im/invitation.txt'):
168
    """
169
    Send invitation email.
170

171
    Raises SendInvitationError
172
    """
173
    subject = _('Invitation to %s alpha2 testing' % SITENAME)
174
    url = '%s?code=%d' % (urljoin(BASEURL, reverse('index')), invitation.code)
175
    message = render_to_string(template_name, {
176
                               'invitation': invitation,
177
                               'url': url,
178
                               'baseurl': BASEURL,
179
                               'site_name': SITENAME,
180
                               'support': DEFAULT_CONTACT_EMAIL})
181
    sender = settings.SERVER_EMAIL
182
    try:
183
        send_mail(subject, message, sender, [invitation.username])
184
    except (SMTPException, socket.error) as e:
185
        logger.exception(e)
186
        raise SendInvitationError()
187
    else:
188
        msg = 'Sent invitation %s' % invitation
189
        logger.log(LOGGING_LEVEL, msg)
190

    
191

    
192
def send_greeting(user, email_template_name='im/welcome_email.txt'):
193
    """
194
    Send welcome email.
195

196
    Raises SMTPException, socket.error
197
    """
198
    subject = _('Welcome to %s alpha2 testing' % SITENAME)
199
    message = render_to_string(email_template_name, {
200
                               'user': user,
201
                               'url': urljoin(BASEURL, reverse('index')),
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, [user.email])
208
    except (SMTPException, socket.error) as e:
209
        logger.exception(e)
210
        raise SendGreetingError()
211
    else:
212
        msg = 'Sent greeting %s' % user.email
213
        logger.log(LOGGING_LEVEL, msg)
214

    
215

    
216
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
217
    subject = _("Feedback from %s alpha2 testing" % SITENAME)
218
    from_email = user.email
219
    recipient_list = [DEFAULT_CONTACT_EMAIL]
220
    content = render_to_string(email_template_name, {
221
        'message': msg,
222
        'data': data,
223
        'user': user})
224
    try:
225
        send_mail(subject, content, from_email, recipient_list)
226
    except (SMTPException, socket.error) as e:
227
        logger.exception(e)
228
        raise SendFeedbackError()
229
    else:
230
        msg = 'Sent feedback from %s' % user.email
231
        logger.log(LOGGING_LEVEL, msg)
232

    
233

    
234
def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
235
    try:
236
        url = reverse('email_change_confirm',
237
                      kwargs={'activation_key': ec.activation_key})
238
        url = request.build_absolute_uri(url)
239
        t = loader.get_template(email_template_name)
240
        c = {'url': url, 'site_name': SITENAME}
241
        from_email = settings.SERVER_EMAIL
242
        send_mail(_("Email change on %s alpha2 testing") % SITENAME,
243
                  t.render(Context(c)), from_email, [ec.new_email_address])
244
    except (SMTPException, socket.error) as e:
245
        logger.exception(e)
246
        raise ChangeEmailError()
247
    else:
248
        msg = 'Sent change email for %s' % ec.user.email
249
        logger.log(LOGGING_LEVEL, msg)
250

    
251

    
252
def activate(user, email_template_name='im/welcome_email.txt',
253
             helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
254
    """
255
    Activates the specific user and sends email.
256

257
    Raises SendGreetingError, ValidationError
258
    """
259
    user.is_active = True
260
    if verify_email:
261
        user.email_verified = True
262
    user.save()
263
    send_helpdesk_notification(user, helpdesk_email_template_name)
264
    send_greeting(user, email_template_name)
265

    
266

    
267
def switch_account_to_shibboleth(user, local_user, greeting_template_name='im/welcome_email.txt'):
268
    if not user or not isinstance(user, AstakosUser):
269
        return
270

    
271
    if not local_user or not isinstance(user, AstakosUser):
272
        return
273

    
274
    if not user.provider == 'shibboleth':
275
        return
276

    
277
    user.delete()
278
    local_user.provider = 'shibboleth'
279
    local_user.third_party_identifier = user.third_party_identifier
280
    local_user.save()
281
    send_greeting(local_user, greeting_template_name)
282
    return local_user
283

    
284

    
285
def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
286
    """
287
    Send an invitation email and upon success reduces inviter's invitation by one.
288

289
    Raises SendInvitationError
290
    """
291
    invitation.inviter = inviter
292
    invitation.save()
293
    send_invitation(invitation, email_template_name)
294
    inviter.invitations = max(0, inviter.invitations - 1)
295
    inviter.save()
296

    
297

    
298
class SendMailError(Exception):
299
    pass
300

    
301

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

    
307

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

    
313

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

    
319

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

    
325

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

    
331

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

    
337

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