Statistics
| Branch: | Tag: | Revision:

root / api / util.py @ b0bc0d35

History | View | Annotate | Download (3.4 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

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

    
19
import json
20

    
21

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

    
24

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

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

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

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

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

    
63

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

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