Statistics
| Branch: | Tag: | Revision:

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

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 (
44
    login as auth_login,
45
    logout as auth_logout,
46
    SESSION_KEY
47
)
48
from django.http import HttpRequest
49

    
50
from urllib import quote
51
from urlparse import urljoin
52
from smtplib import SMTPException
53
from datetime import datetime
54
from functools import wraps
55

    
56
from astakos.im.settings import (
57
    DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL,
58
    SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL, LOGGING_LEVEL,
59
    VERIFICATION_EMAIL_SUBJECT, ADMIN_NOTIFICATION_EMAIL_SUBJECT,
60
    HELPDESK_NOTIFICATION_EMAIL_SUBJECT, INVITATION_EMAIL_SUBJECT,
61
    GREETING_EMAIL_SUBJECT, FEEDBACK_EMAIL_SUBJECT, EMAIL_CHANGE_EMAIL_SUBJECT
62
)
63
from astakos.im.models import Invitation, AstakosUser, SessionCatalog
64

    
65
logger = logging.getLogger(__name__)
66

    
67
def logged(func, msg):
68
    @wraps(func)
69
    def with_logging(*args, **kwargs):
70
        email = ''
71
        user = None
72
        if len(args) == 2 and isinstance(args[1], AstakosUser):
73
            user = args[1]
74
        elif len(args) == 1 and isinstance(args[0], HttpRequest):
75
            request = args[0]
76
            user = request.user
77
        email = user.email if user and user.is_authenticated() else ''
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
    SessionCatalog(session_key=request.session.session_key, user=user).save()
88

    
89
login = logged(login, '%s logged in.')
90
logout = logged(auth_logout, '%s logged out.')
91

    
92
def send_verification(user, template_name='im/activation_email.txt'):
93
    """
94
    Send email to user to verify his/her email and activate his/her account.
95
    
96
    Raises SendVerificationError
97
    """
98
    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('astakos.im.views.activate')),
99
                                    quote(user.auth_token),
100
                                    quote(urljoin(BASEURL, reverse('astakos.im.views.index'))))
101
    message = render_to_string(template_name, {
102
            'user': user,
103
            'url': url,
104
            'baseurl': BASEURL,
105
            'site_name': SITENAME,
106
            'support': DEFAULT_CONTACT_EMAIL})
107
    sender = DEFAULT_FROM_EMAIL
108
    try:
109
        send_mail(_(VERIFICATION_EMAIL_SUBJECT), message, sender, [user.email])
110
    except (SMTPException, socket.error) as e:
111
        logger.exception(e)
112
        raise SendVerificationError()
113
    else:
114
        msg = 'Sent activation %s' % user.email
115
        logger._log(LOGGING_LEVEL, msg, [])
116

    
117
def send_activation(user, template_name='im/activation_email.txt'):
118
    send_verification(user, template_name)
119
    user.activation_sent = datetime.now()
120
    user.save()
121

    
122
def send_admin_notification(user, template_name='im/admin_notification.txt'):
123
    """
124
    Send email to DEFAULT_ADMIN_EMAIL to notify for a new user registration.
125
    
126
    Raises SendNotificationError
127
    """
128
    if not DEFAULT_ADMIN_EMAIL:
129
        return
130
    message = render_to_string(template_name, {
131
            'user': user,
132
            'baseurl': BASEURL,
133
            'site_name': SITENAME,
134
            'support': DEFAULT_CONTACT_EMAIL})
135
    sender = DEFAULT_FROM_EMAIL
136
    try:
137
        send_mail(_(ADMIN_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email}, message, sender, [DEFAULT_ADMIN_EMAIL])
138
    except (SMTPException, socket.error) as e:
139
        logger.exception(e)
140
        raise SendNotificationError()
141
    else:
142
        msg = 'Sent admin notification for user %s' % user.email
143
        logger._log(LOGGING_LEVEL, msg, [])
144

    
145
def send_helpdesk_notification(user, template_name='im/helpdesk_notification.txt'):
146
    """
147
    Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
148
    
149
    Raises SendNotificationError
150
    """
151
    if not DEFAULT_CONTACT_EMAIL:
152
        return
153
    message = render_to_string(template_name, {
154
            'user': user,
155
            'baseurl': BASEURL,
156
            'site_name': SITENAME,
157
            'support': DEFAULT_ADMIN_EMAIL})
158
    sender = DEFAULT_FROM_EMAIL
159
    try:
160
        send_mail(_(HELPDESK_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email}, message, sender, [DEFAULT_CONTACT_EMAIL])
161
    except (SMTPException, socket.error) as e:
162
        logger.exception(e)
163
        raise SendNotificationError()
164
    else:
165
        msg = 'Sent helpdesk admin notification for user %s' % user.email
166
        logger._log(LOGGING_LEVEL, msg, [])
167

    
168
def send_invitation(invitation, template_name='im/invitation.txt'):
169
    """
170
    Send invitation email.
171
    
172
    Raises SendInvitationError
173
    """
174
    subject = _(INVITATION_EMAIL_SUBJECT)
175
    url = '%s?code=%d' % (urljoin(BASEURL, reverse('astakos.im.views.index')), invitation.code)
176
    message = render_to_string('im/invitation.txt', {
177
                'invitation': invitation,
178
                'url': url,
179
                'baseurl': BASEURL,
180
                'site_name': SITENAME,
181
                'support': DEFAULT_CONTACT_EMAIL})
182
    sender = DEFAULT_FROM_EMAIL
183
    try:
184
        send_mail(subject, message, sender, [invitation.username])
185
    except (SMTPException, socket.error) as e:
186
        logger.exception(e)
187
        raise SendInvitationError()
188
    else:
189
        msg = 'Sent invitation %s' % invitation
190
        logger._log(LOGGING_LEVEL, msg, [])
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 = _(GREETING_EMAIL_SUBJECT)
199
    message = render_to_string(email_template_name, {
200
                'user': user,
201
                'url': urljoin(BASEURL, reverse('astakos.im.views.index')),
202
                'baseurl': BASEURL,
203
                'site_name': SITENAME,
204
                'support': DEFAULT_CONTACT_EMAIL})
205
    sender = DEFAULT_FROM_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
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
216
    subject = _(FEEDBACK_EMAIL_SUBJECT)
217
    from_email = user.email
218
    recipient_list = [DEFAULT_CONTACT_EMAIL]
219
    content = render_to_string(email_template_name, {
220
        'message': msg,
221
        'data': data,
222
        'user': user})
223
    try:
224
        send_mail(subject, content, from_email, recipient_list)
225
    except (SMTPException, socket.error) as e:
226
        logger.exception(e)
227
        raise SendFeedbackError()
228
    else:
229
        msg = 'Sent feedback from %s' % user.email
230
        logger._log(LOGGING_LEVEL, msg, [])
231

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

    
249
def activate(user, email_template_name='im/welcome_email.txt',
250
                helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
251
    """
252
    Activates the specific user and sends email.
253
    
254
    Raises SendGreetingError, ValidationError
255
    """
256
    user.is_active = True
257
    if verify_email:
258
        user.email_verified = True
259
    user.save()
260
    send_helpdesk_notification(user, helpdesk_email_template_name)
261
    send_greeting(user, email_template_name)
262

    
263
def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
264
    """
265
    Send an invitation email and upon success reduces inviter's invitation by one.
266
    
267
    Raises SendInvitationError
268
    """
269
    invitation.inviter = inviter
270
    invitation.save()
271
    send_invitation(invitation, email_template_name)
272
    inviter.invitations = max(0, inviter.invitations - 1)
273
    inviter.save()
274

    
275
def set_user_credibility(email, has_credits):
276
    try:
277
        user = AstakosUser.objects.get(email=email, is_active=True)
278
        user.has_credits = has_credits
279
        user.save()
280
    except AstakosUser.DoesNotExist, e:
281
        logger.exception(e)
282
    except ValidationError, e:
283
        logger.exception(e)
284

    
285
class SendMailError(Exception):
286
    pass
287

    
288
class SendAdminNotificationError(SendMailError):
289
    def __init__(self):
290
        self.message = _('Failed to send notification')
291
        super(SendAdminNotificationError, self).__init__()
292

    
293
class SendVerificationError(SendMailError):
294
    def __init__(self):
295
        self.message = _('Failed to send verification')
296
        super(SendVerificationError, self).__init__()
297

    
298
class SendInvitationError(SendMailError):
299
    def __init__(self):
300
        self.message = _('Failed to send invitation')
301
        super(SendInvitationError, self).__init__()
302

    
303
class SendGreetingError(SendMailError):
304
    def __init__(self):
305
        self.message = _('Failed to send greeting')
306
        super(SendGreetingError, self).__init__()
307

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

    
313
class ChangeEmailError(SendMailError):
314
    def __init__(self):
315
        self.message = _('Failed to send change email')
316
        super(ChangeEmailError, self).__init__()
317

    
318
class SendNotificationError(SendMailError):
319
    def __init__(self):
320
        self.message = _('Failed to send notification email')
321
        super(SendNotificationError, self).__init__()