Statistics
| Branch: | Tag: | Revision:

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

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

    
46
from urllib import quote
47
from urlparse import urljoin
48
from smtplib import SMTPException
49
from datetime import datetime
50
from functools import wraps
51

    
52
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, \
53
    SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL, LOGGING_LEVEL
54
from astakos.im.models import AstakosUser
55

    
56
logger = logging.getLogger(__name__)
57

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

    
75
login = logged(auth_login, '%s logged in.')
76
logout = logged(auth_logout, '%s logged out.')
77

    
78
def send_verification(user, template_name='im/activation_email.txt'):
79
    """
80
    Send email to user to verify his/her email and activate his/her account.
81
    
82
    Raises SendVerificationError
83
    """
84
    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('activate')),
85
                                    quote(user.auth_token),
86
                                    quote(urljoin(BASEURL, reverse('index'))))
87
    message = render_to_string(template_name, {
88
            'user': user,
89
            'url': url,
90
            'baseurl': BASEURL,
91
            'site_name': SITENAME,
92
            'support': DEFAULT_CONTACT_EMAIL})
93
    sender = DEFAULT_FROM_EMAIL
94
    try:
95
        send_mail('%s alpha2 testing account activation is needed' % SITENAME, message, sender, [user.email])
96
    except (SMTPException, socket.error) as e:
97
        logger.exception(e)
98
        raise SendVerificationError()
99
    else:
100
        msg = 'Sent activation %s' % user.email
101
        logger.log(LOGGING_LEVEL, msg)
102

    
103
def send_activation(user, template_name='im/activation_email.txt'):
104
    send_verification(user, template_name)
105
    user.activation_sent = datetime.now()
106
    user.save()
107

    
108
def send_admin_notification(template_name,
109
    dictionary=None,
110
    subject='alpha2 testing notification',
111
):
112
    """
113
    Send notification email to DEFAULT_ADMIN_EMAIL.
114
    
115
    Raises SendNotificationError
116
    """
117
    if not DEFAULT_ADMIN_EMAIL:
118
        return
119
    dictionary = dictionary or {}
120
    message = render_to_string(template_name, dictionary)
121
    sender = DEFAULT_FROM_EMAIL
122
    try:
123
        send_mail(subject, message, sender, [DEFAULT_ADMIN_EMAIL])
124
    except (SMTPException, socket.error) as e:
125
        logger.exception(e)
126
        raise SendNotificationError()
127
    else:
128
        msg = 'Sent admin notification for user %s' % dictionary
129
        logger.log(LOGGING_LEVEL, msg)
130

    
131
def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
132
    """
133
    Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
134
    
135
    Raises SendNotificationError
136
    """
137
    if not DEFAULT_CONTACT_EMAIL:
138
        return
139
    message = render_to_string(
140
        template_name,
141
        {'user': user}
142
    )
143
    sender = DEFAULT_FROM_EMAIL
144
    try:
145
        send_mail(
146
            '%s alpha2 testing account activated' % SITENAME,
147
            message,
148
            sender,
149
            [DEFAULT_CONTACT_EMAIL]
150
        )
151
    except (SMTPException, socket.error) as e:
152
        logger.exception(e)
153
        raise SendNotificationError()
154
    else:
155
        msg = 'Sent helpdesk admin notification for %s' % user.email
156
        logger.log(LOGGING_LEVEL, msg)
157

    
158
def send_invitation(invitation, template_name='im/invitation.txt'):
159
    """
160
    Send invitation email.
161
    
162
    Raises SendInvitationError
163
    """
164
    subject = _('Invitation to %s alpha2 testing' % SITENAME)
165
    url = '%s?code=%d' % (urljoin(BASEURL, reverse('index')), invitation.code)
166
    message = render_to_string(template_name, {
167
                'invitation': invitation,
168
                'url': url,
169
                'baseurl': BASEURL,
170
                'site_name': SITENAME,
171
                'support': DEFAULT_CONTACT_EMAIL})
172
    sender = DEFAULT_FROM_EMAIL
173
    try:
174
        send_mail(subject, message, sender, [invitation.username])
175
    except (SMTPException, socket.error) as e:
176
        logger.exception(e)
177
        raise SendInvitationError()
178
    else:
179
        msg = 'Sent invitation %s' % invitation
180
        logger.log(LOGGING_LEVEL, msg)
181

    
182
def send_greeting(user, email_template_name='im/welcome_email.txt'):
183
    """
184
    Send welcome email.
185
    
186
    Raises SMTPException, socket.error
187
    """
188
    subject = _('Welcome to %s alpha2 testing' % SITENAME)
189
    message = render_to_string(email_template_name, {
190
                'user': user,
191
                'url': urljoin(BASEURL, reverse('index')),
192
                'baseurl': BASEURL,
193
                'site_name': SITENAME,
194
                'support': DEFAULT_CONTACT_EMAIL})
195
    sender = DEFAULT_FROM_EMAIL
196
    try:
197
        send_mail(subject, message, sender, [user.email])
198
    except (SMTPException, socket.error) as e:
199
        logger.exception(e)
200
        raise SendGreetingError()
201
    else:
202
        msg = 'Sent greeting %s' % user.email
203
        logger.log(LOGGING_LEVEL, msg)
204

    
205
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
206
    subject = _("Feedback from %s alpha2 testing" % SITENAME)
207
    from_email = user.email
208
    recipient_list = [DEFAULT_CONTACT_EMAIL]
209
    content = render_to_string(email_template_name, {
210
        'message': msg,
211
        'data': data,
212
        'user': user})
213
    try:
214
        send_mail(subject, content, from_email, recipient_list)
215
    except (SMTPException, socket.error) as e:
216
        logger.exception(e)
217
        raise SendFeedbackError()
218
    else:
219
        msg = 'Sent feedback from %s' % user.email
220
        logger.log(LOGGING_LEVEL, msg)
221

    
222
def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
223
    try:
224
        url = reverse('email_change_confirm',
225
                      kwargs={'activation_key':ec.activation_key})
226
        url = request.build_absolute_uri(url)
227
        t = loader.get_template(email_template_name)
228
        c = {'url': url, 'site_name': SITENAME}
229
        from_email = DEFAULT_FROM_EMAIL
230
        send_mail(_("Email change on %s alpha2 testing") % SITENAME,
231
            t.render(Context(c)), from_email, [ec.new_email_address])
232
    except (SMTPException, socket.error) as e:
233
        logger.exception(e)
234
        raise ChangeEmailError()
235
    else:
236
        msg = 'Sent change email for %s' % ec.user.email
237
        logger.log(LOGGING_LEVEL, msg)
238

    
239
def activate(user, email_template_name='im/welcome_email.txt',
240
                helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
241
    """
242
    Activates the specific user and sends email.
243
    
244
    Raises SendGreetingError, ValidationError
245
    """
246
    user.is_active = True
247
    if verify_email:
248
        user.email_verified = True
249
    user.save()
250
    send_helpdesk_notification(user, helpdesk_email_template_name)
251
    send_greeting(user, email_template_name)
252

    
253
def switch_account_to_shibboleth(user, local_user, greeting_template_name='im/welcome_email.txt'):
254
    if not user or not isinstance(user, AstakosUser):
255
        return
256
    
257
    if not local_user or not isinstance(user, AstakosUser):
258
        return
259
    
260
    if not user.provider == 'shibboleth':
261
        return
262
    
263
    user.delete()
264
    local_user.provider = 'shibboleth'
265
    local_user.third_party_identifier = user.third_party_identifier
266
    local_user.save()
267
    send_greeting(local_user, greeting_template_name)
268
    return local_user
269

    
270
def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
271
    """
272
    Send an invitation email and upon success reduces inviter's invitation by one.
273
    
274
    Raises SendInvitationError
275
    """
276
    invitation.inviter = inviter
277
    invitation.save()
278
    send_invitation(invitation, email_template_name)
279
    inviter.invitations = max(0, inviter.invitations - 1)
280
    inviter.save()
281

    
282
def set_user_credibility(email, has_credits):
283
    try:
284
        user = AstakosUser.objects.get(email=email, is_active=True)
285
        user.has_credits = has_credits
286
        user.save()
287
    except AstakosUser.DoesNotExist, e:
288
        logger.exception(e)
289
    except ValidationError, e:
290
        logger.exception(e)
291

    
292
class SendMailError(Exception):
293
    pass
294

    
295
class SendAdminNotificationError(SendMailError):
296
    def __init__(self):
297
        self.message = _('Failed to send notification')
298
        super(SendAdminNotificationError, self).__init__()
299

    
300
class SendVerificationError(SendMailError):
301
    def __init__(self):
302
        self.message = _('Failed to send verification')
303
        super(SendVerificationError, self).__init__()
304

    
305
class SendInvitationError(SendMailError):
306
    def __init__(self):
307
        self.message = _('Failed to send invitation')
308
        super(SendInvitationError, self).__init__()
309

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

    
315
class SendFeedbackError(SendMailError):
316
    def __init__(self):
317
        self.message = _('Failed to send feedback')
318
        super(SendFeedbackError, self).__init__()
319

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

    
325
class SendNotificationError(SendMailError):
326
    def __init__(self):
327
        self.message = _('Failed to send notification email')
328
        super(SendNotificationError, self).__init__()