Display calendar in timeline date fields
[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 from django.conf import settings
46
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
52
53 from astakos.im.settings import (DEFAULT_CONTACT_EMAIL, SITENAME, BASEURL,
54                                  LOGGING_LEVEL
55                                  )
56 from astakos.im.models import AstakosUser
57
58 logger = logging.getLogger(__name__)
59
60
61 def logged(func, msg):
62     @wraps(func)
63     def with_logging(*args, **kwargs):
64         email = ''
65         user = None
66         if len(args) == 2 and isinstance(args[1], AstakosUser):
67             user = args[1]
68         elif len(args) == 1 and isinstance(args[0], HttpRequest):
69             request = args[0]
70             user = request.user
71         email = user.email if user and user.is_authenticated() else ''
72         r = func(*args, **kwargs)
73         if LOGGING_LEVEL:
74             logger.log(LOGGING_LEVEL, msg % email)
75         return r
76     return with_logging
77
78 login = logged(auth_login, '%s logged in.')
79 logout = logged(auth_logout, '%s logged out.')
80
81
82 def send_verification(user, template_name='im/activation_email.txt'):
83     """
84     Send email to user to verify his/her email and activate his/her account.
85
86     Raises SendVerificationError
87     """
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, {
92                                'user': user,
93                                'url': url,
94                                'baseurl': BASEURL,
95                                'site_name': SITENAME,
96                                'support': DEFAULT_CONTACT_EMAIL})
97     sender = settings.SERVER_EMAIL
98     try:
99         send_mail('%s alpha2 testing account activation is needed' %
100                   SITENAME, message, sender, [user.email])
101     except (SMTPException, socket.error) as e:
102         logger.exception(e)
103         raise SendVerificationError()
104     else:
105         msg = 'Sent activation %s' % user.email
106         logger.log(LOGGING_LEVEL, msg)
107
108
109 def send_activation(user, template_name='im/activation_email.txt'):
110     send_verification(user, template_name)
111     user.activation_sent = datetime.now()
112     user.save()
113
114
115 def send_admin_notification(template_name,
116                             dictionary=None,
117                             subject='alpha2 testing notification',
118                             ):
119     """
120     Send notification email to settings.ADMINS.
121
122     Raises SendNotificationError
123     """
124     if not settings.ADMINS:
125         return
126     dictionary = dictionary or {}
127     message = render_to_string(template_name, dictionary)
128     sender = settings.SERVER_EMAIL
129     try:
130         send_mail(subject, message, sender, [i[1] for i in settings.ADMINS])
131     except (SMTPException, socket.error) as e:
132         logger.exception(e)
133         raise SendNotificationError()
134     else:
135         msg = 'Sent admin notification for user %s' % dictionary
136         logger.log(LOGGING_LEVEL, msg)
137
138
139 def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
140     """
141     Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
142
143     Raises SendNotificationError
144     """
145     if not DEFAULT_CONTACT_EMAIL:
146         return
147     message = render_to_string(
148         template_name,
149         {'user': user}
150     )
151     sender = settings.SERVER_EMAIL
152     try:
153         send_mail(
154             '%s alpha2 testing account activated' % SITENAME,
155             message,
156             sender,
157             [DEFAULT_CONTACT_EMAIL]
158         )
159     except (SMTPException, socket.error) as e:
160         logger.exception(e)
161         raise SendNotificationError()
162     else:
163         msg = 'Sent helpdesk admin notification for %s' % user.email
164         logger.log(LOGGING_LEVEL, msg)
165
166
167 def send_invitation(invitation, template_name='im/invitation.txt'):
168     """
169     Send invitation email.
170
171     Raises SendInvitationError
172     """
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,
177                                'url': url,
178                                'baseurl': BASEURL,
179                                'site_name': SITENAME,
180                                'support': DEFAULT_CONTACT_EMAIL})
181     sender = settings.SERVER_EMAIL
182     try:
183         send_mail(subject, message, sender, [invitation.username])
184     except (SMTPException, socket.error) as e:
185         logger.exception(e)
186         raise SendInvitationError()
187     else:
188         msg = 'Sent invitation %s' % invitation
189         logger.log(LOGGING_LEVEL, msg)
190
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('index')),
202                                'baseurl': BASEURL,
203                                'site_name': SITENAME,
204                                'support': DEFAULT_CONTACT_EMAIL})
205     sender = settings.SERVER_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
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, {
221         'message': msg,
222         'data': data,
223         'user': user})
224     try:
225         send_mail(subject, content, from_email, recipient_list)
226     except (SMTPException, socket.error) as e:
227         logger.exception(e)
228         raise SendFeedbackError()
229     else:
230         msg = 'Sent feedback from %s' % user.email
231         logger.log(LOGGING_LEVEL, msg)
232
233
234 def send_change_email(ec, request, email_template_name='registration/email_change_email.txt'):
235     try:
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:
245         logger.exception(e)
246         raise ChangeEmailError()
247     else:
248         msg = 'Sent change email for %s' % ec.user.email
249         logger.log(LOGGING_LEVEL, msg)
250
251
252 def activate(user, email_template_name='im/welcome_email.txt',
253              helpdesk_email_template_name='im/helpdesk_notification.txt', verify_email=False):
254     """
255     Activates the specific user and sends email.
256
257     Raises SendGreetingError, ValidationError
258     """
259     user.is_active = True
260     if verify_email:
261         user.email_verified = True
262     user.save()
263     send_helpdesk_notification(user, helpdesk_email_template_name)
264     send_greeting(user, email_template_name)
265
266
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):
269         return
270
271     if not local_user or not isinstance(user, AstakosUser):
272         return
273
274     if not user.provider == 'shibboleth':
275         return
276
277     user.delete()
278     local_user.provider = 'shibboleth'
279     local_user.third_party_identifier = user.third_party_identifier
280     local_user.save()
281     send_greeting(local_user, greeting_template_name)
282     return local_user
283
284
285 def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
286     """
287     Send an invitation email and upon success reduces inviter's invitation by one.
288
289     Raises SendInvitationError
290     """
291     invitation.inviter = inviter
292     invitation.save()
293     send_invitation(invitation, email_template_name)
294     inviter.invitations = max(0, inviter.invitations - 1)
295     inviter.save()
296
297
298 class SendMailError(Exception):
299     pass
300
301
302 class SendAdminNotificationError(SendMailError):
303     def __init__(self):
304         self.message = _('Failed to send notification')
305         super(SendAdminNotificationError, self).__init__()
306
307
308 class SendVerificationError(SendMailError):
309     def __init__(self):
310         self.message = _('Failed to send verification')
311         super(SendVerificationError, self).__init__()
312
313
314 class SendInvitationError(SendMailError):
315     def __init__(self):
316         self.message = _('Failed to send invitation')
317         super(SendInvitationError, self).__init__()
318
319
320 class SendGreetingError(SendMailError):
321     def __init__(self):
322         self.message = _('Failed to send greeting')
323         super(SendGreetingError, self).__init__()
324
325
326 class SendFeedbackError(SendMailError):
327     def __init__(self):
328         self.message = _('Failed to send feedback')
329         super(SendFeedbackError, self).__init__()
330
331
332 class ChangeEmailError(SendMailError):
333     def __init__(self):
334         self.message = _('Failed to send change email')
335         super(ChangeEmailError, self).__init__()
336
337
338 class SendNotificationError(SendMailError):
339     def __init__(self):
340         self.message = _('Failed to send notification email')
341         super(SendNotificationError, self).__init__()