From aea6c424fc162e97572d6172f9c8d98492b12bc0 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 15 Jun 2015 21:29:34 +0100 Subject: [PATCH 1/4] Check mediaplayer is loaded before trying to use it when blanking. Fixes bug 1465390. Fixes: https://launchpad.net/bugs/1465390 --- openlp/core/ui/media/mediacontroller.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 39e7d3b65..5209a8253 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -721,8 +721,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): display = self._define_display(self.live_controller) if self.live_controller.controller_type in self.current_media_players and \ self.current_media_players[self.live_controller.controller_type].state == MediaState.Playing: - self.current_media_players[self.live_controller.controller_type].pause(display) - self.current_media_players[self.live_controller.controller_type].set_visible(display, False) + self.current_media_players[self.live_controller.controller_type].pause(display) + self.current_media_players[self.live_controller.controller_type].set_visible(display, False) def media_blank(self, msg): """ @@ -737,7 +737,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): return Registry().execute('live_display_hide', hide_mode) display = self._define_display(self.live_controller) - if self.current_media_players[self.live_controller.controller_type].state == MediaState.Playing: + if self.live_controller.controller_type in self.current_media_players and \ + self.current_media_players[self.live_controller.controller_type].state == MediaState.Playing: self.current_media_players[self.live_controller.controller_type].pause(display) self.current_media_players[self.live_controller.controller_type].set_visible(display, False) From 3b0b75e5b61348f1893a05816bd0a72cba5700a3 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 16 Jun 2015 09:47:42 +0200 Subject: [PATCH 2/4] Remove unneeded import. --- openlp/plugins/presentations/lib/powerpointcontroller.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index a2e4e1c68..138d095bc 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -33,7 +33,6 @@ from openlp.core.common import is_win, Settings if is_win(): from win32com.client import Dispatch - import win32com import win32con import winreg import win32ui From 03b5ec6d16303007d3c01f6114ce56386d3ea8f5 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 17 Jun 2015 18:46:45 +0100 Subject: [PATCH 3/4] Catch songselect connections error. Fixes bug 1464421. Fixes: https://launchpad.net/bugs/1464421 --- openlp/plugins/songs/lib/songselect.py | 43 ++++++++++++++++++-------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/openlp/plugins/songs/lib/songselect.py b/openlp/plugins/songs/lib/songselect.py index 5d7baab96..6df493dd2 100644 --- a/openlp/plugins/songs/lib/songselect.py +++ b/openlp/plugins/songs/lib/songselect.py @@ -25,8 +25,10 @@ The :mod:`~openlp.plugins.songs.lib.songselect` module contains the SongSelect i import logging from http.cookiejar import CookieJar from urllib.parse import urlencode -from urllib.request import HTTPCookieProcessor, HTTPError, build_opener +from urllib.request import HTTPCookieProcessor, URLError, build_opener from html.parser import HTMLParser +from html import unescape + from bs4 import BeautifulSoup, NavigableString @@ -72,7 +74,11 @@ class SongSelectImport(object): """ if callback: callback() - login_page = BeautifulSoup(self.opener.open(LOGIN_URL).read(), 'lxml') + try: + login_page = BeautifulSoup(self.opener.open(LOGIN_URL).read(), 'lxml') + except (TypeError, URLError) as e: + log.exception('Could not login to SongSelect, %s', e) + return False if callback: callback() token_input = login_page.find('input', attrs={'name': '__RequestVerificationToken'}) @@ -82,7 +88,11 @@ class SongSelectImport(object): 'Password': password, 'RememberMe': 'false' }) - posted_page = BeautifulSoup(self.opener.open(LOGIN_URL, data.encode('utf-8')).read(), 'lxml') + try: + posted_page = BeautifulSoup(self.opener.open(LOGIN_URL, data.encode('utf-8')).read(), 'lxml') + except (TypeError, URLError) as e: + log.exception('Could not login to SongSelect, %s', e) + return False if callback: callback() return not posted_page.find('input', attrs={'name': '__RequestVerificationToken'}) @@ -91,7 +101,10 @@ class SongSelectImport(object): """ Log the user out of SongSelect """ - self.opener.open(LOGOUT_URL) + try: + self.opener.open(LOGOUT_URL) + except (TypeError, URLError) as e: + log.exception('Could not log of SongSelect, %s', e) def search(self, search_text, max_results, callback=None): """ @@ -108,14 +121,18 @@ class SongSelectImport(object): while True: if current_page > 1: params['page'] = current_page - results_page = BeautifulSoup(self.opener.open(SEARCH_URL + '?' + urlencode(params)).read(), 'lxml') - search_results = results_page.find_all('li', 'result pane') + try: + results_page = BeautifulSoup(self.opener.open(SEARCH_URL + '?' + urlencode(params)).read(), 'lxml') + search_results = results_page.find_all('li', 'result pane') + except (TypeError, URLError) as e: + log.exception('Could not search SongSelect, %s', e) + search_results = None if not search_results: break for result in search_results: song = { - 'title': self.html_parser.unescape(result.find('h3').string), - 'authors': [self.html_parser.unescape(author.string) for author in result.find_all('li')], + 'title': unescape(result.find('h3').string), + 'authors': [unescape(author.string) for author in result.find_all('li')], 'link': BASE_URL + result.find('a')['href'] } if callback: @@ -138,20 +155,20 @@ class SongSelectImport(object): callback() try: song_page = BeautifulSoup(self.opener.open(song['link']).read(), 'lxml') - except (TypeError, HTTPError) as e: + except (TypeError, URLError) as e: log.exception('Could not get song from SongSelect, %s', e) return None if callback: callback() try: lyrics_page = BeautifulSoup(self.opener.open(song['link'] + '/lyrics').read(), 'lxml') - except (TypeError, HTTPError): + except (TypeError, URLError): log.exception('Could not get lyrics from SongSelect') return None if callback: callback() song['copyright'] = '/'.join([li.string for li in song_page.find('ul', 'copyright').find_all('li')]) - song['copyright'] = self.html_parser.unescape(song['copyright']) + song['copyright'] = unescape(song['copyright']) song['ccli_number'] = song_page.find('ul', 'info').find('li').string.split(':')[1].strip() song['verses'] = [] verses = lyrics_page.find('section', 'lyrics').find_all('p') @@ -164,9 +181,9 @@ class SongSelectImport(object): else: verse['lyrics'] += '\n' verse['lyrics'] = verse['lyrics'].strip(' \n\r\t') - song['verses'].append(self.html_parser.unescape(verse)) + song['verses'].append(unescape(verse)) for counter, author in enumerate(song['authors']): - song['authors'][counter] = self.html_parser.unescape(author) + song['authors'][counter] = unescape(author) return song def save_song(self, song): From 5444614ced1675a557d8b3185621b40ae2cf4b41 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 24 Jun 2015 21:26:52 +0100 Subject: [PATCH 4/4] Added songselect login except test --- .../openlp_plugins/songs/test_songselect.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/functional/openlp_plugins/songs/test_songselect.py b/tests/functional/openlp_plugins/songs/test_songselect.py index d96d5d877..05627b40e 100644 --- a/tests/functional/openlp_plugins/songs/test_songselect.py +++ b/tests/functional/openlp_plugins/songs/test_songselect.py @@ -81,6 +81,23 @@ class TestSongSelectImport(TestCase, TestMixin): self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice') self.assertFalse(result, 'The login method should have returned False') + @patch('openlp.plugins.songs.lib.songselect.build_opener') + def login_except_test(self, mocked_build_opener): + """ + Test that when logging in to SongSelect fails, the login method raises URLError + """ + # GIVEN: A bunch of mocked out stuff and an importer object + mocked_build_opener.open.side_effect = URLError('Fake URLError') + mock_callback = MagicMock() + importer = SongSelectImport(None) + + # WHEN: The login method is called after being rigged to fail + result = importer.login('username', 'password', mock_callback) + + # THEN: callback was called 1 time and False was returned + self.assertEqual(1, mock_callback.call_count, 'callback should have been called 1 times') + self.assertFalse(result, 'The login method should have returned False') + @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') def login_succeeds_test(self, MockedBeautifulSoup, mocked_build_opener):