diff --git a/cps/__init__.py b/cps/__init__.py index 03945b57..1a7dc868 100644 --- a/cps/__init__.py +++ b/cps/__init__.py @@ -94,7 +94,8 @@ def create_app(): app.root_path = app.root_path.decode('utf-8') app.instance_path = app.instance_path.decode('utf-8') - cache_buster.init_cache_busting(app) + if os.environ.get('FLASK_DEBUG'): + cache_buster.init_cache_busting(app) log.info('Starting Calibre Web...') Principal(app) diff --git a/cps/admin.py b/cps/admin.py index b38c1313..45f4cd9b 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -206,7 +206,10 @@ def edit_domain(allow): vals = request.form.to_dict() answer = ub.session.query(ub.Registration).filter(ub.Registration.id == vals['pk']).first() answer.domain = vals['value'].replace('*', '%').replace('?', '_').lower() - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "" @@ -220,7 +223,10 @@ def add_domain(allow): if not check: new_domain = ub.Registration(domain=domain_name, allow=allow) ub.session.add(new_domain) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "" @@ -230,12 +236,18 @@ def add_domain(allow): def delete_domain(): domain_id = request.form.to_dict()['domainid'].replace('*', '%').replace('?', '_').lower() ub.session.query(ub.Registration).filter(ub.Registration.id == domain_id).delete() - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() # If last domain was deleted, add all domains by default if not ub.session.query(ub.Registration).filter(ub.Registration.allow==1).count(): new_domain = ub.Registration(domain="%.%",allow=1) ub.session.add(new_domain) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "" @@ -275,7 +287,10 @@ def edit_restriction(res_type): elementlist = usr.list_allowed_tags() elementlist[int(element['id'][1:])]=element['Element'] usr.allowed_tags = ','.join(elementlist) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() if res_type == 3: # CColumn per user usr_id = os.path.split(request.referrer)[-1] if usr_id.isdigit() == True: @@ -285,7 +300,10 @@ def edit_restriction(res_type): elementlist = usr.list_allowed_column_values() elementlist[int(element['id'][1:])]=element['Element'] usr.allowed_column_value = ','.join(elementlist) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() if element['id'].startswith('d'): if res_type == 0: # Tags as template elementlist = config.list_denied_tags() @@ -306,7 +324,10 @@ def edit_restriction(res_type): elementlist = usr.list_denied_tags() elementlist[int(element['id'][1:])]=element['Element'] usr.denied_tags = ','.join(elementlist) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() if res_type == 3: # CColumn per user usr_id = os.path.split(request.referrer)[-1] if usr_id.isdigit() == True: @@ -316,7 +337,10 @@ def edit_restriction(res_type): elementlist = usr.list_denied_column_values() elementlist[int(element['id'][1:])]=element['Element'] usr.denied_column_value = ','.join(elementlist) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "" def restriction_addition(element, list_func): @@ -362,10 +386,16 @@ def add_restriction(res_type): usr = current_user if 'submit_allow' in element: usr.allowed_tags = restriction_addition(element, usr.list_allowed_tags) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() elif 'submit_deny' in element: usr.denied_tags = restriction_addition(element, usr.list_denied_tags) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() if res_type == 3: # CustomC per user usr_id = os.path.split(request.referrer)[-1] if usr_id.isdigit() == True: @@ -374,10 +404,16 @@ def add_restriction(res_type): usr = current_user if 'submit_allow' in element: usr.allowed_column_value = restriction_addition(element, usr.list_allowed_column_values) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() elif 'submit_deny' in element: usr.denied_column_value = restriction_addition(element, usr.list_denied_column_values) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "" @admi.route("/ajax/deleterestriction/", methods=['POST']) @@ -407,10 +443,16 @@ def delete_restriction(res_type): usr = current_user if element['id'].startswith('a'): usr.allowed_tags = restriction_deletion(element, usr.list_allowed_tags) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() elif element['id'].startswith('d'): usr.denied_tags = restriction_deletion(element, usr.list_denied_tags) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() elif res_type == 3: # Columns per user usr_id = os.path.split(request.referrer)[-1] if usr_id.isdigit() == True: # select current user if admins are editing their own rights @@ -419,10 +461,16 @@ def delete_restriction(res_type): usr = current_user if element['id'].startswith('a'): usr.allowed_column_value = restriction_deletion(element, usr.list_allowed_column_values) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() elif element['id'].startswith('d'): usr.denied_column_value = restriction_deletion(element, usr.list_denied_column_values) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "" @@ -815,7 +863,10 @@ def _handle_new_user(to_save, content,languages, translations, kobo_support): content.allowed_column_value = config.config_allowed_column_value content.denied_column_value = config.config_denied_column_value ub.session.add(content) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() flash(_(u"User '%(user)s' created", user=content.nickname), category="success") return redirect(url_for('admin.admin')) except IntegrityError: @@ -831,7 +882,10 @@ def _handle_edit_user(to_save, content,languages, translations, kobo_support): if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN, ub.User.id != content.id).count(): ub.session.query(ub.User).filter(ub.User.id == content.id).delete() - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() flash(_(u"User '%(nick)s' deleted", nick=content.nickname), category="success") return redirect(url_for('admin.admin')) else: @@ -906,7 +960,10 @@ def _handle_edit_user(to_save, content,languages, translations, kobo_support): if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail: content.kindle_mail = to_save["kindle_mail"] try: - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() flash(_(u"User '%(nick)s' updated", nick=content.nickname), category="success") except IntegrityError: ub.session.rollback() diff --git a/cps/config_sql.py b/cps/config_sql.py index 877ad1c2..e3322cb9 100644 --- a/cps/config_sql.py +++ b/cps/config_sql.py @@ -22,6 +22,7 @@ import os import sys from sqlalchemy import exc, Column, String, Integer, SmallInteger, Boolean, BLOB, JSON +from sqlalchemy.exc import OperationalError from sqlalchemy.ext.declarative import declarative_base from . import constants, cli, logger, ub @@ -139,6 +140,7 @@ class _ConfigSQL(object): # pylint: disable=no-member def __init__(self, session): self._session = session + self._session.expire_on_commit = False self._settings = None self.db_configured = None self.config_calibre_dir = None @@ -295,7 +297,11 @@ class _ConfigSQL(object): log.warning("Log path %s not valid, falling back to default", self.config_logfile) self.config_logfile = logfile self._session.merge(s) - self._session.commit() + try: + self._session.commit() + except OperationalError as e: + log.error('Database error: %s', e) + self._session.rollback() def save(self): '''Apply all configuration values to the underlying storage.''' @@ -309,7 +315,11 @@ class _ConfigSQL(object): log.debug("_ConfigSQL updating storage") self._session.merge(s) - self._session.commit() + try: + self._session.commit() + except OperationalError as e: + log.error('Database error: %s', e) + self._session.rollback() self.load() def invalidate(self, error=None): @@ -350,7 +360,10 @@ def _migrate_table(session, orm_class): changed = True if changed: - session.commit() + try: + session.commit() + except OperationalError: + session.rollback() def autodetect_calibre_binary(): diff --git a/cps/db.py b/cps/db.py index f648a794..bc564638 100644 --- a/cps/db.py +++ b/cps/db.py @@ -32,9 +32,9 @@ from sqlalchemy.orm import relationship, sessionmaker, scoped_session from sqlalchemy.orm.collections import InstrumentedList from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta from sqlalchemy.pool import StaticPool -from flask_login import current_user from sqlalchemy.sql.expression import and_, true, false, text, func, or_ from sqlalchemy.ext.associationproxy import association_proxy +from flask_login import current_user from babel import Locale as LC from babel.core import UnknownLocaleError from flask_babel import gettext as _ @@ -425,18 +425,19 @@ class CalibreDB(): # instances alive once they reach the end of their respective scopes instances = WeakSet() - def __init__(self): + def __init__(self, expire_on_commit=True): """ Initialize a new CalibreDB session """ self.session = None if self._init: - self.initSession() + self.initSession(expire_on_commit) self.instances.add(self) - def initSession(self): + def initSession(self, expire_on_commit=True): self.session = self.session_factory() + self.session.expire_on_commit = expire_on_commit self.update_title_sort(self.config) @classmethod diff --git a/cps/gdriveutils.py b/cps/gdriveutils.py index 489bc6f5..1c5dec05 100644 --- a/cps/gdriveutils.py +++ b/cps/gdriveutils.py @@ -89,7 +89,7 @@ class Singleton: except AttributeError: self._instance = self._decorated() return self._instance - except ImportError as e: + except (ImportError, NameError) as e: log.debug(e) return None diff --git a/cps/helper.py b/cps/helper.py index 9845df97..f0d556d9 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -24,10 +24,7 @@ import io import mimetypes import re import shutil -import glob import time -import zipfile -import json import unicodedata from datetime import datetime, timedelta from tempfile import gettempdir diff --git a/cps/kobo.py b/cps/kobo.py index 90d0182e..21a9b2ce 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -43,6 +43,7 @@ from flask_login import current_user from werkzeug.datastructures import Headers from sqlalchemy import func from sqlalchemy.sql.expression import and_, or_ +from sqlalchemy.exc import OperationalError from sqlalchemy.orm import load_only from sqlalchemy.exc import StatementError import requests @@ -451,8 +452,10 @@ def HandleTagCreate(): items_unknown_to_calibre = add_items_to_shelf(items, shelf) if items_unknown_to_calibre: log.debug("Received request to add unknown books to a collection. Silently ignoring items.") - ub.session.commit() - + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return make_response(jsonify(str(shelf.uuid)), 201) @@ -484,7 +487,10 @@ def HandleTagUpdate(tag_id): shelf.name = name ub.session.merge(shelf) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return make_response(' ', 200) @@ -536,7 +542,10 @@ def HandleTagAddItem(tag_id): log.debug("Received request to add an unknown book to a collection. Silently ignoring item.") ub.session.merge(shelf) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return make_response('', 201) @@ -577,7 +586,10 @@ def HandleTagRemoveItem(tag_id): shelf.books.filter(ub.BookShelf.book_id == book.id).delete() except KeyError: items_unknown_to_calibre.append(item) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() if items_unknown_to_calibre: log.debug("Received request to remove an unknown book to a collecition. Silently ignoring item.") @@ -623,7 +635,10 @@ def sync_shelves(sync_token, sync_results): "ChangedTag": tag }) sync_token.tags_last_modified = new_tags_last_modified - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() # Creates a Kobo "Tag" object from a ub.Shelf object @@ -704,7 +719,10 @@ def HandleStateRequest(book_uuid): abort(400, description="Malformed request data is missing 'ReadingStates' key") ub.session.merge(kobo_reading_state) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return jsonify({ "RequestResult": "Success", "UpdateResults": [update_results_response], @@ -742,7 +760,10 @@ def get_or_create_reading_state(book_id): kobo_reading_state.statistics = ub.KoboStatistics() book_read.kobo_reading_state = kobo_reading_state ub.session.add(book_read) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return book_read.kobo_reading_state @@ -845,7 +866,10 @@ def HandleBookDeletionRequest(book_uuid): archived_book.last_modified = datetime.datetime.utcnow() ub.session.merge(archived_book) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return ("", 204) diff --git a/cps/kobo_auth.py b/cps/kobo_auth.py index 0f6cd174..85d7b7ac 100644 --- a/cps/kobo_auth.py +++ b/cps/kobo_auth.py @@ -66,6 +66,7 @@ from os import urandom from flask import g, Blueprint, url_for, abort, request from flask_login import login_user, login_required from flask_babel import gettext as _ +from sqlalchemy.exc import OperationalError from . import logger, ub, lm from .web import render_title_template @@ -147,7 +148,10 @@ def generate_auth_token(user_id): auth_token.token_type = 1 ub.session.add(auth_token) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return render_title_template( "generate_kobo_auth_url.html", title=_(u"Kobo Setup"), @@ -164,5 +168,8 @@ def delete_auth_token(user_id): # Invalidate any prevously generated Kobo Auth token for this user. ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.user_id == user_id)\ .filter(ub.RemoteAuthToken.token_type==1).delete() - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "" diff --git a/cps/oauth_bb.py b/cps/oauth_bb.py index 4d489cdd..754a065c 100644 --- a/cps/oauth_bb.py +++ b/cps/oauth_bb.py @@ -32,6 +32,7 @@ from flask_dance.contrib.github import make_github_blueprint, github from flask_dance.contrib.google import make_google_blueprint, google from flask_login import login_user, current_user from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.exc import OperationalError from . import constants, logger, config, app, ub from .web import login_required @@ -109,7 +110,10 @@ if ub.oauth_support: oauthProvider.provider_name = "google" oauthProvider.active = False ub.session.add(oauthProvider) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() oauth_ids = ub.session.query(ub.OAuthProvider).all() ele1 = dict(provider_name='github', diff --git a/cps/opds.py b/cps/opds.py index 05e9c68c..4074fe7d 100644 --- a/cps/opds.py +++ b/cps/opds.py @@ -33,7 +33,7 @@ from werkzeug.security import check_password_hash from . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages from .helper import get_download_link, get_book_cover from .pagination import Pagination -from .web import render_read_books, download_required, load_user_from_request +from .web import render_read_books, load_user_from_request from flask_babel import gettext as _ from babel import Locale as LC from babel.core import UnknownLocaleError diff --git a/cps/shelf.py b/cps/shelf.py index ea7f1eeb..e7dcc4e7 100644 --- a/cps/shelf.py +++ b/cps/shelf.py @@ -322,8 +322,11 @@ def delete_shelf_helper(cur_shelf): ub.session.delete(cur_shelf) ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).delete() ub.session.add(ub.ShelfArchive(uuid=cur_shelf.uuid, user_id=cur_shelf.user_id)) - ub.session.commit() - log.info("successfully deleted %s", cur_shelf) + try: + ub.session.commit() + log.info("successfully deleted %s", cur_shelf) + except OperationalError: + ub.session.rollback() diff --git a/cps/tasks/convert.py b/cps/tasks/convert.py index 659c6e9c..5e38b8ef 100644 --- a/cps/tasks/convert.py +++ b/cps/tasks/convert.py @@ -9,7 +9,7 @@ from shutil import copyfile from sqlalchemy.exc import SQLAlchemyError from cps.services.worker import CalibreTask -from cps import calibre_db, db +from cps import db from cps import logger, config from cps.subproc_wrapper import process_open from flask_babel import gettext as _ @@ -33,8 +33,9 @@ class TaskConvert(CalibreTask): def run(self, worker_thread): self.worker_thread = worker_thread if config.config_use_google_drive: - cur_book = calibre_db.get_book(self.bookid) - data = calibre_db.get_book_format(self.bookid, self.settings['old_book_format']) + worker_db = db.CalibreDB(expire_on_commit=False) + cur_book = worker_db.get_book(self.bookid) + data = worker_db.get_book_format(self.bookid, self.settings['old_book_format']) df = gdriveutils.getFileFromEbooksFolder(cur_book.path, data.name + "." + self.settings['old_book_format'].lower()) if df: @@ -44,10 +45,12 @@ class TaskConvert(CalibreTask): if not os.path.exists(os.path.join(config.config_calibre_dir, cur_book.path)): os.makedirs(os.path.join(config.config_calibre_dir, cur_book.path)) df.GetContentFile(datafile) + worker_db.session.close() else: error_message = _(u"%(format)s not found on Google Drive: %(fn)s", format=self.settings['old_book_format'], fn=data.name + "." + self.settings['old_book_format'].lower()) + worker_db.session.close() return error_message filename = self._convert_ebook_format() @@ -71,7 +74,7 @@ class TaskConvert(CalibreTask): def _convert_ebook_format(self): error_message = None - local_session = db.CalibreDB().session + local_db = db.CalibreDB(expire_on_commit=False) file_path = self.file_path book_id = self.bookid format_old_ext = u'.' + self.settings['old_book_format'].lower() @@ -82,10 +85,11 @@ class TaskConvert(CalibreTask): # this will allow send to kindle workflow to continue to work if os.path.isfile(file_path + format_new_ext): log.info("Book id %d already converted to %s", book_id, format_new_ext) - cur_book = calibre_db.get_book(book_id) + cur_book = local_db.get_book(book_id) self.results['path'] = file_path self.results['title'] = cur_book.title self._handleSuccess() + local_db.session.close() return os.path.basename(file_path + format_new_ext) else: log.info("Book id %d - target format of %s does not exist. Moving forward with convert.", @@ -105,18 +109,19 @@ class TaskConvert(CalibreTask): check, error_message = self._convert_calibre(file_path, format_old_ext, format_new_ext) if check == 0: - cur_book = calibre_db.get_book(book_id) + cur_book = local_db.get_book(book_id) if os.path.isfile(file_path + format_new_ext): # self.db_queue.join() new_format = db.Data(name=cur_book.data[0].name, book_format=self.settings['new_book_format'].upper(), book=book_id, uncompressed_size=os.path.getsize(file_path + format_new_ext)) try: - local_session.merge(new_format) - local_session.commit() + local_db.session.merge(new_format) + local_db.session.commit() except SQLAlchemyError as e: - local_session.rollback() + local_db.rollback() log.error("Database error: %s", e) + local_db.session.close() return self.results['path'] = cur_book.path self.results['title'] = cur_book.title @@ -125,6 +130,7 @@ class TaskConvert(CalibreTask): return os.path.basename(file_path + format_new_ext) else: error_message = _('%(format)s format not found on disk', format=format_new_ext.upper()) + local_db.session.close() log.info("ebook converter failed with error while converting book") if not error_message: error_message = _('Ebook converter failed with unknown error') diff --git a/cps/ub.py b/cps/ub.py index 145575d1..d7900737 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -45,7 +45,7 @@ from sqlalchemy import Column, ForeignKey from sqlalchemy import String, Integer, SmallInteger, Boolean, DateTime, Float, JSON from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm.attributes import flag_modified -from sqlalchemy.orm import backref, relationship, sessionmaker, Session +from sqlalchemy.orm import backref, relationship, sessionmaker, Session, scoped_session from werkzeug.security import generate_password_hash from . import constants @@ -677,14 +677,20 @@ def update_download(book_id, user_id): if not check: new_download = Downloads(user_id=user_id, book_id=book_id) - session.add(new_download) - session.commit() + ub.session.add(new_download) + try: + ub.session.commit() + except exc.OperationalError: + ub.session.rollback() # Delete non exisiting downloaded books in calibre-web's own database def delete_download(book_id): - session.query(Downloads).filter(book_id == Downloads.book_id).delete() - session.commit() + ub.session.query(Downloads).filter(book_id == Downloads.book_id).delete() + try: + ub.session.commit() + except exc.OperationalError: + ub.session.rollback() # Generate user Guest (translated text), as anonymous user, no rights def create_anonymous_user(session): @@ -725,7 +731,7 @@ def init_db(app_db_path): app_DB_path = app_db_path engine = create_engine(u'sqlite:///{0}'.format(app_db_path), echo=False) - Session = sessionmaker() + Session = scoped_session(sessionmaker()) Session.configure(bind=engine) session = Session() diff --git a/cps/web.py b/cps/web.py index f41c3e0d..5fbb39af 100644 --- a/cps/web.py +++ b/cps/web.py @@ -351,7 +351,6 @@ def import_ldap_users(): username = user_data[user_login_field][0].decode('utf-8') # check for duplicate username if ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == username.lower()).first(): - # if ub.session.query(ub.User).filter(ub.User.nickname == username).first(): log.warning("LDAP User %s Already in Database", user_data) continue @@ -432,7 +431,10 @@ def bookmark(book_id, book_format): ub.Bookmark.book_id == book_id, ub.Bookmark.format == book_format)).delete() if not bookmark_key: - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "", 204 lbookmark = ub.Bookmark(user_id=current_user.id, @@ -440,7 +442,10 @@ def bookmark(book_id, book_format): format=book_format, bookmark_key=bookmark_key) ub.session.merge(lbookmark) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "", 201 @@ -465,7 +470,10 @@ def toggle_read(book_id): kobo_reading_state.statistics = ub.KoboStatistics() book.kobo_reading_state = kobo_reading_state ub.session.merge(book) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() else: try: calibre_db.update_title_sort(config) @@ -499,7 +507,10 @@ def toggle_archived(book_id): archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id) archived_book.is_archived = True ub.session.merge(archived_book) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() return "" @@ -749,8 +760,6 @@ def render_hot_books(page): entries.append(downloadBook) else: ub.delete_download(book.Downloads.book_id) - # ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete() - # ub.session.commit() numBooks = entries.__len__() pagination = Pagination(page, config.config_books_per_page, numBooks) return render_title_template('index.html', random=random, entries=entries, pagination=pagination, @@ -1086,11 +1095,12 @@ def update_table_settings(): except AttributeError: pass ub.session.commit() - except InvalidRequestError: + except (InvalidRequestError, OperationalError): log.error("Invalid request received: %r ", request, ) return "Invalid request", 400 return "" + @web.route("/author") @login_required_if_no_ano def author_list(): @@ -1676,7 +1686,10 @@ def logout(): def remote_login(): auth_token = ub.RemoteAuthToken() ub.session.add(auth_token) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() verify_url = url_for('web.verify_token', token=auth_token.auth_token, _external=true) log.debug(u"Remot Login request with token: %s", auth_token.auth_token) @@ -1708,7 +1721,10 @@ def verify_token(token): # Update token with user information auth_token.user_id = current_user.id auth_token.verified = True - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() flash(_(u"Success! Please return to your device"), category="success") log.debug(u"Remote Login token for userid %s verified", auth_token.user_id) @@ -1731,7 +1747,10 @@ def token_verified(): # Token expired elif datetime.now() > auth_token.expiration: ub.session.delete(auth_token) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() data['status'] = 'error' data['message'] = _(u"Token has expired") @@ -1744,7 +1763,10 @@ def token_verified(): login_user(user) ub.session.delete(auth_token) - ub.session.commit() + try: + ub.session.commit() + except OperationalError: + ub.session.rollback() data['status'] = 'success' log.debug(u"Remote Login for userid %s succeded", user.id) @@ -1836,14 +1858,11 @@ def profile(): ub.session.rollback() flash(_(u"Found an existing account for this e-mail address."), category="error") log.debug(u"Found an existing account for this e-mail address.") - '''return render_title_template("user_edit.html", - content=current_user, - translations=translations, - kobo_support=kobo_support, - title=_(u"%(name)s's profile", name=current_user.nickname), - page="me", - registered_oauth=local_oauth_check, - oauth_status=oauth_status)''' + except OperationalError as e: + ub.session.rollback() + log.error("Database error: %s", e) + flash(_(u"Database error: %(error)s.", error=e), category="error") + return render_title_template("user_edit.html", translations=translations, profile=1, diff --git a/test/Calibre-Web TestSummary_Linux.html b/test/Calibre-Web TestSummary_Linux.html index e96fa1ac..4133a3ff 100644 --- a/test/Calibre-Web TestSummary_Linux.html +++ b/test/Calibre-Web TestSummary_Linux.html @@ -37,20 +37,20 @@
-

Start Time: 2020-12-02 15:51:36

+

Start Time: 2020-12-08 08:19:58

-

Stop Time: 2020-12-02 18:01:04

+

Stop Time: 2020-12-08 10:00:52

-

Duration: 1h 41 min

+

Duration: 1h 15 min

@@ -511,162 +511,730 @@ AssertionError: False is not true : BMP file is not detected - + TestEbookConvertCalibreGDrive - 6 - 6 + 12 0 0 + 12 0 - Detail + Detail - +
TestEbookConvertCalibreGDrive - test_convert_email
- PASS + +
+ ERROR +
+ + + + - + -
TestEbookConvertCalibreGDrive - test_convert_failed_and_email
+
TestEbookConvertCalibreGDrive - test_convert_email
+ + +
+ ERROR +
+ + + - PASS - + -
TestEbookConvertCalibreGDrive - test_convert_only
+
TestEbookConvertCalibreGDrive - test_convert_failed_and_email
+ + +
+ ERROR +
+ + + - PASS - + -
TestEbookConvertCalibreGDrive - test_convert_parameter
+
TestEbookConvertCalibreGDrive - test_convert_failed_and_email
+ + +
+ ERROR +
+ + + - PASS - + -
TestEbookConvertCalibreGDrive - test_email_failed
+
TestEbookConvertCalibreGDrive - test_convert_only
+ + +
+ ERROR +
+ + + - PASS - + -
TestEbookConvertCalibreGDrive - test_email_only
+
TestEbookConvertCalibreGDrive - test_convert_only
- PASS - - - + +
+ ERROR +
+ + + - PASS - + -
TestEbookConvertKepubify - test_convert_only
+
TestEbookConvertCalibreGDrive - test_convert_parameter
+ + +
+ ERROR +
+ + + - PASS - + -
TestEbookConvertKepubify - test_convert_wrong_excecutable
+
TestEbookConvertCalibreGDrive - test_convert_parameter
- PASS - - - + +
+ ERROR +
+ + + - PASS - + -
TestEbookConvertGDriveKepubify - test_convert_only
+
TestEbookConvertCalibreGDrive - test_email_failed
- FAIL + ERROR
-