Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / util.py @ 7233d542

History | View | Annotate | Download (8.9 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 5ce3ce4f Sofia Papagiannaki
#
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 5ce3ce4f Sofia Papagiannaki
#
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 5ce3ce4f Sofia Papagiannaki
#
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 5ce3ce4f Sofia Papagiannaki
#
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 5ce3ce4f Sofia Papagiannaki
#
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 18ffbee1 Sofia Papagiannaki
import time
37 63ecdd20 Sofia Papagiannaki
38 c0b26605 Sofia Papagiannaki
from urlparse import urlparse
39 64cd4730 Antony Chazapis
from datetime import tzinfo, timedelta
40 c0b26605 Sofia Papagiannaki
41 27e26a41 Sofia Papagiannaki
from django.http import HttpResponse, HttpResponseBadRequest, urlencode
42 0905ccd2 Sofia Papagiannaki
from django.template import RequestContext
43 111f3da6 Sofia Papagiannaki
from django.contrib.auth import authenticate
44 63ecdd20 Sofia Papagiannaki
from django.core.urlresolvers import reverse
45 9a06d96f Olga Brani
from django.core.exceptions import ValidationError, ObjectDoesNotExist
46 ae497612 Olga Brani
from django.utils.translation import ugettext as _
47 ae497612 Olga Brani
48 aab4d540 Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation
49 217994f8 Sofia Papagiannaki
from astakos.im.settings import (
50 c0b26605 Sofia Papagiannaki
    COOKIE_DOMAIN, FORCE_PROFILE_UPDATE
51 217994f8 Sofia Papagiannaki
)
52 111f3da6 Sofia Papagiannaki
from astakos.im.functions import login
53 64cd4730 Antony Chazapis
54 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
55 ae497612 Olga Brani
56 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
57 e015e9e6 Sofia Papagiannaki
58 5ce3ce4f Sofia Papagiannaki
59 64cd4730 Antony Chazapis
class UTC(tzinfo):
60 aab4d540 Sofia Papagiannaki
    def utcoffset(self, dt):
61 aab4d540 Sofia Papagiannaki
        return timedelta(0)
62 5ce3ce4f Sofia Papagiannaki
63 aab4d540 Sofia Papagiannaki
    def tzname(self, dt):
64 aab4d540 Sofia Papagiannaki
        return 'UTC'
65 5ce3ce4f Sofia Papagiannaki
66 aab4d540 Sofia Papagiannaki
    def dst(self, dt):
67 aab4d540 Sofia Papagiannaki
        return timedelta(0)
68 64cd4730 Antony Chazapis
69 5ce3ce4f Sofia Papagiannaki
70 64cd4730 Antony Chazapis
def isoformat(d):
71 aab4d540 Sofia Papagiannaki
    """Return an ISO8601 date string that includes a timezone."""
72 5ce3ce4f Sofia Papagiannaki
73 aab4d540 Sofia Papagiannaki
    return d.replace(tzinfo=UTC()).isoformat()
74 0905ccd2 Sofia Papagiannaki
75 5ce3ce4f Sofia Papagiannaki
76 18ffbee1 Sofia Papagiannaki
def epoch(datetime):
77 5ce3ce4f Sofia Papagiannaki
    return int(time.mktime(datetime.timetuple()) * 1000)
78 5ce3ce4f Sofia Papagiannaki
79 18ffbee1 Sofia Papagiannaki
80 aab4d540 Sofia Papagiannaki
def get_context(request, extra_context=None, **kwargs):
81 aab4d540 Sofia Papagiannaki
    extra_context = extra_context or {}
82 0905ccd2 Sofia Papagiannaki
    extra_context.update(kwargs)
83 0905ccd2 Sofia Papagiannaki
    return RequestContext(request, extra_context)
84 e2125441 Sofia Papagiannaki
85 5ce3ce4f Sofia Papagiannaki
86 15efc749 Sofia Papagiannaki
def get_invitation(request):
87 15efc749 Sofia Papagiannaki
    """
88 15efc749 Sofia Papagiannaki
    Returns the invitation identified by the ``code``.
89 5ce3ce4f Sofia Papagiannaki

90 0a569195 Sofia Papagiannaki
    Raises ValueError if the invitation is consumed or there is another account
91 0a569195 Sofia Papagiannaki
    associated with this email.
92 15efc749 Sofia Papagiannaki
    """
93 15efc749 Sofia Papagiannaki
    code = request.GET.get('code')
94 15efc749 Sofia Papagiannaki
    if request.method == 'POST':
95 15efc749 Sofia Papagiannaki
        code = request.POST.get('code')
96 15efc749 Sofia Papagiannaki
    if not code:
97 15efc749 Sofia Papagiannaki
        return
98 5ce3ce4f Sofia Papagiannaki
    invitation = Invitation.objects.get(code=code)
99 15efc749 Sofia Papagiannaki
    if invitation.is_consumed:
100 ae497612 Olga Brani
        raise ValueError(_(astakos_messages.INVITATION_CONSUMED_ERR))
101 0a569195 Sofia Papagiannaki
    if reserved_email(invitation.username):
102 ae497612 Olga Brani
        email = invitation.username
103 c0b26605 Sofia Papagiannaki
        raise ValueError(_(astakos_messages.EMAIL_RESERVED) % locals())
104 63ecdd20 Sofia Papagiannaki
    return invitation
105 63ecdd20 Sofia Papagiannaki
106 217994f8 Sofia Papagiannaki
def restrict_next(url, domain=None, allowed_schemes=()):
107 217994f8 Sofia Papagiannaki
    """
108 217994f8 Sofia Papagiannaki
    Return url if having the supplied ``domain`` (if present) or one of the ``allowed_schemes``.
109 217994f8 Sofia Papagiannaki
    Otherwise return None.
110 217994f8 Sofia Papagiannaki
    
111 217994f8 Sofia Papagiannaki
    >>> print restrict_next('/im/feedback', '.okeanos.grnet.gr')
112 217994f8 Sofia Papagiannaki
    /im/feedback
113 217994f8 Sofia Papagiannaki
    >>> print restrict_next('pithos.okeanos.grnet.gr/im/feedback', '.okeanos.grnet.gr')
114 55baa300 Sofia Papagiannaki
    //pithos.okeanos.grnet.gr/im/feedback
115 217994f8 Sofia Papagiannaki
    >>> print restrict_next('https://pithos.okeanos.grnet.gr/im/feedback', '.okeanos.grnet.gr')
116 217994f8 Sofia Papagiannaki
    https://pithos.okeanos.grnet.gr/im/feedback
117 217994f8 Sofia Papagiannaki
    >>> print restrict_next('pithos://127.0.0,1', '.okeanos.grnet.gr')
118 217994f8 Sofia Papagiannaki
    None
119 217994f8 Sofia Papagiannaki
    >>> print restrict_next('pithos://127.0.0,1', '.okeanos.grnet.gr', allowed_schemes=('pithos'))
120 217994f8 Sofia Papagiannaki
    pithos://127.0.0,1
121 217994f8 Sofia Papagiannaki
    >>> print restrict_next('node1.example.com', '.okeanos.grnet.gr')
122 217994f8 Sofia Papagiannaki
    None
123 217994f8 Sofia Papagiannaki
    >>> print restrict_next('//node1.example.com', '.okeanos.grnet.gr')
124 217994f8 Sofia Papagiannaki
    None
125 217994f8 Sofia Papagiannaki
    >>> print restrict_next('https://node1.example.com', '.okeanos.grnet.gr')
126 217994f8 Sofia Papagiannaki
    None
127 217994f8 Sofia Papagiannaki
    >>> print restrict_next('https://node1.example.com')
128 217994f8 Sofia Papagiannaki
    https://node1.example.com
129 217994f8 Sofia Papagiannaki
    >>> print restrict_next('//node1.example.com')
130 217994f8 Sofia Papagiannaki
    //node1.example.com
131 217994f8 Sofia Papagiannaki
    >>> print restrict_next('node1.example.com')
132 55baa300 Sofia Papagiannaki
    //node1.example.com
133 217994f8 Sofia Papagiannaki
    """
134 217994f8 Sofia Papagiannaki
    if not url:
135 217994f8 Sofia Papagiannaki
        return
136 217994f8 Sofia Papagiannaki
    parts = urlparse(url, scheme='http')
137 55baa300 Sofia Papagiannaki
    if not parts.netloc and not parts.path.startswith('/'):
138 217994f8 Sofia Papagiannaki
        # fix url if does not conforms RFC 1808
139 217994f8 Sofia Papagiannaki
        url = '//%s' % url
140 217994f8 Sofia Papagiannaki
        parts = urlparse(url, scheme='http')
141 217994f8 Sofia Papagiannaki
    # TODO more scientific checks?
142 217994f8 Sofia Papagiannaki
    if not parts.netloc:    # internal url
143 217994f8 Sofia Papagiannaki
        return url
144 217994f8 Sofia Papagiannaki
    elif not domain:
145 217994f8 Sofia Papagiannaki
        return url
146 217994f8 Sofia Papagiannaki
    elif parts.netloc.endswith(domain):
147 217994f8 Sofia Papagiannaki
        return url
148 217994f8 Sofia Papagiannaki
    elif parts.scheme in allowed_schemes:
149 217994f8 Sofia Papagiannaki
        return url
150 5ce3ce4f Sofia Papagiannaki
151 8fbf5367 root
def prepare_response(request, user, next='', renew=False):
152 63ecdd20 Sofia Papagiannaki
    """Return the unique username and the token
153 63ecdd20 Sofia Papagiannaki
       as 'X-Auth-User' and 'X-Auth-Token' headers,
154 63ecdd20 Sofia Papagiannaki
       or redirect to the URL provided in 'next'
155 63ecdd20 Sofia Papagiannaki
       with the 'user' and 'token' as parameters.
156 5ce3ce4f Sofia Papagiannaki

157 63ecdd20 Sofia Papagiannaki
       Reissue the token even if it has not yet
158 63ecdd20 Sofia Papagiannaki
       expired, if the 'renew' parameter is present
159 63ecdd20 Sofia Papagiannaki
       or user has not a valid token.
160 63ecdd20 Sofia Papagiannaki
    """
161 63ecdd20 Sofia Papagiannaki
    renew = renew or (not user.auth_token)
162 f627a979 Sofia Papagiannaki
    renew = renew or (user.auth_token_expires < datetime.datetime.now())
163 63ecdd20 Sofia Papagiannaki
    if renew:
164 bf0c6de5 Sofia Papagiannaki
        user.renew_token(
165 bf0c6de5 Sofia Papagiannaki
            flush_sessions=True,
166 bf0c6de5 Sofia Papagiannaki
            current_key=request.session.session_key
167 bf0c6de5 Sofia Papagiannaki
        )
168 27e26a41 Sofia Papagiannaki
        try:
169 27e26a41 Sofia Papagiannaki
            user.save()
170 27e26a41 Sofia Papagiannaki
        except ValidationError, e:
171 27e26a41 Sofia Papagiannaki
            return HttpResponseBadRequest(e) 
172 63ecdd20 Sofia Papagiannaki
    
173 217994f8 Sofia Papagiannaki
    next = restrict_next(next, domain=COOKIE_DOMAIN)
174 217994f8 Sofia Papagiannaki
    
175 92defad4 Sofia Papagiannaki
    if FORCE_PROFILE_UPDATE and not user.is_verified and not user.is_superuser:
176 63ecdd20 Sofia Papagiannaki
        params = ''
177 63ecdd20 Sofia Papagiannaki
        if next:
178 63ecdd20 Sofia Papagiannaki
            params = '?' + urlencode({'next': next})
179 6ff7a7ca Sofia Papagiannaki
        next = reverse('edit_profile') + params
180 5ce3ce4f Sofia Papagiannaki
181 63ecdd20 Sofia Papagiannaki
    response = HttpResponse()
182 5ce3ce4f Sofia Papagiannaki
183 8fbf5367 root
    # authenticate before login
184 8fbf5367 root
    user = authenticate(email=user.email, auth_token=user.auth_token)
185 8fbf5367 root
    login(request, user)
186 b42b0987 Sofia Papagiannaki
    request.session.set_expiry(user.auth_token_expires)
187 5ce3ce4f Sofia Papagiannaki
188 63ecdd20 Sofia Papagiannaki
    if not next:
189 63ecdd20 Sofia Papagiannaki
        next = reverse('astakos.im.views.index')
190 55baa300 Sofia Papagiannaki
        
191 63ecdd20 Sofia Papagiannaki
    response['Location'] = next
192 63ecdd20 Sofia Papagiannaki
    response.status_code = 302
193 8fbf5367 root
    return response
194 c301698f Sofia Papagiannaki
195 270dd48d Sofia Papagiannaki
class lazy_string(object):
196 270dd48d Sofia Papagiannaki
    def __init__(self, function, *args, **kwargs):
197 5ce3ce4f Sofia Papagiannaki
        self.function = function
198 5ce3ce4f Sofia Papagiannaki
        self.args = args
199 5ce3ce4f Sofia Papagiannaki
        self.kwargs = kwargs
200 5ce3ce4f Sofia Papagiannaki
201 270dd48d Sofia Papagiannaki
    def __str__(self):
202 270dd48d Sofia Papagiannaki
        if not hasattr(self, 'str'):
203 5ce3ce4f Sofia Papagiannaki
            self.str = self.function(*self.args, **self.kwargs)
204 270dd48d Sofia Papagiannaki
        return self.str
205 270dd48d Sofia Papagiannaki
206 5ce3ce4f Sofia Papagiannaki
207 270dd48d Sofia Papagiannaki
def reverse_lazy(*args, **kwargs):
208 270dd48d Sofia Papagiannaki
    return lazy_string(reverse, *args, **kwargs)
209 270dd48d Sofia Papagiannaki
210 5ce3ce4f Sofia Papagiannaki
211 0a569195 Sofia Papagiannaki
def reserved_email(email):
212 9a06d96f Olga Brani
    return AstakosUser.objects.filter(email__iexact=email).count() != 0
213 5ce3ce4f Sofia Papagiannaki
214 0a569195 Sofia Papagiannaki
215 0a569195 Sofia Papagiannaki
def get_query(request):
216 f627a979 Sofia Papagiannaki
    try:
217 f627a979 Sofia Papagiannaki
        return request.__getattribute__(request.method)
218 f627a979 Sofia Papagiannaki
    except AttributeError:
219 9a06d96f Olga Brani
        return {}
220 9a06d96f Olga Brani
221 9a06d96f Olga Brani
222 9a06d96f Olga Brani
def model_to_dict(obj, exclude=['AutoField', 'ForeignKey', 'OneToOneField'],
223 9a06d96f Olga Brani
                  include_empty=True):
224 9a06d96f Olga Brani
    '''
225 9a06d96f Olga Brani
        serialize model object to dict with related objects
226 9a06d96f Olga Brani

227 9a06d96f Olga Brani
        author: Vadym Zakovinko <vp@zakovinko.com>
228 9a06d96f Olga Brani
        date: January 31, 2011
229 9a06d96f Olga Brani
        http://djangosnippets.org/snippets/2342/
230 9a06d96f Olga Brani
    '''
231 9a06d96f Olga Brani
    tree = {}
232 9a06d96f Olga Brani
    for field_name in obj._meta.get_all_field_names():
233 9a06d96f Olga Brani
        try:
234 9a06d96f Olga Brani
            field = getattr(obj, field_name)
235 9a06d96f Olga Brani
        except (ObjectDoesNotExist, AttributeError):
236 9a06d96f Olga Brani
            continue
237 9a06d96f Olga Brani
238 9a06d96f Olga Brani
        if field.__class__.__name__ in ['RelatedManager', 'ManyRelatedManager']:
239 9a06d96f Olga Brani
            if field.model.__name__ in exclude:
240 9a06d96f Olga Brani
                continue
241 9a06d96f Olga Brani
242 9a06d96f Olga Brani
            if field.__class__.__name__ == 'ManyRelatedManager':
243 9a06d96f Olga Brani
                exclude.append(obj.__class__.__name__)
244 9a06d96f Olga Brani
            subtree = []
245 9a06d96f Olga Brani
            for related_obj in getattr(obj, field_name).all():
246 9a06d96f Olga Brani
                value = model_to_dict(related_obj, exclude=exclude)
247 9a06d96f Olga Brani
                if value or include_empty:
248 9a06d96f Olga Brani
                    subtree.append(value)
249 9a06d96f Olga Brani
            if subtree or include_empty:
250 9a06d96f Olga Brani
                tree[field_name] = subtree
251 9a06d96f Olga Brani
            continue
252 9a06d96f Olga Brani
253 9a06d96f Olga Brani
        field = obj._meta.get_field_by_name(field_name)[0]
254 9a06d96f Olga Brani
        if field.__class__.__name__ in exclude:
255 9a06d96f Olga Brani
            continue
256 9a06d96f Olga Brani
257 9a06d96f Olga Brani
        if field.__class__.__name__ == 'RelatedObject':
258 9a06d96f Olga Brani
            exclude.append(field.model.__name__)
259 9a06d96f Olga Brani
            tree[field_name] = model_to_dict(getattr(obj, field_name),
260 9a06d96f Olga Brani
                                             exclude=exclude)
261 9a06d96f Olga Brani
            continue
262 9a06d96f Olga Brani
263 9a06d96f Olga Brani
        value = getattr(obj, field_name)
264 9a06d96f Olga Brani
        if field.__class__.__name__ == 'ForeignKey':
265 9a06d96f Olga Brani
            value = unicode(value) if value is not None else value
266 9a06d96f Olga Brani
        if value or include_empty:
267 9a06d96f Olga Brani
            tree[field_name] = value
268 9a06d96f Olga Brani
269 9a06d96f Olga Brani
    return tree