diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 77f19737d..935b94bb9 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -60,6 +60,35 @@ def init_db(url, auto_flush=True, auto_commit=False, base=None): return session, metadata +def get_db_path(plugin_name, db_file_name=None): + """ + Create a path to a database from the plugin name and database name + + :param plugin_name: Name of plugin + :param db_file_name: File name of database + :return: The path to the database as type str + """ + if db_file_name is None: + return 'sqlite:///%s/%s.sqlite' % (AppLocation.get_section_data_path(plugin_name), plugin_name) + else: + return 'sqlite:///%s/%s' % (AppLocation.get_section_data_path(plugin_name), db_file_name) + + +def handle_db_error(plugin_name, db_file_name): + """ + Log and report to the user that a database cannot be loaded + + :param plugin_name: Name of plugin + :param db_file_name: File name of database + :return: None + """ + db_path = get_db_path(plugin_name, db_file_name) + log.exception('Error loading database: %s', db_path) + critical_error_message_box(translate('OpenLP.Manager', 'Database Error'), + translate('OpenLP.Manager', 'OpenLP cannot load your database.\n\nDatabase: %s') + % db_path) + + def init_url(plugin_name, db_file_name=None): """ Return the database URL. @@ -69,13 +98,9 @@ def init_url(plugin_name, db_file_name=None): """ settings = Settings() settings.beginGroup(plugin_name) - db_url = '' db_type = settings.value('db type') if db_type == 'sqlite': - if db_file_name is None: - db_url = 'sqlite:///%s/%s.sqlite' % (AppLocation.get_section_data_path(plugin_name), plugin_name) - else: - db_url = 'sqlite:///%s/%s' % (AppLocation.get_section_data_path(plugin_name), db_file_name) + db_url = get_db_path(plugin_name, db_file_name) else: db_url = '%s://%s:%s@%s/%s' % (db_type, urlquote(settings.value('db username')), urlquote(settings.value('db password')), @@ -212,7 +237,7 @@ class Manager(object): try: db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) except (SQLAlchemyError, DBAPIError): - log.exception('Error loading database: %s', self.db_url) + handle_db_error(plugin_name, db_file_name) return if db_ver > up_ver: critical_error_message_box( @@ -225,10 +250,7 @@ class Manager(object): try: self.session = init_schema(self.db_url) except (SQLAlchemyError, DBAPIError): - log.exception('Error loading database: %s', self.db_url) - critical_error_message_box(translate('OpenLP.Manager', 'Database Error'), - translate('OpenLP.Manager', 'OpenLP cannot load your database.\n\nDatabase: %s') - % self.db_url) + handle_db_error(plugin_name, db_file_name) def save_object(self, object_instance, commit=True): """ @@ -362,6 +384,8 @@ class Manager(object): :param object_class: The type of objects to return. :param filter_clause: The filter governing selection of objects to return. Defaults to None. """ + if not self.session: + return query = self.session.query(object_class) if filter_clause is not None: query = query.filter(filter_clause) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index 9c3b7bf09..914b9e512 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -22,6 +22,7 @@ """ This module contains the first time wizard. """ +import hashlib import logging import os import time @@ -221,8 +222,9 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): self.application.process_events() title = self.config.get('songs_%s' % song, 'title') filename = self.config.get('songs_%s' % song, 'filename') + sha256 = self.config.get('songs_%s' % song, 'sha256', fallback=None) item = QtGui.QListWidgetItem(title, self.songs_list_widget) - item.setData(QtCore.Qt.UserRole, filename) + item.setData(QtCore.Qt.UserRole, (filename, sha256)) item.setCheckState(QtCore.Qt.Unchecked) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) bible_languages = self.config.get('bibles', 'languages') @@ -372,7 +374,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): Settings().setValue('core/has run wizard', True) self.close() - def url_get_file(self, url, f_path): + def url_get_file(self, url, f_path, sha256=None): """" Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any point. Returns False on download error. @@ -396,7 +398,11 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): block_count += 1 self._download_progress(block_count, block_size) filename.close() - except ConnectionError: + if sha256 and hashlib.sha256(open(f_path, 'rb').read()).hexdigest() != sha256: + log.error('sha256 sums did not match for file: {}'.format(f_path)) + os.remove(f_path) + return False + except urllib.error.URLError: trace_error_handler(log) filename.close() os.remove(f_path) @@ -436,7 +442,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) meta = site.info() return int(meta.get("Content-Length")) - except ConnectionException: + except urllib.error.URLError: if retries > CONNECTION_RETRIES: raise else: @@ -478,7 +484,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): self.application.process_events() item = self.songs_list_widget.item(i) if item.checkState() == QtCore.Qt.Checked: - filename = item.data(QtCore.Qt.UserRole) + filename, _ = item.data(QtCore.Qt.UserRole) size = self._get_file_size('%s%s' % (self.songs_url, filename)) self.max_progress += size # Loop through the Bibles list and increase for each selected item @@ -499,7 +505,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): filename = item.data(QtCore.Qt.UserRole) size = self._get_file_size('%s%s' % (self.themes_url, filename)) self.max_progress += size - except ConnectionError: + except urllib.error.URLError: trace_error_handler(log) critical_error_message_box(translate('OpenLP.FirstTimeWizard', 'Download Error'), translate('OpenLP.FirstTimeWizard', 'There was a connection problem during ' @@ -595,11 +601,11 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): for i in range(self.songs_list_widget.count()): item = self.songs_list_widget.item(i) if item.checkState() == QtCore.Qt.Checked: - filename = item.data(QtCore.Qt.UserRole) + filename, sha256 = item.data(QtCore.Qt.UserRole) self._increment_progress_bar(self.downloading % filename, 0) self.previous_size = 0 destination = os.path.join(songs_destination, str(filename)) - if not self.url_get_file('%s%s' % (self.songs_url, filename), destination): + if not self.url_get_file('%s%s' % (self.songs_url, filename), destination, sha256): return False # Download Bibles bibles_iterator = QtGui.QTreeWidgetItemIterator(self.bibles_tree_widget) diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 2c14f3f9f..dabdd71e4 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -144,8 +144,9 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties): if 'file' in kwargs: self.file = kwargs['file'] Manager.__init__(self, 'bibles', init_schema, self.file, upgrade) - if 'file' in kwargs: - self.get_name() + if self.session: + if 'file' in kwargs: + self.get_name() if 'path' in kwargs: self.path = kwargs['path'] self.wizard = None diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 8ad06632c..742671ac1 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -121,6 +121,8 @@ class BibleManager(RegistryProperties): self.old_bible_databases = [] for filename in files: bible = BibleDB(self.parent, path=self.path, file=filename) + if not bible.session: + continue name = bible.get_name() # Remove corrupted files. if name is None: