1 # Copyright 2011 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
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.
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.
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.
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
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
53 from astakos.im.settings import (DEFAULT_CONTACT_EMAIL, SITENAME, BASEURL,
56 from astakos.im.models import AstakosUser
58 logger = logging.getLogger(__name__)
61 def logged(func, msg):
63 def with_logging(*args, **kwargs):
66 if len(args) == 2 and isinstance(args[1], AstakosUser):
68 elif len(args) == 1 and isinstance(args[0], HttpRequest):
71 email = user.email if user and user.is_authenticated() else ''
72 r = func(*args, **kwargs)
74 logger.log(LOGGING_LEVEL, msg % email)
78 login = logged(auth_login, '%s logged in.')
79 logout = logged(auth_logout, '%s logged out.')
82 def send_verification(user, template_name='im/activation_email.txt'):
84 Send email to user to verify his/her email and activate his/her account.
86 Raises SendVerificationError
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, {
95 'site_name': SITENAME,
96 'support': DEFAULT_CONTACT_EMAIL})
97 sender = settings.SERVER_EMAIL
99 send_mail('%s alpha2 testing account activation is needed' %
100 SITENAME, message, sender, [user.email])
101 except (SMTPException, socket.error) as e:
103 raise SendVerificationError()
105 msg = 'Sent activation %s' % user.email
106 logger.log(LOGGING_LEVEL, msg)
109 def send_activation(user, template_name='im/activation_email.txt'):
110 send_verification(user, template_name)
111 user.activation_sent = datetime.now()
115 def send_admin_notification(template_name,
117 subject='alpha2 testing notification',
120 Send notification email to settings.ADMINS.
122 Raises SendNotificationError
124 if not settings.ADMINS:
126 dictionary = dictionary or {}
127 message = render_to_string(template_name, dictionary)
128 sender = settings.SERVER_EMAIL
130 send_mail(subject, message, sender, [i[1] for i in settings.ADMINS])
131 except (SMTPException, socket.error) as e:
133 raise SendNotificationError()
135 msg = 'Sent admin notification for user %s' % dictionary
136 logger.log(LOGGING_LEVEL, msg)
139 def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
141 Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
143 Raises SendNotificationError
145 if not DEFAULT_CONTACT_EMAIL:
147 message = render_to_string(
151 sender = settings.SERVER_EMAIL
154 '%s alpha2 testing account activated' % SITENAME,
157 [DEFAULT_CONTACT_EMAIL]
159 except (SMTPException, socket.error) as e:
161 raise SendNotificationError()
163 msg = 'Sent helpdesk admin notification for %s' % user.email
164 logger.log(LOGGING_LEVEL, msg)
167 def send_invitation(invitation, template_name='im/invitation.txt'):
169 Send invitation email.
171 Raises SendInvitationError
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,
179 'site_name': SITENAME,
180 'support': DEFAULT_CONTACT_EMAIL})
181 sender = settings.SERVER_EMAIL
183 send_mail(subject, message, sender, [invitation.username])
184 except (SMTPException, socket.error) as e:
186 raise SendInvitationError()
188 msg = 'Sent invitation %s' % invitation
189 logger.log(LOGGING_LEVEL, msg)
192 def send_greeting(user, email_template_name='im/welcome_email.txt'):
196 Raises SMTPException, socket.error
198 subject = _(GREETING_EMAIL_SUBJECT)
199 message = render_to_string(email_template_name, {
201 'url': urljoin(BASEURL, reverse('index')),
203 'site_name': SITENAME,
204 'support': DEFAULT_CONTACT_EMAIL})
205 sender = settings.SERVER_EMAIL
207 send_mail(subject, message, sender, [user.email])
208 except (SMTPException, socket.error) as e:
210 raise SendGreetingError()
212 msg = 'Sent greeting %s' % user.email
213 logger.log(LOGGING_LEVEL, msg)
216 def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
217 subject = _(FEEDBACK_EMAIL_SUBJECT)
218 from_email = user.email
219 recipient_list = [DEFAULT_CONTACT_EMAIL]
220 content = render_to_string(email_template_name, {
225 send_mail(subject, content, from_email, recipient_list)
226 except (SMTPException, socket.error) as e:
228 raise SendFeedbackError()
230 msg = 'Sent feedback from %s' % user.email
231 logger.log(LOGGING_LEVEL, msg)
234 def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
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:
246 raise ChangeEmailError()
248 msg = 'Sent change email for %s' % ec.user.email
249 logger.log(LOGGING_LEVEL, msg)
252 def activate(user, email_template_name='im/welcome_email.txt',
253 helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
255 Activates the specific user and sends email.
257 Raises SendGreetingError, ValidationError
259 user.is_active = True
261 user.email_verified = True
263 send_helpdesk_notification(user, helpdesk_email_template_name)
264 send_greeting(user, email_template_name)
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):
271 if not local_user or not isinstance(user, AstakosUser):
274 if not user.provider == 'shibboleth':
278 local_user.provider = 'shibboleth'
279 local_user.third_party_identifier = user.third_party_identifier
281 send_greeting(local_user, greeting_template_name)
285 def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
287 Send an invitation email and upon success reduces inviter's invitation by one.
289 Raises SendInvitationError
291 invitation.inviter = inviter
293 send_invitation(invitation, email_template_name)
294 inviter.invitations = max(0, inviter.invitations - 1)
298 class SendMailError(Exception):
302 class SendAdminNotificationError(SendMailError):
304 self.message = _('Failed to send notification')
305 super(SendAdminNotificationError, self).__init__()
308 class SendVerificationError(SendMailError):
310 self.message = _('Failed to send verification')
311 super(SendVerificationError, self).__init__()
314 class SendInvitationError(SendMailError):
316 self.message = _('Failed to send invitation')
317 super(SendInvitationError, self).__init__()
320 class SendGreetingError(SendMailError):
322 self.message = _('Failed to send greeting')
323 super(SendGreetingError, self).__init__()
326 class SendFeedbackError(SendMailError):
328 self.message = _('Failed to send feedback')
329 super(SendFeedbackError, self).__init__()
332 class ChangeEmailError(SendMailError):
334 self.message = _('Failed to send change email')
335 super(ChangeEmailError, self).__init__()
338 class SendNotificationError(SendMailError):
340 self.message = _('Failed to send notification email')
341 super(SendNotificationError, self).__init__()