aboutsummaryrefslogtreecommitdiffstats
path: root/flywheel/emitters.py
blob: 7492b07b067ffb1678ac67511622490490848d15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from django.template import RequestContext, loader

from flywheel.response import NoContent

from utils import dict2xml
try:
    import json
except ImportError:
    import simplejson as json



class BaseEmitter(object):
    media_type = None

    def __init__(self, resource):
        self.resource = resource

    def emit(self, output=NoContent, verbose=False):
        raise Exception('emit() function on a subclass of BaseEmitter must be implemented')


from django import forms
class JSONForm(forms.Form):
    _contenttype = forms.CharField(max_length=256, initial='application/json', label='Content Type')
    _content = forms.CharField(label='Content', widget=forms.Textarea)

class DocumentingTemplateEmitter(BaseEmitter):
    """Emitter used to self-document the API"""
    template = None

    def emit(self, output=NoContent):
        resource = self.resource

        # Find the first valid emitter and emit the content. (Don't another documenting emitter.)
        emitters = [emitter for emitter in resource.emitters if not isinstance(emitter, DocumentingTemplateEmitter)]
        if not emitters:
            content = 'No emitters were found'
        else:
            content = emitters[0](resource).emit(output, verbose=True)

        # Get the form instance if we have one bound to the input
        form_instance = resource.form_instance
        
        # Otherwise if this isn't an error response
        # then attempt to get a form bound to the response object
        if not form_instance and not resource.response.is_error and resource.response.has_content_body:
            try:
                form_instance = resource.get_form(resource.response.raw_content)
            except:
                pass
        
        # If we still don't have a form instance then try to get an unbound form
        if not form_instance:
            try:
                form_instance = self.resource.get_form()
            except:
                pass

        if not form_instance:
            form_instance = JSONForm()

        template = loader.get_template(self.template)
        context = RequestContext(self.resource.request, {
            'content': content,
            'resource': self.resource,
            'request': self.resource.request,
            'response': self.resource.response,
            'form': form_instance
        })
        
        ret = template.render(context)

        # Munge DELETE Response code to allow us to return content
        # (Do this *after* we've rendered the template so that we include the normal deletion response code in the output)
        if self.resource.response.status == 204:
            self.resource.response.status = 200

        return ret


class JSONEmitter(BaseEmitter):
    media_type = 'application/json'

    def emit(self, output=NoContent, verbose=False):
        if output is NoContent:
            return ''
        if verbose:
            return json.dumps(output, indent=4, sort_keys=True)
        return json.dumps(output)


class XMLEmitter(BaseEmitter):
    media_type = 'application/xml'

    def emit(self, output=NoContent, verbose=False):
        if output is NoContent:
            return ''
        return dict2xml(output)


class DocumentingHTMLEmitter(DocumentingTemplateEmitter):
    media_type = 'text/html'
    uses_forms = True
    template = 'emitter.html'


class DocumentingXHTMLEmitter(DocumentingTemplateEmitter):
    media_type = 'application/xhtml+xml'
    uses_forms = True
    template = 'emitter.html'


class DocumentingPlainTextEmitter(DocumentingTemplateEmitter):
    media_type = 'text/plain'
    template = 'emitter.txt'