Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / util.py @ 3b258643

History | View | Annotate | Download (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 4bdd7e3d Kostas Papadimitriou
    return AstakosUser.objects.filter(email__iexact=email).count() > 0 or \
213 4bdd7e3d Kostas Papadimitriou
        AstakosUser.objects.filter(username__iexact=email).count() > 0
214 5ce3ce4f Sofia Papagiannaki
215 0a569195 Sofia Papagiannaki
216 0a569195 Sofia Papagiannaki
def get_query(request):
217 f627a979 Sofia Papagiannaki
    try:
218 f627a979 Sofia Papagiannaki
        return request.__getattribute__(request.method)
219 f627a979 Sofia Papagiannaki
    except AttributeError:
220 9a06d96f Olga Brani
        return {}
221 9a06d96f Olga Brani
222 9a06d96f Olga Brani
223 9a06d96f Olga Brani
def model_to_dict(obj, exclude=['AutoField', 'ForeignKey', 'OneToOneField'],
224 9a06d96f Olga Brani
                  include_empty=True):
225 9a06d96f Olga Brani
    '''
226 9a06d96f Olga Brani
        serialize model object to dict with related objects
227 9a06d96f Olga Brani

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