Statistics
| Branch: | Tag: | Revision:

root / api / util.py @ 29a59bc1

History | View | Annotate | Download (3.5 kB)

1 7e2f9d4b Giorgos Verigakis
#
2 7e2f9d4b Giorgos Verigakis
# Copyright (c) 2010 Greek Research and Technology Network
3 7e2f9d4b Giorgos Verigakis
#
4 7e2f9d4b Giorgos Verigakis
5 7e2f9d4b Giorgos Verigakis
from synnefo.api.errors import *
6 7e2f9d4b Giorgos Verigakis
from synnefo.db.models import *
7 7e2f9d4b Giorgos Verigakis
8 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
9 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
10 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
11 7e2f9d4b Giorgos Verigakis
12 7e2f9d4b Giorgos Verigakis
from functools import wraps
13 7e2f9d4b Giorgos Verigakis
from logging import getLogger
14 7e2f9d4b Giorgos Verigakis
from random import choice
15 7e2f9d4b Giorgos Verigakis
from string import ascii_letters, digits
16 7e2f9d4b Giorgos Verigakis
from traceback import format_exc
17 7e2f9d4b Giorgos Verigakis
from xml.etree import ElementTree
18 7e2f9d4b Giorgos Verigakis
from xml.parsers.expat import ExpatError
19 7e2f9d4b Giorgos Verigakis
20 7e2f9d4b Giorgos Verigakis
21 7e2f9d4b Giorgos Verigakis
log = getLogger('synnefo.api')
22 7e2f9d4b Giorgos Verigakis
23 7e2f9d4b Giorgos Verigakis
24 7e2f9d4b Giorgos Verigakis
def tag_name(e):
25 7e2f9d4b Giorgos Verigakis
    ns, sep, name = e.tag.partition('}')
26 7e2f9d4b Giorgos Verigakis
    return name if sep else e.tag
27 7e2f9d4b Giorgos Verigakis
28 7e2f9d4b Giorgos Verigakis
def xml_to_dict(s):
29 c36934a7 Giorgos Verigakis
    # XXX Quick and dirty
30 7e2f9d4b Giorgos Verigakis
    def _xml_to_dict(e):
31 7e2f9d4b Giorgos Verigakis
        root = {}
32 7e2f9d4b Giorgos Verigakis
        d = root[tag_name(e)] = dict(e.items())
33 7e2f9d4b Giorgos Verigakis
        for child in e.getchildren():
34 7e2f9d4b Giorgos Verigakis
            d.update(_xml_to_dict(child))
35 7e2f9d4b Giorgos Verigakis
        return root
36 7e2f9d4b Giorgos Verigakis
    return _xml_to_dict(ElementTree.fromstring(s.strip()))
37 7e2f9d4b Giorgos Verigakis
38 7e2f9d4b Giorgos Verigakis
def get_user():
39 7e2f9d4b Giorgos Verigakis
    # XXX Placeholder function, everything belongs to a single SynnefoUser for now
40 7e2f9d4b Giorgos Verigakis
    try:
41 7e2f9d4b Giorgos Verigakis
        return SynnefoUser.objects.all()[0]
42 7e2f9d4b Giorgos Verigakis
    except IndexError:
43 7e2f9d4b Giorgos Verigakis
        raise Unauthorized
44 7e2f9d4b Giorgos Verigakis
45 7e2f9d4b Giorgos Verigakis
def get_request_dict(request):
46 7e2f9d4b Giorgos Verigakis
    data = request.raw_post_data
47 7e2f9d4b Giorgos Verigakis
    if request.type == 'xml':
48 7e2f9d4b Giorgos Verigakis
        try:
49 7e2f9d4b Giorgos Verigakis
            return xml_to_dict(data)
50 7e2f9d4b Giorgos Verigakis
        except ExpatError:
51 7e2f9d4b Giorgos Verigakis
            raise BadRequest
52 7e2f9d4b Giorgos Verigakis
    else:
53 7e2f9d4b Giorgos Verigakis
        try:
54 7e2f9d4b Giorgos Verigakis
            return json.loads(data)
55 7e2f9d4b Giorgos Verigakis
        except ValueError:
56 7e2f9d4b Giorgos Verigakis
            raise BadRequest
57 7e2f9d4b Giorgos Verigakis
58 7e2f9d4b Giorgos Verigakis
def random_password(length=8):
59 7e2f9d4b Giorgos Verigakis
    pool = ascii_letters + digits
60 7e2f9d4b Giorgos Verigakis
    return ''.join(choice(pool) for i in range(length))
61 7e2f9d4b Giorgos Verigakis
62 7e2f9d4b Giorgos Verigakis
63 c36934a7 Giorgos Verigakis
def render_fault(request, fault):
64 7e2f9d4b Giorgos Verigakis
    if settings.DEBUG or request.META.get('SERVER_NAME', None) == 'testserver':
65 7e2f9d4b Giorgos Verigakis
        fault.details = format_exc(fault)
66 7e2f9d4b Giorgos Verigakis
    if request.type == 'xml':
67 7e2f9d4b Giorgos Verigakis
        mimetype = 'application/xml'
68 7e2f9d4b Giorgos Verigakis
        data = render_to_string('fault.xml', dict(fault=fault))
69 7e2f9d4b Giorgos Verigakis
    else:
70 7e2f9d4b Giorgos Verigakis
        mimetype = 'application/json'
71 7e2f9d4b Giorgos Verigakis
        d = {fault.name: {'code': fault.code, 'message': fault.message, 'details': fault.details}}
72 7e2f9d4b Giorgos Verigakis
        data = json.dumps(d)
73 7e2f9d4b Giorgos Verigakis
    return HttpResponse(data, mimetype=mimetype, status=fault.code)    
74 7e2f9d4b Giorgos Verigakis
75 c36934a7 Giorgos Verigakis
def api_method(http_method):
76 c36934a7 Giorgos Verigakis
    def decorator(func):
77 c36934a7 Giorgos Verigakis
        @wraps(func)
78 c36934a7 Giorgos Verigakis
        def wrapper(request, *args, **kwargs):
79 c36934a7 Giorgos Verigakis
            try:
80 c36934a7 Giorgos Verigakis
                if request.path.endswith('.json'):
81 8b800b6f Giorgos Verigakis
                    request.type = 'json'
82 c36934a7 Giorgos Verigakis
                elif request.path.endswith('.xml'):
83 8b800b6f Giorgos Verigakis
                    request.type = 'xml'
84 c36934a7 Giorgos Verigakis
                else:
85 8b800b6f Giorgos Verigakis
                    request.type = 'json'       # Default response format
86 b0bc0d35 Giorgos Verigakis
                    for item in request.META.get('HTTP_ACCEPT', '').split(','):
87 b0bc0d35 Giorgos Verigakis
                        accept, sep, rest = item.strip().partition(';')
88 8b800b6f Giorgos Verigakis
                        if accept == 'application/json':
89 8b800b6f Giorgos Verigakis
                            break
90 8b800b6f Giorgos Verigakis
                        elif accept == 'application/xml':
91 8b800b6f Giorgos Verigakis
                            request.type = 'xml'
92 8b800b6f Giorgos Verigakis
                            break
93 c36934a7 Giorgos Verigakis
                
94 c36934a7 Giorgos Verigakis
                if request.method != http_method:
95 c36934a7 Giorgos Verigakis
                    raise BadRequest()
96 c36934a7 Giorgos Verigakis
                
97 c36934a7 Giorgos Verigakis
                resp = func(request, *args, **kwargs)
98 8b800b6f Giorgos Verigakis
                resp['Content-Type'] = 'application/xml' if request.type == 'xml' else 'application/json'
99 c36934a7 Giorgos Verigakis
                return resp
100 c36934a7 Giorgos Verigakis
            except Fault, fault:
101 c36934a7 Giorgos Verigakis
                return render_fault(request, fault)
102 a62a4d20 Giorgos Verigakis
            except BaseException, e:
103 c36934a7 Giorgos Verigakis
                log.exception('Unexpected error: %s' % e)
104 c36934a7 Giorgos Verigakis
                fault = ServiceUnavailable()
105 c36934a7 Giorgos Verigakis
                return render_fault(request, fault)
106 c36934a7 Giorgos Verigakis
        return wrapper
107 c36934a7 Giorgos Verigakis
    return decorator