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
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
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 Invitation, AstakosUser
56 logger = logging.getLogger(__name__)
58 def logged(func, msg):
60 def with_logging(*args, **kwargs):
63 if len(args) == 2 and isinstance(args[1], AstakosUser):
65 elif len(args) == 1 and isinstance(args[0], HttpRequest):
68 email = user.email if user and user.is_authenticated() else ''
69 r = func(*args, **kwargs)
71 logger._log(LOGGING_LEVEL, msg % email, [])
75 login = logged(auth_login, '%s logged in.')
76 logout = logged(auth_logout, '%s logged out.')
78 def send_verification(user, template_name='im/activation_email.txt'):
80 Send email to user to verify his/her email and activate his/her account.
82 Raises SendVerificationError
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, {
91 'site_name': SITENAME,
92 'support': DEFAULT_CONTACT_EMAIL})
93 sender = DEFAULT_FROM_EMAIL
95 send_mail('%s alpha2 testing account activation is needed' % SITENAME, message, sender, [user.email])
96 except (SMTPException, socket.error) as e:
98 raise SendVerificationError()
100 msg = 'Sent activation %s' % user.email
101 logger._log(LOGGING_LEVEL, msg, [])
103 def send_activation(user, template_name='im/activation_email.txt'):
104 send_verification(user, template_name)
105 user.activation_sent = datetime.now()
108 def send_admin_notification(template_name,
110 subject='alpha2 testing notification',
113 Send notification email to DEFAULT_ADMIN_EMAIL.
115 Raises SendNotificationError
117 if not DEFAULT_ADMIN_EMAIL:
119 message = render_to_string(template_name, dictionary)
120 sender = DEFAULT_FROM_EMAIL
122 send_mail(subject, message, sender, [DEFAULT_ADMIN_EMAIL])
123 except (SMTPException, socket.error) as e:
125 raise SendNotificationError()
127 msg = 'Sent admin notification for user %s' % dictionary
128 logger._log(LOGGING_LEVEL, msg, [])
130 def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
132 Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
134 Raises SendNotificationError
136 if not DEFAULT_CONTACT_EMAIL:
138 message = render_to_string(
142 sender = DEFAULT_FROM_EMAIL
145 '%s alpha2 testing account activated' % SITENAME,
148 [DEFAULT_CONTACT_EMAIL]
150 except (SMTPException, socket.error) as e:
152 raise SendNotificationError()
154 msg = 'Sent helpdesk admin notification for %s' % user.email
155 logger._log(LOGGING_LEVEL, msg, [])
157 def send_invitation(invitation, template_name='im/invitation.txt'):
159 Send invitation email.
161 Raises SendInvitationError
163 subject = _('Invitation to %s alpha2 testing' % SITENAME)
164 url = '%s?code=%d' % (urljoin(BASEURL, reverse('index')), invitation.code)
165 message = render_to_string('im/invitation.txt', {
166 'invitation': invitation,
169 'site_name': SITENAME,
170 'support': DEFAULT_CONTACT_EMAIL})
171 sender = DEFAULT_FROM_EMAIL
173 send_mail(subject, message, sender, [invitation.username])
174 except (SMTPException, socket.error) as e:
176 raise SendInvitationError()
178 msg = 'Sent invitation %s' % invitation
179 logger._log(LOGGING_LEVEL, msg, [])
181 def send_greeting(user, email_template_name='im/welcome_email.txt'):
185 Raises SMTPException, socket.error
187 subject = _('Welcome to %s alpha2 testing' % SITENAME)
188 message = render_to_string(email_template_name, {
190 'url': urljoin(BASEURL, reverse('index')),
192 'site_name': SITENAME,
193 'support': DEFAULT_CONTACT_EMAIL})
194 sender = DEFAULT_FROM_EMAIL
196 send_mail(subject, message, sender, [user.email])
197 except (SMTPException, socket.error) as e:
199 raise SendGreetingError()
201 msg = 'Sent greeting %s' % user.email
202 logger._log(LOGGING_LEVEL, msg, [])
204 def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
205 subject = _("Feedback from %s alpha2 testing" % SITENAME)
206 from_email = user.email
207 recipient_list = [DEFAULT_CONTACT_EMAIL]
208 content = render_to_string(email_template_name, {
213 send_mail(subject, content, from_email, recipient_list)
214 except (SMTPException, socket.error) as e:
216 raise SendFeedbackError()
218 msg = 'Sent feedback from %s' % user.email
219 logger._log(LOGGING_LEVEL, msg, [])
221 def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
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 on %s alpha2 testing") % SITENAME,
230 t.render(Context(c)), from_email, [ec.new_email_address])
231 except (SMTPException, socket.error) as e:
233 raise ChangeEmailError()
235 msg = 'Sent change email for %s' % ec.user.email
236 logger._log(LOGGING_LEVEL, msg, [])
238 def activate(user, email_template_name='im/welcome_email.txt',
239 helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
241 Activates the specific user and sends email.
243 Raises SendGreetingError, ValidationError
245 user.is_active = True
247 user.email_verified = True
249 send_helpdesk_notification(user, helpdesk_email_template_name)
250 send_greeting(user, email_template_name)
252 def switch_account_to_shibboleth(user, local_user, greeting_template_name='im/welcome_email.txt'):
253 if not user or not isinstance(user, AstakosUser):
256 if not local_user or not isinstance(user, AstakosUser):
259 if not user.provider == 'shibboleth':
263 local_user.provider = 'shibboleth'
264 local_user.third_party_identifier = user.third_party_identifier
266 send_greeting(local_user, greeting_template_name)
269 def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
271 Send an invitation email and upon success reduces inviter's invitation by one.
273 Raises SendInvitationError
275 invitation.inviter = inviter
277 send_invitation(invitation, email_template_name)
278 inviter.invitations = max(0, inviter.invitations - 1)
281 def set_user_credibility(email, has_credits):
283 user = AstakosUser.objects.get(email=email, is_active=True)
284 user.has_credits = has_credits
286 except AstakosUser.DoesNotExist, e:
288 except ValidationError, e:
291 class SendMailError(Exception):
294 class SendAdminNotificationError(SendMailError):
296 self.message = _('Failed to send notification')
297 super(SendAdminNotificationError, self).__init__()
299 class SendVerificationError(SendMailError):
301 self.message = _('Failed to send verification')
302 super(SendVerificationError, self).__init__()
304 class SendInvitationError(SendMailError):
306 self.message = _('Failed to send invitation')
307 super(SendInvitationError, self).__init__()
309 class SendGreetingError(SendMailError):
311 self.message = _('Failed to send greeting')
312 super(SendGreetingError, self).__init__()
314 class SendFeedbackError(SendMailError):
316 self.message = _('Failed to send feedback')
317 super(SendFeedbackError, self).__init__()
319 class ChangeEmailError(SendMailError):
321 self.message = _('Failed to send change email')
322 super(ChangeEmailError, self).__init__()
324 class SendNotificationError(SendMailError):
326 self.message = _('Failed to send notification email')
327 super(SendNotificationError, self).__init__()