From 1b6a54c55d64ee1f47d3276c15450cbba3ff838d Mon Sep 17 00:00:00 2001
From: phill-ridout
Date: Fri, 15 Feb 2013 19:57:05 +0000
Subject: [PATCH 01/71] started on tests for SongShowPlusImport
---
openlp/plugins/songs/lib/__init__.py | 2 +-
.../openlp_plugins_songs_lib/__init__.py | 0
.../test_songshowplusimport.py | 43 +++++++++++++++++++
3 files changed, 44 insertions(+), 1 deletion(-)
create mode 100644 tests/functional/openlp_plugins_songs_lib/__init__.py
create mode 100644 tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py
index c7c24533b..4041bb12e 100644
--- a/openlp/plugins/songs/lib/__init__.py
+++ b/openlp/plugins/songs/lib/__init__.py
@@ -167,7 +167,7 @@ class VerseType(object):
translate('SongsPlugin.VerseType', 'Intro'),
translate('SongsPlugin.VerseType', 'Ending'),
translate('SongsPlugin.VerseType', 'Other')]
- TranslatedTags = [name[0].lower() for name in TranslatedNames]
+ TranslatedTags = [unicode(name[0]).lower() for name in TranslatedNames]
@staticmethod
def translated_tag(verse_tag, default=Other):
diff --git a/tests/functional/openlp_plugins_songs_lib/__init__.py b/tests/functional/openlp_plugins_songs_lib/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py b/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
new file mode 100644
index 000000000..6189c6a7f
--- /dev/null
+++ b/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
@@ -0,0 +1,43 @@
+"""
+ Package to test the openlp.plugins.songs.lib package.
+"""
+import os
+
+from unittest import TestCase
+from mock import MagicMock, patch
+from openlp.plugins.songs.lib import songshowplusimport
+
+TESTPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
+
+
+class TestSongShowPlusImport(TestCase):
+
+ def default_test(self):
+ """
+ Test the defaults of songshowplusimport
+ """
+ # Given: The songshowplusimport module as imported
+
+ # When: Imported the module should have defaults set
+ constants = {u'TITLE' : 1, u'AUTHOR' : 2, u'COPYRIGHT' : 3, u'CCLI_NO' : 5, u'VERSE' : 12, u'CHORUS' : 20,
+ u'BRIDGE' : 24, u'TOPIC' : 29, u'COMMENTS' : 30, u'VERSE_ORDER' : 31, u'SONG_BOOK' : 35,
+ u'SONG_NUMBER' : 36, u'CUSTOM_VERSE' : 37, u'SongShowPlusImport.otherList' : {},
+ u'SongShowPlusImport.otherCount' : 0}
+
+ # Then: The constants should not have changed.
+ for constant in constants:
+ value = constants[constant]
+ self.assertEquals(eval(u'songshowplusimport.%s' % constant), value,
+ u'%s should be set as %s' % (constant, value))
+
+
+ def do_import_test(self):
+ mocked_manager = MagicMock()
+ songshowplusimport.SongImport = MagicMock()
+
+ with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport') as mocked_song_import:
+ ssp_import_class = songshowplusimport.SongShowPlusImport(mocked_manager)
+
+ songshowplusimport.SongShowPlusImport.importSource = ''
+
+ self.assertEquals(ssp_import_class.SongShowPlusImport().doImport(), False)
From ca2b2db6402fbe94e55e8698a00dc193714de7e2 Mon Sep 17 00:00:00 2001
From: phill-ridout
Date: Sun, 17 Feb 2013 19:37:59 +0000
Subject: [PATCH 02/71] fixed duplicates in verse order when adding verses with
the same tag. fixed handling of part verses eg (1a, 1b, 1.5, etc) in
SongShowPlus importer
---
openlp/plugins/songs/lib/songimport.py | 3 ++-
.../plugins/songs/lib/songshowplusimport.py | 16 +++++++++-----
.../test_songshowplusimport.py | 22 +++++--------------
3 files changed, 17 insertions(+), 24 deletions(-)
diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py
index f6a84945c..0d563935f 100644
--- a/openlp/plugins/songs/lib/songimport.py
+++ b/openlp/plugins/songs/lib/songimport.py
@@ -260,7 +260,8 @@ class SongImport(QtCore.QObject):
elif int(verse_def[1:]) > self.verseCounts[verse_def[0]]:
self.verseCounts[verse_def[0]] = int(verse_def[1:])
self.verses.append([verse_def, verse_text.rstrip(), lang])
- self.verseOrderListGenerated.append(verse_def)
+ if verse_def not in self.verseOrderListGenerated:
+ self.verseOrderListGenerated.append(verse_def)
def repeatVerse(self):
"""
diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py
index c5bb8832d..8e4957c71 100644
--- a/openlp/plugins/songs/lib/songshowplusimport.py
+++ b/openlp/plugins/songs/lib/songshowplusimport.py
@@ -32,6 +32,7 @@ SongShow Plus songs into the OpenLP database.
"""
import os
import logging
+import re
import struct
from openlp.core.ui.wizard import WizardStrings
@@ -44,13 +45,13 @@ COPYRIGHT = 3
CCLI_NO = 5
VERSE = 12
CHORUS = 20
+BRIDGE = 24
TOPIC = 29
COMMENTS = 30
VERSE_ORDER = 31
SONG_BOOK = 35
SONG_NUMBER = 36
CUSTOM_VERSE = 37
-BRIDGE = 24
log = logging.getLogger(__name__)
@@ -183,13 +184,16 @@ class SongShowPlusImport(SongImport):
self.logError(file)
def toOpenLPVerseTag(self, verse_name, ignore_unique=False):
- if verse_name.find(" ") != -1:
- verse_parts = verse_name.split(" ")
- verse_type = verse_parts[0]
- verse_number = verse_parts[1]
+ # Have we got any digits? If so, verse number is everything from the digits to the end (OpenLP does not have
+ # concept of part verses, so just ignore any non integers on the end (including floats))
+ match = re.match(u'(\D*)(\d+)', verse_name)
+ if match is not None:
+ verse_type = match.group(1).strip()
+ verse_number = match.group(2)
else:
+ # otherwise we assume number 1 and take the whole prefix as the verse tag
verse_type = verse_name
- verse_number = "1"
+ verse_number = u'1'
verse_type = verse_type.lower()
if verse_type == "verse":
verse_tag = VerseType.Tags[VerseType.Verse]
diff --git a/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py b/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
index 6189c6a7f..77733a1ba 100644
--- a/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
+++ b/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
@@ -12,28 +12,16 @@ TESTPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..',
class TestSongShowPlusImport(TestCase):
- def default_test(self):
- """
- Test the defaults of songshowplusimport
- """
- # Given: The songshowplusimport module as imported
+#test do import
+ # set self.import source to non list type. Do import should return None or False?
+ # set self.import source to a list of files
+ # importWizard.progressBar should be set to the number of files in the list
+ # set self.stop_import_flag to true. Do import should return None or False?
- # When: Imported the module should have defaults set
- constants = {u'TITLE' : 1, u'AUTHOR' : 2, u'COPYRIGHT' : 3, u'CCLI_NO' : 5, u'VERSE' : 12, u'CHORUS' : 20,
- u'BRIDGE' : 24, u'TOPIC' : 29, u'COMMENTS' : 30, u'VERSE_ORDER' : 31, u'SONG_BOOK' : 35,
- u'SONG_NUMBER' : 36, u'CUSTOM_VERSE' : 37, u'SongShowPlusImport.otherList' : {},
- u'SongShowPlusImport.otherCount' : 0}
-
- # Then: The constants should not have changed.
- for constant in constants:
- value = constants[constant]
- self.assertEquals(eval(u'songshowplusimport.%s' % constant), value,
- u'%s should be set as %s' % (constant, value))
def do_import_test(self):
mocked_manager = MagicMock()
- songshowplusimport.SongImport = MagicMock()
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport') as mocked_song_import:
ssp_import_class = songshowplusimport.SongShowPlusImport(mocked_manager)
From ea86ce905c382cc674a439f3a5e76bf57b679524 Mon Sep 17 00:00:00 2001
From: phill-ridout
Date: Mon, 18 Feb 2013 17:15:07 +0000
Subject: [PATCH 03/71] Simplified if statment
---
openlp/plugins/songs/lib/songshowplusimport.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py
index 8e4957c71..c9f9617df 100644
--- a/openlp/plugins/songs/lib/songshowplusimport.py
+++ b/openlp/plugins/songs/lib/songshowplusimport.py
@@ -187,7 +187,7 @@ class SongShowPlusImport(SongImport):
# Have we got any digits? If so, verse number is everything from the digits to the end (OpenLP does not have
# concept of part verses, so just ignore any non integers on the end (including floats))
match = re.match(u'(\D*)(\d+)', verse_name)
- if match is not None:
+ if match:
verse_type = match.group(1).strip()
verse_number = match.group(2)
else:
From 40de8647cf36dab6c14c8201777cc3a9df44d9b7 Mon Sep 17 00:00:00 2001
From: Andreas Preikschat
Date: Thu, 28 Feb 2013 21:47:59 +0100
Subject: [PATCH 04/71] renamed general settings to core
Fixes: https://launchpad.net/bugs/1133237
---
openlp/core/__init__.py | 10 +--
openlp/core/lib/screen.py | 12 +--
openlp/core/lib/settings.py | 73 +++++++++++++------
openlp/core/ui/firsttimeform.py | 6 +-
openlp/core/ui/generaltab.py | 2 +-
openlp/core/ui/maindisplay.py | 8 +-
openlp/core/ui/mainwindow.py | 2 +-
openlp/core/ui/media/mediacontroller.py | 2 +-
openlp/core/utils/languagemanager.py | 4 +-
openlp/plugins/songs/lib/mediaitem.py | 4 +-
.../openlp_core_lib/test_settings.py | 6 +-
11 files changed, 78 insertions(+), 51 deletions(-)
diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py
index 3ad0e1348..176fa059a 100644
--- a/openlp/core/__init__.py
+++ b/openlp/core/__init__.py
@@ -113,10 +113,10 @@ class OpenLP(QtGui.QApplication):
# Decide how many screens we have and their size
screens = ScreenList.create(self.desktop())
# First time checks in settings
- has_run_wizard = Settings().value(u'general/has run wizard')
+ has_run_wizard = Settings().value(u'core/has run wizard')
if not has_run_wizard:
if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
- Settings().setValue(u'general/has run wizard', True)
+ Settings().setValue(u'core/has run wizard', True)
# Correct stylesheet bugs
application_stylesheet = u''
if not Settings().value(u'advanced/alternate rows'):
@@ -128,7 +128,7 @@ class OpenLP(QtGui.QApplication):
application_stylesheet += nt_repair_stylesheet
if application_stylesheet:
self.setStyleSheet(application_stylesheet)
- show_splash = Settings().value(u'general/show splash')
+ show_splash = Settings().value(u'core/show splash')
if show_splash:
self.splash = SplashScreen()
self.splash.show()
@@ -147,7 +147,7 @@ class OpenLP(QtGui.QApplication):
self.processEvents()
if not has_run_wizard:
self.main_window.first_time()
- update_check = Settings().value(u'general/update check')
+ update_check = Settings().value(u'core/update check')
if update_check:
VersionThread(self.main_window).start()
self.main_window.is_display_blank()
@@ -309,7 +309,7 @@ def main(args=None):
if application.is_already_running():
sys.exit()
# First time checks in settings
- if not Settings().value(u'general/has run wizard'):
+ if not Settings().value(u'core/has run wizard'):
if not FirstTimeLanguageForm().exec_():
# if cancel then stop processing
sys.exit()
diff --git a/openlp/core/lib/screen.py b/openlp/core/lib/screen.py
index 913ad539c..149f07ce1 100644
--- a/openlp/core/lib/screen.py
+++ b/openlp/core/lib/screen.py
@@ -247,15 +247,15 @@ class ScreenList(object):
# Add the screen settings to the settings dict. This has to be done here due to cyclic dependency.
# Do not do this anywhere else.
screen_settings = {
- u'general/x position': self.current[u'size'].x(),
- u'general/y position': self.current[u'size'].y(),
- u'general/monitor': self.display_count - 1,
- u'general/height': self.current[u'size'].height(),
- u'general/width': self.current[u'size'].width()
+ u'core/x position': self.current[u'size'].x(),
+ u'core/y position': self.current[u'size'].y(),
+ u'core/monitor': self.display_count - 1,
+ u'core/height': self.current[u'size'].height(),
+ u'core/width': self.current[u'size'].width()
}
Settings.extend_default_settings(screen_settings)
settings = Settings()
- settings.beginGroup(u'general')
+ settings.beginGroup(u'core')
monitor = settings.value(u'monitor')
self.set_current_display(monitor)
self.display = settings.value(u'display on monitor')
diff --git a/openlp/core/lib/settings.py b/openlp/core/lib/settings.py
index be869ade6..e067242dc 100644
--- a/openlp/core/lib/settings.py
+++ b/openlp/core/lib/settings.py
@@ -116,30 +116,30 @@ class Settings(QtCore.QSettings):
u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
u'crashreport/last directory': u'',
u'displayTags/html_tags': u'',
- u'general/audio repeat list': False,
- u'general/auto open': False,
- u'general/auto preview': False,
- u'general/audio start paused': True,
- u'general/auto unblank': False,
- u'general/blank warning': False,
- u'general/ccli number': u'',
- u'general/has run wizard': False,
- u'general/language': u'[en]',
+ u'core/audio repeat list': False,
+ u'core/auto open': False,
+ u'core/auto preview': False,
+ u'core/audio start paused': True,
+ u'core/auto unblank': False,
+ u'core/blank warning': False,
+ u'core/ccli number': u'',
+ u'core/has run wizard': False,
+ u'core/language': u'[en]',
# This defaults to yesterday in order to force the update check to run when you've never run it before.
- u'general/last version test': datetime.datetime.now().date() - datetime.timedelta(days=1),
- u'general/loop delay': 5,
- u'general/recent files': [],
- u'general/save prompt': False,
- u'general/screen blank': False,
- u'general/show splash': True,
- u'general/songselect password': u'',
- u'general/songselect username': u'',
- u'general/update check': True,
- u'general/view mode': u'default',
+ u'core/last version test': datetime.datetime.now().date() - datetime.timedelta(days=1),
+ u'core/loop delay': 5,
+ u'core/recent files': [],
+ u'core/save prompt': False,
+ u'core/screen blank': False,
+ u'core/show splash': True,
+ u'core/songselect password': u'',
+ u'core/songselect username': u'',
+ u'core/update check': True,
+ u'core/view mode': u'default',
# The other display settings (display position and dimensions) are defined in the ScreenList class due to a
# circular dependency.
- u'general/display on monitor': True,
- u'general/override position': False,
+ u'core/display on monitor': True,
+ u'core/override position': False,
u'images/background color': u'#000000',
u'media/players': u'webkit',
u'media/override player': QtCore.Qt.Unchecked,
@@ -304,7 +304,7 @@ class Settings(QtCore.QSettings):
# Changed during 1.9.x development.
(u'bibles/bookname language', u'bibles/book name language', []),
(u'general/enable slide loop', u'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)]),
- (u'songs/ccli number', u'general/ccli number', []),
+ (u'songs/ccli number', u'core/ccli number', []),
# Changed during 2.1.x development.
(u'advanced/stylesheet fix', u'', []),
(u'bibles/last directory 1', u'bibles/last directory import', []),
@@ -314,7 +314,34 @@ class Settings(QtCore.QSettings):
(u'songs/last directory 1', u'songs/last directory import', []),
(u'songusage/last directory 1', u'songusage/last directory export', []),
(u'user interface/mainwindow splitter geometry', u'user interface/main window splitter geometry', []),
- (u'shortcuts/makeLive', u'shortcuts/make_live', [])
+ (u'shortcuts/makeLive', u'shortcuts/make_live', []),
+ (u'general/audio repeat list', u'core/audio repeat list', []),
+ (u'general/auto open', u'core/auto open', []),
+ (u'general/auto preview', u'core/auto preview', []),
+ (u'general/audio start paused', u'core/audio start paused', []),
+ (u'general/auto unblank', u'core/auto unblank', []),
+ (u'general/blank warning', u'core/blank warning', []),
+ (u'general/ccli number', u'core/ccli number', []),
+ (u'general/has run wizard', u'core/has run wizard', []),
+ (u'general/language', u'core/language', []),
+ (u'general/last version test', u'core/last version test', []),
+ (u'general/loop delay', u'core/loop delay', []),
+ (u'general/recent files', u'core/recent files', []),
+ (u'general/save prompt', u'core/save prompt', []),
+ (u'general/screen blank', u'core/screen blank', []),
+ (u'general/show splash', u'core/show splash', []),
+ (u'general/songselect password', u'core/songselect password', []),
+ (u'general/songselect username', u'core/songselect username', []),
+ (u'general/update check', u'core/update check', []),
+ (u'general/view mode', u'core/view mode', []),
+ (u'general/display on monitor', u'core/display on monitor', []),
+ (u'general/override position', u'core/override position', []),
+ (u'general/x position', u'core/x position', []),
+ (u'general/y position', u'core/y position', []),
+ (u'general/monitor', u'core/monitor', []),
+ (u'general/height', u'core/height', []),
+ (u'general/monitor', u'core/monitor', []),
+ (u'general/width', u'core/width', [])
]
@staticmethod
diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py
index 188bc3c02..0d749176b 100644
--- a/openlp/core/ui/firsttimeform.py
+++ b/openlp/core/ui/firsttimeform.py
@@ -120,7 +120,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
check_directory_exists(os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
self.noInternetFinishButton.setVisible(False)
# Check if this is a re-run of the wizard.
- self.hasRunWizard = Settings().value(u'general/has run wizard')
+ self.hasRunWizard = Settings().value(u'core/has run wizard')
# Sort out internet access for downloads
if self.web_access:
songs = self.config.get(u'songs', u'languages')
@@ -254,7 +254,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.application.set_busy_cursor()
self._performWizard()
self.application.set_normal_cursor()
- Settings().setValue(u'general/has run wizard', True)
+ Settings().setValue(u'core/has run wizard', True)
self.close()
def urlGetFile(self, url, fpath):
@@ -461,7 +461,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.urlGetFile(u'%s%s' % (self.web, theme), os.path.join(themes_destination, theme))
# Set Default Display
if self.displayComboBox.currentIndex() != -1:
- Settings().setValue(u'General/monitor', self.displayComboBox.currentIndex())
+ Settings().setValue(u'core/monitor', self.displayComboBox.currentIndex())
self.screens.set_current_display(self.displayComboBox.currentIndex())
# Set Global Theme
if self.themeComboBox.currentIndex() != -1:
diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py
index a20206f9b..af99c3271 100644
--- a/openlp/core/ui/generaltab.py
+++ b/openlp/core/ui/generaltab.py
@@ -49,7 +49,7 @@ class GeneralTab(SettingsTab):
self.screens = ScreenList()
self.iconPath = u':/icon/openlp-logo-16x16.png'
generalTranslated = translate('OpenLP.GeneralTab', 'General')
- SettingsTab.__init__(self, parent, u'General', generalTranslated)
+ SettingsTab.__init__(self, parent, u'Core', generalTranslated)
def setupUi(self):
"""
diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py
index 58d832101..41413b503 100644
--- a/openlp/core/ui/maindisplay.py
+++ b/openlp/core/ui/maindisplay.py
@@ -367,7 +367,7 @@ class MainDisplay(Display):
# Single screen active
if self.screens.display_count == 1:
# Only make visible if setting enabled.
- if Settings().value(u'general/display on monitor'):
+ if Settings().value(u'core/display on monitor'):
self.setVisible(True)
else:
self.setVisible(True)
@@ -416,7 +416,7 @@ class MainDisplay(Display):
self.footer(serviceItem.foot_text)
# if was hidden keep it hidden
if self.hideMode and self.isLive and not serviceItem.is_media():
- if Settings().value(u'general/auto unblank'):
+ if Settings().value(u'core/auto unblank'):
Registry().execute(u'slidecontroller_live_unblank')
else:
self.hide_display(self.hideMode)
@@ -438,7 +438,7 @@ class MainDisplay(Display):
log.debug(u'hide_display mode = %d', mode)
if self.screens.display_count == 1:
# Only make visible if setting enabled.
- if not Settings().value(u'general/display on monitor'):
+ if not Settings().value(u'core/display on monitor'):
return
if mode == HideMode.Screen:
self.frame.evaluateJavaScript(u'show_blank("desktop");')
@@ -462,7 +462,7 @@ class MainDisplay(Display):
log.debug(u'show_display')
if self.screens.display_count == 1:
# Only make visible if setting enabled.
- if not Settings().value(u'general/display on monitor'):
+ if not Settings().value(u'core/display on monitor'):
return
self.frame.evaluateJavaScript('show_blank("show");')
if self.isHidden():
diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py
index 14186cf78..0d77da403 100644
--- a/openlp/core/ui/mainwindow.py
+++ b/openlp/core/ui/mainwindow.py
@@ -469,7 +469,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.arguments = self.application.args
# Set up settings sections for the main application (not for use by plugins).
self.uiSettingsSection = u'user interface'
- self.generalSettingsSection = u'general'
+ self.generalSettingsSection = u'core'
self.advancedSettingsSection = u'advanced'
self.shortcutsSettingsSection = u'shortcuts'
self.serviceManagerSettingsSection = u'servicemanager'
diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py
index 048fb5f4d..60c09ca21 100644
--- a/openlp/core/ui/media/mediacontroller.py
+++ b/openlp/core/ui/media/mediacontroller.py
@@ -417,7 +417,7 @@ class MediaController(object):
elif not hidden or controller.media_info.is_background or serviceItem.will_auto_start:
autoplay = True
# Unblank on load set
- elif Settings().value(u'general/auto unblank'):
+ elif Settings().value(u'core/auto unblank'):
autoplay = True
if autoplay:
if not self.media_play(controller):
diff --git a/openlp/core/utils/languagemanager.py b/openlp/core/utils/languagemanager.py
index 00a0d0079..6dc18c1ad 100644
--- a/openlp/core/utils/languagemanager.py
+++ b/openlp/core/utils/languagemanager.py
@@ -98,7 +98,7 @@ class LanguageManager(object):
"""
Retrieve a saved language to use from settings
"""
- language = Settings().value(u'general/language')
+ language = Settings().value(u'core/language')
language = str(language)
log.info(u'Language file: \'%s\' Loaded from conf file' % language)
if re.match(r'[[].*[]]', language):
@@ -128,7 +128,7 @@ class LanguageManager(object):
language = unicode(qm_list[action_name])
if LanguageManager.auto_language:
language = u'[%s]' % language
- Settings().setValue(u'general/language', language)
+ Settings().setValue(u'core/language', language)
log.info(u'Language file: \'%s\' written to conf file' % language)
if message:
QtGui.QMessageBox.information(None,
diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py
index da706bdcb..e3860aeda 100644
--- a/openlp/plugins/songs/lib/mediaitem.py
+++ b/openlp/plugins/songs/lib/mediaitem.py
@@ -457,9 +457,9 @@ class SongMediaItem(MediaManagerItem):
service_item.raw_footer.append(song.title)
service_item.raw_footer.append(create_separated_list(author_list))
service_item.raw_footer.append(song.copyright)
- if Settings().value(u'general/ccli number'):
+ if Settings().value(u'core/ccli number'):
service_item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
- Settings().value(u'general/ccli number'))
+ Settings().value(u'core/ccli number'))
service_item.audit = [
song.title, author_list, song.copyright, unicode(song.ccli_number)
]
diff --git a/tests/functional/openlp_core_lib/test_settings.py b/tests/functional/openlp_core_lib/test_settings.py
index 827bfa156..2cd15a16f 100644
--- a/tests/functional/openlp_core_lib/test_settings.py
+++ b/tests/functional/openlp_core_lib/test_settings.py
@@ -35,16 +35,16 @@ class TestSettings(TestCase):
# GIVEN: A new Settings setup
# WHEN reading a setting for the first time
- default_value = Settings().value(u'general/has run wizard')
+ default_value = Settings().value(u'core/has run wizard')
# THEN the default value is returned
assert default_value is False, u'The default value should be False'
# WHEN a new value is saved into config
- Settings().setValue(u'general/has run wizard', True)
+ Settings().setValue(u'core/has run wizard', True)
# THEN the new value is returned when re-read
- assert Settings().value(u'general/has run wizard') is True, u'The saved value should have been returned'
+ assert Settings().value(u'core/has run wizard') is True, u'The saved value should have been returned'
def settings_override_test(self):
"""
From f1aadde13cd30ecf89afb8d8bd07ad9f4e0b5210 Mon Sep 17 00:00:00 2001
From: Tim Bentley
Date: Wed, 6 Mar 2013 21:53:29 +0000
Subject: [PATCH 05/71] Initial Cherrypy implementation
---
openlp/core/ui/exceptionform.py | 6 +
openlp/core/ui/slidecontroller.py | 7 +-
openlp/core/utils/__init__.py | 7 +-
openlp/plugins/remotes/html/stage.js | 6 +-
openlp/plugins/remotes/lib/httpauth.py | 192 ++++++++++++++++
openlp/plugins/remotes/lib/httpserver.py | 281 +++++++++++------------
openlp/plugins/remotes/lib/remotetab.py | 271 ++++++++++++++--------
openlp/plugins/remotes/remoteplugin.py | 5 +
scripts/check_dependencies.py | 1 +
9 files changed, 534 insertions(+), 242 deletions(-)
create mode 100644 openlp/plugins/remotes/lib/httpauth.py
diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py
index 50885b15b..c10f98d9b 100644
--- a/openlp/core/ui/exceptionform.py
+++ b/openlp/core/ui/exceptionform.py
@@ -69,6 +69,11 @@ try:
MAKO_VERSION = mako.__version__
except ImportError:
MAKO_VERSION = u'-'
+try:
+ import cherrypy
+ CHERRYPY_VERSION = cherrypy.__version__
+except ImportError:
+ CHERRYPY_VERSION = u'-'
try:
import uno
arg = uno.createUnoStruct(u'com.sun.star.beans.PropertyValue')
@@ -138,6 +143,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
u'PyEnchant: %s\n' % ENCHANT_VERSION + \
u'PySQLite: %s\n' % SQLITE_VERSION + \
u'Mako: %s\n' % MAKO_VERSION + \
+ u'CherryPy: %s\n' % CHERRYPY_VERSION + \
u'pyUNO bridge: %s\n' % UNO_VERSION
if platform.system() == u'Linux':
if os.environ.get(u'KDE_FULL_SESSION') == u'true':
diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py
index 84ea296d2..3a2c0b582 100644
--- a/openlp/core/ui/slidecontroller.py
+++ b/openlp/core/ui/slidecontroller.py
@@ -362,8 +362,9 @@ class SlideController(DisplayController):
# Signals
QtCore.QObject.connect(self.previewListWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
if self.isLive:
+ # Need to use event as called across threads and UI is updated
+ QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_toggle_display'), self.toggle_display)
Registry().register_function(u'slidecontroller_live_spin_delay', self.receive_spin_delay)
- Registry().register_function(u'slidecontroller_toggle_display', self.toggle_display)
self.toolbar.setWidgetVisible(self.loopList, False)
self.toolbar.setWidgetVisible(self.wideMenu, False)
else:
@@ -867,9 +868,9 @@ class SlideController(DisplayController):
"""
Go to the requested slide
"""
- index = int(message[0])
- if not self.serviceItem:
+ if not self.serviceItem or not message[0]:
return
+ index = int(message[0])
if self.serviceItem.is_command():
Registry().execute(u'%s_slide' % self.serviceItem.name.lower(), [self.serviceItem, self.isLive, index])
self.updatePreview()
diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py
index 104567039..dd611d303 100644
--- a/openlp/core/utils/__init__.py
+++ b/openlp/core/utils/__init__.py
@@ -90,6 +90,7 @@ class AppLocation(object):
VersionDir = 5
CacheDir = 6
LanguageDir = 7
+ SharedData = 8
# Base path where data/config/cache dir is located
BaseDir = None
@@ -150,18 +151,18 @@ def _get_os_dir_path(dir_type):
if sys.platform == u'win32':
if dir_type == AppLocation.DataDir:
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp', u'data')
- elif dir_type == AppLocation.LanguageDir:
+ elif dir_type == AppLocation.LanguageDir or dir_type == AppLocation.SharedData:
return os.path.split(openlp.__file__)[0]
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp')
elif sys.platform == u'darwin':
if dir_type == AppLocation.DataDir:
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Library', u'Application Support', u'openlp', u'Data')
- elif dir_type == AppLocation.LanguageDir:
+ elif dir_type == AppLocation.LanguageDir or dir_type == AppLocation.SharedData:
return os.path.split(openlp.__file__)[0]
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp')
else:
- if dir_type == AppLocation.LanguageDir:
+ if dir_type == AppLocation.LanguageDir or dir_type == AppLocation.SharedData:
prefixes = [u'/usr/local', u'/usr']
for prefix in prefixes:
directory = os.path.join(prefix, u'share', u'openlp')
diff --git a/openlp/plugins/remotes/html/stage.js b/openlp/plugins/remotes/html/stage.js
index dcc2e4b70..dff51537c 100644
--- a/openlp/plugins/remotes/html/stage.js
+++ b/openlp/plugins/remotes/html/stage.js
@@ -26,7 +26,7 @@
window.OpenLP = {
loadService: function (event) {
$.getJSON(
- "/api/service/list",
+ "/stage/api/service/list",
function (data, status) {
OpenLP.nextSong = "";
$("#notes").html("");
@@ -46,7 +46,7 @@ window.OpenLP = {
},
loadSlides: function (event) {
$.getJSON(
- "/api/controller/live/text",
+ "/stage/api/controller/live/text",
function (data, status) {
OpenLP.currentSlides = data.results.slides;
OpenLP.currentSlide = 0;
@@ -137,7 +137,7 @@ window.OpenLP = {
},
pollServer: function () {
$.getJSON(
- "/api/poll",
+ "/stage/api/poll",
function (data, status) {
OpenLP.updateClock(data);
if (OpenLP.currentItem != data.results.item ||
diff --git a/openlp/plugins/remotes/lib/httpauth.py b/openlp/plugins/remotes/lib/httpauth.py
new file mode 100644
index 000000000..ce3ea091e
--- /dev/null
+++ b/openlp/plugins/remotes/lib/httpauth.py
@@ -0,0 +1,192 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# 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 :mod:`http` module manages the HTTP authorisation logic. This code originates from
+http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
+
+"""
+
+import cherrypy
+import urlparse
+
+SESSION_KEY = '_cp_openlp'
+
+
+def check_credentials(user_name, password):
+ """
+ Verifies credentials for username and password.
+ Returns None on success or a string describing the error on failure
+ """
+ # @todo make from config
+ if user_name == 'openlp' and password == 'openlp':
+ return None
+ else:
+ return u"Incorrect username or password."
+ # if u.password != md5.new(password).hexdigest():
+ # return u"Incorrect password"
+
+
+def check_auth(*args, **kwargs):
+ """
+ A tool that looks in config for 'auth.require'. If found and it
+ is not None, a login is required and the entry is evaluated as a list of
+ conditions that the user must fulfill
+ """
+ print "check"
+ conditions = cherrypy.request.config.get('auth.require', None)
+ print conditions
+ print args, kwargs
+ print urlparse.urlparse(cherrypy.url())
+ url = urlparse.urlparse(cherrypy.url())
+ print urlparse.parse_qs(url.query)
+ if conditions is not None:
+ username = cherrypy.session.get(SESSION_KEY)
+ if username:
+ cherrypy.request.login = username
+ for condition in conditions:
+ # A condition is just a callable that returns true or false
+ if not condition():
+ raise cherrypy.HTTPRedirect("/auth/login")
+ else:
+ raise cherrypy.HTTPRedirect("/auth/login")
+
+cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth)
+
+
+def require_auth(*conditions):
+ """
+ A decorator that appends conditions to the auth.require config variable.
+ """
+ print conditions
+ def decorate(f):
+ if not hasattr(f, '_cp_config'):
+ f._cp_config = dict()
+ if 'auth.require' not in f._cp_config:
+ f._cp_config['auth.require'] = []
+ f._cp_config['auth.require'].extend(conditions)
+ print "a ", [f]
+ return f
+ return decorate
+
+
+# Conditions are callables that return True
+# if the user fulfills the conditions they define, False otherwise
+#
+# They can access the current username as cherrypy.request.login
+#
+# Define those at will however suits the application.
+
+#def member_of(groupname):
+# def check():
+# # replace with actual check if is in
+# return cherrypy.request.login == 'joe' and groupname == 'admin'
+# return check
+
+
+#def name_is(reqd_username):
+# return lambda: reqd_username == cherrypy.request.login
+
+#def any_of(*conditions):
+# """
+# Returns True if any of the conditions match
+# """
+# def check():
+# for c in conditions:
+# if c():
+# return True
+# return False
+# return check
+
+# By default all conditions are required, but this might still be
+# needed if you want to use it inside of an any_of(...) condition
+#def all_of(*conditions):
+# """
+# Returns True if all of the conditions match
+# """
+# def check():
+# for c in conditions:
+# if not c():
+# return False
+# return True
+# return check
+# Controller to provide login and logout actions
+
+
+class AuthController(object):
+
+ def on_login(self, username):
+ """
+ Called on successful login
+ """
+
+ def on_logout(self, username):
+ """
+ Called on logout
+ """
+
+ def get_loginform(self, username, msg="Enter login information", from_page="/"):
+ """
+ Provides a login form
+ """
+ return """
+
+ User name:
+ Password:
+
+
+
\ No newline at end of file
diff --git a/openlp/plugins/remotes/html/openlp.css b/openlp/plugins/remotes/html/openlp.css
index 4bc1bf907..60a8fe625 100644
--- a/openlp/plugins/remotes/html/openlp.css
+++ b/openlp/plugins/remotes/html/openlp.css
@@ -36,3 +36,11 @@
.ui-li .ui-btn-text a.ui-link-inherit{
white-space: normal;
}
+
+.ui-page{
+ padding: 100px 100px 100px 100px;
+ width: 300px;
+}
+.ui-input-text{
+ width: 30px;
+}
\ No newline at end of file
diff --git a/openlp/plugins/remotes/lib/httpauth.py b/openlp/plugins/remotes/lib/httpauth.py
index 7e0e2ebe5..d46620855 100644
--- a/openlp/plugins/remotes/lib/httpauth.py
+++ b/openlp/plugins/remotes/lib/httpauth.py
@@ -35,8 +35,12 @@ http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
import cherrypy
import logging
+import os
+
+from mako.template import Template
from openlp.core.lib import Settings
+from openlp.core.utils import AppLocation, translate
SESSION_KEY = '_cp_openlp'
@@ -48,6 +52,7 @@ def check_credentials(user_name, password):
Verifies credentials for username and password.
Returns None on success or a string describing the error on failure
"""
+ print "check"
if user_name == Settings().value(u'remotes/user id') and password == Settings().value(u'remotes/password'):
return None
else:
@@ -70,9 +75,12 @@ def check_auth(*args, **kwargs):
for condition in conditions:
# A condition is just a callable that returns true or false
if not condition():
+ print "r1"
raise cherrypy.HTTPRedirect("/auth/login")
else:
+ print "r2"
raise cherrypy.HTTPRedirect("/auth/login")
+ print "r3"
cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth)
@@ -100,36 +108,31 @@ class AuthController(object):
"""
Called on successful login
"""
+ pass
def on_logout(self, username):
"""
Called on logout
"""
+ pass
- def get_loginform(self, username, msg="Enter login information", from_page="/"):
+ def get_login_form(self, username, message=None, from_page="/"):
"""
Provides a login form
"""
- return """
-
-
-
- User Login
-
-
-
-
-
-
-
-
-
-
- %(msg)s
- Username:
- Password:
-
- """ % locals()
+ if not message:
+ message = translate('RemotePlugin.Mobile', 'Enter login information')
+ variables = {
+ 'title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 User Login'),
+ 'from_page': from_page,
+ 'message': message,
+ 'username': username
+ }
+ directory = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), u'remotes', u'html')
+ login_html = os.path.normpath(os.path.join(directory, u'login.html'))
+ html = Template(filename=login_html, input_encoding=u'utf-8', output_encoding=u'utf-8').render(**variables)
+ cherrypy.response.headers['Content-Type'] = u'text/html'
+ return html
@cherrypy.expose
def login(self, username=None, password=None, from_page="/"):
@@ -137,14 +140,14 @@ class AuthController(object):
Provides the actual login control
"""
if username is None or password is None:
- return self.get_loginform("", from_page=from_page)
-
+ return self.get_login_form("", from_page=from_page)
error_msg = check_credentials(username, password)
if error_msg:
- return self.get_loginform(username, error_msg, from_page)
+ return self.get_login_form(username, from_page, error_msg,)
else:
cherrypy.session[SESSION_KEY] = cherrypy.request.login = username
self.on_login(username)
+ print from_page
raise cherrypy.HTTPRedirect(from_page or "/")
@cherrypy.expose
diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py
index 211608858..db6143eb0 100644
--- a/openlp/plugins/remotes/lib/httpserver.py
+++ b/openlp/plugins/remotes/lib/httpserver.py
@@ -174,6 +174,8 @@ class HttpServer(object):
cherrypy.config.update({'environment': 'embedded'})
cherrypy.config.update({'engine.autoreload_on': False})
cherrypy.tree.mount(HttpConnection(self), '/', config=self.conf)
+ # Turn off the flood of access messages cause by poll
+ cherrypy.log.access_log.propagate = False
cherrypy.engine.start()
Registry().register_function(u'slidecontroller_live_changed', self.slide_change)
Registry().register_function(u'slidecontroller_live_started', self.item_change)
From 3c32bc75011eac3b7ed3d07d90c8f818a6dab80d Mon Sep 17 00:00:00 2001
From: Tim Bentley
Date: Wed, 13 Mar 2013 19:51:56 +0000
Subject: [PATCH 09/71] Added tests
---
openlp/plugins/remotes/lib/httpauth.py | 2 +-
.../openlp_core_lib/test_settings.py | 4 +-
.../openlp_plugins/remotes/__init__.py | 1 +
.../openlp_plugins/remotes/test_auth.py | 65 +++++++++++++++++++
4 files changed, 70 insertions(+), 2 deletions(-)
create mode 100644 tests/functional/openlp_plugins/remotes/__init__.py
create mode 100644 tests/functional/openlp_plugins/remotes/test_auth.py
diff --git a/openlp/plugins/remotes/lib/httpauth.py b/openlp/plugins/remotes/lib/httpauth.py
index d46620855..6fe4197e2 100644
--- a/openlp/plugins/remotes/lib/httpauth.py
+++ b/openlp/plugins/remotes/lib/httpauth.py
@@ -56,7 +56,7 @@ def check_credentials(user_name, password):
if user_name == Settings().value(u'remotes/user id') and password == Settings().value(u'remotes/password'):
return None
else:
- return u"Incorrect username or password."
+ return translate('RemotePlugin.Mobile', 'Incorrect username or password.')
def check_auth(*args, **kwargs):
diff --git a/tests/functional/openlp_core_lib/test_settings.py b/tests/functional/openlp_core_lib/test_settings.py
index 827bfa156..b06bb4eac 100644
--- a/tests/functional/openlp_core_lib/test_settings.py
+++ b/tests/functional/openlp_core_lib/test_settings.py
@@ -11,7 +11,9 @@ from PyQt4 import QtGui
class TestSettings(TestCase):
-
+ """
+ Test the functions in the Settings module
+ """
def setUp(self):
"""
Create the UI
diff --git a/tests/functional/openlp_plugins/remotes/__init__.py b/tests/functional/openlp_plugins/remotes/__init__.py
new file mode 100644
index 000000000..f87606f07
--- /dev/null
+++ b/tests/functional/openlp_plugins/remotes/__init__.py
@@ -0,0 +1 @@
+__author__ = 'tim'
diff --git a/tests/functional/openlp_plugins/remotes/test_auth.py b/tests/functional/openlp_plugins/remotes/test_auth.py
new file mode 100644
index 000000000..a300c0127
--- /dev/null
+++ b/tests/functional/openlp_plugins/remotes/test_auth.py
@@ -0,0 +1,65 @@
+"""
+This module contains tests for the lib submodule of the Remotes plugin.
+"""
+import os
+from unittest import TestCase
+from tempfile import mkstemp
+from mock import patch
+
+from openlp.core.lib import Settings
+from openlp.plugins.remotes.lib.httpauth import check_credentials
+from PyQt4 import QtGui
+
+__default_settings__ = {
+ u'remotes/twelve hour': True,
+ u'remotes/port': 4316,
+ u'remotes/https port': 4317,
+ u'remotes/https enabled': False,
+ u'remotes/user id': u'openlp',
+ u'remotes/password': u'password',
+ u'remotes/authentication enabled': False,
+ u'remotes/ip address': u'0.0.0.0'
+}
+
+
+class TestLib(TestCase):
+ """
+ Test the functions in the :mod:`lib` module.
+ """
+ def setUp(self):
+ """
+ Create the UI
+ """
+ fd, self.ini_file = mkstemp(u'.ini')
+ Settings().set_filename(self.ini_file)
+ self.application = QtGui.QApplication.instance()
+ Settings().extend_default_settings(__default_settings__)
+
+ def tearDown(self):
+ """
+ Delete all the C++ objects at the end so that we don't have a segfault
+ """
+ del self.application
+ os.unlink(self.ini_file)
+ os.unlink(Settings().fileName())
+
+ def check_credentials_test(self):
+ """
+ Test the clean_string() function
+ """
+ # GIVEN: A user and password
+ Settings().setValue(u'remotes/user id', u'twinkle')
+ Settings().setValue(u'remotes/password', u'mongoose')
+
+ # WHEN: We run the string through the function
+ authenticated = check_credentials(u'', u'')
+
+ # THEN: The string should be cleaned up and lower-cased
+ self.assertEqual(authenticated, u'Incorrect username or password.',
+ u'The return should be a error message string')
+
+ # WHEN: We run the string through the function
+ authenticated = check_credentials(u'twinkle', u'mongoose')
+
+ # THEN: The string should be cleaned up and lower-cased
+ self.assertEqual(authenticated, None, u'The return should be a None string')
From d04dbd791f9ef141f947ca555fbc014cf84fd614 Mon Sep 17 00:00:00 2001
From: Tim Bentley
Date: Fri, 15 Mar 2013 08:40:00 +0000
Subject: [PATCH 10/71] more changes
---
openlp/plugins/remotes/html/login.html | 2 +-
openlp/plugins/remotes/html/openlp.css | 8 --------
openlp/plugins/remotes/html/openlp.js | 2 +-
openlp/plugins/remotes/lib/httpauth.py | 3 ---
openlp/plugins/remotes/lib/httpserver.py | 7 +------
5 files changed, 3 insertions(+), 19 deletions(-)
diff --git a/openlp/plugins/remotes/html/login.html b/openlp/plugins/remotes/html/login.html
index 4441958de..736d3f0ab 100644
--- a/openlp/plugins/remotes/html/login.html
+++ b/openlp/plugins/remotes/html/login.html
@@ -33,7 +33,7 @@
${title}
-
+
diff --git a/openlp/plugins/remotes/html/openlp.css b/openlp/plugins/remotes/html/openlp.css
index 60a8fe625..4bc1bf907 100644
--- a/openlp/plugins/remotes/html/openlp.css
+++ b/openlp/plugins/remotes/html/openlp.css
@@ -36,11 +36,3 @@
.ui-li .ui-btn-text a.ui-link-inherit{
white-space: normal;
}
-
-.ui-page{
- padding: 100px 100px 100px 100px;
- width: 300px;
-}
-.ui-input-text{
- width: 30px;
-}
\ No newline at end of file
diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js
index 00877e332..7c5c19e32 100644
--- a/openlp/plugins/remotes/html/openlp.js
+++ b/openlp/plugins/remotes/html/openlp.js
@@ -359,5 +359,5 @@ $.ajaxSetup({cache: false});
$("#search").live("pageinit", function (event) {
OpenLP.getSearchablePlugins();
});
-setInterval("OpenLP.pollServer();", 500);
+setInterval("OpenLP.pollServer();", 5000);
OpenLP.pollServer();
diff --git a/openlp/plugins/remotes/lib/httpauth.py b/openlp/plugins/remotes/lib/httpauth.py
index 6fe4197e2..bd3c1f911 100644
--- a/openlp/plugins/remotes/lib/httpauth.py
+++ b/openlp/plugins/remotes/lib/httpauth.py
@@ -75,12 +75,9 @@ def check_auth(*args, **kwargs):
for condition in conditions:
# A condition is just a callable that returns true or false
if not condition():
- print "r1"
raise cherrypy.HTTPRedirect("/auth/login")
else:
- print "r2"
raise cherrypy.HTTPRedirect("/auth/login")
- print "r3"
cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth)
diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py
index b8acc574f..308533b9d 100644
--- a/openlp/plugins/remotes/lib/httpserver.py
+++ b/openlp/plugins/remotes/lib/httpserver.py
@@ -144,8 +144,6 @@ class HttpServer(object):
self.plugin = plugin
self.html_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), u'remotes', u'html')
self.connections = []
- self.current_item = None
- self.current_slide = None
self.conf = {'/files': {u'tools.staticdir.on': True,
u'tools.staticdir.dir': self.html_dir}}
self.start_server()
@@ -177,8 +175,6 @@ class HttpServer(object):
# Turn off the flood of access messages cause by poll
cherrypy.log.access_log.propagate = False
cherrypy.engine.start()
- Registry().register_function(u'slidecontroller_live_changed', self.slide_change)
- Registry().register_function(u'slidecontroller_live_started', self.item_change)
log.debug(u'TCP listening on port %d' % port)
def close(self):
@@ -481,8 +477,7 @@ class HttpConnection(object):
if action == u'list':
cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': {u'items': self._get_service_items()}})
- else:
- event += u'_item'
+ event += u'_item'
if self.url_params and self.url_params.get(u'data'):
try:
data = json.loads(self.url_params[u'data'][0])
From 0f6216d653f1df071556e6e57867d8c2c477ff84 Mon Sep 17 00:00:00 2001
From: Tim Bentley
Date: Sun, 17 Mar 2013 21:20:40 +0000
Subject: [PATCH 11/71] More changes
---
openlp/core/ui/servicemanager.py | 5 ++++-
openlp/core/ui/slidecontroller.py | 2 +-
openlp/plugins/remotes/html/openlp.js | 4 ++--
openlp/plugins/remotes/lib/httpserver.py | 17 +++++++++++------
4 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py
index 9e99e2303..c7ab8dd77 100644
--- a/openlp/core/ui/servicemanager.py
+++ b/openlp/core/ui/servicemanager.py
@@ -270,7 +270,6 @@ class ServiceManagerDialog(object):
Registry().register_function(u'config_screen_changed', self.regenerate_service_Items)
Registry().register_function(u'theme_update_global', self.theme_change)
Registry().register_function(u'mediaitem_suffix_reset', self.reset_supported_suffixes)
- Registry().register_function(u'servicemanager_set_item', self.on_set_item)
def drag_enter_event(self, event):
"""
@@ -313,6 +312,9 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.layout.setSpacing(0)
self.layout.setMargin(0)
self.setup_ui(self)
+ # Need to use event as called across threads and UI is updated
+ print self
+ QtCore.QObject.connect(self, QtCore.SIGNAL(u'servicemanager_set_item'), self.on_set_item)
def set_modified(self, modified=True):
"""
@@ -1008,6 +1010,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
"""
Called by a signal to select a specific item.
"""
+ print "hello", message
self.set_item(int(message))
def set_item(self, index):
diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py
index 0c22a6353..3b2824fda 100644
--- a/openlp/core/ui/slidecontroller.py
+++ b/openlp/core/ui/slidecontroller.py
@@ -99,7 +99,7 @@ class SlideController(DisplayController):
u'delay_spin_box'
]
self.audio_list = [
- u'audio_pause_item',
+ u'audioPauseItem',
u'audio_time_label'
]
self.wide_menu = [
diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js
index 7c5c19e32..3cbe65366 100644
--- a/openlp/plugins/remotes/html/openlp.js
+++ b/openlp/plugins/remotes/html/openlp.js
@@ -147,7 +147,7 @@ window.OpenLP = {
},
pollServer: function () {
$.getJSON(
- "/api/poll",
+ "/stage/api/poll",
function (data, status) {
var prevItem = OpenLP.currentItem;
OpenLP.currentSlide = data.results.slide;
@@ -359,5 +359,5 @@ $.ajaxSetup({cache: false});
$("#search").live("pageinit", function (event) {
OpenLP.getSearchablePlugins();
});
-setInterval("OpenLP.pollServer();", 5000);
+setInterval("OpenLP.pollServer();", 500);
OpenLP.pollServer();
diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py
index 308533b9d..a594c1bca 100644
--- a/openlp/plugins/remotes/lib/httpserver.py
+++ b/openlp/plugins/remotes/lib/httpserver.py
@@ -199,7 +199,7 @@ class HttpConnection(object):
def __init__(self, parent):
"""
- Initialise the http connection. Listen out for socket signals.
+ Initialise the CherryPy Server
"""
self.parent = parent
self.routes = [
@@ -229,6 +229,9 @@ class HttpConnection(object):
"""
url = urlparse.urlparse(cherrypy.url())
self.url_params = urlparse.parse_qs(url.query)
+ self.request_data = None
+ if isinstance(kwargs, dict):
+ self.request_data = kwargs.get(u'data', None)
# Loop through the routes we set up earlier and execute them
return self._process_http_request(args, kwargs)
@@ -255,7 +258,7 @@ class HttpConnection(object):
Common function to process HTTP requests where secure or insecure
"""
url = urlparse.urlparse(cherrypy.url())
- self.url_params = urlparse.parse_qs(url.query)
+ self.url_params = kwargs
response = None
for route, func in self.routes:
match = re.match(route, url.path)
@@ -478,13 +481,15 @@ class HttpConnection(object):
cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': {u'items': self._get_service_items()}})
event += u'_item'
- if self.url_params and self.url_params.get(u'data'):
+ if self.request_data:
try:
- data = json.loads(self.url_params[u'data'][0])
- except KeyError, ValueError:
+ data = json.loads(self.request_data)[u'request'][u'id']
+ except KeyError:
return self._http_bad_request()
- Registry().execute(event, data[u'request'][u'id'])
+ print "A", event , data
+ self.service_manager.emit(QtCore.SIGNAL(event, data))
else:
+ print "B", event
Registry().execute(event)
cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': {u'success': True}})
From 729c93b70b6a154dfc723405dd40c75410a57c8b Mon Sep 17 00:00:00 2001
From: Tim Bentley
Date: Wed, 20 Mar 2013 20:17:00 +0000
Subject: [PATCH 12/71] More changes
---
openlp/core/ui/servicemanager.py | 2 +-
openlp/plugins/remotes/lib/httpserver.py | 40 +++++++++++-------------
2 files changed, 20 insertions(+), 22 deletions(-)
diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py
index 97c6ca2db..7c3745299 100644
--- a/openlp/core/ui/servicemanager.py
+++ b/openlp/core/ui/servicemanager.py
@@ -1008,7 +1008,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
def on_set_item(self, message):
"""
- Called by a signal to select a specific item.
+ Called by a signal to select a specific item and make it live usually from remote.
"""
print "hello", message
self.set_item(int(message))
diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py
index a594c1bca..368bf0192 100644
--- a/openlp/plugins/remotes/lib/httpserver.py
+++ b/openlp/plugins/remotes/lib/httpserver.py
@@ -155,17 +155,17 @@ class HttpServer(object):
clients. Listen out for socket connections.
"""
log.debug(u'Start CherryPy server')
- if Settings().value(self.plugin.settingsSection + u'/https enabled'):
- port = Settings().value(self.plugin.settingsSection + u'/https port')
- address = Settings().value(self.plugin.settingsSection + u'/ip address')
+ if Settings().value(self.plugin.settings_section + u'/https enabled'):
+ port = Settings().value(self.plugin.settings_section + u'/https port')
+ address = Settings().value(self.plugin.settings_section + u'/ip address')
shared_data = AppLocation.get_directory(AppLocation.SharedData)
server_config = {u'server.socket_host': str(address),
u'server.socket_port': port,
u'server.ssl_certificate': os.path.join(shared_data, u'openlp.crt'),
u'server.ssl_private_key': os.path.join(shared_data, u'openlp.key')}
else:
- port = Settings().value(self.plugin.settingsSection + u'/port')
- address = Settings().value(self.plugin.settingsSection + u'/ip address')
+ port = Settings().value(self.plugin.settings_section + u'/port')
+ address = Settings().value(self.plugin.settings_section + u'/ip address')
server_config = {u'server.socket_host': str(address),
u'server.socket_port': port}
cherrypy.config.update(server_config)
@@ -214,7 +214,7 @@ class HttpConnection(object):
(r'^/stage/api/service/(.*)$', self.service),
(r'^/api/display/(hide|show|blank|theme|desktop)$', self.display),
(r'^/api/alert$', self.alert),
- (r'^/api/plugin/(search)$', self.pluginInfo),
+ (r'^/api/plugin/(search)$', self.plugin_info),
(r'^/api/(.*)/search$', self.search),
(r'^/api/(.*)/live$', self.go_live),
(r'^/api/(.*)/add$', self.add_to_service)
@@ -456,9 +456,9 @@ class HttpConnection(object):
if current_item:
json_data[u'results'][u'item'] = self.live_controller.service_item.unique_identifier
else:
- if self.url_params and self.url_params.get(u'data'):
+ if self.request_data:
try:
- data = json.loads(self.url_params[u'data'][0])
+ data = json.loads(self.request_data)[u'request'][u'id']
except KeyError, ValueError:
return self._http_bad_request()
log.info(data)
@@ -486,15 +486,13 @@ class HttpConnection(object):
data = json.loads(self.request_data)[u'request'][u'id']
except KeyError:
return self._http_bad_request()
- print "A", event , data
- self.service_manager.emit(QtCore.SIGNAL(event, data))
+ self.service_manager.emit(QtCore.SIGNAL(event), data)
else:
- print "B", event
Registry().execute(event)
cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': {u'success': True}})
- def pluginInfo(self, action):
+ def plugin_info(self, action):
"""
Return plugin related information, based on the action.
@@ -505,8 +503,8 @@ class HttpConnection(object):
if action == u'search':
searches = []
for plugin in self.plugin_manager.plugins:
- if plugin.status == PluginStatus.Active and plugin.mediaItem and plugin.mediaItem.hasSearch:
- searches.append([plugin.name, unicode(plugin.textStrings[StringContent.Name][u'plural'])])
+ if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.hasSearch:
+ searches.append([plugin.name, unicode(plugin.text_strings[StringContent.Name][u'plural'])])
cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': {u'items': searches}})
@@ -523,8 +521,8 @@ class HttpConnection(object):
return self._http_bad_request()
text = urllib.unquote(text)
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
- if plugin.status == PluginStatus.Active and plugin.mediaItem and plugin.mediaItem.hasSearch:
- results = plugin.mediaItem.search(text, False)
+ if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.has_search:
+ results = plugin.media_item.search(text, False)
else:
results = []
cherrypy.response.headers['Content-Type'] = u'application/json'
@@ -539,8 +537,8 @@ class HttpConnection(object):
except KeyError, ValueError:
return self._http_bad_request()
plugin = self.plugin_manager.get_plugin_by_name(type)
- if plugin.status == PluginStatus.Active and plugin.mediaItem:
- plugin.mediaItem.goLive(id, remote=True)
+ if plugin.status == PluginStatus.Active and plugin.media_item:
+ plugin.media_item.go_live(id, remote=True)
return self._http_success()
def add_to_service(self, plugin_name):
@@ -552,9 +550,9 @@ class HttpConnection(object):
except KeyError, ValueError:
return self._http_bad_request()
plugin = self.plugin_manager.get_plugin_by_name(type)
- if plugin.status == PluginStatus.Active and plugin.mediaItem:
- item_id = plugin.mediaItem.createItemFromId(id)
- plugin.mediaItem.addToService(item_id, remote=True)
+ if plugin.status == PluginStatus.Active and plugin.media_item:
+ item_id = plugin.media_item.create_item_from_id(id)
+ plugin.media_item.add_to_service(item_id, remote=True)
self._http_success()
def _http_success(self):
From 86fb3437599062d4972d6a0c7815ebdee1b7ca2f Mon Sep 17 00:00:00 2001
From: phill-ridout
Date: Sun, 24 Mar 2013 11:32:03 +0000
Subject: [PATCH 13/71] Added test for SongShowPlus
---
.../plugins/songs/lib/songshowplusimport.py | 17 +-
.../songs/test_songshowplusimport.py | 169 ++++++++++++++++++
.../openlp_plugins_songs_lib/__init__.py | 0
.../test_songshowplusimport.py | 31 ----
tests/resources/Amazing Grace.sbsong | Bin 0 -> 1018 bytes
5 files changed, 178 insertions(+), 39 deletions(-)
create mode 100644 tests/functional/openlp_plugins/songs/test_songshowplusimport.py
delete mode 100644 tests/functional/openlp_plugins_songs_lib/__init__.py
delete mode 100644 tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
create mode 100644 tests/resources/Amazing Grace.sbsong
diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py
index 84e888856..57a0f3236 100644
--- a/openlp/plugins/songs/lib/songshowplusimport.py
+++ b/openlp/plugins/songs/lib/songshowplusimport.py
@@ -89,8 +89,9 @@ class SongShowPlusImport(SongImport):
* .sbsong
"""
- otherList = {}
- otherCount = 0
+
+ other_count = 0
+ other_list = {}
def __init__(self, manager, **kwargs):
"""
@@ -109,8 +110,8 @@ class SongShowPlusImport(SongImport):
if self.stop_import_flag:
return
self.sspVerseOrderList = []
- other_count = 0
- other_list = {}
+ self.other_count = 0
+ self.other_list = {}
file_name = os.path.split(file)[1]
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % file_name, 0)
song_data = open(file, 'rb')
@@ -204,11 +205,11 @@ class SongShowPlusImport(SongImport):
elif verse_type == "pre-chorus":
verse_tag = VerseType.tags[VerseType.PreChorus]
else:
- if verse_name not in self.otherList:
+ if verse_name not in self.other_list:
if ignore_unique:
return None
- self.otherCount += 1
- self.otherList[verse_name] = str(self.otherCount)
+ self.other_count += 1
+ self.other_list[verse_name] = str(self.other_count)
verse_tag = VerseType.tags[VerseType.Other]
- verse_number = self.otherList[verse_name]
+ verse_number = self.other_list[verse_name]
return verse_tag + verse_number
diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py
new file mode 100644
index 000000000..38962b79d
--- /dev/null
+++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py
@@ -0,0 +1,169 @@
+"""
+This module contains tests for the OpenLP song importer.
+"""
+
+import os
+from unittest import TestCase
+from mock import call, patch, MagicMock
+
+from openlp.plugins.songs.lib import VerseType
+from openlp.plugins.songs.lib.songshowplusimport import SongShowPlusImport
+
+TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'../../../resources'))
+
+class TestSongShowPlusFileImport(TestCase):
+ """
+ Test the functions in the :mod:`lib` module.
+ """
+ def create_importer_test(self):
+ """
+ Test creating an instance of the SongShow Plus file importer
+ """
+ # GIVEN: A mocked out SongImport class, and a mocked out "manager"
+ with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
+ mocked_manager = MagicMock()
+
+ # WHEN: An importer object is created
+ importer = SongShowPlusImport(mocked_manager)
+
+ # THEN: The importer object should not be None
+ self.assertIsNotNone(importer, u'Import should not be none')
+
+ def toOpenLPVerseTag_test(self):
+ """
+ Test toOpenLPVerseTag method
+ """
+ # GIVEN: A mocked out SongImport class, and a mocked out "manager"
+ with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
+ mocked_manager = MagicMock()
+ importer = SongShowPlusImport(mocked_manager)
+
+ # WHEN: Supplied with the following arguments replicating verses being added
+ test_values = [(u'Verse 1', VerseType.tags[VerseType.Verse] + u'1'),
+ (u'Verse 2', VerseType.tags[VerseType.Verse] + u'2'),
+ (u'verse1', VerseType.tags[VerseType.Verse] + u'1'),
+ (u'Verse', VerseType.tags[VerseType.Verse] + u'1'),
+ (u'Verse1', VerseType.tags[VerseType.Verse] + u'1'),
+ (u'chorus 1', VerseType.tags[VerseType.Chorus] + u'1'),
+ (u'bridge 1', VerseType.tags[VerseType.Bridge] + u'1'),
+ (u'pre-chorus 1', VerseType.tags[VerseType.PreChorus] + u'1'),
+ (u'different 1', VerseType.tags[VerseType.Other] + u'1'),
+ (u'random 1', VerseType.tags[VerseType.Other] + u'2')]
+
+ # THEN: The returned value should should correlate with the input arguments
+ for original_tag, openlp_tag in test_values:
+ self.assertEquals(importer.toOpenLPVerseTag(original_tag), openlp_tag,
+ u'SongShowPlusImport.toOpenLPVerseTag should return "%s" when called with "%s"'
+ % (openlp_tag, original_tag))
+
+ # WHEN: Supplied with the following arguments replicating a verse order being added
+ test_values = [(u'Verse 1', VerseType.tags[VerseType.Verse] + u'1'),
+ (u'Verse 2', VerseType.tags[VerseType.Verse] + u'2'),
+ (u'verse1', VerseType.tags[VerseType.Verse] + u'1'),
+ (u'Verse', VerseType.tags[VerseType.Verse] + u'1'),
+ (u'Verse1', VerseType.tags[VerseType.Verse] + u'1'),
+ (u'chorus 1', VerseType.tags[VerseType.Chorus] + u'1'),
+ (u'bridge 1', VerseType.tags[VerseType.Bridge] + u'1'),
+ (u'pre-chorus 1', VerseType.tags[VerseType.PreChorus] + u'1'),
+ (u'different 1', VerseType.tags[VerseType.Other] + u'1'),
+ (u'random 1', VerseType.tags[VerseType.Other] + u'2'),
+ (u'unused 2', None)]
+
+ # THEN: The returned value should should correlate with the input arguments
+ for original_tag, openlp_tag in test_values:
+ self.assertEquals(importer.toOpenLPVerseTag(original_tag, ignore_unique=True), openlp_tag,
+ u'SongShowPlusImport.toOpenLPVerseTag should return "%s" when called with "%s"'
+ % (openlp_tag, original_tag))
+
+
+
+
+ def import_source_test(self):
+ """
+ Test creating an instance of the SongShow Plus file importer
+ """
+ # GIVEN: A mocked out SongImport class, and a mocked out "manager"
+ with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
+ mocked_manager = MagicMock()
+ mocked_import_wizard = MagicMock()
+ importer = SongShowPlusImport(mocked_manager)
+ importer.import_wizard = mocked_import_wizard
+ importer.stop_import_flag = True
+
+ # WHEN: Import source is a string
+ importer.import_source = u'not a list'
+
+ # THEN: doImport should return none and the progress bar maximum should not be set.
+ self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
+ self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
+ u'setMaxium on import_wizard.progress_bar should not have been called')
+
+ # WHEN: Import source is an int
+ importer.import_source = 0
+
+ # THEN: doImport should return none and the progress bar maximum should not be set.
+ self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
+ self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
+ u'setMaxium on import_wizard.progress_bar should not have been called')
+
+ # WHEN: Import source is a list
+ importer.import_source = [u'List', u'of', u'files']
+
+ # THEN: doImport should return none and the progress bar maximum should be set.
+ self.assertIsNone(importer.doImport(),
+ u'doImport should return None when import_source is a list and stop_import_flag is True')
+ mocked_import_wizard.progress_bar.setMaximum.assert_called_with(
+ len(importer.import_source))
+
+ def file_import_test(self):
+ """
+ Test creating an instance of the SongShow Plus file importer
+ """
+
+ # GIVEN: A mocked out SongImport class, and a mocked out "manager"
+ with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
+ mocked_manager = MagicMock()
+ mocked_import_wizard = MagicMock()
+ mocked_parse_author = MagicMock()
+ mocked_add_copyright = MagicMock()
+ mocked_add_verse = MagicMock()
+ mocked_finish = MagicMock()
+ mocked_finish.return_value = True
+ importer = SongShowPlusImport(mocked_manager)
+ importer.import_wizard = mocked_import_wizard
+ importer.stop_import_flag = False
+ importer.parse_author = mocked_parse_author
+ importer.addCopyright = mocked_add_copyright
+ importer.addVerse = mocked_add_verse
+ importer.finish = mocked_finish
+ importer.topics = []
+
+ # WHEN: Import source is a string
+ importer.import_source = [os.path.join(TEST_PATH, u'Amazing Grace.sbsong')]
+
+ # THEN: doImport should return none and the progress bar maximum should not be set.
+ self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
+ self.assertEquals(importer.title, u'Amazing Grace (Demonstration)',
+ u'Title for Amazing Grace.sbsong should be "Amazing Grace (Demonstration)"')
+ calls = [call(u'John Newton'), call(u'Edwin Excell'), call(u'John P. Rees')]
+ mocked_parse_author.assert_has_calls(calls)
+ mocked_add_copyright.assert_called_with(u'Public Domain ')
+ self.assertEquals(importer.ccliNumber, 22025, u'ccliNumber should be set as 22025 for Amazing Grace.sbsong')
+ calls = [call(u'Amazing grace! How sweet the sound!\r\nThat saved a wretch like me!\r\n'
+ u'I once was lost, but now am found;\r\nWas blind, but now I see.', u'v1'),
+ call(u"'Twas grace that taught my heart to fear,\r\nAnd grace my fears relieved.\r\n"
+ u"How precious did that grace appear,\r\nThe hour I first believed.", u'v2'),
+ call(u'The Lord has promised good to me,\r\nHis Word my hope secures.\r\n'
+ u'He will my shield and portion be\r\nAs long as life endures.', u'v3'),
+ call(u"Thro' many dangers, toils and snares\r\nI have already come.\r\n"
+ u"'Tis grace that brought me safe thus far,\r\nAnd grace will lead me home.", u'v4'),
+ call(u"When we've been there ten thousand years,\r\nBright shining as the sun,\r\n"
+ u"We've no less days to sing God's praise,\r\nThan when we first begun.", u'v5')]
+ mocked_add_verse.assert_has_calls(calls)
+ self.assertEquals(importer.topics, [u'Assurance', u'Grace', u'Praise', u'Salvation'])
+ self.assertEquals(importer.comments, u'\n\n\n', u'comments should be "\\n\\n\\n" Amazing Grace.sbsong')
+ self.assertEquals(importer.songBookName, u'Demonstration Songs', u'songBookName should be '
+ u'"Demonstration Songs"')
+ self.assertEquals(importer.songNumber, 0, u'songNumber should be 0')
+ self.assertEquals(importer.verseOrderList, [], u'verseOrderList should be empty')
+ mocked_finish.assert_called_with()
\ No newline at end of file
diff --git a/tests/functional/openlp_plugins_songs_lib/__init__.py b/tests/functional/openlp_plugins_songs_lib/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py b/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
deleted file mode 100644
index 77733a1ba..000000000
--- a/tests/functional/openlp_plugins_songs_lib/test_songshowplusimport.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""
- Package to test the openlp.plugins.songs.lib package.
-"""
-import os
-
-from unittest import TestCase
-from mock import MagicMock, patch
-from openlp.plugins.songs.lib import songshowplusimport
-
-TESTPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
-
-
-class TestSongShowPlusImport(TestCase):
-
-#test do import
- # set self.import source to non list type. Do import should return None or False?
- # set self.import source to a list of files
- # importWizard.progressBar should be set to the number of files in the list
- # set self.stop_import_flag to true. Do import should return None or False?
-
-
-
- def do_import_test(self):
- mocked_manager = MagicMock()
-
- with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport') as mocked_song_import:
- ssp_import_class = songshowplusimport.SongShowPlusImport(mocked_manager)
-
- songshowplusimport.SongShowPlusImport.importSource = ''
-
- self.assertEquals(ssp_import_class.SongShowPlusImport().doImport(), False)
diff --git a/tests/resources/Amazing Grace.sbsong b/tests/resources/Amazing Grace.sbsong
new file mode 100644
index 0000000000000000000000000000000000000000..14b7c35971ad673c98ca9ad8e128e0ad3922444c
GIT binary patch
literal 1018
zcmZ8g-)j>=5KdZq+S7<2K31nFL?J{8_~cWhwT*}r8_4tKZgRJ{w;Oi%dX4xXC@3QS
z&3<#&AL_#;vpcijeDlprzt`(M!k6q#EA>g+f{wh(n4TVR#*FANZ?v30Foz50$#@$t?#ZjWC-u_kj1F9-
z5cULjg1FV&!S79p*qKaTOkO51`}lU{u8X*JW!;7)U$Xm#=!j^#q&ql%lYoBm<+8X!
zirc4S*HCDfBgK*_xZ39XgLGc1NI{)(PKp}OF)PXFk4zQAJ0oWyOrruB7vhMPbtDTQ
zRnbZiUJcR(oT$a-*WMWg=CN@3C0w?WAH%s|v`mm5DWj^3GE%jnl9k8V(F(?BkWOuW
z5eTQ;1@de(gW`CQN)>C*nRa!cT<0BH2dviX4q}c1OILfE(MtOeX?Y1CoIVSu?c`jd
z-Z`IB32JNaDjlFg;T%96>Iau&9cUpT!qcrG8)voWAVeUGHby+5)NG(1h_9WO*+D`S
zBBEiqfNu1PiEZA#6%OBp!;R$Yy!38Jm9iVkl`Ys~R-)4;v}nO9B$GCj=nyI6S>+qb
zT*Y88oP*t8k}kdLGzCqCe6fT?tN%1@IUB&BK$HX^q4Qhl>?A)IC0lBEh-6EKiAnJQ
zYApyZ6>g*>kmj}5(m>R1WrI*;J65%YZ_y%HM}`Bsq&9Fm3hk!3d?;!wh>b{$9};$1
zuX5fJlwC-YlNRmz#i=r9?Fv7HTNWzWPSX_sy+1Rg
B8W{ip
literal 0
HcmV?d00001
From c3492d6aedd1ce06f3cb680f8eb3c72ae61b2968 Mon Sep 17 00:00:00 2001
From: phill-ridout
Date: Sun, 24 Mar 2013 13:25:31 +0000
Subject: [PATCH 14/71] Added an extra test song, and cleaned up the test some
what
---
.../songs/test_songshowplusimport.py | 228 +++++++++++-------
.../Beautiful Garden Of Prayer.sbsong | Bin 0 -> 964 bytes
2 files changed, 140 insertions(+), 88 deletions(-)
create mode 100644 tests/resources/Beautiful Garden Of Prayer.sbsong
diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py
index 38962b79d..4fb1e2479 100644
--- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py
+++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py
@@ -1,5 +1,5 @@
"""
-This module contains tests for the OpenLP song importer.
+This module contains tests for the SongShow Plus song importer.
"""
import os
@@ -10,10 +10,51 @@ from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.songshowplusimport import SongShowPlusImport
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'../../../resources'))
+SONG_TEST_DATA = {u'Amazing Grace.sbsong':
+ {u'title': u'Amazing Grace (Demonstration)',
+ u'authors': [u'John Newton', u'Edwin Excell', u'John P. Rees'],
+ u'copyright': u'Public Domain ',
+ u'ccli_number': 22025,
+ u'verses':
+ [(u'Amazing grace! How sweet the sound!\r\nThat saved a wretch like me!\r\n'
+ u'I once was lost, but now am found;\r\nWas blind, but now I see.', u'v1'),
+ (u'\'Twas grace that taught my heart to fear,\r\nAnd grace my fears relieved.\r\n'
+ u'How precious did that grace appear,\r\nThe hour I first believed.', u'v2'),
+ (u'The Lord has promised good to me,\r\nHis Word my hope secures.\r\n'
+ u'He will my shield and portion be\r\nAs long as life endures.', u'v3'),
+ (u'Thro\' many dangers, toils and snares\r\nI have already come.\r\n'
+ u'\'Tis grace that brought me safe thus far,\r\nAnd grace will lead me home.', u'v4'),
+ (u'When we\'ve been there ten thousand years,\r\nBright shining as the sun,\r\n'
+ u'We\'ve no less days to sing God\'s praise,\r\nThan when we first begun.', u'v5')],
+ u'topics': [u'Assurance', u'Grace', u'Praise', u'Salvation'],
+ u'comments': u'\n\n\n',
+ u'song_book_name': u'Demonstration Songs',
+ u'song_number': 0,
+ u'verse_order_list': []},
+ u'Beautiful Garden Of Prayer.sbsong':
+ {u'title': u'Beautiful Garden Of Prayer (Demonstration)',
+ u'authors': [u'Eleanor Allen Schroll', u'James H. Fillmore'],
+ u'copyright': u'Public Domain ',
+ u'ccli_number': 60252,
+ u'verses':
+ [(u'There\'s a garden where Jesus is waiting,\r\nThere\'s a place that is wondrously fair.\r\n'
+ u'For it glows with the light of His presence,\r\n\'Tis the beautiful garden of prayer.', u'v1'),
+ (u'There\'s a garden where Jesus is waiting,\r\nAnd I go with my burden and care.\r\n'
+ u'Just to learn from His lips, words of comfort,\r\nIn the beautiful garden of prayer.', u'v2'),
+ (u'There\'s a garden where Jesus is waiting,\r\nAnd He bids you to come meet Him there,\r\n'
+ u'Just to bow and receive a new blessing,\r\nIn the beautiful garden of prayer.', u'v3'),
+ (u'O the beautiful garden, the garden of prayer,\r\nO the beautiful garden of prayer.\r\n'
+ u'There my Savior awaits, and He opens the gates\r\nTo the beautiful garden of prayer.', u'c1')],
+ u'topics': [u'Devotion', u'Prayer'],
+ u'comments': u'',
+ u'song_book_name': u'',
+ u'song_number': 0,
+ u'verse_order_list': []}}
-class TestSongShowPlusFileImport(TestCase):
+
+class TestSongShowPlusImport(TestCase):
"""
- Test the functions in the :mod:`lib` module.
+ Test the functions in the :mod:`songshowplusimport` module.
"""
def create_importer_test(self):
"""
@@ -29,6 +70,43 @@ class TestSongShowPlusFileImport(TestCase):
# THEN: The importer object should not be None
self.assertIsNotNone(importer, u'Import should not be none')
+ def import_source_test(self):
+ """
+ Test SongShowPlusImport.doImport handles different import_source values
+ """
+ # GIVEN: A mocked out SongImport class, and a mocked out "manager"
+ with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
+ mocked_manager = MagicMock()
+ mocked_import_wizard = MagicMock()
+ importer = SongShowPlusImport(mocked_manager)
+ importer.import_wizard = mocked_import_wizard
+ importer.stop_import_flag = True
+
+ # WHEN: Import source is a string
+ importer.import_source = u'not a list'
+
+ # THEN: doImport should return none and the progress bar maximum should not be set.
+ self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
+ self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
+ u'setMaxium on import_wizard.progress_bar should not have been called')
+
+ # WHEN: Import source is an int
+ importer.import_source = 0
+
+ # THEN: doImport should return none and the progress bar maximum should not be set.
+ self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
+ self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
+ u'setMaxium on import_wizard.progress_bar should not have been called')
+
+ # WHEN: Import source is a list
+ importer.import_source = [u'List', u'of', u'files']
+
+ # THEN: doImport should return none and the progress bar setMaximum should be called with the length of
+ # import_source.
+ self.assertIsNone(importer.doImport(),
+ u'doImport should return None when import_source is a list and stop_import_flag is True')
+ mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source))
+
def toOpenLPVerseTag_test(self):
"""
Test toOpenLPVerseTag method
@@ -75,95 +153,69 @@ class TestSongShowPlusFileImport(TestCase):
u'SongShowPlusImport.toOpenLPVerseTag should return "%s" when called with "%s"'
% (openlp_tag, original_tag))
-
-
-
- def import_source_test(self):
- """
- Test creating an instance of the SongShow Plus file importer
- """
- # GIVEN: A mocked out SongImport class, and a mocked out "manager"
- with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
- mocked_manager = MagicMock()
- mocked_import_wizard = MagicMock()
- importer = SongShowPlusImport(mocked_manager)
- importer.import_wizard = mocked_import_wizard
- importer.stop_import_flag = True
-
- # WHEN: Import source is a string
- importer.import_source = u'not a list'
-
- # THEN: doImport should return none and the progress bar maximum should not be set.
- self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
- self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
- u'setMaxium on import_wizard.progress_bar should not have been called')
-
- # WHEN: Import source is an int
- importer.import_source = 0
-
- # THEN: doImport should return none and the progress bar maximum should not be set.
- self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
- self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False,
- u'setMaxium on import_wizard.progress_bar should not have been called')
-
- # WHEN: Import source is a list
- importer.import_source = [u'List', u'of', u'files']
-
- # THEN: doImport should return none and the progress bar maximum should be set.
- self.assertIsNone(importer.doImport(),
- u'doImport should return None when import_source is a list and stop_import_flag is True')
- mocked_import_wizard.progress_bar.setMaximum.assert_called_with(
- len(importer.import_source))
-
def file_import_test(self):
"""
- Test creating an instance of the SongShow Plus file importer
+ Test the actual import of real song files and check that the imported data is correct.
"""
- # GIVEN: A mocked out SongImport class, and a mocked out "manager"
+ # GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard",
+ # and mocked out "author", "add_copyright", "add_verse", "finish" methods.
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
- mocked_manager = MagicMock()
- mocked_import_wizard = MagicMock()
- mocked_parse_author = MagicMock()
- mocked_add_copyright = MagicMock()
- mocked_add_verse = MagicMock()
- mocked_finish = MagicMock()
- mocked_finish.return_value = True
- importer = SongShowPlusImport(mocked_manager)
- importer.import_wizard = mocked_import_wizard
- importer.stop_import_flag = False
- importer.parse_author = mocked_parse_author
- importer.addCopyright = mocked_add_copyright
- importer.addVerse = mocked_add_verse
- importer.finish = mocked_finish
- importer.topics = []
+ for song_file in SONG_TEST_DATA:
+ mocked_manager = MagicMock()
+ mocked_import_wizard = MagicMock()
+ mocked_parse_author = MagicMock()
+ mocked_add_copyright = MagicMock()
+ mocked_add_verse = MagicMock()
+ mocked_finish = MagicMock()
+ mocked_finish.return_value = True
+ importer = SongShowPlusImport(mocked_manager)
+ importer.import_wizard = mocked_import_wizard
+ importer.stop_import_flag = False
+ importer.parse_author = mocked_parse_author
+ importer.addCopyright = mocked_add_copyright
+ importer.addVerse = mocked_add_verse
+ importer.finish = mocked_finish
+ importer.topics = []
- # WHEN: Import source is a string
- importer.import_source = [os.path.join(TEST_PATH, u'Amazing Grace.sbsong')]
+ # WHEN: Importing each file
+ importer.import_source = [os.path.join(TEST_PATH, song_file)]
+ title = SONG_TEST_DATA[song_file][u'title']
+ parse_author_calls = [call(author) for author in SONG_TEST_DATA[song_file][u'authors']]
+ song_copyright = SONG_TEST_DATA[song_file][u'copyright']
+ ccli_number = SONG_TEST_DATA[song_file][u'ccli_number']
+ add_verse_calls = \
+ [call(verse_text, verse_tag) for verse_text, verse_tag in SONG_TEST_DATA[song_file][u'verses']]
+ topics = SONG_TEST_DATA[song_file][u'topics']
+ comments = SONG_TEST_DATA[song_file][u'comments']
+ song_book_name = SONG_TEST_DATA[song_file][u'song_book_name']
+ song_number = SONG_TEST_DATA[song_file][u'song_number']
+ verse_order_list = SONG_TEST_DATA[song_file][u'verse_order_list']
- # THEN: doImport should return none and the progress bar maximum should not be set.
- self.assertIsNone(importer.doImport(), u'doImport should return None when import_source is not a list')
- self.assertEquals(importer.title, u'Amazing Grace (Demonstration)',
- u'Title for Amazing Grace.sbsong should be "Amazing Grace (Demonstration)"')
- calls = [call(u'John Newton'), call(u'Edwin Excell'), call(u'John P. Rees')]
- mocked_parse_author.assert_has_calls(calls)
- mocked_add_copyright.assert_called_with(u'Public Domain ')
- self.assertEquals(importer.ccliNumber, 22025, u'ccliNumber should be set as 22025 for Amazing Grace.sbsong')
- calls = [call(u'Amazing grace! How sweet the sound!\r\nThat saved a wretch like me!\r\n'
- u'I once was lost, but now am found;\r\nWas blind, but now I see.', u'v1'),
- call(u"'Twas grace that taught my heart to fear,\r\nAnd grace my fears relieved.\r\n"
- u"How precious did that grace appear,\r\nThe hour I first believed.", u'v2'),
- call(u'The Lord has promised good to me,\r\nHis Word my hope secures.\r\n'
- u'He will my shield and portion be\r\nAs long as life endures.', u'v3'),
- call(u"Thro' many dangers, toils and snares\r\nI have already come.\r\n"
- u"'Tis grace that brought me safe thus far,\r\nAnd grace will lead me home.", u'v4'),
- call(u"When we've been there ten thousand years,\r\nBright shining as the sun,\r\n"
- u"We've no less days to sing God's praise,\r\nThan when we first begun.", u'v5')]
- mocked_add_verse.assert_has_calls(calls)
- self.assertEquals(importer.topics, [u'Assurance', u'Grace', u'Praise', u'Salvation'])
- self.assertEquals(importer.comments, u'\n\n\n', u'comments should be "\\n\\n\\n" Amazing Grace.sbsong')
- self.assertEquals(importer.songBookName, u'Demonstration Songs', u'songBookName should be '
- u'"Demonstration Songs"')
- self.assertEquals(importer.songNumber, 0, u'songNumber should be 0')
- self.assertEquals(importer.verseOrderList, [], u'verseOrderList should be empty')
- mocked_finish.assert_called_with()
\ No newline at end of file
+ # THEN: doImport should return none, the song data should be as expected, and finish should have been
+ # called.
+ self.assertIsNone(importer.doImport(), u'doImport should return None when it has completed')
+ self.assertEquals(importer.title, title, u'title for %s should be "%s"' % (song_file, title))
+ mocked_parse_author.assert_has_calls(parse_author_calls)
+ if song_copyright:
+ mocked_add_copyright.assert_called_with(song_copyright)
+ if ccli_number:
+ self.assertEquals(importer.ccliNumber, ccli_number, u'ccliNumber for %s should be %s'
+ % (song_file, ccli_number))
+ mocked_add_verse.assert_has_calls(add_verse_calls)
+ if topics:
+ self.assertEquals(importer.topics, topics, u'topics for %s should be %s' % (song_file, topics))
+ if comments:
+ self.assertEquals(importer.comments, comments, u'comments for %s should be "%s"'
+ % (song_file, comments))
+ if song_book_name:
+ self.assertEquals(importer.songBookName, song_book_name, u'songBookName for %s should be "%s"'
+ % (song_file, song_book_name))
+ if song_number:
+ self.assertEquals(importer.songNumber, song_number, u'songNumber for %s should be %s'
+ % (song_file, song_number))
+ if verse_order_list:
+ self.assertEquals(importer.verseOrderList, [], u'verseOrderList for %s should be %s'
+ % (song_file, verse_order_list))
+ mocked_finish.assert_called_with()
+
\ No newline at end of file
diff --git a/tests/resources/Beautiful Garden Of Prayer.sbsong b/tests/resources/Beautiful Garden Of Prayer.sbsong
new file mode 100644
index 0000000000000000000000000000000000000000..c227d48097fb3f8722a874447c39476a80e35828
GIT binary patch
literal 964
zcmb7@ZEMs(5XW;@8r#!~puQ9a6zW4frJ(Ptv0m>@3)e5O$xV`l%}&_eT(~czpd#X@
zbS61^DhJgU8)hf}o&C+jj-n_^c*W1(p=yIJS_2=ITcU-F0xq3eql2d@)?|HfDrmCL
z9<%!kmMHe$zCL+#60n0Q7yOfjBJ53>Ok^vn4?}H_s?PnnL+P|cHK<+
zfGK|n=_vkou`{it_x{}trr0f)Qf(Tx85iK9FVsr&Kq#3cE~-FtrqrMv+Fq)Fp7pd7
c;kTHNn03M{K1gvz^7zCflOD&z+hjBP1!=b$FaQ7m
literal 0
HcmV?d00001
From 401da98d7cf4d3357038a50035e36f57bf89a584 Mon Sep 17 00:00:00 2001
From: phill-ridout
Date: Sun, 24 Mar 2013 14:56:22 +0000
Subject: [PATCH 15/71] increased line lengths to 120 renamed
SongShowPlusImport vairables and methods to standards
---
.../plugins/songs/lib/songshowplusimport.py | 35 ++++++++-----------
.../songs/test_songshowplusimport.py | 11 +++---
2 files changed, 19 insertions(+), 27 deletions(-)
diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py
index 57a0f3236..14631ebc2 100644
--- a/openlp/plugins/songs/lib/songshowplusimport.py
+++ b/openlp/plugins/songs/lib/songshowplusimport.py
@@ -57,31 +57,24 @@ log = logging.getLogger(__name__)
class SongShowPlusImport(SongImport):
"""
- The :class:`SongShowPlusImport` class provides the ability to import song
- files from SongShow Plus.
+ The :class:`SongShowPlusImport` class provides the ability to import song files from SongShow Plus.
**SongShow Plus Song File Format:**
The SongShow Plus song file format is as follows:
- * Each piece of data in the song file has some information that precedes
- it.
+ * Each piece of data in the song file has some information that precedes it.
* The general format of this data is as follows:
- 4 Bytes, forming a 32 bit number, a key if you will, this describes what
- the data is (see blockKey below)
- 4 Bytes, forming a 32 bit number, which is the number of bytes until the
- next block starts
+ 4 Bytes, forming a 32 bit number, a key if you will, this describes what the data is (see blockKey below)
+ 4 Bytes, forming a 32 bit number, which is the number of bytes until the next block starts
1 Byte, which tells how many bytes follows
- 1 or 4 Bytes, describes how long the string is, if its 1 byte, the string
- is less than 255
+ 1 or 4 Bytes, describes how long the string is, if its 1 byte, the string is less than 255
The next bytes are the actual data.
The next block of data follows on.
- This description does differ for verses. Which includes extra bytes
- stating the verse type or number. In some cases a "custom" verse is used,
- in that case, this block will in include 2 strings, with the associated
- string length descriptors. The first string is the name of the verse, the
- second is the verse content.
+ This description does differ for verses. Which includes extra bytes stating the verse type or number. In some cases
+ a "custom" verse is used, in that case, this block will in include 2 strings, with the associated string length
+ descriptors. The first string is the name of the verse, the second is the verse content.
The file is ended with four null bytes.
@@ -109,7 +102,7 @@ class SongShowPlusImport(SongImport):
for file in self.import_source:
if self.stop_import_flag:
return
- self.sspVerseOrderList = []
+ self.ssp_verse_order_list = []
self.other_count = 0
self.other_list = {}
file_name = os.path.split(file)[1]
@@ -164,27 +157,27 @@ class SongShowPlusImport(SongImport):
elif block_key == COMMENTS:
self.comments = unicode(data, u'cp1252')
elif block_key == VERSE_ORDER:
- verse_tag = self.toOpenLPVerseTag(data, True)
+ verse_tag = self.to_openlp_verse_tag(data, True)
if verse_tag:
if not isinstance(verse_tag, unicode):
verse_tag = unicode(verse_tag, u'cp1252')
- self.sspVerseOrderList.append(verse_tag)
+ self.ssp_verse_order_list.append(verse_tag)
elif block_key == SONG_BOOK:
self.songBookName = unicode(data, u'cp1252')
elif block_key == SONG_NUMBER:
self.songNumber = ord(data)
elif block_key == CUSTOM_VERSE:
- verse_tag = self.toOpenLPVerseTag(verse_name)
+ verse_tag = self.to_openlp_verse_tag(verse_name)
self.addVerse(unicode(data, u'cp1252'), verse_tag)
else:
log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data))
song_data.seek(next_block_starts)
- self.verseOrderList = self.sspVerseOrderList
+ self.verseOrderList = self.ssp_verse_order_list
song_data.close()
if not self.finish():
self.logError(file)
- def toOpenLPVerseTag(self, verse_name, ignore_unique=False):
+ def to_openlp_verse_tag(self, verse_name, ignore_unique=False):
# Have we got any digits? If so, verse number is everything from the digits to the end (OpenLP does not have
# concept of part verses, so just ignore any non integers on the end (including floats))
match = re.match(u'(\D*)(\d+)', verse_name)
diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py
index 4fb1e2479..9db0ee421 100644
--- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py
+++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py
@@ -109,7 +109,7 @@ class TestSongShowPlusImport(TestCase):
def toOpenLPVerseTag_test(self):
"""
- Test toOpenLPVerseTag method
+ Test to_openlp_verse_tag method
"""
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch(u'openlp.plugins.songs.lib.songshowplusimport.SongImport'):
@@ -130,8 +130,8 @@ class TestSongShowPlusImport(TestCase):
# THEN: The returned value should should correlate with the input arguments
for original_tag, openlp_tag in test_values:
- self.assertEquals(importer.toOpenLPVerseTag(original_tag), openlp_tag,
- u'SongShowPlusImport.toOpenLPVerseTag should return "%s" when called with "%s"'
+ self.assertEquals(importer.to_openlp_verse_tag(original_tag), openlp_tag,
+ u'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"'
% (openlp_tag, original_tag))
# WHEN: Supplied with the following arguments replicating a verse order being added
@@ -149,8 +149,8 @@ class TestSongShowPlusImport(TestCase):
# THEN: The returned value should should correlate with the input arguments
for original_tag, openlp_tag in test_values:
- self.assertEquals(importer.toOpenLPVerseTag(original_tag, ignore_unique=True), openlp_tag,
- u'SongShowPlusImport.toOpenLPVerseTag should return "%s" when called with "%s"'
+ self.assertEquals(importer.to_openlp_verse_tag(original_tag, ignore_unique=True), openlp_tag,
+ u'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"'
% (openlp_tag, original_tag))
def file_import_test(self):
@@ -218,4 +218,3 @@ class TestSongShowPlusImport(TestCase):
self.assertEquals(importer.verseOrderList, [], u'verseOrderList for %s should be %s'
% (song_file, verse_order_list))
mocked_finish.assert_called_with()
-
\ No newline at end of file
From 401f5ac2be3b087abfecf4bf6fbbcbca06289d7e Mon Sep 17 00:00:00 2001
From: Tim Bentley
Date: Tue, 26 Mar 2013 08:55:05 +0000
Subject: [PATCH 16/71] More updates
---
openlp/core/ui/slidecontroller.py | 2 -
openlp/plugins/remotes/html/login.html | 3 +-
openlp/plugins/remotes/lib/httpauth.py | 10 ++---
openlp/plugins/remotes/lib/httpserver.py | 14 ++-----
.../openlp_plugins/remotes/test_auth.py | 38 +++++++++++++++----
5 files changed, 40 insertions(+), 27 deletions(-)
diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py
index 518e2a715..a66d0057b 100644
--- a/openlp/core/ui/slidecontroller.py
+++ b/openlp/core/ui/slidecontroller.py
@@ -1080,7 +1080,6 @@ class SlideController(DisplayController):
"""
Go to the next slide.
"""
- print "next"
if not self.service_item:
return
Registry().execute(u'%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live])
@@ -1108,7 +1107,6 @@ class SlideController(DisplayController):
"""
Go to the previous slide.
"""
- print "prev"
if not self.service_item:
return
Registry().execute(u'%s_previous' % self.service_item.name.lower(), [self.service_item, self.is_live])
diff --git a/openlp/plugins/remotes/html/login.html b/openlp/plugins/remotes/html/login.html
index 736d3f0ab..5d649629b 100644
--- a/openlp/plugins/remotes/html/login.html
+++ b/openlp/plugins/remotes/html/login.html
@@ -36,7 +36,6 @@
-
@@ -48,4 +47,4 @@
Password: