diff --git a/cps/admin.py b/cps/admin.py index 84a94cba..d2e3bd87 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -34,7 +34,7 @@ from flask import Blueprint, flash, redirect, url_for, abort, request, make_resp from flask_login import login_required, current_user, logout_user from flask_babel import gettext as _ from sqlalchemy import and_ -from sqlalchemy.exc import IntegrityError +from sqlalchemy.exc import IntegrityError, OperationalError, InvalidRequestError from sqlalchemy.sql.expression import func from . import constants, logger, helper, services @@ -615,78 +615,83 @@ def _configuration_update_helper(): to_save = request.form.to_dict() to_save['config_calibre_dir'] = re.sub('[\\/]metadata\.db$', '', to_save['config_calibre_dir'], flags=re.IGNORECASE) - db_change |= _config_string(to_save, "config_calibre_dir") + try: + db_change |= _config_string(to_save, "config_calibre_dir") + + # Google drive setup + gdriveError = _configuration_gdrive_helper(to_save) + + reboot_required |= _config_int(to_save, "config_port") + + reboot_required |= _config_string(to_save, "config_keyfile") + if config.config_keyfile and not os.path.isfile(config.config_keyfile): + return _configuration_result(_('Keyfile Location is not Valid, Please Enter Correct Path'), gdriveError) + + reboot_required |= _config_string(to_save, "config_certfile") + if config.config_certfile and not os.path.isfile(config.config_certfile): + return _configuration_result(_('Certfile Location is not Valid, Please Enter Correct Path'), gdriveError) + + _config_checkbox_int(to_save, "config_uploading") + _config_checkbox_int(to_save, "config_anonbrowse") + _config_checkbox_int(to_save, "config_public_reg") + _config_checkbox_int(to_save, "config_register_email") + reboot_required |= _config_checkbox_int(to_save, "config_kobo_sync") + _config_checkbox_int(to_save, "config_kobo_proxy") + + _config_string(to_save, "config_upload_formats") + constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip() for x in config.config_upload_formats.split(',')] + + _config_string(to_save, "config_calibre") + _config_string(to_save, "config_converterpath") + _config_string(to_save, "config_kepubifypath") - # Google drive setup - gdriveError = _configuration_gdrive_helper(to_save) + reboot_required |= _config_int(to_save, "config_login_type") - reboot_required |= _config_int(to_save, "config_port") + #LDAP configurator, + if config.config_login_type == constants.LOGIN_LDAP: + reboot, message = _configuration_ldap_helper(to_save, gdriveError) + if message: + return message + reboot_required |= reboot - reboot_required |= _config_string(to_save, "config_keyfile") - if config.config_keyfile and not os.path.isfile(config.config_keyfile): - return _configuration_result(_('Keyfile Location is not Valid, Please Enter Correct Path'), gdriveError) + # Remote login configuration - reboot_required |= _config_string(to_save, "config_certfile") - if config.config_certfile and not os.path.isfile(config.config_certfile): - return _configuration_result(_('Certfile Location is not Valid, Please Enter Correct Path'), gdriveError) + _config_checkbox(to_save, "config_remote_login") + if not config.config_remote_login: + ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.token_type==0).delete() - _config_checkbox_int(to_save, "config_uploading") - _config_checkbox_int(to_save, "config_anonbrowse") - _config_checkbox_int(to_save, "config_public_reg") - _config_checkbox_int(to_save, "config_register_email") - reboot_required |= _config_checkbox_int(to_save, "config_kobo_sync") - _config_checkbox_int(to_save, "config_kobo_proxy") + # Goodreads configuration + _config_checkbox(to_save, "config_use_goodreads") + _config_string(to_save, "config_goodreads_api_key") + _config_string(to_save, "config_goodreads_api_secret") + if services.goodreads_support: + services.goodreads_support.connect(config.config_goodreads_api_key, + config.config_goodreads_api_secret, + config.config_use_goodreads) - _config_string(to_save, "config_upload_formats") - constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip() for x in config.config_upload_formats.split(',')] + _config_int(to_save, "config_updatechannel") - _config_string(to_save, "config_calibre") - _config_string(to_save, "config_converterpath") - _config_string(to_save, "config_kepubifypath") + # Reverse proxy login configuration + _config_checkbox(to_save, "config_allow_reverse_proxy_header_login") + _config_string(to_save, "config_reverse_proxy_login_header_name") - reboot_required |= _config_int(to_save, "config_login_type") + # OAuth configuration + if config.config_login_type == constants.LOGIN_OAUTH: + reboot_required |= _configuration_oauth_helper(to_save) - #LDAP configurator, - if config.config_login_type == constants.LOGIN_LDAP: - reboot, message = _configuration_ldap_helper(to_save, gdriveError) + reboot, message = _configuration_logfile_helper(to_save, gdriveError) if message: return message reboot_required |= reboot - - # Remote login configuration - _config_checkbox(to_save, "config_remote_login") - if not config.config_remote_login: - ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.token_type==0).delete() - - # Goodreads configuration - _config_checkbox(to_save, "config_use_goodreads") - _config_string(to_save, "config_goodreads_api_key") - _config_string(to_save, "config_goodreads_api_secret") - if services.goodreads_support: - services.goodreads_support.connect(config.config_goodreads_api_key, - config.config_goodreads_api_secret, - config.config_use_goodreads) - - _config_int(to_save, "config_updatechannel") - - # Reverse proxy login configuration - _config_checkbox(to_save, "config_allow_reverse_proxy_header_login") - _config_string(to_save, "config_reverse_proxy_login_header_name") - - # OAuth configuration - if config.config_login_type == constants.LOGIN_OAUTH: - reboot_required |= _configuration_oauth_helper(to_save) - - reboot, message = _configuration_logfile_helper(to_save, gdriveError) - if message: - return message - reboot_required |= reboot - # Rarfile Content configuration - _config_string(to_save, "config_rarfile_location") - if "config_rarfile_location" in to_save: - unrar_status = helper.check_unrar(config.config_rarfile_location) - if unrar_status: - return _configuration_result(unrar_status, gdriveError) + # Rarfile Content configuration + _config_string(to_save, "config_rarfile_location") + if "config_rarfile_location" in to_save: + unrar_status = helper.check_unrar(config.config_rarfile_location) + if unrar_status: + return _configuration_result(unrar_status, gdriveError) + except (OperationalError, InvalidRequestError): + ub.session.rollback() + _configuration_result(_(u"Settings DB is not Writeable"), gdriveError) try: metadata_db = os.path.join(config.config_calibre_dir, "metadata.db") @@ -783,6 +788,9 @@ def _handle_new_user(to_save, content,languages, translations, kobo_support): except IntegrityError: ub.session.rollback() flash(_(u"Found an existing account for this e-mail address or nickname."), category="error") + except OperationalError: + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") def _handle_edit_user(to_save, content,languages, translations, kobo_support, downloads): @@ -872,6 +880,9 @@ def _handle_edit_user(to_save, content,languages, translations, kobo_support, do except IntegrityError: ub.session.rollback() flash(_(u"An unknown error occured."), category="error") + except OperationalError: + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") @admi.route("/admin/user/new", methods=["GET", "POST"]) @@ -916,7 +927,12 @@ def update_mailsettings(): _config_string(to_save, "mail_password") _config_string(to_save, "mail_from") _config_int(to_save, "mail_size", lambda y: int(y)*1024*1024) - config.save() + try: + config.save() + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") + return edit_mailsettings() if to_save.get("test"): if current_user.email: diff --git a/cps/services/simpleldap.py b/cps/services/simpleldap.py index b6fd0ac2..0933a933 100644 --- a/cps/services/simpleldap.py +++ b/cps/services/simpleldap.py @@ -64,7 +64,6 @@ def init_app(app, config): app.config['LDAP_OPENLDAP'] = bool(config.config_ldap_openldap) app.config['LDAP_GROUP_OBJECT_FILTER'] = config.config_ldap_group_object_filter app.config['LDAP_GROUP_MEMBERS_FIELD'] = config.config_ldap_group_members_field - # app.config['LDAP_CUSTOM_OPTIONS'] = {'OPT_NETWORK_TIMEOUT': 10} _ldap.init_app(app) diff --git a/cps/shelf.py b/cps/shelf.py index 30768930..37cfc02a 100644 --- a/cps/shelf.py +++ b/cps/shelf.py @@ -27,8 +27,9 @@ from flask import Blueprint, request, flash, redirect, url_for from flask_babel import gettext as _ from flask_login import login_required, current_user from sqlalchemy.sql.expression import func +from sqlalchemy.exc import OperationalError, InvalidRequestError -from . import logger, ub, searched_ids, db, calibre_db +from . import logger, ub, searched_ids, calibre_db from .web import render_title_template @@ -91,8 +92,16 @@ def add_to_shelf(shelf_id, book_id): shelf.books.append(ub.BookShelf(shelf=shelf.id, book_id=book_id, order=maxOrder + 1)) shelf.last_modified = datetime.utcnow() - ub.session.merge(shelf) - ub.session.commit() + try: + ub.session.merge(shelf) + ub.session.commit() + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") + if "HTTP_REFERER" in request.environ: + return redirect(request.environ["HTTP_REFERER"]) + else: + return redirect(url_for('web.index')) if not xhr: flash(_(u"Book has been added to shelf: %(sname)s", sname=shelf.name), category="success") if "HTTP_REFERER" in request.environ: @@ -143,9 +152,13 @@ def search_to_shelf(shelf_id): maxOrder = maxOrder + 1 shelf.books.append(ub.BookShelf(shelf=shelf.id, book_id=book, order=maxOrder)) shelf.last_modified = datetime.utcnow() - ub.session.merge(shelf) - ub.session.commit() - flash(_(u"Books have been added to shelf: %(sname)s", sname=shelf.name), category="success") + try: + ub.session.merge(shelf) + ub.session.commit() + flash(_(u"Books have been added to shelf: %(sname)s", sname=shelf.name), category="success") + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") else: flash(_(u"Could not add books to shelf: %(sname)s", sname=shelf.name), category="error") return redirect(url_for('web.index')) @@ -180,10 +193,17 @@ def remove_from_shelf(shelf_id, book_id): return redirect(url_for('web.index')) return "Book already removed from shelf", 410 - ub.session.delete(book_shelf) - shelf.last_modified = datetime.utcnow() - ub.session.commit() - + try: + ub.session.delete(book_shelf) + shelf.last_modified = datetime.utcnow() + ub.session.commit() + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") + if "HTTP_REFERER" in request.environ: + return redirect(request.environ["HTTP_REFERER"]) + else: + return redirect(url_for('web.index')) if not xhr: flash(_(u"Book has been removed from shelf: %(sname)s", sname=shelf.name), category="success") if "HTTP_REFERER" in request.environ: @@ -235,7 +255,11 @@ def create_shelf(): ub.session.commit() flash(_(u"Shelf %(title)s created", title=to_save["title"]), category="success") return redirect(url_for('shelf.show_shelf', shelf_id=shelf.id)) + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") except Exception: + ub.session.rollback() flash(_(u"There was an error"), category="error") return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Create a Shelf"), page="shelfcreate") else: @@ -280,7 +304,11 @@ def edit_shelf(shelf_id): try: ub.session.commit() flash(_(u"Shelf %(title)s changed", title=to_save["title"]), category="success") + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") except Exception: + ub.session.rollback() flash(_(u"There was an error"), category="error") return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Edit a shelf"), page="shelfedit") else: @@ -298,11 +326,16 @@ def delete_shelf_helper(cur_shelf): log.info("successfully deleted %s", cur_shelf) + @shelf.route("/shelf/delete/") @login_required def delete_shelf(shelf_id): cur_shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() - delete_shelf_helper(cur_shelf) + try: + delete_shelf_helper(cur_shelf) + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") return redirect(url_for('web.index')) @@ -327,8 +360,12 @@ def show_shelf(shelf_type, shelf_id): cur_book = calibre_db.get_book(book.book_id) if not cur_book: log.info('Not existing book %s in %s deleted', book.book_id, shelf) - ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete() - ub.session.commit() + try: + ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete() + ub.session.commit() + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") return render_title_template(page, entries=result, title=_(u"Shelf: '%(name)s'", name=shelf.name), shelf=shelf, page="shelf") else: @@ -348,7 +385,11 @@ def order_shelf(shelf_id): setattr(book, 'order', to_save[str(book.book_id)]) counter += 1 # if order diffrent from before -> shelf.last_modified = datetime.utcnow() - ub.session.commit() + try: + ub.session.commit() + except (OperationalError, InvalidRequestError): + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() result = list() diff --git a/cps/ub.py b/cps/ub.py index c923dce2..1a2c260a 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -19,6 +19,7 @@ from __future__ import division, print_function, unicode_literals import os +import sys import datetime import itertools import uuid @@ -603,9 +604,13 @@ def migrate_Database(session): session.commit() # Remove login capability of user Guest - conn = engine.connect() - conn.execute("UPDATE user SET password='' where nickname = 'Guest' and password !=''") - session.commit() + try: + conn = engine.connect() + conn.execute("UPDATE user SET password='' where nickname = 'Guest' and password !=''") + session.commit() + except exc.OperationalError: + print('Settings database is not writeable. Exiting...') + sys.exit(1) def clean_database(session):