Merge lp:~tomasgroth/openlp/bugfixes7 into lp:openlp

Proposed by Tomas Groth
Status: Merged
Merged at revision: 2451
Proposed branch: lp:~tomasgroth/openlp/bugfixes7
Merge into: lp:openlp
Diff against target: 276 lines (+108/-28)
7 files modified
openlp/core/ui/slidecontroller.py (+5/-0)
openlp/plugins/remotes/html/openlp.js (+7/-3)
openlp/plugins/remotes/html/stage.js (+2/-2)
openlp/plugins/remotes/lib/httprouter.py (+1/-3)
openlp/plugins/songs/lib/upgrade.py (+37/-20)
tests/functional/openlp_core_ui/test_slidecontroller.py (+4/-0)
tests/functional/openlp_plugins/songs/test_db.py (+52/-0)
To merge this branch: bzr merge lp:~tomasgroth/openlp/bugfixes7
Reviewer Review Type Date Requested Status
Raoul Snyman Approve
Tim Bentley Approve
Review via email: mp+242851@code.launchpad.net

Description of the change

Fix upgrade on song db with lost version. Fixes bug 1391638.
Treat slide notes and servicemanager notes differently in the web remote and stage view. Fixes bug 1390015.
When escaping live display stop looping to prevent display to reappear. Fixes bug 1266271.

To post a comment you must log in.
Revision history for this message
Tomas Groth (tomasgroth) wrote :
Revision history for this message
Tim Bentley (trb143) wrote :

Looks good.

review: Approve
Revision history for this message
Raoul Snyman (raoul-snyman) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/ui/slidecontroller.py'
2--- openlp/core/ui/slidecontroller.py 2014-11-13 11:21:54 +0000
3+++ openlp/core/ui/slidecontroller.py 2014-11-25 22:34:10 +0000
4@@ -493,6 +493,11 @@
5 """
6 self.display.setVisible(False)
7 self.media_controller.media_stop(self)
8+ # Stop looping if active
9+ if self.play_slides_loop.isChecked():
10+ self.on_play_slides_loop(False)
11+ elif self.play_slides_once.isChecked():
12+ self.on_play_slides_once(False)
13
14 def toggle_display(self, action):
15 """
16
17=== modified file 'openlp/plugins/remotes/html/openlp.js'
18--- openlp/plugins/remotes/html/openlp.js 2014-09-11 09:52:32 +0000
19+++ openlp/plugins/remotes/html/openlp.js 2014-11-25 22:34:10 +0000
20@@ -67,8 +67,12 @@
21 var ul = $("#service-manager > div[data-role=content] > ul[data-role=listview]");
22 ul.html("");
23 $.each(data.results.items, function (idx, value) {
24+ var text = value["title"];
25+ if (value["notes"]) {
26+ text += ' - ' + value["notes"];
27+ }
28 var li = $("<li data-icon=\"false\">").append(
29- $("<a href=\"#\">").attr("value", parseInt(idx, 10)).text(value["title"]));
30+ $("<a href=\"#\">").attr("value", parseInt(idx, 10)).text(text));
31 li.attr("uuid", value["id"])
32 li.children("a").click(OpenLP.setItem);
33 ul.append(li);
34@@ -98,8 +102,8 @@
35 } else {
36 text += slide["text"];
37 }
38- if (slide["notes"]) {
39- text += ("<div style='font-size:smaller;font-weight:normal'>" + slide["notes"] + "</div>");
40+ if (slide["slide_notes"]) {
41+ text += ("<div style='font-size:smaller;font-weight:normal'>" + slide["slide_notes"] + "</div>");
42 }
43 text = text.replace(/\n/g, '<br />');
44 if (slide["img"]) {
45
46=== modified file 'openlp/plugins/remotes/html/stage.js'
47--- openlp/plugins/remotes/html/stage.js 2014-07-14 12:41:27 +0000
48+++ openlp/plugins/remotes/html/stage.js 2014-11-25 22:34:10 +0000
49@@ -114,8 +114,8 @@
50 text += "<br /><img src='" + slide["img"].replace("/thumbnails/", "/thumbnails320x240/") + "'><br />";
51 }
52 // use notes if available
53- if (slide["notes"]) {
54- text += '<br />' + slide["notes"];
55+ if (slide["slide_notes"]) {
56+ text += '<br />' + slide["slide_notes"];
57 }
58 text = text.replace(/\n/g, "<br />");
59 $("#currentslide").html(text);
60
61=== modified file 'openlp/plugins/remotes/lib/httprouter.py'
62--- openlp/plugins/remotes/lib/httprouter.py 2014-10-27 12:52:56 +0000
63+++ openlp/plugins/remotes/lib/httprouter.py 2014-11-25 22:34:10 +0000
64@@ -521,7 +521,7 @@
65 if current_item.is_capable(ItemCapabilities.HasDisplayTitle):
66 item['title'] = str(frame['display_title'])
67 if current_item.is_capable(ItemCapabilities.HasNotes):
68- item['notes'] = str(frame['notes'])
69+ item['slide_notes'] = str(frame['notes'])
70 if current_item.is_capable(ItemCapabilities.HasThumbnails) and \
71 Settings().value('remotes/thumbnails'):
72 # If the file is under our app directory tree send the portion after the match
73@@ -531,8 +531,6 @@
74 item['text'] = str(frame['title'])
75 item['html'] = str(frame['title'])
76 item['selected'] = (self.live_controller.selected_row == index)
77- if current_item.notes:
78- item['notes'] = item.get('notes', '') + '\n' + current_item.notes
79 data.append(item)
80 json_data = {'results': {'slides': data}}
81 if current_item:
82
83=== modified file 'openlp/plugins/songs/lib/upgrade.py'
84--- openlp/plugins/songs/lib/upgrade.py 2014-07-17 21:04:58 +0000
85+++ openlp/plugins/songs/lib/upgrade.py 2014-11-25 22:34:10 +0000
86@@ -32,10 +32,11 @@
87 """
88 import logging
89
90-from sqlalchemy import Column, ForeignKey, types
91+from sqlalchemy import Table, Column, ForeignKey, types
92 from sqlalchemy.sql.expression import func, false, null, text
93
94 from openlp.core.lib.db import get_upgrade_op
95+from openlp.core.common import trace_error_handler
96
97 log = logging.getLogger(__name__)
98 __version__ = 4
99@@ -57,12 +58,16 @@
100 :param metadata:
101 """
102 op = get_upgrade_op(session)
103- op.drop_table('media_files_songs')
104- op.add_column('media_files', Column('song_id', types.Integer(), server_default=null()))
105- op.add_column('media_files', Column('weight', types.Integer(), server_default=text('0')))
106- if metadata.bind.url.get_dialect().name != 'sqlite':
107- # SQLite doesn't support ALTER TABLE ADD CONSTRAINT
108- op.create_foreign_key('fk_media_files_song_id', 'media_files', 'songs', ['song_id', 'id'])
109+ songs_table = Table('songs', metadata, autoload=True)
110+ if 'media_files_songs' in [t.name for t in metadata.tables.values()]:
111+ op.drop_table('media_files_songs')
112+ op.add_column('media_files', Column('song_id', types.Integer(), server_default=null()))
113+ op.add_column('media_files', Column('weight', types.Integer(), server_default=text('0')))
114+ if metadata.bind.url.get_dialect().name != 'sqlite':
115+ # SQLite doesn't support ALTER TABLE ADD CONSTRAINT
116+ op.create_foreign_key('fk_media_files_song_id', 'media_files', 'songs', ['song_id', 'id'])
117+ else:
118+ log.warning('Skipping upgrade_1 step of upgrading the song db')
119
120
121 def upgrade_2(session, metadata):
122@@ -72,8 +77,12 @@
123 This upgrade adds a create_date and last_modified date to the songs table
124 """
125 op = get_upgrade_op(session)
126- op.add_column('songs', Column('create_date', types.DateTime(), default=func.now()))
127- op.add_column('songs', Column('last_modified', types.DateTime(), default=func.now()))
128+ songs_table = Table('songs', metadata, autoload=True)
129+ if 'create_date' not in [col.name for col in songs_table.c.values()]:
130+ op.add_column('songs', Column('create_date', types.DateTime(), default=func.now()))
131+ op.add_column('songs', Column('last_modified', types.DateTime(), default=func.now()))
132+ else:
133+ log.warning('Skipping upgrade_2 step of upgrading the song db')
134
135
136 def upgrade_3(session, metadata):
137@@ -83,10 +92,14 @@
138 This upgrade adds a temporary song flag to the songs table
139 """
140 op = get_upgrade_op(session)
141- if metadata.bind.url.get_dialect().name == 'sqlite':
142- op.add_column('songs', Column('temporary', types.Boolean(create_constraint=False), server_default=false()))
143+ songs_table = Table('songs', metadata, autoload=True)
144+ if 'temporary' not in [col.name for col in songs_table.c.values()]:
145+ if metadata.bind.url.get_dialect().name == 'sqlite':
146+ op.add_column('songs', Column('temporary', types.Boolean(create_constraint=False), server_default=false()))
147+ else:
148+ op.add_column('songs', Column('temporary', types.Boolean(), server_default=false()))
149 else:
150- op.add_column('songs', Column('temporary', types.Boolean(), server_default=false()))
151+ log.warning('Skipping upgrade_3 step of upgrading the song db')
152
153
154 def upgrade_4(session, metadata):
155@@ -98,11 +111,15 @@
156 # Since SQLite doesn't support changing the primary key of a table, we need to recreate the table
157 # and copy the old values
158 op = get_upgrade_op(session)
159- op.create_table('authors_songs_tmp',
160- Column('author_id', types.Integer(), ForeignKey('authors.id'), primary_key=True),
161- Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True),
162- Column('author_type', types.String(), primary_key=True,
163- nullable=False, server_default=text('""')))
164- op.execute('INSERT INTO authors_songs_tmp SELECT author_id, song_id, "" FROM authors_songs')
165- op.drop_table('authors_songs')
166- op.rename_table('authors_songs_tmp', 'authors_songs')
167+ songs_table = Table('songs', metadata)
168+ if 'author_type' not in [col.name for col in songs_table.c.values()]:
169+ op.create_table('authors_songs_tmp',
170+ Column('author_id', types.Integer(), ForeignKey('authors.id'), primary_key=True),
171+ Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True),
172+ Column('author_type', types.String(), primary_key=True,
173+ nullable=False, server_default=text('""')))
174+ op.execute('INSERT INTO authors_songs_tmp SELECT author_id, song_id, "" FROM authors_songs')
175+ op.drop_table('authors_songs')
176+ op.rename_table('authors_songs_tmp', 'authors_songs')
177+ else:
178+ log.warning('Skipping upgrade_4 step of upgrading the song db')
179
180=== modified file 'tests/functional/openlp_core_ui/test_slidecontroller.py'
181--- tests/functional/openlp_core_ui/test_slidecontroller.py 2014-07-22 20:06:48 +0000
182+++ tests/functional/openlp_core_ui/test_slidecontroller.py 2014-11-25 22:34:10 +0000
183@@ -225,6 +225,10 @@
184 Registry().register('media_controller', mocked_media_controller)
185 slide_controller = SlideController(None)
186 slide_controller.display = mocked_display
187+ play_slides = MagicMock()
188+ play_slides.isChecked.return_value = False
189+ slide_controller.play_slides_loop = play_slides
190+ slide_controller.play_slides_once = play_slides
191
192 # WHEN: live_escape() is called
193 slide_controller.live_escape()
194
195=== modified file 'tests/functional/openlp_plugins/songs/test_db.py'
196--- tests/functional/openlp_plugins/songs/test_db.py 2014-07-17 21:16:00 +0000
197+++ tests/functional/openlp_plugins/songs/test_db.py 2014-11-25 22:34:10 +0000
198@@ -29,9 +29,15 @@
199 """
200 This module contains tests for the db submodule of the Songs plugin.
201 """
202+import os
203+import shutil
204 from unittest import TestCase
205+from tempfile import mkdtemp
206
207 from openlp.plugins.songs.lib.db import Song, Author, AuthorType
208+from openlp.plugins.songs.lib import upgrade
209+from openlp.core.lib.db import upgrade_db
210+from tests.utils.constants import TEST_RESOURCES_PATH
211
212
213 class TestDB(TestCase):
214@@ -39,6 +45,18 @@
215 Test the functions in the :mod:`db` module.
216 """
217
218+ def setUp(self):
219+ """
220+ Setup for tests
221+ """
222+ self.tmp_folder = mkdtemp()
223+
224+ def tearDown(self):
225+ """
226+ Clean up after tests
227+ """
228+ shutil.rmtree(self.tmp_folder)
229+
230 def test_add_author(self):
231 """
232 Test adding an author to a song
233@@ -153,3 +171,37 @@
234
235 # THEN: It should return the name with the type in brackets
236 self.assertEqual("John Doe (Words)", display_name)
237+
238+ def test_upgrade_old_song_db(self):
239+ """
240+ Test that we can upgrade an old song db to the current schema
241+ """
242+ # GIVEN: An old song db
243+ old_db_path = os.path.join(TEST_RESOURCES_PATH, "songs", 'songs-1.9.7.sqlite')
244+ old_db_tmp_path = os.path.join(self.tmp_folder, 'songs-1.9.7.sqlite')
245+ shutil.copyfile(old_db_path, old_db_tmp_path)
246+ db_url = 'sqlite:///' + old_db_tmp_path
247+
248+ # WHEN: upgrading the db
249+ updated_to_version, latest_version = upgrade_db(db_url, upgrade)
250+
251+ # Then the song db should have been upgraded to the latest version
252+ self.assertEqual(updated_to_version, latest_version,
253+ 'The song DB should have been upgrade to the latest version')
254+
255+ def test_upgrade_invalid_song_db(self):
256+ """
257+ Test that we can upgrade an invalid song db to the current schema
258+ """
259+ # GIVEN: A song db with invalid version
260+ invalid_db_path = os.path.join(TEST_RESOURCES_PATH, "songs", 'songs-2.2-invalid.sqlite')
261+ invalid_db_tmp_path = os.path.join(self.tmp_folder, 'songs-2.2-invalid.sqlite')
262+ shutil.copyfile(invalid_db_path, invalid_db_tmp_path)
263+ db_url = 'sqlite:///' + invalid_db_tmp_path
264+
265+ # WHEN: upgrading the db
266+ updated_to_version, latest_version = upgrade_db(db_url, upgrade)
267+
268+ # Then the song db should have been upgraded to the latest version without errors
269+ self.assertEqual(updated_to_version, latest_version,
270+ 'The song DB should have been upgrade to the latest version')
271
272=== added directory 'tests/resources/songs'
273=== added file 'tests/resources/songs/songs-1.9.7.sqlite'
274Binary files tests/resources/songs/songs-1.9.7.sqlite 1970-01-01 00:00:00 +0000 and tests/resources/songs/songs-1.9.7.sqlite 2014-11-25 22:34:10 +0000 differ
275=== added file 'tests/resources/songs/songs-2.2-invalid.sqlite'
276Binary files tests/resources/songs/songs-2.2-invalid.sqlite 1970-01-01 00:00:00 +0000 and tests/resources/songs/songs-2.2-invalid.sqlite 2014-11-25 22:34:10 +0000 differ