Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / api.py @ be3de0d6

History | View | Annotate | Download (10.1 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 7a0c3713 Kostas Papadimitriou
#
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 7a0c3713 Kostas Papadimitriou
#
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 7a0c3713 Kostas Papadimitriou
#
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 7a0c3713 Kostas Papadimitriou
#
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 7a0c3713 Kostas Papadimitriou
#
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 3a9f4931 Sofia Papagiannaki
import logging
35 63fa03fe Sofia Papagiannaki
import urllib
36 3a9f4931 Sofia Papagiannaki
37 18ffbee1 Sofia Papagiannaki
from functools import wraps
38 64cd4730 Antony Chazapis
from traceback import format_exc
39 64cd4730 Antony Chazapis
from time import time, mktime
40 1ae97c83 Sofia Papagiannaki
from urllib import quote
41 1ae97c83 Sofia Papagiannaki
from urlparse import urlparse
42 1ae97c83 Sofia Papagiannaki
43 64cd4730 Antony Chazapis
from django.conf import settings
44 64cd4730 Antony Chazapis
from django.http import HttpResponse
45 64cd4730 Antony Chazapis
from django.utils import simplejson as json
46 1ae97c83 Sofia Papagiannaki
from django.core.urlresolvers import reverse
47 64cd4730 Antony Chazapis
48 18ffbee1 Sofia Papagiannaki
from astakos.im.faults import BadRequest, Unauthorized, InternalServerError, Fault
49 0905ccd2 Sofia Papagiannaki
from astakos.im.models import AstakosUser
50 63fa03fe Sofia Papagiannaki
from astakos.im.settings import CLOUD_SERVICES, INVITATIONS_ENABLED, COOKIE_NAME
51 09e7393c Sofia Papagiannaki
from astakos.im.util import epoch
52 64cd4730 Antony Chazapis
53 3a9f4931 Sofia Papagiannaki
logger = logging.getLogger(__name__)
54 3a9f4931 Sofia Papagiannaki
55 64cd4730 Antony Chazapis
def render_fault(request, fault):
56 a5676ab6 Antony Chazapis
    if isinstance(fault, InternalServerError) and settings.DEBUG:
57 64cd4730 Antony Chazapis
        fault.details = format_exc(fault)
58 7a0c3713 Kostas Papadimitriou
59 64cd4730 Antony Chazapis
    request.serialization = 'text'
60 863193cb Sofia Papagiannaki
    data = fault.message + '\n'
61 863193cb Sofia Papagiannaki
    if fault.details:
62 863193cb Sofia Papagiannaki
        data += '\n' + fault.details
63 64cd4730 Antony Chazapis
    response = HttpResponse(data, status=fault.code)
64 64cd4730 Antony Chazapis
    response['Content-Length'] = len(response.content)
65 863193cb Sofia Papagiannaki
    return response
66 64cd4730 Antony Chazapis
67 18ffbee1 Sofia Papagiannaki
def api_method(http_method=None, token_required=False, perms=[]):
68 18ffbee1 Sofia Papagiannaki
    """Decorator function for views that implement an API method."""
69 18ffbee1 Sofia Papagiannaki
    
70 18ffbee1 Sofia Papagiannaki
    def decorator(func):
71 18ffbee1 Sofia Papagiannaki
        @wraps(func)
72 18ffbee1 Sofia Papagiannaki
        def wrapper(request, *args, **kwargs):
73 18ffbee1 Sofia Papagiannaki
            try:
74 18ffbee1 Sofia Papagiannaki
                if http_method and request.method != http_method:
75 18ffbee1 Sofia Papagiannaki
                    raise BadRequest('Method not allowed.')
76 18ffbee1 Sofia Papagiannaki
                x_auth_token = request.META.get('HTTP_X_AUTH_TOKEN')
77 18ffbee1 Sofia Papagiannaki
                if token_required:
78 18ffbee1 Sofia Papagiannaki
                    if not x_auth_token:
79 18ffbee1 Sofia Papagiannaki
                        raise Unauthorized('Access denied')
80 18ffbee1 Sofia Papagiannaki
                    try:
81 18ffbee1 Sofia Papagiannaki
                        user = AstakosUser.objects.get(auth_token=x_auth_token)
82 18ffbee1 Sofia Papagiannaki
                        if not user.has_perms(perms):
83 18ffbee1 Sofia Papagiannaki
                            raise Unauthorized('Unauthorized request')
84 18ffbee1 Sofia Papagiannaki
                    except AstakosUser.DoesNotExist, e:
85 18ffbee1 Sofia Papagiannaki
                        raise Unauthorized('Invalid X-Auth-Token')
86 18ffbee1 Sofia Papagiannaki
                    kwargs['user'] = user
87 18ffbee1 Sofia Papagiannaki
                response = func(request, *args, **kwargs)
88 18ffbee1 Sofia Papagiannaki
                return response
89 18ffbee1 Sofia Papagiannaki
            except Fault, fault:
90 18ffbee1 Sofia Papagiannaki
                return render_fault(request, fault)
91 18ffbee1 Sofia Papagiannaki
            except BaseException, e:
92 18ffbee1 Sofia Papagiannaki
                logger.exception('Unexpected error: %s' % e)
93 18ffbee1 Sofia Papagiannaki
                fault = InternalServerError('Unexpected error')
94 18ffbee1 Sofia Papagiannaki
                return render_fault(request, fault)
95 18ffbee1 Sofia Papagiannaki
        return wrapper
96 18ffbee1 Sofia Papagiannaki
    return decorator
97 18ffbee1 Sofia Papagiannaki
98 18ffbee1 Sofia Papagiannaki
@api_method(http_method='GET', token_required=True)
99 18ffbee1 Sofia Papagiannaki
def authenticate_old(request, user=None):
100 64cd4730 Antony Chazapis
    # Normal Response Codes: 204
101 863193cb Sofia Papagiannaki
    # Error Response Codes: internalServerError (500)
102 64cd4730 Antony Chazapis
    #                       badRequest (400)
103 64cd4730 Antony Chazapis
    #                       unauthorised (401)
104 18ffbee1 Sofia Papagiannaki
    if not user:
105 18ffbee1 Sofia Papagiannaki
        raise BadRequest('No user')
106 18ffbee1 Sofia Papagiannaki
    
107 18ffbee1 Sofia Papagiannaki
    # Check if the is active.
108 18ffbee1 Sofia Papagiannaki
    if not user.is_active:
109 18ffbee1 Sofia Papagiannaki
        raise Unauthorized('User inactive')
110 1ae97c83 Sofia Papagiannaki
111 18ffbee1 Sofia Papagiannaki
    # Check if the token has expired.
112 18ffbee1 Sofia Papagiannaki
    if (time() - mktime(user.auth_token_expires.timetuple())) > 0:
113 18ffbee1 Sofia Papagiannaki
        raise Unauthorized('Authentication expired')
114 18ffbee1 Sofia Papagiannaki
    
115 09e7393c Sofia Papagiannaki
    if not user.signed_terms():
116 18ffbee1 Sofia Papagiannaki
        raise Unauthorized('Pending approval terms')
117 18ffbee1 Sofia Papagiannaki
    
118 18ffbee1 Sofia Papagiannaki
    response = HttpResponse()
119 18ffbee1 Sofia Papagiannaki
    response.status=204
120 18ffbee1 Sofia Papagiannaki
    user_info = {'username':user.username,
121 18ffbee1 Sofia Papagiannaki
                 'uniq':user.email,
122 18ffbee1 Sofia Papagiannaki
                 'auth_token':user.auth_token,
123 18ffbee1 Sofia Papagiannaki
                 'auth_token_created':user.auth_token_created.isoformat(),
124 18ffbee1 Sofia Papagiannaki
                 'auth_token_expires':user.auth_token_expires.isoformat(),
125 18ffbee1 Sofia Papagiannaki
                 'has_credits':user.has_credits,
126 09e7393c Sofia Papagiannaki
                 'has_signed_terms':user.signed_terms()}
127 18ffbee1 Sofia Papagiannaki
    response.content = json.dumps(user_info)
128 18ffbee1 Sofia Papagiannaki
    response['Content-Type'] = 'application/json; charset=UTF-8'
129 18ffbee1 Sofia Papagiannaki
    response['Content-Length'] = len(response.content)
130 18ffbee1 Sofia Papagiannaki
    return response
131 18ffbee1 Sofia Papagiannaki
132 18ffbee1 Sofia Papagiannaki
@api_method(http_method='GET', token_required=True)
133 18ffbee1 Sofia Papagiannaki
def authenticate(request, user=None):
134 18ffbee1 Sofia Papagiannaki
    # Normal Response Codes: 204
135 18ffbee1 Sofia Papagiannaki
    # Error Response Codes: internalServerError (500)
136 18ffbee1 Sofia Papagiannaki
    #                       badRequest (400)
137 18ffbee1 Sofia Papagiannaki
    #                       unauthorised (401)
138 18ffbee1 Sofia Papagiannaki
    if not user:
139 18ffbee1 Sofia Papagiannaki
        raise BadRequest('No user')
140 18ffbee1 Sofia Papagiannaki
    
141 18ffbee1 Sofia Papagiannaki
    # Check if the is active.
142 18ffbee1 Sofia Papagiannaki
    if not user.is_active:
143 18ffbee1 Sofia Papagiannaki
        raise Unauthorized('User inactive')
144 18ffbee1 Sofia Papagiannaki
145 18ffbee1 Sofia Papagiannaki
    # Check if the token has expired.
146 18ffbee1 Sofia Papagiannaki
    if (time() - mktime(user.auth_token_expires.timetuple())) > 0:
147 18ffbee1 Sofia Papagiannaki
        raise Unauthorized('Authentication expired')
148 18ffbee1 Sofia Papagiannaki
    
149 09e7393c Sofia Papagiannaki
    if not user.signed_terms():
150 18ffbee1 Sofia Papagiannaki
        raise Unauthorized('Pending approval terms')
151 18ffbee1 Sofia Papagiannaki
    
152 18ffbee1 Sofia Papagiannaki
    response = HttpResponse()
153 18ffbee1 Sofia Papagiannaki
    response.status=204
154 18ffbee1 Sofia Papagiannaki
    user_info = {'userid':user.username,
155 18ffbee1 Sofia Papagiannaki
                 'email':[user.email],
156 18ffbee1 Sofia Papagiannaki
                 'name':user.realname,
157 18ffbee1 Sofia Papagiannaki
                 'auth_token':user.auth_token,
158 18ffbee1 Sofia Papagiannaki
                 'auth_token_created':epoch(user.auth_token_created),
159 18ffbee1 Sofia Papagiannaki
                 'auth_token_expires':epoch(user.auth_token_expires),
160 18ffbee1 Sofia Papagiannaki
                 'has_credits':user.has_credits,
161 18ffbee1 Sofia Papagiannaki
                 'is_active':user.is_active,
162 18ffbee1 Sofia Papagiannaki
                 'groups':[g.name for g in user.groups.all()]}
163 18ffbee1 Sofia Papagiannaki
    response.content = json.dumps(user_info)
164 18ffbee1 Sofia Papagiannaki
    response['Content-Type'] = 'application/json; charset=UTF-8'
165 18ffbee1 Sofia Papagiannaki
    response['Content-Length'] = len(response.content)
166 18ffbee1 Sofia Papagiannaki
    return response
167 7a0c3713 Kostas Papadimitriou
168 18ffbee1 Sofia Papagiannaki
@api_method(http_method='GET')
169 18ffbee1 Sofia Papagiannaki
def get_services(request):
170 7a0c3713 Kostas Papadimitriou
    callback = request.GET.get('callback', None)
171 1ae97c83 Sofia Papagiannaki
    data = json.dumps(CLOUD_SERVICES)
172 7a0c3713 Kostas Papadimitriou
    mimetype = 'application/json'
173 7a0c3713 Kostas Papadimitriou
174 7a0c3713 Kostas Papadimitriou
    if callback:
175 7a0c3713 Kostas Papadimitriou
        mimetype = 'application/javascript'
176 7a0c3713 Kostas Papadimitriou
        data = '%s(%s)' % (callback, data)
177 7a0c3713 Kostas Papadimitriou
178 7a0c3713 Kostas Papadimitriou
    return HttpResponse(content=data, mimetype=mimetype)
179 1ae97c83 Sofia Papagiannaki
180 18ffbee1 Sofia Papagiannaki
@api_method()
181 cb79e2ed Kostas Papadimitriou
def get_menu(request, with_extra_links=False, with_signout=True):
182 ebd369d0 Sofia Papagiannaki
    exclude = []
183 ebd369d0 Sofia Papagiannaki
    index_url = reverse('index')
184 26774255 Sofia Papagiannaki
    absolute = lambda (url): request.build_absolute_uri(url)
185 ebd369d0 Sofia Papagiannaki
    l = [{ 'url': absolute(index_url), 'name': "Sign in"}]
186 63fa03fe Sofia Papagiannaki
    cookie = urllib.unquote(request.COOKIES.get(COOKIE_NAME, ''))
187 63fa03fe Sofia Papagiannaki
    email = cookie.partition('|')[0]
188 63fa03fe Sofia Papagiannaki
    try:
189 0a569195 Sofia Papagiannaki
        user = AstakosUser.objects.get(email=email, is_active=True)
190 63fa03fe Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
191 63fa03fe Sofia Papagiannaki
        pass
192 63fa03fe Sofia Papagiannaki
    else:
193 1ae97c83 Sofia Papagiannaki
        l = []
194 ebd369d0 Sofia Papagiannaki
        l.append({ 'url': absolute(reverse('astakos.im.views.index')),
195 63fa03fe Sofia Papagiannaki
                  'name': user.email})
196 26774255 Sofia Papagiannaki
        l.append({ 'url': absolute(reverse('astakos.im.views.edit_profile')),
197 cb79e2ed Kostas Papadimitriou
                  'name': "My account" })
198 cb79e2ed Kostas Papadimitriou
        if with_extra_links:
199 63fa03fe Sofia Papagiannaki
            if user.has_usable_password():
200 cb79e2ed Kostas Papadimitriou
                l.append({ 'url': absolute(reverse('password_change')),
201 cb79e2ed Kostas Papadimitriou
                          'name': "Change password" })
202 cb79e2ed Kostas Papadimitriou
            if INVITATIONS_ENABLED:
203 cb79e2ed Kostas Papadimitriou
                l.append({ 'url': absolute(reverse('astakos.im.views.invite')),
204 cb79e2ed Kostas Papadimitriou
                          'name': "Invitations" })
205 8f5a3a06 Sofia Papagiannaki
            l.append({ 'url': absolute(reverse('astakos.im.views.feedback')),
206 cb79e2ed Kostas Papadimitriou
                      'name': "Feedback" })
207 cb79e2ed Kostas Papadimitriou
        if with_signout:
208 cb79e2ed Kostas Papadimitriou
            l.append({ 'url': absolute(reverse('astakos.im.views.logout')),
209 cb79e2ed Kostas Papadimitriou
                      'name': "Sign out"})
210 067961d3 Sofia Papagiannaki
    
211 7a0c3713 Kostas Papadimitriou
    callback = request.GET.get('callback', None)
212 1ae97c83 Sofia Papagiannaki
    data = json.dumps(tuple(l))
213 7a0c3713 Kostas Papadimitriou
    mimetype = 'application/json'
214 7a0c3713 Kostas Papadimitriou
215 7a0c3713 Kostas Papadimitriou
    if callback:
216 7a0c3713 Kostas Papadimitriou
        mimetype = 'application/javascript'
217 7a0c3713 Kostas Papadimitriou
        data = '%s(%s)' % (callback, data)
218 7a0c3713 Kostas Papadimitriou
219 7a0c3713 Kostas Papadimitriou
    return HttpResponse(content=data, mimetype=mimetype)
220 18ffbee1 Sofia Papagiannaki
221 18ffbee1 Sofia Papagiannaki
@api_method(http_method='GET', token_required=True, perms=['astakos.im.can_find_userid'])
222 18ffbee1 Sofia Papagiannaki
def find_userid(request):
223 18ffbee1 Sofia Papagiannaki
    # Normal Response Codes: 204
224 18ffbee1 Sofia Papagiannaki
    # Error Response Codes: internalServerError (500)
225 18ffbee1 Sofia Papagiannaki
    #                       badRequest (400)
226 18ffbee1 Sofia Papagiannaki
    #                       unauthorised (401)
227 18ffbee1 Sofia Papagiannaki
    email = request.GET.get('email')
228 18ffbee1 Sofia Papagiannaki
    if not email:
229 18ffbee1 Sofia Papagiannaki
        raise BadRequest('Email missing')
230 18ffbee1 Sofia Papagiannaki
    try:
231 0a569195 Sofia Papagiannaki
        user = AstakosUser.objects.get(email = email, is_active=True)
232 18ffbee1 Sofia Papagiannaki
    except AstakosUser.DoesNotExist, e:
233 18ffbee1 Sofia Papagiannaki
        raise BadRequest('Invalid email')
234 18ffbee1 Sofia Papagiannaki
    else:
235 18ffbee1 Sofia Papagiannaki
        response = HttpResponse()
236 18ffbee1 Sofia Papagiannaki
        response.status=204
237 18ffbee1 Sofia Papagiannaki
        user_info = {'userid':user.username}
238 18ffbee1 Sofia Papagiannaki
        response.content = json.dumps(user_info)
239 18ffbee1 Sofia Papagiannaki
        response['Content-Type'] = 'application/json; charset=UTF-8'
240 18ffbee1 Sofia Papagiannaki
        response['Content-Length'] = len(response.content)
241 18ffbee1 Sofia Papagiannaki
        return response
242 18ffbee1 Sofia Papagiannaki
243 18ffbee1 Sofia Papagiannaki
@api_method(http_method='GET', token_required=True, perms=['astakos.im.can_find_email'])
244 18ffbee1 Sofia Papagiannaki
def find_email(request):
245 18ffbee1 Sofia Papagiannaki
    # Normal Response Codes: 204
246 18ffbee1 Sofia Papagiannaki
    # Error Response Codes: internalServerError (500)
247 18ffbee1 Sofia Papagiannaki
    #                       badRequest (400)
248 18ffbee1 Sofia Papagiannaki
    #                       unauthorised (401)
249 18ffbee1 Sofia Papagiannaki
    userid = request.GET.get('userid')
250 18ffbee1 Sofia Papagiannaki
    if not userid:
251 18ffbee1 Sofia Papagiannaki
        raise BadRequest('Userid missing')
252 18ffbee1 Sofia Papagiannaki
    try:
253 18ffbee1 Sofia Papagiannaki
        user = AstakosUser.objects.get(username = userid)
254 18ffbee1 Sofia Papagiannaki
    except AstakosUser.DoesNotExist, e:
255 18ffbee1 Sofia Papagiannaki
        raise BadRequest('Invalid userid')
256 18ffbee1 Sofia Papagiannaki
    else:
257 18ffbee1 Sofia Papagiannaki
        response = HttpResponse()
258 18ffbee1 Sofia Papagiannaki
        response.status=204
259 18ffbee1 Sofia Papagiannaki
        user_info = {'userid':user.email}
260 18ffbee1 Sofia Papagiannaki
        response.content = json.dumps(user_info)
261 18ffbee1 Sofia Papagiannaki
        response['Content-Type'] = 'application/json; charset=UTF-8'
262 18ffbee1 Sofia Papagiannaki
        response['Content-Length'] = len(response.content)
263 18ffbee1 Sofia Papagiannaki
        return response