Send helpdesk notification on account activation
[astakos] / snf-astakos-app / astakos / im / functions.py
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 from astakos.im.models import Invitation, AstakosUser
55
56 logger = logging.getLogger(__name__)
57
58 def logged(func, msg):
59     @wraps(func)
60     def with_logging(*args, **kwargs):
61         email = ''
62         user = None
63         if len(args) == 2 and isinstance(args[1], AstakosUser):
64             user = args[1]
65         elif len(args) == 1 and isinstance(args[0], HttpRequest):
66             request = args[0]
67             user = request.user
68         email = user.email if user and user.is_authenticated() else ''
69         r = func(*args, **kwargs)
70         if LOGGING_LEVEL:
71             logger._log(LOGGING_LEVEL, msg % email, [])
72         return r
73     return with_logging
74
75 login = logged(auth_login, '%s logged in.')
76 logout = logged(auth_logout, '%s logged out.')
77
78 def send_verification(user, template_name='im/activation_email.txt'):
79     """
80     Send email to user to verify his/her email and activate his/her account.
81     
82     Raises SendVerificationError
83     """
84     url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('astakos.im.views.activate')),
85                                     quote(user.auth_token),
86                                     quote(urljoin(BASEURL, reverse('astakos.im.views.index'))))
87     message = render_to_string(template_name, {
88             'user': user,
89             'url': url,
90             'baseurl': BASEURL,
91             'site_name': SITENAME,
92             'support': DEFAULT_CONTACT_EMAIL})
93     sender = DEFAULT_FROM_EMAIL
94     try:
95         send_mail('%s alpha2 testing account activation is needed' % SITENAME, message, sender, [user.email])
96     except (SMTPException, socket.error) as e:
97         logger.exception(e)
98         raise SendVerificationError()
99     else:
100         msg = 'Sent activation %s' % user.email
101         logger._log(LOGGING_LEVEL, msg, [])
102
103 def send_activation(user, template_name='im/activation_email.txt'):
104     send_verification(user, template_name)
105     user.activation_sent = datetime.now()
106     user.save()
107
108 def send_admin_notification(user, template_name='im/admin_notification.txt'):
109     """
110     Send email to DEFAULT_ADMIN_EMAIL to notify for a new user registration.
111     
112     Raises SendNotificationError
113     """
114     if not DEFAULT_ADMIN_EMAIL:
115         return
116     message = render_to_string(template_name, {
117             'user': user,
118             'baseurl': BASEURL,
119             'site_name': SITENAME,
120             'support': DEFAULT_CONTACT_EMAIL})
121     sender = DEFAULT_FROM_EMAIL
122     try:
123         send_mail('%s alpha2 testing account notification' % SITENAME, message, sender, [DEFAULT_ADMIN_EMAIL])
124     except (SMTPException, socket.error) as e:
125         logger.exception(e)
126         raise SendNotificationError()
127     else:
128         msg = 'Sent admin notification for user %s' % user.email
129         logger._log(LOGGING_LEVEL, msg, [])
130
131 def send_helpdesk_notification(user, template_name='im/helpdesk_notification.txt'):
132     """
133     Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
134     
135     Raises SendNotificationError
136     """
137     if not DEFAULT_CONTACT_EMAIL:
138         return
139     message = render_to_string(template_name, {
140             'user': user,
141             'baseurl': BASEURL,
142             'site_name': SITENAME,
143             'support': DEFAULT_ADMIN_EMAIL})
144     sender = DEFAULT_FROM_EMAIL
145     try:
146         send_mail('%s alpha2 testing account notification' % SITENAME, message, sender, [DEFAULT_CONTACT_EMAIL])
147     except (SMTPException, socket.error) as e:
148         logger.exception(e)
149         raise SendNotificationError()
150     else:
151         msg = 'Sent helpdesk admin notification for user %s' % user.email
152         logger._log(LOGGING_LEVEL, msg, [])
153
154 def send_invitation(invitation, template_name='im/invitation.txt'):
155     """
156     Send invitation email.
157     
158     Raises SendInvitationError
159     """
160     subject = _('Invitation to %s alpha2 testing' % SITENAME)
161     url = '%s?code=%d' % (urljoin(BASEURL, reverse('astakos.im.views.index')), invitation.code)
162     message = render_to_string('im/invitation.txt', {
163                 'invitation': invitation,
164                 'url': url,
165                 'baseurl': BASEURL,
166                 'site_name': SITENAME,
167                 'support': DEFAULT_CONTACT_EMAIL})
168     sender = DEFAULT_FROM_EMAIL
169     try:
170         send_mail(subject, message, sender, [invitation.username])
171     except (SMTPException, socket.error) as e:
172         logger.exception(e)
173         raise SendInvitationError()
174     else:
175         msg = 'Sent invitation %s' % invitation
176         logger._log(LOGGING_LEVEL, msg, [])
177
178 def send_greeting(user, email_template_name='im/welcome_email.txt'):
179     """
180     Send welcome email.
181     
182     Raises SMTPException, socket.error
183     """
184     subject = _('Welcome to %s alpha2 testing' % SITENAME)
185     message = render_to_string(email_template_name, {
186                 'user': user,
187                 'url': urljoin(BASEURL, reverse('astakos.im.views.index')),
188                 'baseurl': BASEURL,
189                 'site_name': SITENAME,
190                 'support': DEFAULT_CONTACT_EMAIL})
191     sender = DEFAULT_FROM_EMAIL
192     try:
193         send_mail(subject, message, sender, [user.email])
194     except (SMTPException, socket.error) as e:
195         logger.exception(e)
196         raise SendGreetingError()
197     else:
198         msg = 'Sent greeting %s' % user.email
199         logger._log(LOGGING_LEVEL, msg, [])
200
201 def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
202     subject = _("Feedback from %s alpha2 testing" % SITENAME)
203     from_email = user.email
204     recipient_list = [DEFAULT_CONTACT_EMAIL]
205     content = render_to_string(email_template_name, {
206         'message': msg,
207         'data': data,
208         'user': user})
209     try:
210         send_mail(subject, content, from_email, recipient_list)
211     except (SMTPException, socket.error) as e:
212         logger.exception(e)
213         raise SendFeedbackError()
214     else:
215         msg = 'Sent feedback from %s' % user.email
216         logger._log(LOGGING_LEVEL, msg, [])
217
218 def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
219     try:
220         url = reverse('email_change_confirm',
221                       kwargs={'activation_key':ec.activation_key})
222         url = request.build_absolute_uri(url)
223         t = loader.get_template(email_template_name)
224         c = {'url': url, 'site_name': SITENAME}
225         from_email = DEFAULT_FROM_EMAIL
226         send_mail(_("Email change on %s alpha2 testing") % SITENAME,
227             t.render(Context(c)), from_email, [ec.new_email_address])
228     except (SMTPException, socket.error) as e:
229         logger.exception(e)
230         raise ChangeEmailError()
231     else:
232         msg = 'Sent change email for %s' % ec.user.email
233         logger._log(LOGGING_LEVEL, msg, [])
234
235 def activate(user, email_template_name='im/welcome_email.txt'):
236     """
237     Activates the specific user and sends email.
238     
239     Raises SendGreetingError, ValidationError
240     """
241     user.is_active = True
242     user.save()
243     send_greeting(user, email_template_name)
244
245 def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
246     """
247     Send an invitation email and upon success reduces inviter's invitation by one.
248     
249     Raises SendInvitationError
250     """
251     invitation.inviter = inviter
252     invitation.save()
253     send_invitation(invitation, email_template_name)
254     inviter.invitations = max(0, inviter.invitations - 1)
255     inviter.save()
256
257 def set_user_credibility(email, has_credits):
258     try:
259         user = AstakosUser.objects.get(email=email, is_active=True)
260         user.has_credits = has_credits
261         user.save()
262     except AstakosUser.DoesNotExist, e:
263         logger.exception(e)
264     except ValidationError, e:
265         logger.exception(e)
266
267 class SendMailError(Exception):
268     pass
269
270 class SendAdminNotificationError(SendMailError):
271     def __init__(self):
272         self.message = _('Failed to send notification')
273         super(SendAdminNotificationError, self).__init__()
274
275 class SendVerificationError(SendMailError):
276     def __init__(self):
277         self.message = _('Failed to send verification')
278         super(SendVerificationError, self).__init__()
279
280 class SendInvitationError(SendMailError):
281     def __init__(self):
282         self.message = _('Failed to send invitation')
283         super(SendInvitationError, self).__init__()
284
285 class SendGreetingError(SendMailError):
286     def __init__(self):
287         self.message = _('Failed to send greeting')
288         super(SendGreetingError, self).__init__()
289
290 class SendFeedbackError(SendMailError):
291     def __init__(self):
292         self.message = _('Failed to send feedback')
293         super(SendFeedbackError, self).__init__()
294
295 class ChangeEmailError(SendMailError):
296     def __init__(self):
297         self.message = _('Failed to send change email')
298         super(ChangeEmailError, self).__init__()
299
300 class SendNotificationError(SendMailError):
301     def __init__(self):
302         self.message = _('Failed to send notification email')
303         super(SendNotificationError, self).__init__()