Allow authors to be tagged by their type (words music etc)

bzr-revno: 2371
This commit is contained in:
Samuel Mehrbrodt 2014-04-26 09:42:26 +01:00 committed by Tim Bentley
commit 20f748d608
18 changed files with 202 additions and 70 deletions

View File

@ -6,6 +6,8 @@
*.ropeproject
*.e4*
.eric4project
.komodotools
*.komodoproject
list
openlp.org 2.0.e4*
documentation/build/html

View File

@ -194,6 +194,7 @@ class Manager(object):
db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod)
except (SQLAlchemyError, DBAPIError):
log.exception('Error loading database: %s', self.db_url)
return
if db_ver > up_ver:
critical_error_message_box(
translate('OpenLP.Manager', 'Database Error'),
@ -215,7 +216,7 @@ class Manager(object):
Save an object to the database
:param object_instance: The object to save
:param commit: Commit the session with this object
:param commit: Commit the session with this object
"""
for try_count in range(3):
try:

View File

@ -114,10 +114,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
"""
Run the wizard.
"""
self.setDefaults()
self.set_defaults()
return QtGui.QWizard.exec_(self)
def setDefaults(self):
def set_defaults(self):
"""
Set up display at start of theme edit.
"""

View File

@ -90,7 +90,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard, RegistryProperties):
self.footer_font_combo_box.activated.connect(self.update_theme)
self.footer_size_spin_box.valueChanged.connect(self.update_theme)
def setDefaults(self):
def set_defaults(self):
"""
Set up display at start of theme edit.
"""
@ -261,7 +261,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard, RegistryProperties):
log.debug('Editing theme %s' % self.theme.theme_name)
self.temp_background_filename = ''
self.update_theme_allowed = False
self.setDefaults()
self.set_defaults()
self.update_theme_allowed = True
self.theme_name_label.setVisible(not edit)
self.theme_name_edit.setVisible(not edit)

View File

@ -197,7 +197,7 @@ class OpenLPWizard(QtGui.QWizard, RegistryProperties):
"""
Run the wizard.
"""
self.setDefaults()
self.set_defaults()
return QtGui.QWizard.exec_(self)
def reject(self):

View File

@ -465,7 +465,7 @@ class BibleImportForm(OpenLPWizard):
self.license_details_page.registerField('license_copyright', self.copyright_edit)
self.license_details_page.registerField('license_permissions', self.permissions_edit)
def setDefaults(self):
def set_defaults(self):
"""
Set default values for the wizard pages.
"""

View File

@ -307,7 +307,7 @@ class BibleUpgradeForm(OpenLPWizard):
if self.currentPage() == self.progress_page:
return True
def setDefaults(self):
def set_defaults(self):
"""
Set default values for the wizard pages.
"""

View File

@ -264,7 +264,7 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
self.break_search = True
self.plugin.media_item.on_search_text_button_clicked()
def setDefaults(self):
def set_defaults(self):
"""
Set default form values for the song import wizard.
"""

View File

@ -118,13 +118,18 @@ class Ui_EditSongDialog(object):
self.authors_group_box.setObjectName('authors_group_box')
self.authors_layout = QtGui.QVBoxLayout(self.authors_group_box)
self.authors_layout.setObjectName('authors_layout')
self.author_add_layout = QtGui.QHBoxLayout()
self.author_add_layout = QtGui.QVBoxLayout()
self.author_add_layout.setObjectName('author_add_layout')
self.author_type_layout = QtGui.QHBoxLayout()
self.author_type_layout.setObjectName('author_type_layout')
self.authors_combo_box = create_combo_box(self.authors_group_box, 'authors_combo_box')
self.author_add_layout.addWidget(self.authors_combo_box)
self.author_types_combo_box = create_combo_box(self.authors_group_box, 'author_types_combo_box', editable=False)
self.author_type_layout.addWidget(self.author_types_combo_box)
self.author_add_button = QtGui.QPushButton(self.authors_group_box)
self.author_add_button.setObjectName('author_add_button')
self.author_add_layout.addWidget(self.author_add_button)
self.author_type_layout.addWidget(self.author_add_button)
self.author_add_layout.addLayout(self.author_type_layout)
self.authors_layout.addLayout(self.author_add_layout)
self.authors_list_view = QtGui.QListWidget(self.authors_group_box)
self.authors_list_view.setAlternatingRowColors(True)
@ -330,7 +335,7 @@ class Ui_EditSongDialog(object):
translate('SongsPlugin.EditSongForm', '<strong>Warning:</strong> You have not entered a verse order.')
def create_combo_box(parent, name):
def create_combo_box(parent, name, editable=True):
"""
Utility method to generate a standard combo box for this dialog.
@ -340,7 +345,7 @@ def create_combo_box(parent, name):
combo_box = QtGui.QComboBox(parent)
combo_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToMinimumContentsLength)
combo_box.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
combo_box.setEditable(True)
combo_box.setEditable(editable)
combo_box.setInsertPolicy(QtGui.QComboBox.NoInsert)
combo_box.setObjectName(name)
return combo_box

View File

@ -42,7 +42,7 @@ from openlp.core.common import Registry, RegistryProperties, AppLocation, UiStri
from openlp.core.lib import FileDialog, PluginStatus, MediaType, create_separated_list
from openlp.core.lib.ui import set_case_insensitive_completer, critical_error_message_box, find_and_set_in_combo_box
from openlp.plugins.songs.lib import VerseType, clean_song
from openlp.plugins.songs.lib.db import Book, Song, Author, Topic, MediaFile
from openlp.plugins.songs.lib.db import Book, Song, Author, AuthorSong, AuthorType, Topic, MediaFile
from openlp.plugins.songs.lib.ui import SongStrings
from openlp.plugins.songs.lib.xml import SongXML
from openlp.plugins.songs.forms.editsongdialog import Ui_EditSongDialog
@ -122,12 +122,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
combo.setItemData(row, obj.id)
set_case_insensitive_completer(cache, combo)
def _add_author_to_list(self, author):
def _add_author_to_list(self, author, author_type):
"""
Add an author to the author list.
"""
author_item = QtGui.QListWidgetItem(str(author.display_name))
author_item.setData(QtCore.Qt.UserRole, author.id)
author_item = QtGui.QListWidgetItem(author.get_display_name(author_type))
author_item.setData(QtCore.Qt.UserRole, (author.id, author_type))
self.authors_list_view.addItem(author_item)
def _extract_verse_order(self, verse_order):
@ -217,8 +217,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
if self.authors_list_view.count() == 0:
self.song_tab_widget.setCurrentIndex(1)
self.authors_list_view.setFocus()
critical_error_message_box(
message=translate('SongsPlugin.EditSongForm', 'You need to have an author for this song.'))
critical_error_message_box(message=translate('SongsPlugin.EditSongForm',
'You need to have an author for this song.'))
return False
if self.verse_order_edit.text():
result = self._validate_verse_list(self.verse_order_edit.text(), self.verse_list_widget.rowCount())
@ -302,6 +302,15 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
self.authors.append(author.display_name)
set_case_insensitive_completer(self.authors, self.authors_combo_box)
# Types
self.author_types_combo_box.clear()
self.author_types_combo_box.addItem('')
# Don't iterate over the dictionary to give them this specific order
self.author_types_combo_box.addItem(AuthorType.Types[AuthorType.Words], AuthorType.Words)
self.author_types_combo_box.addItem(AuthorType.Types[AuthorType.Music], AuthorType.Music)
self.author_types_combo_box.addItem(AuthorType.Types[AuthorType.WordsAndMusic], AuthorType.WordsAndMusic)
self.author_types_combo_box.addItem(AuthorType.Types[AuthorType.Translation], AuthorType.Translation)
def load_topics(self):
"""
Load the topics into the combobox.
@ -454,10 +463,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
self.tag_rows()
# clear the results
self.authors_list_view.clear()
for author in self.song.authors:
author_name = QtGui.QListWidgetItem(str(author.display_name))
author_name.setData(QtCore.Qt.UserRole, author.id)
self.authors_list_view.addItem(author_name)
for author_song in self.song.authors_songs:
self._add_author_to_list(author_song.author, author_song.author_type)
# clear the results
self.topics_list_view.clear()
for topic in self.song.topics:
@ -496,6 +503,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
"""
item = int(self.authors_combo_box.currentIndex())
text = self.authors_combo_box.currentText().strip(' \r\n\t')
author_type = self.author_types_combo_box.itemData(self.author_types_combo_box.currentIndex())
# This if statement is for OS X, which doesn't seem to work well with
# the QCompleter auto-completion class. See bug #812628.
if text in self.authors:
@ -513,7 +521,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
author = Author.populate(first_name=text.rsplit(' ', 1)[0], last_name=text.rsplit(' ', 1)[1],
display_name=text)
self.manager.save_object(author)
self._add_author_to_list(author)
self._add_author_to_list(author, author_type)
self.load_authors()
self.authors_combo_box.setCurrentIndex(0)
else:
@ -521,11 +529,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
elif item > 0:
item_id = (self.authors_combo_box.itemData(item))
author = self.manager.get_object(Author, item_id)
if self.authors_list_view.findItems(str(author.display_name), QtCore.Qt.MatchExactly):
if self.authors_list_view.findItems(author.get_display_name(author_type), QtCore.Qt.MatchExactly):
critical_error_message_box(
message=translate('SongsPlugin.EditSongForm', 'This author is already in the list.'))
else:
self._add_author_to_list(author)
self._add_author_to_list(author, author_type)
self.authors_combo_box.setCurrentIndex(0)
else:
QtGui.QMessageBox.warning(
@ -905,13 +913,13 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
else:
self.song.theme_name = None
self._process_lyrics()
self.song.authors = []
self.song.authors_songs = []
for row in range(self.authors_list_view.count()):
item = self.authors_list_view.item(row)
author_id = (item.data(QtCore.Qt.UserRole))
author = self.manager.get_object(Author, author_id)
if author is not None:
self.song.authors.append(author)
author_song = AuthorSong()
author_song.author_id = item.data(QtCore.Qt.UserRole)[0]
author_song.author_type = item.data(QtCore.Qt.UserRole)[1]
self.song.authors_songs.append(author_song)
self.song.topics = []
for row in range(self.topics_list_view.count()):
item = self.topics_list_view.item(row)

View File

@ -304,7 +304,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
"""
self.source_page.emit(QtCore.SIGNAL('completeChanged()'))
def setDefaults(self):
def set_defaults(self):
"""
Set default form values for the song import wizard.
"""

View File

@ -390,7 +390,7 @@ def clean_song(manager, song):
verses = SongXML().get_verses(song.lyrics)
song.search_lyrics = ' '.join([clean_string(verse[1]) for verse in verses])
# The song does not have any author, add one.
if not song.authors:
if not song.authors and not song.authors_songs: # Need to check both relations
name = SongStrings.AuthorUnknown
author = manager.get_object_filtered(Author, Author.display_name == name)
if author is None:

View File

@ -35,19 +35,52 @@ import re
from sqlalchemy import Column, ForeignKey, Table, types
from sqlalchemy.orm import mapper, relation, reconstructor
from sqlalchemy.sql.expression import func
from sqlalchemy.sql.expression import func, text
from openlp.core.lib.db import BaseModel, init_db
from openlp.core.utils import get_natural_key
from openlp.core.lib import translate
class Author(BaseModel):
"""
Author model
"""
def get_display_name(self, author_type=None):
if author_type:
return "%s (%s)" % (self.display_name, AuthorType.Types[author_type])
return self.display_name
class AuthorSong(BaseModel):
"""
Relationship between Authors and Songs (many to many).
Need to define this relationship table explicit to get access to the
Association Object (author_type).
http://docs.sqlalchemy.org/en/latest/orm/relationships.html#association-object
"""
pass
class AuthorType(object):
"""
Enumeration for Author types.
They are defined by OpenLyrics: http://openlyrics.info/dataformat.html#authors
The 'words+music' type is not an official type, but is provided for convenience.
"""
Words = 'words'
Music = 'music'
WordsAndMusic = 'words+music'
Translation = 'translation'
Types = {
Words: translate('OpenLP.Ui', 'Words'),
Music: translate('OpenLP.Ui', 'Music'),
WordsAndMusic: translate('OpenLP.Ui', 'Words and Music'),
Translation: translate('OpenLP.Ui', 'Translation')
}
class Book(BaseModel):
"""
Book model
@ -67,6 +100,7 @@ class Song(BaseModel):
"""
Song model
"""
def __init__(self):
self.sort_key = []
@ -120,6 +154,7 @@ def init_schema(url):
* author_id
* song_id
* author_type
**media_files Table**
* id
@ -230,7 +265,8 @@ def init_schema(url):
authors_songs_table = Table(
'authors_songs', metadata,
Column('author_id', types.Integer(), ForeignKey('authors.id'), primary_key=True),
Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True)
Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True),
Column('author_type', types.String(), primary_key=True, nullable=False, server_default=text('""'))
)
# Definition of the "songs_topics" table
@ -241,10 +277,15 @@ def init_schema(url):
)
mapper(Author, authors_table)
mapper(AuthorSong, authors_songs_table, properties={
'author': relation(Author)
})
mapper(Book, song_books_table)
mapper(MediaFile, media_files_table)
mapper(Song, songs_table, properties={
'authors': relation(Author, backref='songs', secondary=authors_songs_table, lazy=False),
# Use the authors_songs relation when you need access to the 'author_type' attribute.
'authors_songs': relation(AuthorSong, cascade="all, delete-orphan"),
'authors': relation(Author, secondary=authors_songs_table),
'book': relation(Book, backref='songs'),
'media_files': relation(MediaFile, backref='songs', order_by=media_files_table.c.weight),
'topics': relation(Topic, backref='songs', secondary=songs_topics_table)

View File

@ -44,7 +44,7 @@ from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
from openlp.plugins.songs.forms.songimportform import SongImportForm
from openlp.plugins.songs.forms.songexportform import SongExportForm
from openlp.plugins.songs.lib import VerseType, clean_string, delete_song
from openlp.plugins.songs.lib.db import Author, Song, Book, MediaFile
from openlp.plugins.songs.lib.db import Author, AuthorType, Song, Book, MediaFile
from openlp.plugins.songs.lib.ui import SongStrings
from openlp.plugins.songs.lib.xml import OpenLyrics, SongXML
@ -234,8 +234,7 @@ class SongMediaItem(MediaManagerItem):
if song.temporary:
continue
author_list = [author.display_name for author in song.authors]
song_title = str(song.title)
song_detail = '%s (%s)' % (song_title, create_separated_list(author_list))
song_detail = '%s (%s)' % (song.title, create_separated_list(author_list)) if author_list else song.title
song_name = QtGui.QListWidgetItem(song_detail)
song_name.setData(QtCore.Qt.UserRole, song.id)
self.list_view.addItem(song_name)
@ -464,23 +463,53 @@ class SongMediaItem(MediaManagerItem):
def generate_footer(self, item, song):
"""
Generates the song footer based on a song and adds details to a service item.
author_list is only required for initial song generation.
:param item: The service item to be amended
:param song: The song to be used to generate the footer
:return: List of all authors (only required for initial song generation)
"""
author_list = [str(author.display_name) for author in song.authors]
authors_words = []
authors_music = []
authors_words_music = []
authors_translation = []
authors_none = []
for author_song in song.authors_songs:
if author_song.author_type == AuthorType.Words:
authors_words.append(author_song.author.display_name)
elif author_song.author_type == AuthorType.Music:
authors_music.append(author_song.author.display_name)
elif author_song.author_type == AuthorType.WordsAndMusic:
authors_words_music.append(author_song.author.display_name)
elif author_song.author_type == AuthorType.Translation:
authors_translation.append(author_song.author.display_name)
else:
authors_none.append(author_song.author.display_name)
authors_all = authors_words_music + authors_words + authors_music + authors_translation + authors_none
item.audit = [
song.title, author_list, song.copyright, str(song.ccli_number)
song.title, authors_all, song.copyright, str(song.ccli_number)
]
item.raw_footer = []
item.raw_footer.append(song.title)
item.raw_footer.append(create_separated_list(author_list))
if authors_none:
item.raw_footer.append("%s: %s" % (translate('OpenLP.Ui', 'Written by'),
create_separated_list(authors_none)))
if authors_words_music:
item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.WordsAndMusic],
create_separated_list(authors_words_music)))
if authors_words:
item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Words],
create_separated_list(authors_words)))
if authors_music:
item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Music],
create_separated_list(authors_music)))
if authors_translation:
item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Translation],
create_separated_list(authors_translation)))
item.raw_footer.append(song.copyright)
if Settings().value('core/ccli number'):
item.raw_footer.append(translate('SongsPlugin.MediaItem',
'CCLI License: ') + Settings().value('core/ccli number'))
return author_list
return authors_all
def service_load(self, item):
"""

View File

@ -40,7 +40,7 @@ class SongStrings(object):
# These strings should need a good reason to be retranslated elsewhere.
Author = translate('OpenLP.Ui', 'Author', 'Singular')
Authors = translate('OpenLP.Ui', 'Authors', 'Plural')
AuthorUnknown = 'Author Unknown' # Used to populate the database.
AuthorUnknown = translate('OpenLP.Ui', 'Author Unknown') # Used to populate the database.
CopyrightSymbol = translate('OpenLP.Ui', '\xa9', 'Copyright symbol.')
SongBook = translate('OpenLP.Ui', 'Song Book', 'Singular')
SongBooks = translate('OpenLP.Ui', 'Song Books', 'Plural')

View File

@ -32,14 +32,14 @@ backend for the Songs plugin
"""
import logging
from sqlalchemy import Column, types
from sqlalchemy import Column, ForeignKey, types
from sqlalchemy.exc import OperationalError
from sqlalchemy.sql.expression import func, false, null, text
from openlp.core.lib.db import get_upgrade_op
log = logging.getLogger(__name__)
__version__ = 3
__version__ = 4
def upgrade_1(session, metadata):
@ -97,3 +97,25 @@ def upgrade_3(session, metadata):
op.add_column('songs', Column('temporary', types.Boolean(), server_default=false()))
except OperationalError:
log.info('Upgrade 3 has already been run')
def upgrade_4(session, metadata):
"""
Version 4 upgrade.
This upgrade adds a column for author type to the authors_songs table
"""
try:
# Since SQLite doesn't support changing the primary key of a table, we need to recreate the table
# and copy the old values
op = get_upgrade_op(session)
op.create_table('authors_songs_tmp',
Column('author_id', types.Integer(), ForeignKey('authors.id'), primary_key=True),
Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True),
Column('author_type', types.String(), primary_key=True,
nullable=False, server_default=text('""')))
op.execute('INSERT INTO authors_songs_tmp SELECT author_id, song_id, "" FROM authors_songs')
op.drop_table('authors_songs')
op.rename_table('authors_songs_tmp', 'authors_songs')
except OperationalError:
log.info('Upgrade 4 has already been run')

View File

@ -71,7 +71,7 @@ from lxml import etree, objectify
from openlp.core.common import translate
from openlp.core.lib import FormattingTags
from openlp.plugins.songs.lib import VerseType, clean_song
from openlp.plugins.songs.lib.db import Author, Book, Song, Topic
from openlp.plugins.songs.lib.db import Author, AuthorSong, AuthorType, Book, Song, Topic
from openlp.core.utils import get_application_version
log = logging.getLogger(__name__)
@ -166,7 +166,7 @@ class OpenLyrics(object):
supported by the :class:`OpenLyrics` class:
``<authors>``
OpenLP does not support the attribute *type* and *lang*.
OpenLP does not support the attribute *lang*.
``<chord>``
This property is not supported.
@ -269,10 +269,18 @@ class OpenLyrics(object):
'verseOrder', properties, song.verse_order.lower())
if song.ccli_number:
self._add_text_to_element('ccliNo', properties, song.ccli_number)
if song.authors:
if song.authors_songs:
authors = etree.SubElement(properties, 'authors')
for author in song.authors:
self._add_text_to_element('author', authors, author.display_name)
for author_song in song.authors_songs:
element = self._add_text_to_element('author', authors, author_song.author.display_name)
if author_song.author_type:
# Handle the special case 'words+music': Need to create two separate authors for that
if author_song.author_type == AuthorType.WordsAndMusic:
element.set('type', AuthorType.Words)
element = self._add_text_to_element('author', authors, author_song.author.display_name)
element.set('type', AuthorType.Music)
else:
element.set('type', author_song.author_type)
book = self.manager.get_object_filtered(Book, Book.id == song.song_book_id)
if book is not None:
book = book.name
@ -501,16 +509,20 @@ class OpenLyrics(object):
if hasattr(properties, 'authors'):
for author in properties.authors.author:
display_name = self._text(author)
author_type = author.get('type', '')
if display_name:
authors.append(display_name)
for display_name in authors:
authors.append((display_name, author_type))
for (display_name, author_type) in authors:
author = self.manager.get_object_filtered(Author, Author.display_name == display_name)
if author is None:
# We need to create a new author, as the author does not exist.
author = Author.populate(display_name=display_name,
last_name=display_name.split(' ')[-1],
first_name=' '.join(display_name.split(' ')[:-1]))
song.authors.append(author)
author_song = AuthorSong()
author_song.author = author
author_song.author_type = author_type
song.authors_songs.append(author_song)
def _process_cclinumber(self, properties, song):
"""

View File

@ -10,6 +10,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.common import Registry, Settings
from openlp.core.lib import ServiceItem
from openlp.plugins.songs.lib.mediaitem import SongMediaItem
from openlp.plugins.songs.lib.db import AuthorType
from tests.functional import patch, MagicMock
from tests.helpers.testmixin import TestMixin
@ -45,10 +46,12 @@ class TestMediaItem(TestCase, TestMixin):
# GIVEN: A Song and a Service Item
mock_song = MagicMock()
mock_song.title = 'My Song'
mock_song.authors_songs = []
mock_author = MagicMock()
mock_author.display_name = 'my author'
mock_song.authors = []
mock_song.authors.append(mock_author)
mock_author_song = MagicMock()
mock_author_song.author = mock_author
mock_song.authors_songs.append(mock_author_song)
mock_song.copyright = 'My copyright'
service_item = ServiceItem(None)
@ -56,7 +59,7 @@ class TestMediaItem(TestCase, TestMixin):
author_list = self.media_item.generate_footer(service_item, mock_song)
# THEN: I get the following Array returned
self.assertEqual(service_item.raw_footer, ['My Song', 'my author', 'My copyright'],
self.assertEqual(service_item.raw_footer, ['My Song', 'Written by: my author', 'My copyright'],
'The array should be returned correctly with a song, one author and copyright')
self.assertEqual(author_list, ['my author'],
'The author list should be returned correctly with one author')
@ -68,13 +71,25 @@ class TestMediaItem(TestCase, TestMixin):
# GIVEN: A Song and a Service Item
mock_song = MagicMock()
mock_song.title = 'My Song'
mock_song.authors_songs = []
mock_author = MagicMock()
mock_author.display_name = 'my author'
mock_song.authors = []
mock_song.authors.append(mock_author)
mock_author_song = MagicMock()
mock_author_song.author = mock_author
mock_author_song.author_type = AuthorType.Music
mock_song.authors_songs.append(mock_author_song)
mock_author = MagicMock()
mock_author.display_name = 'another author'
mock_song.authors.append(mock_author)
mock_author_song = MagicMock()
mock_author_song.author = mock_author
mock_author_song.author_type = AuthorType.Words
mock_song.authors_songs.append(mock_author_song)
mock_author = MagicMock()
mock_author.display_name = 'translator'
mock_author_song = MagicMock()
mock_author_song.author = mock_author
mock_author_song.author_type = AuthorType.Translation
mock_song.authors_songs.append(mock_author_song)
mock_song.copyright = 'My copyright'
service_item = ServiceItem(None)
@ -82,22 +97,19 @@ class TestMediaItem(TestCase, TestMixin):
author_list = self.media_item.generate_footer(service_item, mock_song)
# THEN: I get the following Array returned
self.assertEqual(service_item.raw_footer, ['My Song', 'my author and another author', 'My copyright'],
self.assertEqual(service_item.raw_footer, ['My Song', 'Words: another author', 'Music: my author',
'Translation: translator', 'My copyright'],
'The array should be returned correctly with a song, two authors and copyright')
self.assertEqual(author_list, ['my author', 'another author'],
self.assertEqual(author_list, ['another author', 'my author', 'translator'],
'The author list should be returned correctly with two authors')
def build_song_footer_base_ccli_test(self):
"""
Test build songs footer with basic song and two authors
Test build songs footer with basic song and a CCLI number
"""
# GIVEN: A Song and a Service Item and a configured CCLI license
mock_song = MagicMock()
mock_song.title = 'My Song'
mock_author = MagicMock()
mock_author.display_name = 'my author'
mock_song.authors = []
mock_song.authors.append(mock_author)
mock_song.copyright = 'My copyright'
service_item = ServiceItem(None)
Settings().setValue('core/ccli number', '1234')
@ -106,7 +118,7 @@ class TestMediaItem(TestCase, TestMixin):
self.media_item.generate_footer(service_item, mock_song)
# THEN: I get the following Array returned
self.assertEqual(service_item.raw_footer, ['My Song', 'my author', 'My copyright', 'CCLI License: 1234'],
self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'CCLI License: 1234'],
'The array should be returned correctly with a song, an author, copyright and ccli')
# WHEN: I amend the CCLI value
@ -114,5 +126,5 @@ class TestMediaItem(TestCase, TestMixin):
self.media_item.generate_footer(service_item, mock_song)
# THEN: I would get an amended footer string
self.assertEqual(service_item.raw_footer, ['My Song', 'my author', 'My copyright', 'CCLI License: 4321'],
self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'CCLI License: 4321'],
'The array should be returned correctly with a song, an author, copyright and amended ccli')