forked from openlp/openlp
Add static routes for serving files, and template rendering built into endpoints
This commit is contained in:
parent
30ee384a9b
commit
968a0ab87a
@ -42,7 +42,13 @@ def register_endpoint(end_point):
|
||||
"""
|
||||
Register an endpoint with the app
|
||||
"""
|
||||
for url, view_func, method, secure in end_point.routes:
|
||||
for url, view_func, method in end_point.routes:
|
||||
# Set the view functions
|
||||
route = _route_from_url(end_point.url_prefix, url)
|
||||
application.add_route(route, view_func, method, secure)
|
||||
application.add_route(route, view_func, method)
|
||||
# Add a static route if necessary
|
||||
if end_point.static_dir:
|
||||
static_route = _route_from_url(end_point.url_prefix, 'static')
|
||||
static_route += '(.*)'
|
||||
application.add_static_route(static_route, end_point.static_dir)
|
||||
|
||||
|
@ -20,29 +20,34 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
openlp/core/api/endpoint.py: Endpoint stuff
|
||||
The Endpoint class, which provides plugins with a way to serve their own portion of the API
|
||||
"""
|
||||
import os
|
||||
|
||||
from mako.template import Template
|
||||
|
||||
|
||||
class Endpoint(object):
|
||||
"""
|
||||
This is an endpoint for the HTTP API
|
||||
"""
|
||||
def __init__(self, url_prefix):
|
||||
def __init__(self, url_prefix, template_dir=None, static_dir=None):
|
||||
"""
|
||||
Create an endpoint with a URL prefix
|
||||
"""
|
||||
print("init")
|
||||
self.url_prefix = url_prefix
|
||||
self.static_dir = static_dir
|
||||
self.template_dir = template_dir
|
||||
self.routes = []
|
||||
|
||||
def add_url_route(self, url, view_func, method, secure):
|
||||
def add_url_route(self, url, view_func, method):
|
||||
"""
|
||||
Add a url route to the list of routes
|
||||
"""
|
||||
self.routes.append((url, view_func, method, secure))
|
||||
self.routes.append((url, view_func, method))
|
||||
|
||||
def route(self, rule, method='GET', secure=False):
|
||||
def route(self, rule, method='GET'):
|
||||
"""
|
||||
Set up a URL route
|
||||
"""
|
||||
@ -50,6 +55,15 @@ class Endpoint(object):
|
||||
"""
|
||||
Make this a decorator
|
||||
"""
|
||||
self.add_url_route(rule, func, method, secure)
|
||||
self.add_url_route(rule, func, method)
|
||||
return func
|
||||
return decorator
|
||||
|
||||
def render_template(self, filename, **kwargs):
|
||||
"""
|
||||
Render a mako template
|
||||
"""
|
||||
if not self.template_dir:
|
||||
raise Exception('No template directory specified')
|
||||
path = os.path.abspath(os.path.join(self.template_dir, filename))
|
||||
return Template(filename=path, input_encoding='utf-8').render(**kwargs)
|
||||
|
@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
# pylint: disable=logging-format-interpolation
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
@ -22,17 +23,48 @@
|
||||
"""
|
||||
App stuff
|
||||
"""
|
||||
import logging
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
from webob import Request, Response
|
||||
from webob.static import DirectoryApp
|
||||
|
||||
from openlp.core.api.http.errors import HttpError, NotFound, ServerError
|
||||
|
||||
ARGS_REGEX = re.compile(r'''\{(\w+)(?::([^}]+))?\}''', re.VERBOSE)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _route_to_regex(route):
|
||||
"""
|
||||
Convert a route to a regular expression
|
||||
|
||||
For example:
|
||||
|
||||
'songs/{song_id}' becomes 'songs/(?P<song_id>[^/]+)'
|
||||
|
||||
and
|
||||
|
||||
'songs/{song_id:\d+}' becomes 'songs/(?P<song_id>\d+)'
|
||||
|
||||
"""
|
||||
route_regex = ''
|
||||
last_pos = 0
|
||||
for match in ARGS_REGEX.finditer(route):
|
||||
route_regex += re.escape(route[last_pos:match.start()])
|
||||
arg_name = match.group(1)
|
||||
expr = match.group(2) or '[^/]+'
|
||||
expr = '(?P<%s>%s)' % (arg_name, expr)
|
||||
route_regex += expr
|
||||
last_pos = match.end()
|
||||
route_regex += re.escape(route[last_pos:])
|
||||
route_regex = '^%s$' % route_regex
|
||||
return route_regex
|
||||
|
||||
|
||||
def _make_response(view_result):
|
||||
"""
|
||||
Create a Response object from response
|
||||
@ -49,18 +81,11 @@ def _make_response(view_result):
|
||||
response = Response(body=body, status=view_result[1],
|
||||
content_type=content_type, charset='utf8')
|
||||
if len(view_result) >= 3:
|
||||
response.headers = view_result[2]
|
||||
response.headers.update(view_result[2])
|
||||
return response
|
||||
elif isinstance(view_result, dict):
|
||||
return Response(body=json.dumps(view_result), status=200,
|
||||
content_type='application/json', charset='utf8')
|
||||
elif isinstance(view_result, str):
|
||||
if 'body {' in view_result:
|
||||
return Response(body=view_result, status=200,
|
||||
content_type='text/css', charset='utf8')
|
||||
else:
|
||||
return Response(body=view_result, status=200,
|
||||
content_type='text/html', charset='utf8')
|
||||
|
||||
|
||||
def _handle_exception(error):
|
||||
@ -83,26 +108,44 @@ class WSGIApplication(object):
|
||||
Create the app object
|
||||
"""
|
||||
self.name = name
|
||||
self.static_routes = {}
|
||||
self.route_map = {}
|
||||
|
||||
def add_route(self, route, view_func, method, secure):
|
||||
def add_route(self, route, view_func, method):
|
||||
"""
|
||||
Add a route
|
||||
"""
|
||||
if route not in self.route_map:
|
||||
self.route_map[route] = {}
|
||||
self.route_map[route][method.upper()] = {'function': view_func, 'secure': secure}
|
||||
route_regex = _route_to_regex(route)
|
||||
if route_regex not in self.route_map:
|
||||
self.route_map[route_regex] = {}
|
||||
self.route_map[route_regex][method.upper()] = view_func
|
||||
|
||||
def add_static_route(self, route, static_dir):
|
||||
"""
|
||||
Add a static directory as a route
|
||||
"""
|
||||
if not route in self.static_routes:
|
||||
self.static_routes[route] = DirectoryApp(os.path.abspath(static_dir))
|
||||
|
||||
def dispatch(self, request):
|
||||
"""
|
||||
Find the appropriate URL and run the view function
|
||||
"""
|
||||
for route, views in self.route_map.items():
|
||||
# First look to see if this is a static file request
|
||||
for route, static_app in self.static_routes.items():
|
||||
if re.match(route, request.path):
|
||||
if request.method.upper() in views:
|
||||
log.debug('Found {method} {url}'.format(method=request.method, url=request.path))
|
||||
view_func = views[request.method.upper()]['function']
|
||||
return _make_response(view_func(request))
|
||||
# Pop the path info twice in order to get rid of the "/<plugin>/static"
|
||||
request.path_info_pop()
|
||||
request.path_info_pop()
|
||||
return request.get_response(static_app)
|
||||
# If not a static route, try the views
|
||||
for route, views in self.route_map.items():
|
||||
match = re.match(route, request.path)
|
||||
if match and request.method.upper() in views:
|
||||
kwargs = match.groupdict()
|
||||
log.debug('Found {method} {url}'.format(method=request.method, url=request.path))
|
||||
view_func = views[request.method.upper()]
|
||||
return _make_response(view_func(request, **kwargs))
|
||||
log.error('Not Found url {url} '.format(url=request.path))
|
||||
raise NotFound()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user