Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / api / admin.py @ 7f47d7ec

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