~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/base/rest.py

ivle.chat now opens /dev/null as std{in,out,err} when daemonising.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
import cjson
24
24
 
25
25
from ivle.webapp.base.views import BaseView
26
 
from ivle.webapp.errors import BadRequest, MethodNotAllowed
 
26
from ivle.webapp.errors import BadRequest, MethodNotAllowed, Unauthorized
27
27
 
28
28
class RESTView(BaseView):
29
29
    """
33
33
    content_type = "application/octet-stream"
34
34
 
35
35
    def __init__(self, req, *args, **kwargs):
36
 
        pass
 
36
        for key in kwargs:
 
37
            setattr(self, key, kwargs[key])
37
38
 
38
39
    def render(self, req):
39
 
        if req.method == 'GET':
40
 
            outstr = self.GET(req)
41
 
        # XXX PATCH hack
42
 
        if req.method == 'PUT':
43
 
            outstr = self.PATCH(req, req.read())
44
 
        req.content_type = self.content_type
45
 
        req.write(outstr)
 
40
        raise NotImplementedError()
46
41
 
47
42
class JSONRESTView(RESTView):
48
43
    """
54
49
        lambda self: [m for m in ('GET', 'PUT', 'PATCH')
55
50
                      if hasattr(self, m)] + ['POST'])
56
51
 
 
52
    def authorize(self, req):
 
53
        return True # Real authz performed in render().
 
54
 
 
55
    def authorize_method(self, req, op):
 
56
        if not hasattr(op, '_rest_api_permission'):
 
57
            raise Unauthorized()
 
58
 
 
59
        if op._rest_api_permission not in self.get_permissions(req.user):
 
60
            raise Unauthorized()
 
61
 
57
62
    def render(self, req):
58
63
        if req.method not in self._allowed_methods:
59
64
            raise MethodNotAllowed(allowed=self._allowed_methods)
60
65
 
61
66
        if req.method == 'GET':
 
67
            self.authorize_method(req, self.GET)
62
68
            outjson = self.GET(req)
63
69
        # Since PATCH isn't yet an official HTTP method, we allow users to
64
70
        # turn a PUT into a PATCH by supplying a special header.
65
71
        elif req.method == 'PATCH' or (req.method == 'PUT' and
66
72
              'X-IVLE-Patch-Semantics' in req.headers_in and
67
73
              req.headers_in['X-IVLE-Patch-Semantics'].lower() == 'yes'):
68
 
            outjson = self.PATCH(req, cjson.decode(req.read()))
 
74
            self.authorize_method(req, self.PATCH)
 
75
            try:
 
76
                input = cjson.decode(req.read())
 
77
            except cjson.DecodeError:
 
78
                raise BadRequest('Invalid JSON data')
 
79
            outjson = self.PATCH(req, input)
69
80
        elif req.method == 'PUT':
70
 
            outjson = self.PUT(req, cjson.decode(req.read()))
 
81
            self.authorize_method(req, self.PUT)
 
82
            try:
 
83
                input = cjson.decode(req.read())
 
84
            except cjson.DecodeError:
 
85
                raise BadRequest('Invalid JSON data')
 
86
            outjson = self.PUT(req, input)
71
87
        # POST implies named operation.
72
88
        elif req.method == 'POST':
73
89
            # TODO: Check Content-Type and implement multipart/form-data.
87
103
               not op._rest_api_callable:
88
104
                raise BadRequest('Invalid named operation.')
89
105
 
 
106
            self.authorize_method(req, op)
 
107
 
90
108
            # Find any missing arguments, except for the first two (self, req)
91
109
            (args, vaargs, varkw, defaults) = inspect.getargspec(op)
92
110
            args = args[2:]
97
115
            # we are OK.
98
116
            unspec = set(args) - set(opargs.keys())
99
117
            if unspec and not defaults:
100
 
                raise BadRequest('Missing arguments: ' + ','.join(unspec))
 
118
                raise BadRequest('Missing arguments: ' + ', '.join(unspec))
101
119
 
102
120
            unspec = [k for k in unspec if k not in args[-len(defaults):]]
103
121
 
104
122
            if unspec:
105
 
                raise BadRequest('Missing arguments: ' + ','.join(unspec))
 
123
                raise BadRequest('Missing arguments: ' + ', '.join(unspec))
106
124
 
107
125
            # We have extra arguments if the are no match args in the function
108
126
            # signature, AND there is no **.
111
129
                raise BadRequest('Extra arguments: ' + ', '.join(extra))
112
130
 
113
131
            outjson = op(req, **opargs)
114
 
        else:
115
 
            raise AssertionError('Unknown method somehow got through.')
116
132
 
117
133
        req.content_type = self.content_type
118
134
        if outjson is not None:
119
135
            req.write(cjson.encode(outjson))
120
136
            req.write("\n")
121
137
 
122
 
def named_operation(meth):
 
138
class named_operation(object):
123
139
    '''Declare a function to be accessible to HTTP users via the REST API.
124
140
    '''
125
 
    meth._rest_api_callable = True
126
 
    return meth
 
141
    def __init__(self, permission):
 
142
        self.permission = permission
 
143
 
 
144
    def __call__(self, func):
 
145
        func._rest_api_callable = True
 
146
        func._rest_api_permission = self.permission
 
147
        return func
 
148
 
 
149
class require_permission(object):
 
150
    '''Declare the permission required for use of a method via the REST API.
 
151
    '''
 
152
    def __init__(self, permission):
 
153
        self.permission = permission
 
154
 
 
155
    def __call__(self, func):
 
156
        func._rest_api_permission = self.permission
 
157
        return func
127
158