Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.6 kB)

1
# Copyright 2011-2013 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 partial
35

    
36
from django.http import HttpResponse
37
from django.utils import simplejson as json
38
from django.core.urlresolvers import reverse
39
from django.utils.translation import ugettext as _
40
from django.contrib import messages
41

    
42
from astakos.im.models import AstakosUser, Service
43
from snf_django.lib import api
44
from snf_django.lib.api import faults
45
from astakos.im.settings import (
46
    INVITATIONS_ENABLED, COOKIE_NAME, EMAILCHANGE_ENABLED, QUOTAHOLDER_URL,
47
    PROJECTS_VISIBLE)
48
from astakos.im.forms import FeedbackForm
49
from astakos.im.functions import send_feedback as send_feedback_func
50

    
51
import logging
52
logger = logging.getLogger(__name__)
53

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

    
56
absolute = lambda request, url: request.build_absolute_uri(url)
57

    
58

    
59
# Decorator for API methods, using common utils.api_method decorator.
60
# It is used for 'get_services' and 'get_menu' methods that do not
61
# require any sort of authentication
62
api_method = partial(api.api_method, user_required=False,
63
                     token_required=False, logger=logger)
64

    
65

    
66
def get_services_dict():
67
    """Return dictionary with information about available Services."""
68
    return Service.catalog().values()
69

    
70

    
71
@api_method(http_method=None)
72
def get_services(request):
73
    callback = request.GET.get('callback', None)
74
    mimetype = 'application/json'
75
    data = json.dumps(get_services_dict())
76

    
77
    if callback:
78
        # Consume session messages. When get_services is loaded from an astakos
79
        # page, messages should have already been consumed in the html
80
        # response. When get_services is loaded from another domain/service we
81
        # consume them here so that no stale messages to appear if user visits
82
        # an astakos view later on.
83
        # TODO: messages could be served to other services/sites in the dict
84
        # response of get_services and/or get_menu. Services could handle those
85
        # messages respectively.
86
        messages_list = list(messages.get_messages(request))
87
        mimetype = 'application/javascript'
88
        data = '%s(%s)' % (callback, data)
89

    
90
    return HttpResponse(content=data, mimetype=mimetype)
91

    
92

    
93
@api_method()
94
def get_menu(request, with_extra_links=False, with_signout=True):
95
    user = request.user
96
    index_url = reverse('index')
97

    
98
    if user.is_authenticated():
99
        l = []
100
        append = l.append
101
        item = MenuItem
102
        item.current_path = absolute(request, request.path)
103
        append(item(url=absolute(request, reverse('index')),
104
                    name=user.email))
105
        if with_extra_links:
106
            append(item(url=absolute(request, reverse('landing')),
107
                        name="Overview"))
108
        if with_signout:
109
            append(item(url=absolute(request, reverse('landing')),
110
                        name="Dashboard"))
111
        if with_extra_links:
112
            append(item(url=absolute(request, reverse('edit_profile')),
113
                        name="Profile"))
114

    
115
        if with_extra_links:
116
            if INVITATIONS_ENABLED:
117
                append(item(url=absolute(request, reverse('invite')),
118
                            name="Invitations"))
119

    
120
            append(item(url=absolute(request, reverse('resource_usage')),
121
                        name="Usage"))
122

    
123
            if QUOTAHOLDER_URL and PROJECTS_VISIBLE:
124
                append(item(url=absolute(request, reverse('project_list')),
125
                            name="Projects"))
126
            #append(item(
127
                #url=absolute(request, reverse('api_access')),
128
                #name="API Access"))
129

    
130
            append(item(url=absolute(request, reverse('feedback')),
131
                        name="Contact"))
132
        if with_signout:
133
            append(item(url=absolute(request, reverse('logout')),
134
                        name="Sign out"))
135
    else:
136
        l = [{'url': absolute(request, index_url),
137
              'name': _("Sign in")}]
138

    
139
    callback = request.GET.get('callback', None)
140
    data = json.dumps(tuple(l))
141
    mimetype = 'application/json'
142

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

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

    
149

    
150
class MenuItem(dict):
151
    current_path = ''
152

    
153
    def __init__(self, *args, **kwargs):
154
        super(MenuItem, self).__init__(*args, **kwargs)
155
        if kwargs.get('url') or kwargs.get('submenu'):
156
            self.__set_is_active__()
157

    
158
    def __setitem__(self, key, value):
159
        super(MenuItem, self).__setitem__(key, value)
160
        if key in ('url', 'submenu'):
161
            self.__set_is_active__()
162

    
163
    def __set_is_active__(self):
164
        if self.get('is_active'):
165
            return
166
        if self.current_path.startswith(self.get('url')):
167
            self.__setitem__('is_active', True)
168
        else:
169
            submenu = self.get('submenu', ())
170
            current = (i for i in submenu if i.get('url') == self.current_path)
171
            try:
172
                current_node = current.next()
173
                if not current_node.get('is_active'):
174
                    current_node.__setitem__('is_active', True)
175
                self.__setitem__('is_active', True)
176
            except StopIteration:
177
                return
178

    
179
    def __setattribute__(self, name, value):
180
        super(MenuItem, self).__setattribute__(name, value)
181
        if name == 'current_path':
182
            self.__set_is_active__()
183

    
184

    
185
def __get_uuid_displayname_catalogs(request, user_call=True):
186
    # Normal Response Codes: 200
187
    # Error Response Codes: BadRequest (400)
188

    
189
    try:
190
        input_data = json.loads(request.raw_post_data)
191
    except:
192
        raise faults.BadRequest('Request body should be json formatted.')
193
    else:
194
        uuids = input_data.get('uuids', [])
195
        if uuids == None and user_call:
196
            uuids = []
197
        displaynames = input_data.get('displaynames', [])
198
        if displaynames == None and user_call:
199
            displaynames = []
200
        user_obj = AstakosUser.objects
201
        d = {'uuid_catalog': user_obj.uuid_catalog(uuids),
202
             'displayname_catalog': user_obj.displayname_catalog(displaynames)}
203

    
204
        response = HttpResponse()
205
        response.content = json.dumps(d)
206
        response['Content-Type'] = 'application/json; charset=UTF-8'
207
        response['Content-Length'] = len(response.content)
208
        return response
209

    
210

    
211
def __send_feedback(request, email_template_name='im/feedback_mail.txt',
212
                    user=None):
213
    if not user:
214
        auth_token = request.POST.get('auth', '')
215
        if not auth_token:
216
            raise faults.BadRequest('Missing user authentication')
217

    
218
        try:
219
            user = AstakosUser.objects.get(auth_token=auth_token)
220
        except AstakosUser.DoesNotExist:
221
            raise faults.BadRequest('Invalid user authentication')
222

    
223
    form = FeedbackForm(request.POST)
224
    if not form.is_valid():
225
        logger.error("Invalid feedback request: %r", form.errors)
226
        raise faults.BadRequest('Invalid data')
227

    
228
    msg = form.cleaned_data['feedback_msg']
229
    data = form.cleaned_data['feedback_data']
230
    try:
231
        send_feedback_func(msg, data, user, email_template_name)
232
    except:
233
        return HttpResponse(status=502)
234
    return HttpResponse(status=200)