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

« back to all changes in this revision

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

Port www/apps/logout to new framework (in ivle.webapp.security).

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, Unauthorized
 
26
from ivle.webapp.errors import BadRequest, MethodNotAllowed
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
 
        for key in kwargs:
37
 
            setattr(self, key, kwargs[key])
 
36
        pass
38
37
 
39
38
    def render(self, req):
40
 
        raise NotImplementedError()
 
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)
41
46
 
42
47
class JSONRESTView(RESTView):
43
48
    """
49
54
        lambda self: [m for m in ('GET', 'PUT', 'PATCH')
50
55
                      if hasattr(self, m)] + ['POST'])
51
56
 
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
 
 
62
57
    def render(self, req):
63
58
        if req.method not in self._allowed_methods:
64
59
            raise MethodNotAllowed(allowed=self._allowed_methods)
65
60
 
66
61
        if req.method == 'GET':
67
 
            self.authorize_method(req, self.GET)
68
62
            outjson = self.GET(req)
69
63
        # Since PATCH isn't yet an official HTTP method, we allow users to
70
64
        # turn a PUT into a PATCH by supplying a special header.
71
65
        elif req.method == 'PATCH' or (req.method == 'PUT' and
72
66
              'X-IVLE-Patch-Semantics' in req.headers_in and
73
67
              req.headers_in['X-IVLE-Patch-Semantics'].lower() == 'yes'):
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)
 
68
            outjson = self.PATCH(req, cjson.decode(req.read()))
80
69
        elif req.method == 'PUT':
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)
 
70
            outjson = self.PUT(req, cjson.decode(req.read()))
87
71
        # POST implies named operation.
88
72
        elif req.method == 'POST':
89
73
            # TODO: Check Content-Type and implement multipart/form-data.
103
87
               not op._rest_api_callable:
104
88
                raise BadRequest('Invalid named operation.')
105
89
 
106
 
            self.authorize_method(req, op)
107
 
 
108
90
            # Find any missing arguments, except for the first two (self, req)
109
91
            (args, vaargs, varkw, defaults) = inspect.getargspec(op)
110
92
            args = args[2:]
115
97
            # we are OK.
116
98
            unspec = set(args) - set(opargs.keys())
117
99
            if unspec and not defaults:
118
 
                raise BadRequest('Missing arguments: ' + ', '.join(unspec))
 
100
                raise BadRequest('Missing arguments: ' + ','.join(unspec))
119
101
 
120
102
            unspec = [k for k in unspec if k not in args[-len(defaults):]]
121
103
 
122
104
            if unspec:
123
 
                raise BadRequest('Missing arguments: ' + ', '.join(unspec))
 
105
                raise BadRequest('Missing arguments: ' + ','.join(unspec))
124
106
 
125
107
            # We have extra arguments if the are no match args in the function
126
108
            # signature, AND there is no **.
129
111
                raise BadRequest('Extra arguments: ' + ', '.join(extra))
130
112
 
131
113
            outjson = op(req, **opargs)
 
114
        else:
 
115
            raise AssertionError('Unknown method somehow got through.')
132
116
 
133
117
        req.content_type = self.content_type
134
118
        if outjson is not None:
135
119
            req.write(cjson.encode(outjson))
136
120
            req.write("\n")
137
121
 
138
 
class named_operation(object):
 
122
def named_operation(meth):
139
123
    '''Declare a function to be accessible to HTTP users via the REST API.
140
124
    '''
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
 
125
    meth._rest_api_callable = True
 
126
    return meth
158
127