Statistics
| Branch: | Tag: | Revision:

root / api / util.py @ 29a59bc1

History | View | Annotate | Download (3.5 kB)

1
#
2
# Copyright (c) 2010 Greek Research and Technology Network
3
#
4

    
5
from synnefo.api.errors import *
6
from synnefo.db.models import *
7

    
8
from django.http import HttpResponse
9
from django.template.loader import render_to_string
10
from django.utils import simplejson as json
11

    
12
from functools import wraps
13
from logging import getLogger
14
from random import choice
15
from string import ascii_letters, digits
16
from traceback import format_exc
17
from xml.etree import ElementTree
18
from xml.parsers.expat import ExpatError
19

    
20

    
21
log = getLogger('synnefo.api')
22

    
23

    
24
def tag_name(e):
25
    ns, sep, name = e.tag.partition('}')
26
    return name if sep else e.tag
27

    
28
def xml_to_dict(s):
29
    # XXX Quick and dirty
30
    def _xml_to_dict(e):
31
        root = {}
32
        d = root[tag_name(e)] = dict(e.items())
33
        for child in e.getchildren():
34
            d.update(_xml_to_dict(child))
35
        return root
36
    return _xml_to_dict(ElementTree.fromstring(s.strip()))
37

    
38
def get_user():
39
    # XXX Placeholder function, everything belongs to a single SynnefoUser for now
40
    try:
41
        return SynnefoUser.objects.all()[0]
42
    except IndexError:
43
        raise Unauthorized
44

    
45
def get_request_dict(request):
46
    data = request.raw_post_data
47
    if request.type == 'xml':
48
        try:
49
            return xml_to_dict(data)
50
        except ExpatError:
51
            raise BadRequest
52
    else:
53
        try:
54
            return json.loads(data)
55
        except ValueError:
56
            raise BadRequest
57

    
58
def random_password(length=8):
59
    pool = ascii_letters + digits
60
    return ''.join(choice(pool) for i in range(length))
61

    
62

    
63
def render_fault(request, fault):
64
    if settings.DEBUG or request.META.get('SERVER_NAME', None) == 'testserver':
65
        fault.details = format_exc(fault)
66
    if request.type == 'xml':
67
        mimetype = 'application/xml'
68
        data = render_to_string('fault.xml', dict(fault=fault))
69
    else:
70
        mimetype = 'application/json'
71
        d = {fault.name: {'code': fault.code, 'message': fault.message, 'details': fault.details}}
72
        data = json.dumps(d)
73
    return HttpResponse(data, mimetype=mimetype, status=fault.code)    
74

    
75
def api_method(http_method):
76
    def decorator(func):
77
        @wraps(func)
78
        def wrapper(request, *args, **kwargs):
79
            try:
80
                if request.path.endswith('.json'):
81
                    request.type = 'json'
82
                elif request.path.endswith('.xml'):
83
                    request.type = 'xml'
84
                else:
85
                    request.type = 'json'       # Default response format
86
                    for item in request.META.get('HTTP_ACCEPT', '').split(','):
87
                        accept, sep, rest = item.strip().partition(';')
88
                        if accept == 'application/json':
89
                            break
90
                        elif accept == 'application/xml':
91
                            request.type = 'xml'
92
                            break
93
                
94
                if request.method != http_method:
95
                    raise BadRequest()
96
                
97
                resp = func(request, *args, **kwargs)
98
                resp['Content-Type'] = 'application/xml' if request.type == 'xml' else 'application/json'
99
                return resp
100
            except Fault, fault:
101
                return render_fault(request, fault)
102
            except BaseException, e:
103
                log.exception('Unexpected error: %s' % e)
104
                fault = ServiceUnavailable()
105
                return render_fault(request, fault)
106
        return wrapper
107
    return decorator