remove http_endpoint

This commit is contained in:
Tim Bentley 2016-08-13 06:02:54 +01:00
parent fa19108885
commit 43a539db64
13 changed files with 10 additions and 623 deletions

View File

@ -23,9 +23,9 @@ import logging
from openlp.core.api.http import register_endpoint from openlp.core.api.http import register_endpoint
from openlp.core.api.http.server import HttpServer from openlp.core.api.http.server import HttpServer
from openlp.core.api.http.endpoint.controller import controller_endpoint, api_controller_endpoint from openlp.core.api.endpoint.controller import controller_endpoint, api_controller_endpoint
from openlp.core.api.http.endpoint.core import stage_endpoint, blank_endpoint, main_endpoint from openlp.core.api.endpoint.core import stage_endpoint, blank_endpoint, main_endpoint
from openlp.core.api.http.endpoint.service import service_endpoint, api_service_endpoint from openlp.core.api.endpoint.service import service_endpoint, api_service_endpoint
from openlp.core.api.websockets import WebSocketServer from openlp.core.api.websockets import WebSocketServer
from openlp.core.api.poll import Poller from openlp.core.api.poll import Poller
from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties

View File

@ -1,79 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
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, template_dir=None, static_dir=None, assets_dir=None):
"""
Create an endpoint with a URL prefix
"""
self.url_prefix = url_prefix
self.static_dir = static_dir
self.template_dir = template_dir
if assets_dir:
self.assets_dir = assets_dir
else:
self.assets_dir = os.path.dirname(os.path.realpath(__file__))
self.routes = []
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))
def route(self, rule, method='GET'):
"""
Set up a URL route
"""
def decorator(func):
"""
Make this a decorator
"""
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))
if self.static_dir:
kwargs['static_url'] = '/{prefix}/static'.format(prefix=self.url_prefix)
kwargs['static_url'] = kwargs['static_url'].replace('//', '/')
kwargs['assets_url'] = '/assets'
return Template(filename=path, input_encoding='utf-8').render(**kwargs)
from .pluginhelpers import search, live, service

View File

@ -1,131 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
import os
import urllib.request
import urllib.error
import json
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import requires_auth
from openlp.core.common import Registry, AppLocation, Settings
from openlp.core.lib import ItemCapabilities, create_thumb
log = logging.getLogger(__name__)
controller_endpoint = Endpoint('controller')
api_controller_endpoint = Endpoint('api')
@api_controller_endpoint.route('controller/live/text')
@controller_endpoint.route('live/text')
def controller_text(request):
"""
Perform an action on the slide controller.
:param request: the http request - not used
"""
log.debug("controller_text ")
live_controller = Registry().get('live_controller')
current_item = live_controller.service_item
data = []
if current_item:
for index, frame in enumerate(current_item.get_frames()):
item = {}
# Handle text (songs, custom, bibles)
if current_item.is_text():
if frame['verseTag']:
item['tag'] = str(frame['verseTag'])
else:
item['tag'] = str(index + 1)
item['text'] = str(frame['text'])
item['html'] = str(frame['html'])
# Handle images, unless a custom thumbnail is given or if thumbnails is disabled
elif current_item.is_image() and not frame.get('image', '') and Settings().value('api/thumbnails'):
item['tag'] = str(index + 1)
thumbnail_path = os.path.join('images', 'thumbnails', frame['title'])
full_thumbnail_path = os.path.join(AppLocation.get_data_path(), thumbnail_path)
# Create thumbnail if it doesn't exists
if not os.path.exists(full_thumbnail_path):
create_thumb(current_item.get_frame_path(index), full_thumbnail_path, False)
Registry().get('image_manager').add_image(full_thumbnail_path, frame['title'], None, 88, 88)
item['img'] = urllib.request.pathname2url(os.path.sep + thumbnail_path)
item['text'] = str(frame['title'])
item['html'] = str(frame['title'])
else:
# Handle presentation etc.
item['tag'] = str(index + 1)
if current_item.is_capable(ItemCapabilities.HasDisplayTitle):
item['title'] = str(frame['display_title'])
if current_item.is_capable(ItemCapabilities.HasNotes):
item['slide_notes'] = str(frame['notes'])
if current_item.is_capable(ItemCapabilities.HasThumbnails) and \
Settings().value('api/thumbnails'):
# If the file is under our app directory tree send the portion after the match
data_path = AppLocation.get_data_path()
if frame['image'][0:len(data_path)] == data_path:
item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])
Registry().get('image_manager').add_image(frame['image'], frame['title'], None, 88, 88)
item['text'] = str(frame['title'])
item['html'] = str(frame['title'])
item['selected'] = (live_controller.selected_row == index)
data.append(item)
json_data = {'results': {'slides': data}}
if current_item:
json_data['results']['item'] = live_controller.service_item.unique_identifier
return json_data
@api_controller_endpoint.route('controller/live/set')
@controller_endpoint.route('live/set')
@requires_auth
def controller_set(request):
"""
Perform an action on the slide controller.
:param request: The action to perform.
"""
event = getattr(Registry().get('live_controller'), 'slidecontroller_live_set')
try:
json_data = request.GET.get('data')
data = int(json.loads(json_data)['request']['id'])
event.emit([data])
except KeyError:
log.error("Endpoint controller/live/set request id not found")
return {'results': {'success': True}}
@api_controller_endpoint.route('/controller/{controller}/{action:next|previous}')
@controller_endpoint.route('/{controller}/{action:next|previous}')
@requires_auth
def controller_direction(request, controller, action):
"""
Handles requests for setting service items in the slide controller
11
:param request: The http request object.
:param controller: the controller slides forward or backward.
:param action: the controller slides forward or backward.
"""
event = getattr(Registry().get('live_controller'), 'slidecontroller_{controller}_{action}'.
format(controller=controller, action=action))
event.emit()
return {'results': {'success': True}}

View File

@ -1,169 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
import os
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import register_endpoint, requires_auth, ROOT_DIR
from openlp.core.common import Registry, UiStrings, translate
from openlp.core.lib import image_to_byte, PluginStatus, StringContent
template_dir = os.path.join(ROOT_DIR, 'templates')
static_dir = os.path.join(ROOT_DIR, 'static')
blank_dir = os.path.join(static_dir, 'index')
log = logging.getLogger(__name__)
stage_endpoint = Endpoint('stage', template_dir=template_dir, static_dir=static_dir)
main_endpoint = Endpoint('main', template_dir=template_dir, static_dir=static_dir)
blank_endpoint = Endpoint('', template_dir=template_dir, static_dir=blank_dir)
FILE_TYPES = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript',
'.jpg': 'image/jpeg',
'.gif': 'image/gif',
'.ico': 'image/x-icon',
'.png': 'image/png'
}
remote = translate('RemotePlugin.Mobile', 'Remote')
stage = translate('RemotePlugin.Mobile', 'Stage View')
live = translate('RemotePlugin.Mobile', 'Live View')
TRANSLATED_STRINGS = {
'app_title': "{main} {remote}".format(main=UiStrings().OLP, remote=remote),
'stage_title': "{main} {stage}".format(main=UiStrings().OLP, stage=stage),
'live_title': "{main} {live}".format(main=UiStrings().OLP, live=live),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'),
'search': translate('RemotePlugin.Mobile', 'Search'),
'home': translate('RemotePlugin.Mobile', 'Home'),
'refresh': translate('RemotePlugin.Mobile', 'Refresh'),
'blank': translate('RemotePlugin.Mobile', 'Blank'),
'theme': translate('RemotePlugin.Mobile', 'Theme'),
'desktop': translate('RemotePlugin.Mobile', 'Desktop'),
'show': translate('RemotePlugin.Mobile', 'Show'),
'prev': translate('RemotePlugin.Mobile', 'Prev'),
'next': translate('RemotePlugin.Mobile', 'Next'),
'text': translate('RemotePlugin.Mobile', 'Text'),
'show_alert': translate('RemotePlugin.Mobile', 'Show Alert'),
'go_live': translate('RemotePlugin.Mobile', 'Go Live'),
'add_to_service': translate('RemotePlugin.Mobile', 'Add to Service'),
'add_and_go_to_service': translate('RemotePlugin.Mobile', 'Add & Go to Service'),
'no_results': translate('RemotePlugin.Mobile', 'No Results'),
'options': translate('RemotePlugin.Mobile', 'Options'),
'service': translate('RemotePlugin.Mobile', 'Service'),
'slides': translate('RemotePlugin.Mobile', 'Slides'),
'settings': translate('RemotePlugin.Mobile', 'Settings'),
}
@stage_endpoint.route('')
def stage_index(request):
"""
Deliver the page for the /stage url
"""
return stage_endpoint.render_template('stage.mako', **TRANSLATED_STRINGS)
@main_endpoint.route('')
def main_index(request):
"""
Deliver the page for the /main url
"""
return main_endpoint.render_template('main.mako', **TRANSLATED_STRINGS)
@blank_endpoint.route('')
def index(request):
"""
Deliver the page for the / url
:param request:
"""
return blank_endpoint.render_template('index.mako', **TRANSLATED_STRINGS)
@blank_endpoint.route('poll')
def poll(request):
"""
Deliver the page for the /poll url
:param request:
"""
return Registry().get('poller').raw_poll()
@blank_endpoint.route('api/display/{display:hide|show|blank|theme|desktop}')
@blank_endpoint.route('display/{display:hide|show|blank|theme|desktop}')
@requires_auth
def toggle_display(request, display):
"""
Deliver the functions for the /display url
:param request: the http request - not used
:param display: the display function to be triggered
"""
Registry().get('live_controller').slidecontroller_toggle_display.emit(display)
return {'results': {'success': True}}
@blank_endpoint.route('api/plugin/search')
@blank_endpoint.route('plugin/search')
def plugin_search_list(request):
"""
Deliver a list of active plugins that support search
:param request: the http request - not used
"""
searches = []
for plugin in Registry().get('plugin_manager').plugins:
if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.has_search:
searches.append([plugin.name, str(plugin.text_strings[StringContent.Name]['plural'])])
return {'results': {'items': searches}}
@main_endpoint.route('image')
def main_image(request):
"""
Return the latest display image as a byte stream.
:param request: base path of the URL. Not used but passed by caller
:return:
"""
live_controller = Registry().get('live_controller')
result = {
'slide_image': 'data:image/png;base64,' + str(image_to_byte(live_controller.slide_image))
}
return {'results': result}
def get_content_type(file_name):
"""
Examines the extension of the file and determines what the content_type should be, defaults to text/plain
Returns the extension and the content_type
:param file_name: name of file
"""
ext = os.path.splitext(file_name)[1]
content_type = FILE_TYPES.get(ext, 'text/plain')
return ext, content_type

View File

@ -1,134 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import os
import json
import re
import urllib
from urllib.parse import urlparse
from webob import Response
from openlp.core.common import Registry, AppLocation
from openlp.core.lib import PluginStatus, image_to_byte
def search(request, plugin_name, log):
"""
Handles requests for searching the plugins
:param request: The http request object.
:param plugin_name: The plugin name.
:param log: The class log object.
"""
try:
json_data = request.GET.get('data')
text = json.loads(json_data)['request']['text']
except KeyError:
log.error("Endpoint {text} search request text not found".format(text=plugin_name))
text = ""
text = urllib.parse.unquote(text)
plugin = Registry().get('plugin_manager').get_plugin_by_name(plugin_name)
if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.has_search:
results = plugin.media_item.search(text, False)
else:
results = []
return {'results': {'items': results}}
def live(request, plugin_name, log):
"""
Handles requests for making live of the plugins
:param request: The http request object.
:param plugin_name: The plugin name.
:param log: The class log object.
"""
try:
json_data = request.GET.get('data')
request_id = json.loads(json_data)['request']['id']
except KeyError:
log.error("Endpoint {text} search request text not found".format(text=plugin_name))
return []
plugin = Registry().get('plugin_manager').get_plugin_by_name(plugin_name)
if plugin.status == PluginStatus.Active and plugin.media_item:
getattr(plugin.media_item, '{name}_go_live'.format(name=plugin_name)).emit([request_id, True])
return []
def service(request, plugin_name, log):
"""
Handles requests for adding to a service of the plugins
:param request: The http request object.
:param plugin_name: The plugin name.
:param log: The class log object.
"""
try:
json_data = request.GET.get('data')
request_id = json.loads(json_data)['request']['id']
except KeyError:
log.error("Endpoint {plugin} search request text not found".format(plugin=plugin_name))
return []
plugin = Registry().get('plugin_manager').get_plugin_by_name(plugin_name)
if plugin.status == PluginStatus.Active and plugin.media_item:
item_id = plugin.media_item.create_item_from_id(request_id)
getattr(plugin.media_item, '{name}_add_to_service'.format(name=plugin_name)).emit([item_id, True])
return []
def display_thumbnails(request, controller_name, log, dimensions, file_name, slide):
"""
Handles requests for adding a song to the service
Return an image to a web page based on a URL
:param request: Request object
:param controller_name: which controller is requesting the image
:param log: the logger object
:param dimensions: the image size eg 88x88
:param file_name: the file name of the image
:param slide: the individual image name
:return:
"""
log.debug('serve thumbnail {cname}/thumbnails{dim}/{fname}/{slide}'.format(cname=controller_name,
dim=dimensions,
fname=file_name,
slide=slide))
# -1 means use the default dimension in ImageManager
width = -1
height = -1
image = None
if dimensions:
match = re.search('(\d+)x(\d+)', dimensions)
if match:
# let's make sure that the dimensions are within reason
width = sorted([10, int(match.group(1)), 1000])[1]
height = sorted([10, int(match.group(2)), 1000])[1]
if controller_name and file_name:
file_name = urllib.parse.unquote(file_name)
if '..' not in file_name: # no hacking please
full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name),
'thumbnails', file_name, slide))
if os.path.exists(full_path):
path, just_file_name = os.path.split(full_path)
Registry().get('image_manager').add_image(full_path, just_file_name, None, width, height)
image = Registry().get('image_manager').get_image(full_path, just_file_name, width, height)
return Response(body=image_to_byte(image, False), status=200, content_type='image/png', charset='utf8')

View File

@ -1,100 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
import json
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import register_endpoint, requires_auth
from openlp.core.common import Registry
log = logging.getLogger(__name__)
service_endpoint = Endpoint('service')
api_service_endpoint = Endpoint('api/service')
@api_service_endpoint.route('list')
@service_endpoint.route('list')
def list_service(request):
"""
Handles requests for service items in the service manager
:param request: The http request object.
"""
return {'results': {'items': get_service_items()}}
@api_service_endpoint.route('set')
@service_endpoint.route('set')
@requires_auth
def service_set(request):
"""
Handles requests for setting service items in the service manager
:param request: The http request object.
"""
event = getattr(Registry().get('service_manager'), 'servicemanager_set_item')
try:
json_data = request.GET.get('data')
data = int(json.loads(json_data)['request']['id'])
event.emit(data)
except KeyError:
log.error("Endpoint service/set request id not found")
return {'results': {'success': True}}
@api_service_endpoint.route('{action:next|previous}')
@service_endpoint.route('{action:next|previous}')
@requires_auth
def service_direction(request, action):
"""
Handles requests for setting service items in the service manager
:param request: The http request object.
:param action: the the service slides forward or backward.
"""
event = getattr(Registry().get('service_manager'), 'servicemanager_{action}_item'.format(action=action))
event.emit()
return {'results': {'success': True}}
def get_service_items():
"""
Read the service item in use and return the data as a json object
"""
live_controller = Registry().get('live_controller')
service_items = []
if live_controller.service_item:
current_unique_identifier = live_controller.service_item.unique_identifier
else:
current_unique_identifier = None
for item in Registry().get('service_manager').service_items:
service_item = item['service_item']
service_items.append({
'id': str(service_item.unique_identifier),
'title': str(service_item.get_display_title()),
'plugin': str(service_item.name),
'notes': str(service_item.notes),
'selected': (service_item.unique_identifier == current_unique_identifier)
})
return service_items

View File

@ -22,7 +22,7 @@
import logging import logging
from openlp.core.api.http.endpoint import Endpoint from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http.endpoint.pluginhelpers import search, live, service from openlp.core.api.endpoint.pluginhelpers import search, live, service
from openlp.core.api.http import requires_auth from openlp.core.api.http import requires_auth

View File

@ -22,7 +22,7 @@
import logging import logging
from openlp.core.api.http.endpoint import Endpoint from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http.endpoint.pluginhelpers import search, live, service from openlp.core.api.endpoint.pluginhelpers import search, live, service
from openlp.core.api.http import requires_auth from openlp.core.api.http import requires_auth

View File

@ -22,7 +22,7 @@
import logging import logging
from openlp.core.api.http.endpoint import Endpoint from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http.endpoint.pluginhelpers import search, live, service, display_thumbnails from openlp.core.api.endpoint.pluginhelpers import search, live, service, display_thumbnails
from openlp.core.api.http import requires_auth from openlp.core.api.http import requires_auth

View File

@ -22,7 +22,7 @@
import logging import logging
from openlp.core.api.http.endpoint import Endpoint from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http.endpoint.pluginhelpers import search, live, service from openlp.core.api.endpoint.pluginhelpers import search, live, service
from openlp.core.api.http import requires_auth from openlp.core.api.http import requires_auth

View File

@ -22,7 +22,7 @@
import logging import logging
from openlp.core.api.http.endpoint import Endpoint from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http.endpoint.pluginhelpers import search, live, service, display_thumbnails from openlp.core.api.endpoint.pluginhelpers import search, live, service, display_thumbnails
from openlp.core.api.http import requires_auth from openlp.core.api.http import requires_auth

View File

@ -24,7 +24,7 @@ import logging
import os import os
from openlp.core.api.http.endpoint import Endpoint from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http.endpoint.core import TRANSLATED_STRINGS from openlp.core.api.endpoint.core import TRANSLATED_STRINGS
from openlp.core.common import AppLocation from openlp.core.common import AppLocation

View File

@ -22,7 +22,7 @@
import logging import logging
from openlp.core.api.http.endpoint import Endpoint from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http.endpoint.pluginhelpers import search, live, service from openlp.core.api.endpoint.pluginhelpers import search, live, service
from openlp.core.api.http import requires_auth from openlp.core.api.http import requires_auth