forked from openlp/openlp
head
This commit is contained in:
commit
48d2956bdd
@ -93,14 +93,14 @@ class GeneralTab(SettingsTab):
|
||||
self.monitor_layout.addWidget(self.custom_width_label, 3, 3)
|
||||
self.custom_width_value_edit = QtGui.QSpinBox(self.monitor_group_box)
|
||||
self.custom_width_value_edit.setObjectName(u'custom_width_value_edit')
|
||||
self.custom_width_value_edit.setMaximum(9999)
|
||||
self.custom_width_value_edit.setRange(1, 9999)
|
||||
self.monitor_layout.addWidget(self.custom_width_value_edit, 4, 3)
|
||||
self.custom_height_label = QtGui.QLabel(self.monitor_group_box)
|
||||
self.custom_height_label.setObjectName(u'custom_height_label')
|
||||
self.monitor_layout.addWidget(self.custom_height_label, 3, 4)
|
||||
self.custom_height_value_edit = QtGui.QSpinBox(self.monitor_group_box)
|
||||
self.custom_height_value_edit.setObjectName(u'custom_height_value_edit')
|
||||
self.custom_height_value_edit.setMaximum(9999)
|
||||
self.custom_height_value_edit.setRange(1, 9999)
|
||||
self.monitor_layout.addWidget(self.custom_height_value_edit, 4, 4)
|
||||
self.display_on_monitor_check = QtGui.QCheckBox(self.monitor_group_box)
|
||||
self.display_on_monitor_check.setObjectName(u'monitor_combo_box')
|
||||
|
@ -38,7 +38,7 @@ from openlp.core.lib import UiStrings, Registry, translate
|
||||
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
|
||||
from openlp.core.lib.ui import critical_error_message_box
|
||||
from openlp.core.ui import ThemeLayoutForm
|
||||
from openlp.core.utils import get_images_filter
|
||||
from openlp.core.utils import get_images_filter, is_not_image_file
|
||||
from themewizard import Ui_ThemeWizard
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -178,7 +178,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
|
||||
"""
|
||||
background_image = BackgroundType.to_string(BackgroundType.Image)
|
||||
if self.page(self.currentId()) == self.backgroundPage and \
|
||||
self.theme.background_type == background_image and not self.imageFileEdit.text():
|
||||
self.theme.background_type == background_image and is_not_image_file(self.imageFileEdit.text()):
|
||||
QtGui.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'),
|
||||
translate('OpenLP.ThemeWizard', 'You have not selected a '
|
||||
'background image. Please select one before continuing.'))
|
||||
|
@ -246,6 +246,23 @@ def get_images_filter():
|
||||
return IMAGES_FILTER
|
||||
|
||||
|
||||
def is_not_image_file(file_name):
|
||||
"""
|
||||
Validate that the file is not an image file.
|
||||
|
||||
``file_name``
|
||||
File name to be checked.
|
||||
"""
|
||||
if not file_name:
|
||||
return True
|
||||
else:
|
||||
formats = [unicode(fmt).lower() for fmt in QtGui.QImageReader.supportedImageFormats()]
|
||||
file_part, file_extension = os.path.splitext(unicode(file_name))
|
||||
if file_extension[1:].lower() in formats and os.path.exists(file_name):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def split_filename(path):
|
||||
"""
|
||||
Return a list of the parts in a given path.
|
||||
|
@ -30,10 +30,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>${live_title}</title>
|
||||
<link rel="stylesheet" href="/files/live.css" />
|
||||
<link rel="stylesheet" href="/files/main.css" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
|
||||
<script type="text/javascript" src="/files/jquery.js"></script>
|
||||
<script type="text/javascript" src="/files/live.js"></script>
|
||||
<script type="text/javascript" src="/files/main.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<img id="image" class="size"/>
|
@ -26,7 +26,7 @@
|
||||
window.OpenLP = {
|
||||
loadSlide: function (event) {
|
||||
$.getJSON(
|
||||
"/live/image",
|
||||
"/main/image",
|
||||
function (data, status) {
|
||||
var img = document.getElementById('image');
|
||||
img.src = data.results.slide_image;
|
||||
@ -36,7 +36,7 @@ window.OpenLP = {
|
||||
},
|
||||
pollServer: function () {
|
||||
$.getJSON(
|
||||
"/live/poll",
|
||||
"/main/poll",
|
||||
function (data, status) {
|
||||
if (OpenLP.slideCount != data.results.slide_count) {
|
||||
OpenLP.slideCount = data.results.slide_count;
|
@ -177,11 +177,11 @@ class HttpServer(object):
|
||||
self.root = self.Public()
|
||||
self.root.files = self.Files()
|
||||
self.root.stage = self.Stage()
|
||||
self.root.live = self.Live()
|
||||
self.root.main = self.Main()
|
||||
self.root.router = self.router
|
||||
self.root.files.router = self.router
|
||||
self.root.stage.router = self.router
|
||||
self.root.live.router = self.router
|
||||
self.root.main.router = self.router
|
||||
cherrypy.tree.mount(self.root, '/', config=self.define_config())
|
||||
# Turn off the flood of access messages cause by poll
|
||||
cherrypy.log.access_log.propagate = False
|
||||
@ -218,7 +218,7 @@ class HttpServer(object):
|
||||
u'/stage': {u'tools.staticdir.on': True,
|
||||
u'tools.staticdir.dir': self.router.html_dir,
|
||||
u'tools.basic_auth.on': False},
|
||||
u'/live': {u'tools.staticdir.on': True,
|
||||
u'/main': {u'tools.staticdir.on': True,
|
||||
u'tools.staticdir.dir': self.router.html_dir,
|
||||
u'tools.basic_auth.on': False}}
|
||||
return directory_config
|
||||
@ -253,9 +253,9 @@ class HttpServer(object):
|
||||
url = urlparse.urlparse(cherrypy.url())
|
||||
return self.router.process_http_request(url.path, *args)
|
||||
|
||||
class Live(object):
|
||||
class Main(object):
|
||||
"""
|
||||
Live view is read only so security is not relevant and would reduce it's usability
|
||||
Main view is read only so security is not relevant and would reduce it's usability
|
||||
"""
|
||||
@cherrypy.expose
|
||||
def default(self, *args, **kwargs):
|
||||
@ -281,12 +281,12 @@ class HttpRouter(object):
|
||||
self.routes = [
|
||||
(u'^/$', self.serve_file),
|
||||
(u'^/(stage)$', self.serve_file),
|
||||
(u'^/(live)$', self.serve_file),
|
||||
(u'^/(main)$', self.serve_file),
|
||||
(r'^/files/(.*)$', self.serve_file),
|
||||
(r'^/api/poll$', self.poll),
|
||||
(r'^/stage/poll$', self.poll),
|
||||
(r'^/live/poll$', self.live_poll),
|
||||
(r'^/live/image$', self.live_image),
|
||||
(r'^/main/poll$', self.main_poll),
|
||||
(r'^/main/image$', self.main_image),
|
||||
(r'^/api/controller/(live|preview)/(.*)$', self.controller),
|
||||
(r'^/stage/controller/(live|preview)/(.*)$', self.controller),
|
||||
(r'^/api/service/(.*)$', self.service),
|
||||
@ -378,7 +378,7 @@ class HttpRouter(object):
|
||||
'slides': translate('RemotePlugin.Mobile', 'Slides')
|
||||
}
|
||||
|
||||
def serve_file(self, filename=None):
|
||||
def serve_file(self, file_name=None):
|
||||
"""
|
||||
Send a file to the socket. For now, just a subset of file types and must be top level inside the html folder.
|
||||
If subfolders requested return 404, easier for security for the present.
|
||||
@ -386,17 +386,17 @@ class HttpRouter(object):
|
||||
Ultimately for i18n, this could first look for xx/file.html before falling back to file.html.
|
||||
where xx is the language, e.g. 'en'
|
||||
"""
|
||||
log.debug(u'serve file request %s' % filename)
|
||||
if not filename:
|
||||
filename = u'index.html'
|
||||
elif filename == u'stage':
|
||||
filename = u'stage.html'
|
||||
elif filename == u'live':
|
||||
filename = u'live.html'
|
||||
path = os.path.normpath(os.path.join(self.html_dir, filename))
|
||||
log.debug(u'serve file request %s' % file_name)
|
||||
if not file_name:
|
||||
file_name = u'index.html'
|
||||
elif file_name == u'stage':
|
||||
file_name = u'stage.html'
|
||||
elif file_name == u'main':
|
||||
file_name = u'main.html'
|
||||
path = os.path.normpath(os.path.join(self.html_dir, file_name))
|
||||
if not path.startswith(self.html_dir):
|
||||
return self._http_not_found()
|
||||
ext = os.path.splitext(filename)[1]
|
||||
ext = os.path.splitext(file_name)[1]
|
||||
html = None
|
||||
if ext == u'.html':
|
||||
mimetype = u'text/html'
|
||||
@ -447,7 +447,7 @@ class HttpRouter(object):
|
||||
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||
return json.dumps({u'results': result}).encode()
|
||||
|
||||
def live_poll(self):
|
||||
def main_poll(self):
|
||||
"""
|
||||
Poll OpenLP to determine the current slide count.
|
||||
"""
|
||||
@ -457,7 +457,7 @@ class HttpRouter(object):
|
||||
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||
return json.dumps({u'results': result}).encode()
|
||||
|
||||
def live_image(self):
|
||||
def main_image(self):
|
||||
"""
|
||||
Return the latest display image as a byte stream.
|
||||
"""
|
||||
|
@ -83,7 +83,6 @@ MODULES = [
|
||||
'bs4',
|
||||
'mako',
|
||||
'cherrypy',
|
||||
'migrate',
|
||||
'uno',
|
||||
'icu',
|
||||
'bs4',
|
||||
|
0
tests/interfaces/openlp_core_utils/__init__.py
Normal file
0
tests/interfaces/openlp_core_utils/__init__.py
Normal file
52
tests/interfaces/openlp_core_utils/test_utils.py
Normal file
52
tests/interfaces/openlp_core_utils/test_utils.py
Normal file
@ -0,0 +1,52 @@
|
||||
"""
|
||||
Functional tests to test the AppLocation class and related methods.
|
||||
"""
|
||||
import os
|
||||
from unittest import TestCase
|
||||
|
||||
from openlp.core.utils import is_not_image_file
|
||||
from tests.utils.constants import TEST_RESOURCES_PATH
|
||||
|
||||
|
||||
class TestUtils(TestCase):
|
||||
"""
|
||||
A test suite to test out various methods around the Utils functions.
|
||||
"""
|
||||
def is_not_image_empty_test(self):
|
||||
"""
|
||||
Test the method handles an empty string
|
||||
"""
|
||||
# Given and empty string
|
||||
file_name = ""
|
||||
|
||||
# WHEN testing for it
|
||||
result = is_not_image_file(file_name)
|
||||
|
||||
# THEN the result is false
|
||||
assert result is True, u'The missing file test should return True'
|
||||
|
||||
def is_not_image_with_image_file_test(self):
|
||||
"""
|
||||
Test the method handles an image file
|
||||
"""
|
||||
# Given and empty string
|
||||
file_name = os.path.join(TEST_RESOURCES_PATH, u'church.jpg')
|
||||
|
||||
# WHEN testing for it
|
||||
result = is_not_image_file(file_name)
|
||||
|
||||
# THEN the result is false
|
||||
assert result is False, u'The file is present so the test should return False'
|
||||
|
||||
def is_not_image_with_none_image_file_test(self):
|
||||
"""
|
||||
Test the method handles a non image file
|
||||
"""
|
||||
# Given and empty string
|
||||
file_name = os.path.join(TEST_RESOURCES_PATH, u'serviceitem_custom_1.osj')
|
||||
|
||||
# WHEN testing for it
|
||||
result = is_not_image_file(file_name)
|
||||
|
||||
# THEN the result is false
|
||||
assert result is True, u'The file is not an image file so the test should return True'
|
Loading…
Reference in New Issue
Block a user