Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / util.py @ ff073f58

History | View | Annotate | Download (6.6 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 64cd4730 Antony Chazapis
# 
3 64cd4730 Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 64cd4730 Antony Chazapis
# without modification, are permitted provided that the following
5 64cd4730 Antony Chazapis
# conditions are met:
6 64cd4730 Antony Chazapis
# 
7 64cd4730 Antony Chazapis
#   1. Redistributions of source code must retain the above
8 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
9 64cd4730 Antony Chazapis
#      disclaimer.
10 64cd4730 Antony Chazapis
# 
11 64cd4730 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 64cd4730 Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 64cd4730 Antony Chazapis
#      provided with the distribution.
15 64cd4730 Antony Chazapis
# 
16 64cd4730 Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64cd4730 Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64cd4730 Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64cd4730 Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64cd4730 Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64cd4730 Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64cd4730 Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64cd4730 Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64cd4730 Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64cd4730 Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64cd4730 Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64cd4730 Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 64cd4730 Antony Chazapis
# 
29 64cd4730 Antony Chazapis
# The views and conclusions contained in the software and
30 64cd4730 Antony Chazapis
# documentation are those of the authors and should not be
31 64cd4730 Antony Chazapis
# interpreted as representing official policies, either expressed
32 64cd4730 Antony Chazapis
# or implied, of GRNET S.A.
33 64cd4730 Antony Chazapis
34 0905ccd2 Sofia Papagiannaki
import logging
35 63ecdd20 Sofia Papagiannaki
import datetime
36 63ecdd20 Sofia Papagiannaki
37 63ecdd20 Sofia Papagiannaki
from urllib import quote
38 63ecdd20 Sofia Papagiannaki
from urlparse import urlsplit, urlunsplit
39 63ecdd20 Sofia Papagiannaki
from functools import wraps
40 0905ccd2 Sofia Papagiannaki
41 64cd4730 Antony Chazapis
from datetime import tzinfo, timedelta
42 63ecdd20 Sofia Papagiannaki
from django.http import HttpResponse, urlencode
43 0905ccd2 Sofia Papagiannaki
from django.template import RequestContext
44 e2125441 Sofia Papagiannaki
from django.contrib.sites.models import Site
45 15efc749 Sofia Papagiannaki
from django.utils.translation import ugettext as _
46 63ecdd20 Sofia Papagiannaki
from django.contrib.auth import login, authenticate
47 63ecdd20 Sofia Papagiannaki
from django.core.urlresolvers import reverse
48 64cd4730 Antony Chazapis
49 270dd48d Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation, ApprovalTerms
50 ca34523e Antony Chazapis
from astakos.im.settings import INVITATIONS_PER_LEVEL, COOKIE_NAME, COOKIE_DOMAIN, COOKIE_SECURE, FORCE_PROFILE_UPDATE
51 64cd4730 Antony Chazapis
52 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
53 e015e9e6 Sofia Papagiannaki
54 64cd4730 Antony Chazapis
class UTC(tzinfo):
55 64cd4730 Antony Chazapis
   def utcoffset(self, dt):
56 64cd4730 Antony Chazapis
       return timedelta(0)
57 64cd4730 Antony Chazapis
58 64cd4730 Antony Chazapis
   def tzname(self, dt):
59 64cd4730 Antony Chazapis
       return 'UTC'
60 64cd4730 Antony Chazapis
61 64cd4730 Antony Chazapis
   def dst(self, dt):
62 64cd4730 Antony Chazapis
       return timedelta(0)
63 64cd4730 Antony Chazapis
64 64cd4730 Antony Chazapis
def isoformat(d):
65 64cd4730 Antony Chazapis
   """Return an ISO8601 date string that includes a timezone."""
66 64cd4730 Antony Chazapis
67 64cd4730 Antony Chazapis
   return d.replace(tzinfo=UTC()).isoformat()
68 0905ccd2 Sofia Papagiannaki
69 b90b602c Sofia Papagiannaki
def get_or_create_user(email, realname='', first_name='', last_name='', affiliation='', level=0, provider='local', password=''):
70 0905ccd2 Sofia Papagiannaki
    """Find or register a user into the internal database
71 0905ccd2 Sofia Papagiannaki
       and issue a token for subsequent requests.
72 0905ccd2 Sofia Papagiannaki
    """
73 b90b602c Sofia Papagiannaki
    user, created = AstakosUser.objects.get_or_create(email=email,
74 0905ccd2 Sofia Papagiannaki
        defaults={
75 0905ccd2 Sofia Papagiannaki
            'password':password,
76 0905ccd2 Sofia Papagiannaki
            'affiliation':affiliation,
77 0905ccd2 Sofia Papagiannaki
            'level':level,
78 ebd369d0 Sofia Papagiannaki
            'invitations':INVITATIONS_PER_LEVEL.get(level, 0),
79 0905ccd2 Sofia Papagiannaki
            'provider':provider,
80 0905ccd2 Sofia Papagiannaki
            'realname':realname,
81 0905ccd2 Sofia Papagiannaki
            'first_name':first_name,
82 0905ccd2 Sofia Papagiannaki
            'last_name':last_name
83 0905ccd2 Sofia Papagiannaki
        })
84 0905ccd2 Sofia Papagiannaki
    if created:
85 0905ccd2 Sofia Papagiannaki
        user.renew_token()
86 0905ccd2 Sofia Papagiannaki
        user.save()
87 e015e9e6 Sofia Papagiannaki
        logger.info('Created user %s', user)
88 0905ccd2 Sofia Papagiannaki
    
89 0905ccd2 Sofia Papagiannaki
    return user
90 0905ccd2 Sofia Papagiannaki
91 0905ccd2 Sofia Papagiannaki
def get_context(request, extra_context={}, **kwargs):
92 0905ccd2 Sofia Papagiannaki
    if not extra_context:
93 0905ccd2 Sofia Papagiannaki
        extra_context = {}
94 0905ccd2 Sofia Papagiannaki
    extra_context.update(kwargs)
95 0905ccd2 Sofia Papagiannaki
    return RequestContext(request, extra_context)
96 e2125441 Sofia Papagiannaki
97 15efc749 Sofia Papagiannaki
def get_invitation(request):
98 15efc749 Sofia Papagiannaki
    """
99 15efc749 Sofia Papagiannaki
    Returns the invitation identified by the ``code``.
100 15efc749 Sofia Papagiannaki
    
101 15efc749 Sofia Papagiannaki
    Raises Invitation.DoesNotExist and Exception if the invitation is consumed
102 15efc749 Sofia Papagiannaki
    """
103 15efc749 Sofia Papagiannaki
    code = request.GET.get('code')
104 15efc749 Sofia Papagiannaki
    if request.method == 'POST':
105 15efc749 Sofia Papagiannaki
        code = request.POST.get('code')
106 15efc749 Sofia Papagiannaki
    if not code:
107 15efc749 Sofia Papagiannaki
        if 'invitation_code' in request.session:
108 15efc749 Sofia Papagiannaki
            code = request.session.pop('invitation_code')
109 15efc749 Sofia Papagiannaki
    if not code:
110 15efc749 Sofia Papagiannaki
        return
111 15efc749 Sofia Papagiannaki
    invitation = Invitation.objects.get(code = code)
112 15efc749 Sofia Papagiannaki
    if invitation.is_consumed:
113 1fefe48c Sofia Papagiannaki
        raise ValueError(_('Invitation is used'))
114 15efc749 Sofia Papagiannaki
    try:
115 15efc749 Sofia Papagiannaki
        AstakosUser.objects.get(email = invitation.username)
116 15efc749 Sofia Papagiannaki
        raise ValueError(_('Email: %s is reserved' % invitation.username))
117 15efc749 Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
118 15efc749 Sofia Papagiannaki
        pass
119 63ecdd20 Sofia Papagiannaki
    return invitation
120 63ecdd20 Sofia Papagiannaki
121 8fbf5367 root
def prepare_response(request, user, next='', renew=False):
122 63ecdd20 Sofia Papagiannaki
    """Return the unique username and the token
123 63ecdd20 Sofia Papagiannaki
       as 'X-Auth-User' and 'X-Auth-Token' headers,
124 63ecdd20 Sofia Papagiannaki
       or redirect to the URL provided in 'next'
125 63ecdd20 Sofia Papagiannaki
       with the 'user' and 'token' as parameters.
126 63ecdd20 Sofia Papagiannaki
       
127 63ecdd20 Sofia Papagiannaki
       Reissue the token even if it has not yet
128 63ecdd20 Sofia Papagiannaki
       expired, if the 'renew' parameter is present
129 63ecdd20 Sofia Papagiannaki
       or user has not a valid token.
130 63ecdd20 Sofia Papagiannaki
    """
131 63ecdd20 Sofia Papagiannaki
    renew = renew or (not user.auth_token)
132 63ecdd20 Sofia Papagiannaki
    renew = renew or (user.auth_token_expires and user.auth_token_expires < datetime.datetime.now())
133 63ecdd20 Sofia Papagiannaki
    if renew:
134 63ecdd20 Sofia Papagiannaki
        user.renew_token()
135 63ecdd20 Sofia Papagiannaki
        user.save()
136 63ecdd20 Sofia Papagiannaki
    
137 92defad4 Sofia Papagiannaki
    if FORCE_PROFILE_UPDATE and not user.is_verified and not user.is_superuser:
138 63ecdd20 Sofia Papagiannaki
        params = ''
139 63ecdd20 Sofia Papagiannaki
        if next:
140 63ecdd20 Sofia Papagiannaki
            params = '?' + urlencode({'next': next})
141 63ecdd20 Sofia Papagiannaki
        next = reverse('astakos.im.views.edit_profile') + params
142 63ecdd20 Sofia Papagiannaki
    
143 63ecdd20 Sofia Papagiannaki
    response = HttpResponse()
144 63ecdd20 Sofia Papagiannaki
    
145 8fbf5367 root
    # authenticate before login
146 8fbf5367 root
    user = authenticate(email=user.email, auth_token=user.auth_token)
147 8fbf5367 root
    login(request, user)
148 c301698f Sofia Papagiannaki
    set_cookie(response, user)
149 63ecdd20 Sofia Papagiannaki
    
150 63ecdd20 Sofia Papagiannaki
    if not next:
151 63ecdd20 Sofia Papagiannaki
        next = reverse('astakos.im.views.index')
152 63ecdd20 Sofia Papagiannaki
    
153 63ecdd20 Sofia Papagiannaki
    response['Location'] = next
154 63ecdd20 Sofia Papagiannaki
    response.status_code = 302
155 8fbf5367 root
    return response
156 c301698f Sofia Papagiannaki
157 c301698f Sofia Papagiannaki
def set_cookie(response, user):
158 c301698f Sofia Papagiannaki
    expire_fmt = user.auth_token_expires.strftime('%a, %d-%b-%Y %H:%M:%S %Z')
159 c301698f Sofia Papagiannaki
    cookie_value = quote(user.email + '|' + user.auth_token)
160 c301698f Sofia Papagiannaki
    response.set_cookie(COOKIE_NAME, value=cookie_value,
161 c301698f Sofia Papagiannaki
                        expires=expire_fmt, path='/',
162 ca34523e Antony Chazapis
                        domain=COOKIE_DOMAIN, secure=COOKIE_SECURE)
163 270dd48d Sofia Papagiannaki
164 270dd48d Sofia Papagiannaki
class lazy_string(object):
165 270dd48d Sofia Papagiannaki
    def __init__(self, function, *args, **kwargs):
166 270dd48d Sofia Papagiannaki
        self.function=function
167 270dd48d Sofia Papagiannaki
        self.args=args
168 270dd48d Sofia Papagiannaki
        self.kwargs=kwargs
169 270dd48d Sofia Papagiannaki
        
170 270dd48d Sofia Papagiannaki
    def __str__(self):
171 270dd48d Sofia Papagiannaki
        if not hasattr(self, 'str'):
172 270dd48d Sofia Papagiannaki
            self.str=self.function(*self.args, **self.kwargs)
173 270dd48d Sofia Papagiannaki
        return self.str
174 270dd48d Sofia Papagiannaki
175 270dd48d Sofia Papagiannaki
def reverse_lazy(*args, **kwargs):
176 270dd48d Sofia Papagiannaki
    return lazy_string(reverse, *args, **kwargs)
177 270dd48d Sofia Papagiannaki
178 d8f63346 Sofia Papagiannaki
def get_latest_terms():
179 270dd48d Sofia Papagiannaki
    try:
180 270dd48d Sofia Papagiannaki
        term = ApprovalTerms.objects.order_by('-id')[0]
181 d8f63346 Sofia Papagiannaki
        return term
182 270dd48d Sofia Papagiannaki
    except IndexError:
183 270dd48d Sofia Papagiannaki
        pass
184 d8f63346 Sofia Papagiannaki
    return None
185 d8f63346 Sofia Papagiannaki
186 d8f63346 Sofia Papagiannaki
def has_signed_terms(user):
187 d8f63346 Sofia Papagiannaki
    term = get_latest_terms()
188 d8f63346 Sofia Papagiannaki
    if not term:
189 d8f63346 Sofia Papagiannaki
        return True
190 d8f63346 Sofia Papagiannaki
    if not user.has_signed_terms:
191 d8f63346 Sofia Papagiannaki
        return False
192 d8f63346 Sofia Papagiannaki
    if not user.date_signed_terms:
193 d8f63346 Sofia Papagiannaki
        return False
194 d8f63346 Sofia Papagiannaki
    if user.date_signed_terms < term.date:
195 d8f63346 Sofia Papagiannaki
        user.has_signed_terms = False
196 d8f63346 Sofia Papagiannaki
        user.save()
197 ff073f58 Sofia Papagiannaki
        return False
198 ff073f58 Sofia Papagiannaki
    return True