Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / api / util.py @ c8a38c0e

History | View | Annotate | Download (7.6 kB)

1 18f21257 Giorgos Korfiatis
# Copyright 2013 GRNET S.A. All rights reserved.
2 18f21257 Giorgos Korfiatis
#
3 18f21257 Giorgos Korfiatis
# Redistribution and use in source and binary forms, with or
4 18f21257 Giorgos Korfiatis
# without modification, are permitted provided that the following
5 18f21257 Giorgos Korfiatis
# conditions are met:
6 18f21257 Giorgos Korfiatis
#
7 18f21257 Giorgos Korfiatis
#   1. Redistributions of source code must retain the above
8 18f21257 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
9 18f21257 Giorgos Korfiatis
#      disclaimer.
10 18f21257 Giorgos Korfiatis
#
11 18f21257 Giorgos Korfiatis
#   2. Redistributions in binary form must reproduce the above
12 18f21257 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
13 18f21257 Giorgos Korfiatis
#      disclaimer in the documentation and/or other materials
14 18f21257 Giorgos Korfiatis
#      provided with the distribution.
15 18f21257 Giorgos Korfiatis
#
16 18f21257 Giorgos Korfiatis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 18f21257 Giorgos Korfiatis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 18f21257 Giorgos Korfiatis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 18f21257 Giorgos Korfiatis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 18f21257 Giorgos Korfiatis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 18f21257 Giorgos Korfiatis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 18f21257 Giorgos Korfiatis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 18f21257 Giorgos Korfiatis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 18f21257 Giorgos Korfiatis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 18f21257 Giorgos Korfiatis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 18f21257 Giorgos Korfiatis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 18f21257 Giorgos Korfiatis
# POSSIBILITY OF SUCH DAMAGE.
28 18f21257 Giorgos Korfiatis
#
29 18f21257 Giorgos Korfiatis
# The views and conclusions contained in the software and
30 18f21257 Giorgos Korfiatis
# documentation are those of the authors and should not be
31 18f21257 Giorgos Korfiatis
# interpreted as representing official policies, either expressed
32 18f21257 Giorgos Korfiatis
# or implied, of GRNET S.A.
33 18f21257 Giorgos Korfiatis
34 79b5d61b Sofia Papagiannaki
from functools import wraps
35 79b5d61b Sofia Papagiannaki
from time import time, mktime
36 bd20edc6 Giorgos Korfiatis
import datetime
37 79b5d61b Sofia Papagiannaki
38 18f21257 Giorgos Korfiatis
from django.http import HttpResponse
39 18f21257 Giorgos Korfiatis
from django.utils import simplejson as json
40 7ac2131c Sofia Papagiannaki
from django.template.loader import render_to_string
41 18f21257 Giorgos Korfiatis
42 bea584e1 Giorgos Korfiatis
from astakos.im.models import AstakosUser, Component
43 79b5d61b Sofia Papagiannaki
from snf_django.lib.api import faults
44 bd20edc6 Giorgos Korfiatis
from snf_django.lib.api.utils import isoformat
45 79b5d61b Sofia Papagiannaki
46 79b5d61b Sofia Papagiannaki
from astakos.im.forms import FeedbackForm
47 79b5d61b Sofia Papagiannaki
from astakos.im.functions import send_feedback as send_feedback_func
48 79b5d61b Sofia Papagiannaki
49 79b5d61b Sofia Papagiannaki
import logging
50 79b5d61b Sofia Papagiannaki
logger = logging.getLogger(__name__)
51 79b5d61b Sofia Papagiannaki
52 79b5d61b Sofia Papagiannaki
absolute = lambda request, url: request.build_absolute_uri(url)
53 79b5d61b Sofia Papagiannaki
54 18f21257 Giorgos Korfiatis
55 bd20edc6 Giorgos Korfiatis
def _dthandler(obj):
56 bd20edc6 Giorgos Korfiatis
    if isinstance(obj, datetime.datetime):
57 bd20edc6 Giorgos Korfiatis
        return isoformat(obj)
58 bd20edc6 Giorgos Korfiatis
    else:
59 bd20edc6 Giorgos Korfiatis
        raise TypeError
60 bd20edc6 Giorgos Korfiatis
61 bd20edc6 Giorgos Korfiatis
62 18f21257 Giorgos Korfiatis
def json_response(content, status_code=None):
63 18f21257 Giorgos Korfiatis
    response = HttpResponse()
64 18f21257 Giorgos Korfiatis
    if status_code is not None:
65 18f21257 Giorgos Korfiatis
        response.status_code = status_code
66 18f21257 Giorgos Korfiatis
67 bd20edc6 Giorgos Korfiatis
    response.content = json.dumps(content, default=_dthandler)
68 18f21257 Giorgos Korfiatis
    response['Content-Type'] = 'application/json; charset=UTF-8'
69 18f21257 Giorgos Korfiatis
    response['Content-Length'] = len(response.content)
70 18f21257 Giorgos Korfiatis
    return response
71 ad730cc5 Giorgos Korfiatis
72 ad730cc5 Giorgos Korfiatis
73 7ac2131c Sofia Papagiannaki
def xml_response(content, template, status_code=None):
74 7ac2131c Sofia Papagiannaki
    response = HttpResponse()
75 7ac2131c Sofia Papagiannaki
    if status_code is not None:
76 7ac2131c Sofia Papagiannaki
        response.status_code = status_code
77 7ac2131c Sofia Papagiannaki
78 7ac2131c Sofia Papagiannaki
    response.content = render_to_string(template, content)
79 7ac2131c Sofia Papagiannaki
    response['Content-Type'] = 'application/xml; charset=UTF-8'
80 7ac2131c Sofia Papagiannaki
    response['Content-Length'] = len(response.content)
81 7ac2131c Sofia Papagiannaki
    return response
82 7ac2131c Sofia Papagiannaki
83 7ac2131c Sofia Papagiannaki
84 2556cf45 Giorgos Korfiatis
def read_json_body(request, default=None):
85 b694875c Christos Stavrakakis
    body = request.body
86 2556cf45 Giorgos Korfiatis
    if not body and request.method == "GET":
87 2556cf45 Giorgos Korfiatis
        body = request.GET.get("body")
88 2556cf45 Giorgos Korfiatis
    if not body:
89 2556cf45 Giorgos Korfiatis
        return default
90 2556cf45 Giorgos Korfiatis
    try:
91 2556cf45 Giorgos Korfiatis
        return json.loads(body)
92 2556cf45 Giorgos Korfiatis
    except json.JSONDecodeError:
93 2556cf45 Giorgos Korfiatis
        raise faults.BadRequest("Request body should be in json format.")
94 2556cf45 Giorgos Korfiatis
95 2556cf45 Giorgos Korfiatis
96 ad730cc5 Giorgos Korfiatis
def is_integer(x):
97 ad730cc5 Giorgos Korfiatis
    return isinstance(x, (int, long))
98 ad730cc5 Giorgos Korfiatis
99 ad730cc5 Giorgos Korfiatis
100 ad730cc5 Giorgos Korfiatis
def are_integer(lst):
101 ad730cc5 Giorgos Korfiatis
    return all(map(is_integer, lst))
102 79b5d61b Sofia Papagiannaki
103 79b5d61b Sofia Papagiannaki
104 bd93595d Sofia Papagiannaki
def validate_user(user):
105 bd93595d Sofia Papagiannaki
    # Check if the user is active.
106 bd93595d Sofia Papagiannaki
    if not user.is_active:
107 bd93595d Sofia Papagiannaki
        raise faults.Unauthorized('User inactive')
108 bd93595d Sofia Papagiannaki
109 bd93595d Sofia Papagiannaki
    # Check if the token has expired.
110 bd93595d Sofia Papagiannaki
    if user.token_expired():
111 bd93595d Sofia Papagiannaki
        raise faults.Unauthorized('Authentication expired')
112 bd93595d Sofia Papagiannaki
113 bd93595d Sofia Papagiannaki
    # Check if the user has accepted the terms.
114 bd93595d Sofia Papagiannaki
    if not user.signed_terms:
115 bd93595d Sofia Papagiannaki
        raise faults.Unauthorized('Pending approval terms')
116 bd93595d Sofia Papagiannaki
117 bd93595d Sofia Papagiannaki
118 79b5d61b Sofia Papagiannaki
def user_from_token(func):
119 79b5d61b Sofia Papagiannaki
    @wraps(func)
120 79b5d61b Sofia Papagiannaki
    def wrapper(request, *args, **kwargs):
121 79b5d61b Sofia Papagiannaki
        try:
122 79b5d61b Sofia Papagiannaki
            token = request.x_auth_token
123 79b5d61b Sofia Papagiannaki
        except AttributeError:
124 79b5d61b Sofia Papagiannaki
            raise faults.Unauthorized("No authentication token")
125 79b5d61b Sofia Papagiannaki
126 79b5d61b Sofia Papagiannaki
        if not token:
127 79b5d61b Sofia Papagiannaki
            raise faults.Unauthorized("Invalid X-Auth-Token")
128 79b5d61b Sofia Papagiannaki
129 79b5d61b Sofia Papagiannaki
        try:
130 67920ea0 Giorgos Korfiatis
            user = AstakosUser.objects.get(auth_token=token)
131 79b5d61b Sofia Papagiannaki
        except AstakosUser.DoesNotExist:
132 79b5d61b Sofia Papagiannaki
            raise faults.Unauthorized('Invalid X-Auth-Token')
133 79b5d61b Sofia Papagiannaki
134 bd93595d Sofia Papagiannaki
        validate_user(user)
135 67920ea0 Giorgos Korfiatis
136 67920ea0 Giorgos Korfiatis
        request.user = user
137 276f454e Sofia Papagiannaki
        return func(request, *args, **kwargs)
138 79b5d61b Sofia Papagiannaki
    return wrapper
139 79b5d61b Sofia Papagiannaki
140 79b5d61b Sofia Papagiannaki
141 bea584e1 Giorgos Korfiatis
def component_from_token(func):
142 bea584e1 Giorgos Korfiatis
    """Decorator for authenticating component by its token.
143 79b5d61b Sofia Papagiannaki

144 bea584e1 Giorgos Korfiatis
    Check that a component with the corresponding token exists. Also,
145 bea584e1 Giorgos Korfiatis
    if component's token has an expiration token, check that it has not
146 79b5d61b Sofia Papagiannaki
    expired.
147 79b5d61b Sofia Papagiannaki

148 79b5d61b Sofia Papagiannaki
    """
149 79b5d61b Sofia Papagiannaki
    @wraps(func)
150 79b5d61b Sofia Papagiannaki
    def wrapper(request, *args, **kwargs):
151 79b5d61b Sofia Papagiannaki
        try:
152 79b5d61b Sofia Papagiannaki
            token = request.x_auth_token
153 79b5d61b Sofia Papagiannaki
        except AttributeError:
154 79b5d61b Sofia Papagiannaki
            raise faults.Unauthorized("No authentication token")
155 79b5d61b Sofia Papagiannaki
156 79b5d61b Sofia Papagiannaki
        if not token:
157 79b5d61b Sofia Papagiannaki
            raise faults.Unauthorized("Invalid X-Auth-Token")
158 79b5d61b Sofia Papagiannaki
        try:
159 bea584e1 Giorgos Korfiatis
            component = Component.objects.get(auth_token=token)
160 bea584e1 Giorgos Korfiatis
        except Component.DoesNotExist:
161 79b5d61b Sofia Papagiannaki
            raise faults.Unauthorized("Invalid X-Auth-Token")
162 79b5d61b Sofia Papagiannaki
163 79b5d61b Sofia Papagiannaki
        # Check if the token has expired
164 bea584e1 Giorgos Korfiatis
        expiration_date = component.auth_token_expires
165 79b5d61b Sofia Papagiannaki
        if expiration_date:
166 79b5d61b Sofia Papagiannaki
            expires_at = mktime(expiration_date.timetuple())
167 79b5d61b Sofia Papagiannaki
            if time() > expires_at:
168 79b5d61b Sofia Papagiannaki
                raise faults.Unauthorized("Authentication expired")
169 79b5d61b Sofia Papagiannaki
170 bea584e1 Giorgos Korfiatis
        request.component_instance = component
171 79b5d61b Sofia Papagiannaki
        return func(request, *args, **kwargs)
172 79b5d61b Sofia Papagiannaki
    return wrapper
173 79b5d61b Sofia Papagiannaki
174 79b5d61b Sofia Papagiannaki
175 7f313da1 Sofia Papagiannaki
def get_uuid_displayname_catalogs(request, user_call=True):
176 79b5d61b Sofia Papagiannaki
    # Normal Response Codes: 200
177 79b5d61b Sofia Papagiannaki
    # Error Response Codes: BadRequest (400)
178 79b5d61b Sofia Papagiannaki
179 79b5d61b Sofia Papagiannaki
    try:
180 b694875c Christos Stavrakakis
        input_data = json.loads(request.body)
181 79b5d61b Sofia Papagiannaki
    except:
182 79b5d61b Sofia Papagiannaki
        raise faults.BadRequest('Request body should be json formatted.')
183 79b5d61b Sofia Papagiannaki
    else:
184 bbf20a4c Sofia Papagiannaki
        if not isinstance(input_data, dict):
185 bbf20a4c Sofia Papagiannaki
            raise faults.BadRequest(
186 bbf20a4c Sofia Papagiannaki
                'Request body should be a json formatted dictionary')
187 79b5d61b Sofia Papagiannaki
        uuids = input_data.get('uuids', [])
188 79b5d61b Sofia Papagiannaki
        if uuids is None and user_call:
189 79b5d61b Sofia Papagiannaki
            uuids = []
190 79b5d61b Sofia Papagiannaki
        displaynames = input_data.get('displaynames', [])
191 79b5d61b Sofia Papagiannaki
        if displaynames is None and user_call:
192 79b5d61b Sofia Papagiannaki
            displaynames = []
193 79b5d61b Sofia Papagiannaki
        user_obj = AstakosUser.objects
194 79b5d61b Sofia Papagiannaki
        d = {'uuid_catalog': user_obj.uuid_catalog(uuids),
195 79b5d61b Sofia Papagiannaki
             'displayname_catalog': user_obj.displayname_catalog(displaynames)}
196 79b5d61b Sofia Papagiannaki
197 79b5d61b Sofia Papagiannaki
        response = HttpResponse()
198 79b5d61b Sofia Papagiannaki
        response.content = json.dumps(d)
199 79b5d61b Sofia Papagiannaki
        response['Content-Type'] = 'application/json; charset=UTF-8'
200 79b5d61b Sofia Papagiannaki
        response['Content-Length'] = len(response.content)
201 79b5d61b Sofia Papagiannaki
        return response
202 79b5d61b Sofia Papagiannaki
203 79b5d61b Sofia Papagiannaki
204 276f454e Sofia Papagiannaki
def send_feedback(request, email_template_name='im/feedback_mail.txt'):
205 79b5d61b Sofia Papagiannaki
    form = FeedbackForm(request.POST)
206 79b5d61b Sofia Papagiannaki
    if not form.is_valid():
207 79b5d61b Sofia Papagiannaki
        logger.error("Invalid feedback request: %r", form.errors)
208 79b5d61b Sofia Papagiannaki
        raise faults.BadRequest('Invalid data')
209 79b5d61b Sofia Papagiannaki
210 79b5d61b Sofia Papagiannaki
    msg = form.cleaned_data['feedback_msg']
211 79b5d61b Sofia Papagiannaki
    data = form.cleaned_data['feedback_data']
212 79b5d61b Sofia Papagiannaki
    try:
213 276f454e Sofia Papagiannaki
        send_feedback_func(msg, data, request.user, email_template_name)
214 79b5d61b Sofia Papagiannaki
    except:
215 79b5d61b Sofia Papagiannaki
        return HttpResponse(status=502)
216 79b5d61b Sofia Papagiannaki
    return HttpResponse(status=200)
217 7ac2131c Sofia Papagiannaki
218 7ac2131c Sofia Papagiannaki
219 7ac2131c Sofia Papagiannaki
def rename_meta_key(d, old, new):
220 7ac2131c Sofia Papagiannaki
    if old not in d:
221 7ac2131c Sofia Papagiannaki
        return
222 7ac2131c Sofia Papagiannaki
    d[new] = d[old]
223 7ac2131c Sofia Papagiannaki
    del(d[old])
224 d29f0371 Sofia Papagiannaki
225 d29f0371 Sofia Papagiannaki
226 d29f0371 Sofia Papagiannaki
def get_int_parameter(p):
227 d29f0371 Sofia Papagiannaki
    if p is not None:
228 d29f0371 Sofia Papagiannaki
        try:
229 d29f0371 Sofia Papagiannaki
            p = int(p)
230 d29f0371 Sofia Papagiannaki
        except ValueError:
231 d29f0371 Sofia Papagiannaki
            return None
232 d29f0371 Sofia Papagiannaki
        if p < 0:
233 d29f0371 Sofia Papagiannaki
            return None
234 d29f0371 Sofia Papagiannaki
    return p
235 d29f0371 Sofia Papagiannaki
236 d29f0371 Sofia Papagiannaki
237 d29f0371 Sofia Papagiannaki
def get_content_length(request):
238 d29f0371 Sofia Papagiannaki
    content_length = get_int_parameter(request.META.get('CONTENT_LENGTH'))
239 d29f0371 Sofia Papagiannaki
    if content_length is None:
240 d29f0371 Sofia Papagiannaki
        raise faults.LengthRequired('Missing or invalid Content-Length header')
241 d29f0371 Sofia Papagiannaki
    return content_length
242 2556cf45 Giorgos Korfiatis
243 2556cf45 Giorgos Korfiatis
244 2556cf45 Giorgos Korfiatis
def invert_dict(d):
245 2556cf45 Giorgos Korfiatis
    return dict((v, k) for k, v in d.iteritems())