More updates

This commit is contained in:
Tim Bentley 2016-06-19 18:39:48 +01:00
parent 549598e5be
commit f92701ff98
10 changed files with 421 additions and 25 deletions

View File

@ -21,9 +21,9 @@
###############################################################################
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import register_endpoint
from openlp.core.api.http import register_endpoint, requires_auth
from openlp.core.api.tab import ApiTab
from openlp.core.api.controller import ApiController
from openlp.core.api.poll import Poller
__all__ = ['Endpoint', 'ApiController', 'ApiTab', 'register_endpoint']
__all__ = ['Endpoint', 'ApiController', 'ApiTab', 'register_endpoint', 'requires_auth']

View File

@ -20,6 +20,11 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import base64
from functools import wraps
from webob import Response
from openlp.core.common.settings import Settings
from openlp.core.api.http.wsgiapp import WSGIApplication
application = WSGIApplication('api')
@ -52,3 +57,53 @@ def register_endpoint(end_point):
static_route += '(.*)'
application.add_static_route(static_route, end_point.static_dir)
def check_auth(auth):
"""
This function is called to check if a username password combination is valid.
:param auth: the authorisation object which needs to be tested
:return Whether authentication have been successful
"""
auth_code = "{user}:{password}".format(user=Settings().value('remotes/user id'),
password=Settings().value('remotes/password'))
try:
auth_base = base64.b64encode(auth_code)
except TypeError:
auth_base = base64.b64encode(auth_code.encode()).decode()
if auth[1] == auth_base:
return True
else:
return False
def authenticate():
"""
Sends a 401 response that enables basic auth to be triggered
"""
resp = Response(status=401)
resp.www_authenticate = 'Basic realm="OpenLP Login Required"'
return resp
def requires_auth(f):
"""
Decorates a function which needs to be authenticated before it can be used from the remote.
:param f: The function which has been wrapped
:return: the called function or a request to authenticate
"""
@wraps(f)
def decorated(*args, **kwargs):
if not Settings().value('remotes/authentication enabled'):
return f(*args, **kwargs)
req = args[0]
if not hasattr(req, 'authorization'):
return authenticate()
else:
auth = req.authorization
if check_auth(auth):
return f(*args, **kwargs)
else:
return authenticate()
return decorated

View File

@ -24,10 +24,8 @@ The Endpoint class, which provides plugins with a way to serve their own portion
"""
import os
from functools import wraps
from mako.template import Template
from webob import Request, Response
class Endpoint(object):
@ -75,3 +73,4 @@ class Endpoint(object):
from .controller import controller_endpoint
from .core import stage_endpoint
from .service import service_endpoint
from .alert import alert_endpoint

View File

@ -0,0 +1,59 @@
# -*- 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
import urllib
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import register_endpoint, requires_auth
from openlp.core.common import Registry
from openlp.core.lib import PluginStatus
log = logging.getLogger(__name__)
alert_endpoint = Endpoint('alert')
@alert_endpoint.route('')
@requires_auth
def alert(request):
"""
Handles requests for setting service items in the service manager
:param request: The http request object.
"""
plugin = Registry().get('plugin_manager').get_plugin_by_name("alerts")
if plugin.status == PluginStatus.Active:
try:
json_data = request.GET.get('data')
text = int(json.loads(json_data)['request']['text'])
except KeyError:
log.error("Endpoint alerts request text not found")
text = urllib.parse.unquote(text)
Registry().get('alerts_manager').alerts_text.emit([text])
success = True
else:
success = False
return {'results': {'success': success}}
register_endpoint(alert_endpoint)

View File

@ -2,11 +2,12 @@ import logging
import os
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import register_endpoint
from openlp.core.api.http import register_endpoint, requires_auth
from openlp.core.common import Registry, AppLocation, UiStrings, translate
from openlp.core.lib import image_to_byte
from openlp.core.lib import image_to_byte, PluginStatus, StringContent
template_dir = static_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
template_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
static_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static')
@ -88,7 +89,7 @@ def main_index(request):
@blank_endpoint.route('')
def static_file_loader(request):
def index(request):
"""
Deliver the page for the / url
:param request:
@ -96,6 +97,40 @@ def static_file_loader(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('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('plugin/{search:search}')
def plugin_search(request, search):
"""
Deliver the functions for the /display url
:param request: the http request - not used
:param search: the display function to be triggered
"""
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}}
# @stage_endpoint.route('(stage)/(.*)$')
# def bespoke_file_access(request):
# """
@ -155,4 +190,4 @@ def get_content_type(file_name):
register_endpoint(stage_endpoint)
register_endpoint(blank_endpoint)
register_endpoint(main_endpoint)
register_endpoint(main_endpoint)

View File

@ -0,0 +1,177 @@
<!DOCTYPE html>
<html>
<!--
###############################################################################
# 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 #
###############################################################################
-->
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1" />
<title>${app_title}</title>
<link rel="stylesheet" href="/static/assets/jquery.mobile.min.css" />
<link rel="stylesheet" href="/static/css/openlp.css" />
<link rel="shortcut icon" type="image/x-icon" href="/static/images/favicon.ico">
<script type="text/javascript" src="/static/assets/jquery.min.js"></script>
<script type="text/javascript" src="/static/js/openlp.js"></script>
<script type="text/javascript" src="/static/assets/jquery.mobile.min.js"></script>
<script type="text/javascript">
translationStrings = {
"go_live": "${go_live}",
"add_to_service": "${add_to_service}",
"no_results": "${no_results}",
"home": "${home}"
}
</script>
</head>
<body>
<div data-role="page" id="home">
<div data-role="header">
<h1>${app_title}</h1>
</div>
<div data-role="content">
<div data-role="controlgroup">
<a href="#service-manager" data-role="button" data-icon="arrow-r" data-iconpos="right">${service_manager}</a>
<a href="#slide-controller" data-role="button" data-icon="arrow-r" data-iconpos="right">${slide_controller}</a>
<a href="#alerts" data-role="button" data-icon="arrow-r" data-iconpos="right">${alerts}</a>
<a href="#search" data-role="button" data-icon="arrow-r" data-iconpos="right">${search}</a>
</div>
</div>
</div>
<div data-role="page" id="service-manager">
<div data-role="header" data-position="fixed">
<a href="#home" data-role="button" data-icon="home" data-iconpos="left">${home}</a>
<h1>${service_manager}</h1>
<a href="#" id="service-refresh" data-role="button" data-icon="refresh">${refresh}</a>
<div data-role="navbar">
<ul>
<li><a href="#service-manager" data-theme="e">${service}</a></li>
<li><a href="#slide-controller">${slides}</a></li>
<li><a href="#alerts">${alerts}</a></li>
<li><a href="#search">${search}</a></li>
</ul>
</div>
</div>
<div data-role="content">
<ul data-role="listview" data-inset="true">
</ul>
</div>
<div data-role="footer" data-theme="b" class="ui-bar" data-position="fixed">
<div data-role="controlgroup" data-type="horizontal" style="float: left;">
<a href="#" id="service-blank" data-role="button" data-icon="blank">${blank}</a>
<a href="#" id="service-theme" data-role="button">${theme}</a>
<a href="#" id="service-desktop" data-role="button">${desktop}</a>
<a href="#" id="service-show" data-role="button" data-icon="unblank" data-iconpos="right">${show}</a>
</div>
<div data-role="controlgroup" data-type="horizontal" style="float: left;">
<a href="#" id="service-previous" data-role="button" data-icon="arrow-l">${prev}</a>
<a href="#" id="service-next" data-role="button" data-icon="arrow-r" data-iconpos="right">${next}</a>
</div>
</div>
</div>
<div data-role="page" id="slide-controller">
<div data-role="header" data-position="fixed">
<a href="#home" data-role="button" data-icon="home" data-iconpos="left">${home}</a>
<h1>${slide_controller}</h1>
<a href="#" id="controller-refresh" data-role="button" data-icon="refresh">${refresh}</a>
<div data-role="navbar">
<ul>
<li><a href="#service-manager">${service}</a></li>
<li><a href="#slide-controller" data-theme="e">${slides}</a></li>
<li><a href="#alerts">${alerts}</a></li>
<li><a href="#search">${search}</a></li>
</ul>
</div>
</div>
<div data-role="content">
<ul data-role="listview" data-inset="true">
</ul>
</div>
<div data-role="footer" data-theme="b" class="ui-bar" data-position="fixed">
<div data-role="controlgroup" data-type="horizontal" style="float: left;">
<a href="#" id="controller-blank" data-role="button" data-icon="blank">${blank}</a>
<a href="#" id="controller-theme" data-role="button">${theme}</a>
<a href="#" id="controller-desktop" data-role="button">${desktop}</a>
<a href="#" id="controller-show" data-role="button" data-icon="unblank" data-iconpos="right">${show}</a>
</div>
<div data-role="controlgroup" data-type="horizontal" style="float: left;">
<a href="#" id="controller-previous" data-role="button" data-icon="arrow-l">${prev}</a>
<a href="#" id="controller-next" data-role="button" data-icon="arrow-r" data-iconpos="right">${next}</a>
</div>
</div>
</div>
<div data-role="page" id="alerts">
<div data-role="header">
<a href="#home" data-role="button" data-icon="home" data-iconpos="left">${home}</a>
<h1>${alerts}</h1>
<div data-role="navbar">
<ul>
<li><a href="#service-manager">${service}</a></li>
<li><a href="#slide-controller">${slides}</a></li>
<li><a href="#alerts" data-theme="e">${alerts}</a></li>
<li><a href="#search">${search}</a></li>
</ul>
</div>
</div>
<div data-role="content">
<div data-role="fieldcontain">
<label for="alert-text">${text}:</label>
<input type="text" name="alert-text" id="alert-text" value="" />
</div>
<a href="#" id="alert-submit" data-role="button">${show_alert}</a>
</div>
</div>
<div data-role="page" id="search">
<div data-role="header" data-position="fixed">
<a href="#home" data-role="button" data-icon="home" data-iconpos="left">${home}</a>
<h1>${search}</h1>
<div data-role="navbar">
<ul>
<li><a href="#service-manager">${service}</a></li>
<li><a href="#slide-controller">${slides}</a></li>
<li><a href="#alerts">${alerts}</a></li>
<li><a href="#search" data-theme="e">${search}</a></li>
</ul>
</div>
</div>
<div data-role="content">
<div data-role="fieldcontain">
<label for="search-plugin">${search}:</label>
<select name="search-plugin" id="search-plugin" data-native-menu="false"></select>
</div>
<div data-role="fieldcontain">
<label for="search-text">${text}:</label>
<input type="search" name="search-text" id="search-text" value="" />
</div>
<a href="#" id="search-submit" data-role="button">${search}</a>
<ul data-role="listview" data-inset="true"/>
</div>
</div>
<div data-role="page" id="options">
<div data-role="header" data-position="inline" data-theme="b">
<h1>${options}</h1>
</div>
<div data-role="content">
<input type="hidden" id="selected-item" value="" />
<a href="#" id="go-live" data-role="button">${go_live}</a>
<a href="#" id="add-to-service" data-role="button">${add_to_service}</a>
<a href="#" id="add-and-go-to-service" data-role="button">${add_and_go_to_service}</a>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<!--
###############################################################################
# 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 #
###############################################################################
-->
<head>
<meta charset="utf-8" />s
<title>${live_title}</title>
<link rel="stylesheet" href="/static/css/main.css" />
<link rel="shortcut icon" type="image/x-icon" href="/static/images/favicon.ico">
<script type="text/javascript" src="/static/assets/jquery.min.js"></script>
<script type="text/javascript" src="/static/js/main.js"></script>
</head>
<body>
<img id="image" class="size"/>
</body>
</html>

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<!--
###############################################################################
# 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 #
###############################################################################
-->
<head>
<meta charset="utf-8" />
<title>${stage_title}</title>
<link rel="stylesheet" href="/static/css/stage.css" />
<link rel="shortcut icon" type="image/x-icon" href="/static/images/favicon.ico">
<script type="text/javascript" src="/static/assets/jquery.min.js"></script>
<script type="text/javascript" src="/static/js/stage.js"></script>
</head>
<body>
<input type="hidden" id="next-text" value="${next}" />
<div id="right">
<div id="clock"></div>
<div id="notes"></div>
</div>
<div id="verseorder"></div>
<div id="currentslide"></div>
<div id="nextslide"></div>
</body>
</html>

View File

@ -69,8 +69,6 @@ def _make_response(view_result):
"""
Create a Response object from response
"""
print("##")
print(type(view_result))
if isinstance(view_result, Response):
return view_result
elif isinstance(view_result, tuple):
@ -120,7 +118,6 @@ class WSGIApplication(object):
Add a route
"""
route_regex = _route_to_regex(route)
print("###", route, route_regex)
if route_regex not in self.route_map:
self.route_map[route_regex] = {}
self.route_map[route_regex][method.upper()] = view_func
@ -137,14 +134,13 @@ class WSGIApplication(object):
Find the appropriate URL and run the view function
"""
# We are not interested in this so discard
print("rrr",request.path)
if '/favicon.ico' in request.path:
return
# First look to see if this is a static file request
for route, static_app in self.static_routes.items():
print(route, request.path)
if re.match(route, request.path):
print("matched")
print("matched static")
# Pop the path info twice in order to get rid of the "/<plugin>/static"
# request.path_info_pop()
request.path_info_pop()
@ -154,9 +150,8 @@ class WSGIApplication(object):
path = request.path
# /api is legacy so we need to handle backwards compatibility
if path.startswith('/api'):
path = path[4:]
print("MMMATCHED")
print(route, request.path, path)
path = path[4:]
print("route MATCHED", route, request.path, path)
match = re.match(route, path)
print(match)
if match and request.method.upper() in views:
@ -183,4 +178,3 @@ class WSGIApplication(object):
Shortcut for wsgi_app.
"""
return self.wsgi_app(environ, start_response)

View File

@ -35,11 +35,8 @@ class Poller(RegistryProperties):
"""
super(Poller, self).__init__()
def poll(self):
"""
Poll OpenLP to determine the current slide number and item name.
"""
result = {
def raw_poll(self):
return {
'service': self.service_manager.service_id,
'slide': self.live_controller.selected_row or 0,
'item': self.live_controller.service_item.unique_identifier if self.live_controller.service_item else '',
@ -47,11 +44,16 @@ class Poller(RegistryProperties):
'blank': self.live_controller.blank_screen.isChecked(),
'theme': self.live_controller.theme_screen.isChecked(),
'display': self.live_controller.desktop_screen.isChecked(),
'version': 2,
'version': 3,
'isSecure': Settings().value('remotes/authentication enabled'),
'isAuthorised': False
}
return json.dumps({'results': result}).encode()
def poll(self):
"""
Poll OpenLP to determine the current slide number and item name.
"""
return json.dumps({'results': self.raw_poll()}).encode()
def main_poll(self):
"""