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)
70 logger._log(LOGGING_LEVEL, msg % email, [])
74 login = logged(auth_login, '%s logged in.')
75 logout = logged(auth_logout, '%s logged out.')
77 def send_verification(user, template_name='im/activation_email.txt'):
79 Send email to user to verify his/her email and activate his/her account.
81 Raises SendVerificationError
83 url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('astakos.im.views.activate')),
84 quote(user.auth_token),
86 message = render_to_string(template_name, {
90 'site_name': SITENAME,
91 'support': DEFAULT_CONTACT_EMAIL})
92 sender = DEFAULT_FROM_EMAIL
94 send_mail('%s alpha2 testing account activation is needed' % SITENAME, message, sender, [user.email])
95 except (SMTPException, socket.error) as e:
97 raise SendVerificationError()
99 msg = 'Sent activation %s' % user.email
100 logger._log(LOGGING_LEVEL, msg, [])
102 def send_activation(user, template_name='im/activation_email.txt'):
103 send_verification(user, template_name)
104 user.activation_sent = datetime.now()
107 def send_admin_notification(user, template_name='im/admin_notification.txt'):
109 Send email to DEFAULT_ADMIN_EMAIL to notify for a new user registration.
111 Raises SendNotificationError
113 if not DEFAULT_ADMIN_EMAIL:
115 message = render_to_string(template_name, {
118 'site_name': SITENAME,
119 'support': DEFAULT_CONTACT_EMAIL})
120 sender = DEFAULT_FROM_EMAIL
122 send_mail('%s alpha2 testing account notification' % SITENAME, message, sender, [DEFAULT_ADMIN_EMAIL])
123 except (SMTPException, socket.error) as e:
125 raise SendNotificationError()
127 msg = 'Sent admin notification for user %s' % user.email
128 logger._log(LOGGING_LEVEL, msg, [])
130 def send_invitation(invitation, template_name='im/invitation.txt'):
132 Send invitation email.
134 Raises SendInvitationError
136 subject = _('Invitation to %s alpha2 testing' % SITENAME)
137 url = '%s?code=%d' % (urljoin(BASEURL, reverse('astakos.im.views.index')), invitation.code)
138 message = render_to_string('im/invitation.txt', {
139 'invitation': invitation,
142 'site_name': SITENAME,
143 'support': DEFAULT_CONTACT_EMAIL})
144 sender = DEFAULT_FROM_EMAIL
146 send_mail(subject, message, sender, [invitation.username])
147 except (SMTPException, socket.error) as e:
149 raise SendInvitationError()
151 msg = 'Sent invitation %s' % invitation
152 logger._log(LOGGING_LEVEL, msg, [])
154 def send_greeting(user, email_template_name='im/welcome_email.txt'):
158 Raises SMTPException, socket.error
160 subject = _('Welcome to %s alpha2 testing' % SITENAME)
161 message = render_to_string(email_template_name, {
163 'url': urljoin(BASEURL, reverse('astakos.im.views.index')),
165 'site_name': SITENAME,
166 'support': DEFAULT_CONTACT_EMAIL})
167 sender = DEFAULT_FROM_EMAIL
169 send_mail(subject, message, sender, [user.email])
170 except (SMTPException, socket.error) as e:
172 raise SendGreetingError()
174 msg = 'Sent greeting %s' % user.email
175 logger._log(LOGGING_LEVEL, msg, [])
177 def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
178 subject = _("Feedback from %s alpha2 testing" % SITENAME)
179 from_email = user.email
180 recipient_list = [DEFAULT_CONTACT_EMAIL]
181 content = render_to_string(email_template_name, {
186 send_mail(subject, content, from_email, recipient_list)
187 except (SMTPException, socket.error) as e:
189 raise SendFeedbackError()
191 msg = 'Sent feedback from %s' % user.email
192 logger._log(LOGGING_LEVEL, msg, [])
194 def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
196 url = reverse('email_change_confirm',
197 kwargs={'activation_key':ec.activation_key})
198 url = request.build_absolute_uri(url)
199 t = loader.get_template(email_template_name)
200 c = {'url': url, 'site_name': SITENAME}
201 from_email = DEFAULT_FROM_EMAIL
202 send_mail(_("Email change on %s alpha2 testing") % SITENAME,
203 t.render(Context(c)), from_email, [ec.new_email_address])
204 except (SMTPException, socket.error) as e:
206 raise ChangeEmailError()
208 msg = 'Sent change email for %s' % ec.user.email
209 logger._log(LOGGING_LEVEL, msg, [])
211 def activate(user, email_template_name='im/welcome_email.txt'):
213 Activates the specific user and sends email.
215 Raises SendGreetingError, ValidationError
217 user.is_active = True
219 send_greeting(user, email_template_name)
221 def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
223 Send an invitation email and upon success reduces inviter's invitation by one.
225 Raises SendInvitationError
227 invitation.inviter = inviter
229 send_invitation(invitation, email_template_name)
230 inviter.invitations = max(0, inviter.invitations - 1)
233 def set_user_credibility(email, has_credits):
235 user = AstakosUser.objects.get(email=email, is_active=True)
236 user.has_credits = has_credits
238 except AstakosUser.DoesNotExist, e:
240 except ValidationError, e:
243 class SendMailError(Exception):
246 class SendAdminNotificationError(SendMailError):
248 self.message = _('Failed to send notification')
249 super(SendAdminNotificationError, self).__init__()
251 class SendVerificationError(SendMailError):
253 self.message = _('Failed to send verification')
254 super(SendVerificationError, self).__init__()
256 class SendInvitationError(SendMailError):
258 self.message = _('Failed to send invitation')
259 super(SendInvitationError, self).__init__()
261 class SendGreetingError(SendMailError):
263 self.message = _('Failed to send greeting')
264 super(SendGreetingError, self).__init__()
266 class SendFeedbackError(SendMailError):
268 self.message = _('Failed to send feedback')
269 super(SendFeedbackError, self).__init__()
271 class ChangeEmailError(SendMailError):
273 self.message = _('Failed to send change email')
274 super(ChangeEmailError, self).__init__()