Mark a custom slide edited from preview as coming from plugin. Fixes bug 1439671.

Use html.escape instead of the deprecated cgi.escape
Fix support for special characters in theme names. Fixes bug 1438563.
Fix another case of traceback when playing media with no players available/enabled (bug 1422761).

bzr-revno: 2526
Fixes: https://launchpad.net/bugs/1439671, https://launchpad.net/bugs/1438563, https://launchpad.net/bugs/1422761
This commit is contained in:
Tomas Groth 2015-04-03 20:31:19 +02:00 committed by Raoul Snyman
commit cff0b412f8
9 changed files with 53 additions and 13 deletions

View File

@ -66,8 +66,9 @@ def check_directory_exists(directory, do_not_log=False):
try: try:
if not os.path.exists(directory): if not os.path.exists(directory):
os.makedirs(directory) os.makedirs(directory)
except IOError: except IOError as e:
pass if not do_not_log:
log.exception('failed to check if directory exists or create directory')
def get_frozen_path(frozen_option, non_frozen_option): def get_frozen_path(frozen_option, non_frozen_option):

View File

@ -90,7 +90,7 @@ def get_text_file_string(text_file):
file_handle = None file_handle = None
content = None content = None
try: try:
file_handle = open(text_file, 'r') file_handle = open(text_file, 'r', encoding='utf-8')
if not file_handle.read(3) == '\xEF\xBB\xBF': if not file_handle.read(3) == '\xEF\xBB\xBF':
# no BOM was found # no BOM was found
file_handle.seek(0) file_handle.seek(0)

View File

@ -29,7 +29,7 @@ Some of the code for this form is based on the examples at:
""" """
import cgi import html
import logging import logging
from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
@ -273,7 +273,7 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties):
""" """
# First we convert <>& marks to html variants, then apply # First we convert <>& marks to html variants, then apply
# formattingtags, finally we double all backslashes for JavaScript. # formattingtags, finally we double all backslashes for JavaScript.
text_prepared = expand_tags(cgi.escape(text)).replace('\\', '\\\\').replace('\"', '\\\"') text_prepared = expand_tags(html.escape(text)).replace('\\', '\\\\').replace('\"', '\\\"')
if self.height() != self.screen['size'].height() or not self.isVisible(): if self.height() != self.screen['size'].height() or not self.isVisible():
shrink = True shrink = True
js = 'show_alert("%s", "%s")' % (text_prepared, 'top') js = 'show_alert("%s", "%s")' % (text_prepared, 'top')

View File

@ -523,6 +523,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
if controller.media_info.file_info.isFile(): if controller.media_info.file_info.isFile():
suffix = '*.%s' % controller.media_info.file_info.suffix().lower() suffix = '*.%s' % controller.media_info.file_info.suffix().lower()
for title in used_players: for title in used_players:
if not title:
continue
player = self.media_players[title] player = self.media_players[title]
if suffix in player.video_extensions_list: if suffix in player.video_extensions_list:
if not controller.media_info.is_background or controller.media_info.is_background and \ if not controller.media_info.is_background or controller.media_info.is_background and \

View File

@ -354,6 +354,10 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R
delete_file(os.path.join(self.path, thumb)) delete_file(os.path.join(self.path, thumb))
delete_file(os.path.join(self.thumb_path, thumb)) delete_file(os.path.join(self.thumb_path, thumb))
try: try:
# Windows is always unicode, so no need to encode filenames
if is_win():
shutil.rmtree(os.path.join(self.path, theme))
else:
encoding = get_filesystem_encoding() encoding = get_filesystem_encoding()
shutil.rmtree(os.path.join(self.path, theme).encode(encoding)) shutil.rmtree(os.path.join(self.path, theme).encode(encoding))
except OSError as os_error: except OSError as os_error:
@ -567,7 +571,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R
check_directory_exists(os.path.dirname(full_name)) check_directory_exists(os.path.dirname(full_name))
if os.path.splitext(name)[1].lower() == '.xml': if os.path.splitext(name)[1].lower() == '.xml':
file_xml = str(theme_zip.read(name), 'utf-8') file_xml = str(theme_zip.read(name), 'utf-8')
out_file = open(full_name, 'w') out_file = open(full_name, 'w', encoding='utf-8')
out_file.write(file_xml) out_file.write(file_xml)
else: else:
out_file = open(full_name, 'wb') out_file = open(full_name, 'wb')
@ -645,8 +649,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R
delete_file(self.old_background_image) delete_file(self.old_background_image)
out_file = None out_file = None
try: try:
out_file = open(theme_file, 'w') out_file = open(theme_file, 'w', encoding='utf-8')
out_file.write(theme_pretty_xml.decode('UTF-8')) out_file.write(theme_pretty_xml.decode('utf-8'))
except IOError: except IOError:
self.log_exception('Saving theme to file failed') self.log_exception('Saving theme to file failed')
finally: finally:

View File

@ -158,6 +158,10 @@ class CustomMediaItem(MediaManagerItem):
self.remote_triggered = None self.remote_triggered = None
self.remote_custom = 1 self.remote_custom = 1
if item: if item:
if preview:
# A custom slide can only be edited if it comes from plugin,
# so we set it again for the new item.
item.from_plugin = True
return item return item
return None return None

View File

@ -55,7 +55,7 @@ The XML of an `OpenLyrics <http://openlyrics.info/>`_ song looks like this::
</lyrics> </lyrics>
</song> </song>
""" """
import cgi import html
import logging import logging
import re import re
@ -318,7 +318,7 @@ class OpenLyrics(object):
if 'lang' in verse[0]: if 'lang' in verse[0]:
verse_element.set('lang', verse[0]['lang']) verse_element.set('lang', verse[0]['lang'])
# Create a list with all "optional" verses. # Create a list with all "optional" verses.
optional_verses = cgi.escape(verse[1]) optional_verses = html.escape(verse[1])
optional_verses = optional_verses.split('\n[---]\n') optional_verses = optional_verses.split('\n[---]\n')
start_tags = '' start_tags = ''
end_tags = '' end_tags = ''

View File

@ -176,7 +176,7 @@ class TestLib(TestCase):
# THEN: None should be returned # THEN: None should be returned
mocked_isfile.assert_called_with(filename) mocked_isfile.assert_called_with(filename)
mocked_open.assert_called_with(filename, 'r') mocked_open.assert_called_with(filename, 'r', encoding='utf-8')
self.assertIsNone(result, 'None should be returned if the file cannot be opened') self.assertIsNone(result, 'None should be returned if the file cannot be opened')
def get_text_file_string_decode_error_test(self): def get_text_file_string_decode_error_test(self):

View File

@ -29,6 +29,7 @@ from unittest import TestCase
from tempfile import mkdtemp from tempfile import mkdtemp
from PyQt4 import QtGui from PyQt4 import QtGui
from tempfile import mkdtemp
from openlp.core.ui import ThemeManager from openlp.core.ui import ThemeManager
from openlp.core.common import Registry from openlp.core.common import Registry
@ -44,6 +45,13 @@ class TestThemeManager(TestCase):
Set up the tests Set up the tests
""" """
Registry.create() Registry.create()
self.temp_folder = mkdtemp()
def tearDown(self):
"""
Clean up
"""
shutil.rmtree(self.temp_folder)
def export_theme_test(self): def export_theme_test(self):
""" """
@ -131,6 +139,27 @@ class TestThemeManager(TestCase):
# THEN: The mocked_copyfile should not have been called # THEN: The mocked_copyfile should not have been called
self.assertTrue(mocked_copyfile.called, 'shutil.copyfile should be called') self.assertTrue(mocked_copyfile.called, 'shutil.copyfile should be called')
def write_theme_special_char_name_test(self):
"""
Test that we can save themes with special characters in the name
"""
# GIVEN: A new theme manager instance, with mocked theme and thememanager-attributes.
theme_manager = ThemeManager(None)
theme_manager.old_background_image = None
theme_manager.generate_and_save_image = MagicMock()
theme_manager.path = self.temp_folder
mocked_theme = MagicMock()
mocked_theme.theme_name = 'theme 愛 name'
mocked_theme.extract_formatted_xml = MagicMock()
mocked_theme.extract_formatted_xml.return_value = 'fake theme 愛 XML'.encode()
# WHEN: Calling _write_theme with a theme with a name with special characters in it
theme_manager._write_theme(mocked_theme, None, None)
# THEN: It should have been created
self.assertTrue(os.path.exists(os.path.join(self.temp_folder, 'theme 愛 name', 'theme 愛 name.xml')),
'Theme with special characters should have been created!')
def over_write_message_box_yes_test(self): def over_write_message_box_yes_test(self):
""" """
Test that theme_manager.over_write_message_box returns True when the user clicks yes. Test that theme_manager.over_write_message_box returns True when the user clicks yes.