Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (11.3 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
    VERIFICATION_EMAIL_SUBJECT, ADMIN_NOTIFICATION_EMAIL_SUBJECT, \
55
    HELPDESK_NOTIFICATION_EMAIL_SUBJECT, INVITATION_EMAIL_SUBJECT, \
56
    GREETING_EMAIL_SUBJECT, FEEDBACK_EMAIL_SUBJECT, EMAIL_CHANGE_EMAIL_SUBJECT
57
from astakos.im.models import Invitation, AstakosUser
58

    
59
logger = logging.getLogger(__name__)
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
def send_verification(user, template_name='im/activation_email.txt'):
82
    """
83
    Send email to user to verify his/her email and activate his/her account.
84
    
85
    Raises SendVerificationError
86
    """
87
    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('astakos.im.views.activate')),
88
                                    quote(user.auth_token),
89
                                    quote(urljoin(BASEURL, reverse('astakos.im.views.index'))))
90
    message = render_to_string(template_name, {
91
            'user': user,
92
            'url': url,
93
            'baseurl': BASEURL,
94
            'site_name': SITENAME,
95
            'support': DEFAULT_CONTACT_EMAIL})
96
    sender = DEFAULT_FROM_EMAIL
97
    try:
98
        send_mail(_(VERIFICATION_EMAIL_SUBJECT), message, sender, [user.email])
99
    except (SMTPException, socket.error) as e:
100
        logger.exception(e)
101
        raise SendVerificationError()
102
    else:
103
        msg = 'Sent activation %s' % user.email
104
        logger._log(LOGGING_LEVEL, msg, [])
105

    
106
def send_activation(user, template_name='im/activation_email.txt'):
107
    send_verification(user, template_name)
108
    user.activation_sent = datetime.now()
109
    user.save()
110

    
111
def send_admin_notification(user, template_name='im/admin_notification.txt'):
112
    """
113
    Send email to DEFAULT_ADMIN_EMAIL to notify for a new user registration.
114
    
115
    Raises SendNotificationError
116
    """
117
    if not DEFAULT_ADMIN_EMAIL:
118
        return
119
    message = render_to_string(template_name, {
120
            'user': user,
121
            'baseurl': BASEURL,
122
            'site_name': SITENAME,
123
            'support': DEFAULT_CONTACT_EMAIL})
124
    sender = DEFAULT_FROM_EMAIL
125
    try:
126
        send_mail(_(ADMIN_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email}, message, sender, [DEFAULT_ADMIN_EMAIL])
127
    except (SMTPException, socket.error) as e:
128
        logger.exception(e)
129
        raise SendNotificationError()
130
    else:
131
        msg = 'Sent admin notification for user %s' % user.email
132
        logger._log(LOGGING_LEVEL, msg, [])
133

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

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

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

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

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

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

    
252
def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
253
    """
254
    Send an invitation email and upon success reduces inviter's invitation by one.
255
    
256
    Raises SendInvitationError
257
    """
258
    invitation.inviter = inviter
259
    invitation.save()
260
    send_invitation(invitation, email_template_name)
261
    inviter.invitations = max(0, inviter.invitations - 1)
262
    inviter.save()
263

    
264
def set_user_credibility(email, has_credits):
265
    try:
266
        user = AstakosUser.objects.get(email=email, is_active=True)
267
        user.has_credits = has_credits
268
        user.save()
269
    except AstakosUser.DoesNotExist, e:
270
        logger.exception(e)
271
    except ValidationError, e:
272
        logger.exception(e)
273

    
274
class SendMailError(Exception):
275
    pass
276

    
277
class SendAdminNotificationError(SendMailError):
278
    def __init__(self):
279
        self.message = _('Failed to send notification')
280
        super(SendAdminNotificationError, self).__init__()
281

    
282
class SendVerificationError(SendMailError):
283
    def __init__(self):
284
        self.message = _('Failed to send verification')
285
        super(SendVerificationError, self).__init__()
286

    
287
class SendInvitationError(SendMailError):
288
    def __init__(self):
289
        self.message = _('Failed to send invitation')
290
        super(SendInvitationError, self).__init__()
291

    
292
class SendGreetingError(SendMailError):
293
    def __init__(self):
294
        self.message = _('Failed to send greeting')
295
        super(SendGreetingError, self).__init__()
296

    
297
class SendFeedbackError(SendMailError):
298
    def __init__(self):
299
        self.message = _('Failed to send feedback')
300
        super(SendFeedbackError, self).__init__()
301

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

    
307
class SendNotificationError(SendMailError):
308
    def __init__(self):
309
        self.message = _('Failed to send notification email')
310
        super(SendNotificationError, self).__init__()