Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / api / __init__.py @ 14c5be5a

History | View | Annotate | Download (7.8 kB)

1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from functools import wraps
35
from traceback import format_exc
36
from urllib import quote, unquote
37

    
38
from django.http import HttpResponse
39
from django.utils import simplejson as json
40
from django.conf import settings
41
from django.core.urlresolvers import reverse
42

    
43
from astakos.im.models import AstakosUser, GroupKind, Service, Resource
44
from astakos.im.encoder import ModelJSONEncoder
45
from astakos.im.api.faults import Fault, ItemNotFound, InternalServerError
46
from astakos.im.settings import INVITATIONS_ENABLED, COOKIE_NAME, EMAILCHANGE_ENABLED
47

    
48
import logging
49
logger = logging.getLogger(__name__)
50

    
51
format = ('%a, %d %b %Y %H:%M:%S GMT')
52

    
53
def render_fault(request, fault):
54
    if isinstance(fault, InternalServerError) and settings.DEBUG:
55
        fault.details = format_exc(fault)
56

    
57
    request.serialization = 'text'
58
    data = fault.message + '\n'
59
    if fault.details:
60
        data += '\n' + fault.details
61
    response = HttpResponse(data, status=fault.code)
62
    response['Content-Length'] = len(response.content)
63
    return response
64

    
65
def api_method(http_method=None):
66
    """Decorator function for views that implement an API method."""
67
    def decorator(func):
68
        @wraps(func)
69
        def wrapper(request, *args, **kwargs):
70
            try:
71
                if http_method and request.method != http_method:
72
                    raise BadRequest('Method not allowed.')
73
                response = func(request, *args, **kwargs)
74
                return response
75
            except Fault, fault:
76
                return render_fault(request, fault)
77
            except BaseException, e:
78
                logger.exception('Unexpected error: %s' % e)
79
                fault = InternalServerError('Unexpected error')
80
                return render_fault(request, fault)
81
        return wrapper
82
    return decorator
83

    
84
def _get_user_by_username(user_id):
85
    try:
86
        user = AstakosUser.objects.get(username = user_id)
87
    except AstakosUser.DoesNotExist, e:
88
        raise ItemNotFound('Invalid userid')
89
    else:
90
        response = HttpResponse()
91
        response.status=200
92
        user_info = {'id':user.id,
93
                     'username':user.username,
94
                     'email':[user.email],
95
                     'name':user.realname,
96
                     'auth_token_created':user.auth_token_created.strftime(format),
97
                     'auth_token_expires':user.auth_token_expires.strftime(format),
98
                     'has_credits':user.has_credits,
99
                     'enabled':user.is_active,
100
                     'groups':[g.name for g in user.groups.all()]}
101
        response.content = json.dumps(user_info)
102
        response['Content-Type'] = 'application/json; charset=UTF-8'
103
        response['Content-Length'] = len(response.content)
104
        return response
105

    
106
def _get_user_by_email(email):
107
    if not email:
108
        raise BadRequest('Email missing')
109
    try:
110
        user = AstakosUser.objects.get(email = email)
111
    except AstakosUser.DoesNotExist, e:
112
        raise ItemNotFound('Invalid email')
113
    
114
    if not user.is_active:
115
        raise ItemNotFound('Inactive user')
116
    else:
117
        response = HttpResponse()
118
        response.status=200
119
        user_info = {'id':user.id,
120
                     'username':user.username,
121
                     'email':[user.email],
122
                     'enabled':user.is_active,
123
                     'name':user.realname,
124
                     'auth_token_created':user.auth_token_created.strftime(format),
125
                     'auth_token_expires':user.auth_token_expires.strftime(format),
126
                     'has_credits':user.has_credits,
127
                     'groups':[g.name for g in user.groups.all()],
128
                     'user_permissions':[p.codename for p in user.user_permissions.all()]}
129
        response.content = json.dumps(user_info)
130
        response['Content-Type'] = 'application/json; charset=UTF-8'
131
        response['Content-Length'] = len(response.content)
132
        return response
133

    
134
@api_method(http_method='GET')
135
def get_services(request):
136
    callback = request.GET.get('callback', None)
137
    services = Service.objects.all()
138
    data = tuple({'id':s.pk, 'name':s.name, 'url':s.url, 'icon':s.icon} for s in services)
139
    data = json.dumps(data)
140
    mimetype = 'application/json'
141

    
142
    if callback:
143
        mimetype = 'application/javascript'
144
        data = '%s(%s)' % (callback, data)
145

    
146
    return HttpResponse(content=data, mimetype=mimetype)
147

    
148
@api_method()
149
def get_menu(request, with_extra_links=False, with_signout=True):
150
    index_url = reverse('index')
151
    absolute = lambda (url): request.build_absolute_uri(url)
152
    l = [{ 'url': absolute(index_url), 'name': "Sign in"}]
153
    cookie = unquote(request.COOKIES.get(COOKIE_NAME, ''))
154
    email = cookie.partition('|')[0]
155
    try:
156
        if not email:
157
            raise ValueError
158
        user = AstakosUser.objects.get(email=email, is_active=True)
159
    except AstakosUser.DoesNotExist:
160
        pass
161
    except ValueError:
162
        pass
163
    else:
164
        l = []
165
        l.append({ 'url': absolute(reverse('astakos.im.views.index')),
166
                  'name': user.email})
167
        l.append({ 'url': absolute(reverse('astakos.im.views.edit_profile')),
168
                  'name': "My account" })
169
        if with_extra_links:
170
            if user.has_usable_password() and user.provider == 'local':
171
                l.append({ 'url': absolute(reverse('password_change')),
172
                          'name': "Change password" })
173
            if EMAILCHANGE_ENABLED:
174
                l.append({'url':absolute(reverse('email_change')),
175
                          'name': "Change email"})
176
            if INVITATIONS_ENABLED:
177
                l.append({ 'url': absolute(reverse('astakos.im.views.invite')),
178
                          'name': "Invitations" })
179
            l.append({ 'url': absolute(reverse('astakos.im.views.feedback')),
180
                      'name': "Feedback" })
181
            l.append({ 'url': absolute(reverse('group_add')),
182
                      'name': "Add group" })
183
        if with_signout:
184
            l.append({ 'url': absolute(reverse('astakos.im.views.logout')),
185
                      'name': "Sign out"})
186

    
187
    callback = request.GET.get('callback', None)
188
    data = json.dumps(tuple(l))
189
    mimetype = 'application/json'
190

    
191
    if callback:
192
        mimetype = 'application/javascript'
193
        data = '%s(%s)' % (callback, data)
194

    
195
    return HttpResponse(content=data, mimetype=mimetype)