Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (6.7 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, Service, Resource
44
from astakos.im.api.faults import Fault, ItemNotFound, InternalServerError, BadRequest
45
from astakos.im.settings import (
46
    INVITATIONS_ENABLED, COOKIE_NAME, EMAILCHANGE_ENABLED, QUOTAHOLDER_URL)
47

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

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

    
53
absolute = lambda request, url: request.build_absolute_uri(url)
54

    
55

    
56
def render_fault(request, fault):
57
    if isinstance(fault, InternalServerError) and settings.DEBUG:
58
        fault.details = format_exc(fault)
59

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

    
68

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

    
88

    
89
@api_method(http_method='GET')
90
def get_services(request):
91
    callback = request.GET.get('callback', None)
92
    services = Service.objects.all()
93
    data = tuple({'id': s.pk, 'name': s.name, 'url': s.url, 'icon':
94
                 s.icon} for s in services)
95
    data = json.dumps(data)
96
    mimetype = 'application/json'
97

    
98
    if callback:
99
        mimetype = 'application/javascript'
100
        data = '%s(%s)' % (callback, data)
101

    
102
    return HttpResponse(content=data, mimetype=mimetype)
103

    
104

    
105
@api_method()
106
def get_menu(request, with_extra_links=False, with_signout=True):
107
    user = request.user
108
    index_url = reverse('index')
109
    l = [{'url': absolute(request, index_url), 'name': "Sign in"}]
110
    if user.is_authenticated():
111
        l = []
112
        append = l.append
113
        item = MenuItem
114
        item.current_path = absolute(request, request.path)
115
        append(item(
116
               url=absolute(request, reverse('index')),
117
               name=user.email))
118
        append(item(url=absolute(request, reverse('edit_profile')),
119
               name="My account"))
120
        if with_extra_links:
121
            if EMAILCHANGE_ENABLED:
122
                append(item(
123
                       url=absolute(request, reverse('email_change')),
124
                       name="Change email"))
125
            if INVITATIONS_ENABLED:
126
                append(item(
127
                       url=absolute(request, reverse('invite')),
128
                       name="Invitations"))
129
            
130
            if QUOTAHOLDER_URL:
131
                append(item(
132
                       url=absolute(request, reverse('project_list')),
133
                       name="Projects"))
134
            append(item(
135
                   url=absolute(request, reverse('resource_usage')),
136
                   name="Usage"))
137
            append(item(
138
                   url=absolute(request, reverse('feedback')),
139
                   name="Contact"))
140
        if with_signout:
141
            append(item(
142
                   url=absolute(request, reverse('logout')),
143
                   name="Sign out"))
144

    
145
    callback = request.GET.get('callback', None)
146
    data = json.dumps(tuple(l))
147
    mimetype = 'application/json'
148

    
149
    if callback:
150
        mimetype = 'application/javascript'
151
        data = '%s(%s)' % (callback, data)
152

    
153
    return HttpResponse(content=data, mimetype=mimetype)
154

    
155

    
156
class MenuItem(dict):
157
    current_path = ''
158

    
159
    def __init__(self, *args, **kwargs):
160
        super(MenuItem, self).__init__(*args, **kwargs)
161
        if kwargs.get('url') or kwargs.get('submenu'):
162
            self.__set_is_active__()
163

    
164
    def __setitem__(self, key, value):
165
        super(MenuItem, self).__setitem__(key, value)
166
        if key in ('url', 'submenu'):
167
            self.__set_is_active__()
168

    
169
    def __set_is_active__(self):
170
        if self.get('is_active'):
171
            return
172
        if self.current_path == self.get('url'):
173
            self.__setitem__('is_active', True)
174
        else:
175
            submenu = self.get('submenu', ())
176
            current = (i for i in submenu if i.get('url') == self.current_path)
177
            try:
178
                current_node = current.next()
179
                if not current_node.get('is_active'):
180
                    current_node.__setitem__('is_active', True)
181
                self.__setitem__('is_active', True)
182
            except StopIteration:
183
                return
184

    
185
    def __setattribute__(self, name, value):
186
        super(MenuItem, self).__setattribute__(name, value)
187
        if name == 'current_path':
188
            self.__set_is_active__()