Merge branch 'session' into Develop

This commit is contained in:
OzzieIsaacs 2020-12-08 11:39:23 +01:00
commit 8f36128fe3
15 changed files with 12911 additions and 927 deletions

View File

@ -94,7 +94,8 @@ def create_app():
app.root_path = app.root_path.decode('utf-8') app.root_path = app.root_path.decode('utf-8')
app.instance_path = app.instance_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...') log.info('Starting Calibre Web...')
Principal(app) Principal(app)

View File

@ -206,7 +206,10 @@ def edit_domain(allow):
vals = request.form.to_dict() vals = request.form.to_dict()
answer = ub.session.query(ub.Registration).filter(ub.Registration.id == vals['pk']).first() answer = ub.session.query(ub.Registration).filter(ub.Registration.id == vals['pk']).first()
answer.domain = vals['value'].replace('*', '%').replace('?', '_').lower() answer.domain = vals['value'].replace('*', '%').replace('?', '_').lower()
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return "" return ""
@ -220,7 +223,10 @@ def add_domain(allow):
if not check: if not check:
new_domain = ub.Registration(domain=domain_name, allow=allow) new_domain = ub.Registration(domain=domain_name, allow=allow)
ub.session.add(new_domain) ub.session.add(new_domain)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return "" return ""
@ -230,12 +236,18 @@ def add_domain(allow):
def delete_domain(): def delete_domain():
domain_id = request.form.to_dict()['domainid'].replace('*', '%').replace('?', '_').lower() domain_id = request.form.to_dict()['domainid'].replace('*', '%').replace('?', '_').lower()
ub.session.query(ub.Registration).filter(ub.Registration.id == domain_id).delete() 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 last domain was deleted, add all domains by default
if not ub.session.query(ub.Registration).filter(ub.Registration.allow==1).count(): if not ub.session.query(ub.Registration).filter(ub.Registration.allow==1).count():
new_domain = ub.Registration(domain="%.%",allow=1) new_domain = ub.Registration(domain="%.%",allow=1)
ub.session.add(new_domain) ub.session.add(new_domain)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return "" return ""
@ -275,7 +287,10 @@ def edit_restriction(res_type):
elementlist = usr.list_allowed_tags() elementlist = usr.list_allowed_tags()
elementlist[int(element['id'][1:])]=element['Element'] elementlist[int(element['id'][1:])]=element['Element']
usr.allowed_tags = ','.join(elementlist) usr.allowed_tags = ','.join(elementlist)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
if res_type == 3: # CColumn per user if res_type == 3: # CColumn per user
usr_id = os.path.split(request.referrer)[-1] usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True: if usr_id.isdigit() == True:
@ -285,7 +300,10 @@ def edit_restriction(res_type):
elementlist = usr.list_allowed_column_values() elementlist = usr.list_allowed_column_values()
elementlist[int(element['id'][1:])]=element['Element'] elementlist[int(element['id'][1:])]=element['Element']
usr.allowed_column_value = ','.join(elementlist) usr.allowed_column_value = ','.join(elementlist)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
if element['id'].startswith('d'): if element['id'].startswith('d'):
if res_type == 0: # Tags as template if res_type == 0: # Tags as template
elementlist = config.list_denied_tags() elementlist = config.list_denied_tags()
@ -306,7 +324,10 @@ def edit_restriction(res_type):
elementlist = usr.list_denied_tags() elementlist = usr.list_denied_tags()
elementlist[int(element['id'][1:])]=element['Element'] elementlist[int(element['id'][1:])]=element['Element']
usr.denied_tags = ','.join(elementlist) usr.denied_tags = ','.join(elementlist)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
if res_type == 3: # CColumn per user if res_type == 3: # CColumn per user
usr_id = os.path.split(request.referrer)[-1] usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True: if usr_id.isdigit() == True:
@ -316,7 +337,10 @@ def edit_restriction(res_type):
elementlist = usr.list_denied_column_values() elementlist = usr.list_denied_column_values()
elementlist[int(element['id'][1:])]=element['Element'] elementlist[int(element['id'][1:])]=element['Element']
usr.denied_column_value = ','.join(elementlist) usr.denied_column_value = ','.join(elementlist)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return "" return ""
def restriction_addition(element, list_func): def restriction_addition(element, list_func):
@ -362,10 +386,16 @@ def add_restriction(res_type):
usr = current_user usr = current_user
if 'submit_allow' in element: if 'submit_allow' in element:
usr.allowed_tags = restriction_addition(element, usr.list_allowed_tags) 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: elif 'submit_deny' in element:
usr.denied_tags = restriction_addition(element, usr.list_denied_tags) 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 if res_type == 3: # CustomC per user
usr_id = os.path.split(request.referrer)[-1] usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True: if usr_id.isdigit() == True:
@ -374,10 +404,16 @@ def add_restriction(res_type):
usr = current_user usr = current_user
if 'submit_allow' in element: if 'submit_allow' in element:
usr.allowed_column_value = restriction_addition(element, usr.list_allowed_column_values) 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: elif 'submit_deny' in element:
usr.denied_column_value = restriction_addition(element, usr.list_denied_column_values) 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 "" return ""
@admi.route("/ajax/deleterestriction/<int:res_type>", methods=['POST']) @admi.route("/ajax/deleterestriction/<int:res_type>", methods=['POST'])
@ -407,10 +443,16 @@ def delete_restriction(res_type):
usr = current_user usr = current_user
if element['id'].startswith('a'): if element['id'].startswith('a'):
usr.allowed_tags = restriction_deletion(element, usr.list_allowed_tags) 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'): elif element['id'].startswith('d'):
usr.denied_tags = restriction_deletion(element, usr.list_denied_tags) 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 elif res_type == 3: # Columns per user
usr_id = os.path.split(request.referrer)[-1] usr_id = os.path.split(request.referrer)[-1]
if usr_id.isdigit() == True: # select current user if admins are editing their own rights 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 usr = current_user
if element['id'].startswith('a'): if element['id'].startswith('a'):
usr.allowed_column_value = restriction_deletion(element, usr.list_allowed_column_values) 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'): elif element['id'].startswith('d'):
usr.denied_column_value = restriction_deletion(element, usr.list_denied_column_values) 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 "" 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.allowed_column_value = config.config_allowed_column_value
content.denied_column_value = config.config_denied_column_value content.denied_column_value = config.config_denied_column_value
ub.session.add(content) 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") flash(_(u"User '%(user)s' created", user=content.nickname), category="success")
return redirect(url_for('admin.admin')) return redirect(url_for('admin.admin'))
except IntegrityError: 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, if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN,
ub.User.id != content.id).count(): ub.User.id != content.id).count():
ub.session.query(ub.User).filter(ub.User.id == content.id).delete() 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") flash(_(u"User '%(nick)s' deleted", nick=content.nickname), category="success")
return redirect(url_for('admin.admin')) return redirect(url_for('admin.admin'))
else: 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: if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail:
content.kindle_mail = to_save["kindle_mail"] content.kindle_mail = to_save["kindle_mail"]
try: try:
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
flash(_(u"User '%(nick)s' updated", nick=content.nickname), category="success") flash(_(u"User '%(nick)s' updated", nick=content.nickname), category="success")
except IntegrityError: except IntegrityError:
ub.session.rollback() ub.session.rollback()

View File

@ -22,6 +22,7 @@ import os
import sys import sys
from sqlalchemy import exc, Column, String, Integer, SmallInteger, Boolean, BLOB, JSON from sqlalchemy import exc, Column, String, Integer, SmallInteger, Boolean, BLOB, JSON
from sqlalchemy.exc import OperationalError
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from . import constants, cli, logger, ub from . import constants, cli, logger, ub
@ -139,6 +140,7 @@ class _ConfigSQL(object):
# pylint: disable=no-member # pylint: disable=no-member
def __init__(self, session): def __init__(self, session):
self._session = session self._session = session
self._session.expire_on_commit = False
self._settings = None self._settings = None
self.db_configured = None self.db_configured = None
self.config_calibre_dir = 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) log.warning("Log path %s not valid, falling back to default", self.config_logfile)
self.config_logfile = logfile self.config_logfile = logfile
self._session.merge(s) 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): def save(self):
'''Apply all configuration values to the underlying storage.''' '''Apply all configuration values to the underlying storage.'''
@ -309,7 +315,11 @@ class _ConfigSQL(object):
log.debug("_ConfigSQL updating storage") log.debug("_ConfigSQL updating storage")
self._session.merge(s) 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() self.load()
def invalidate(self, error=None): def invalidate(self, error=None):
@ -350,7 +360,10 @@ def _migrate_table(session, orm_class):
changed = True changed = True
if changed: if changed:
session.commit() try:
session.commit()
except OperationalError:
session.rollback()
def autodetect_calibre_binary(): def autodetect_calibre_binary():

View File

@ -32,9 +32,9 @@ from sqlalchemy.orm import relationship, sessionmaker, scoped_session
from sqlalchemy.orm.collections import InstrumentedList from sqlalchemy.orm.collections import InstrumentedList
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
from sqlalchemy.pool import StaticPool from sqlalchemy.pool import StaticPool
from flask_login import current_user
from sqlalchemy.sql.expression import and_, true, false, text, func, or_ from sqlalchemy.sql.expression import and_, true, false, text, func, or_
from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.associationproxy import association_proxy
from flask_login import current_user
from babel import Locale as LC from babel import Locale as LC
from babel.core import UnknownLocaleError from babel.core import UnknownLocaleError
from flask_babel import gettext as _ from flask_babel import gettext as _
@ -425,18 +425,19 @@ class CalibreDB():
# instances alive once they reach the end of their respective scopes # instances alive once they reach the end of their respective scopes
instances = WeakSet() instances = WeakSet()
def __init__(self): def __init__(self, expire_on_commit=True):
""" Initialize a new CalibreDB session """ Initialize a new CalibreDB session
""" """
self.session = None self.session = None
if self._init: if self._init:
self.initSession() self.initSession(expire_on_commit)
self.instances.add(self) self.instances.add(self)
def initSession(self): def initSession(self, expire_on_commit=True):
self.session = self.session_factory() self.session = self.session_factory()
self.session.expire_on_commit = expire_on_commit
self.update_title_sort(self.config) self.update_title_sort(self.config)
@classmethod @classmethod

View File

@ -89,7 +89,7 @@ class Singleton:
except AttributeError: except AttributeError:
self._instance = self._decorated() self._instance = self._decorated()
return self._instance return self._instance
except ImportError as e: except (ImportError, NameError) as e:
log.debug(e) log.debug(e)
return None return None

View File

@ -24,10 +24,7 @@ import io
import mimetypes import mimetypes
import re import re
import shutil import shutil
import glob
import time import time
import zipfile
import json
import unicodedata import unicodedata
from datetime import datetime, timedelta from datetime import datetime, timedelta
from tempfile import gettempdir from tempfile import gettempdir

View File

@ -43,6 +43,7 @@ from flask_login import current_user
from werkzeug.datastructures import Headers from werkzeug.datastructures import Headers
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.sql.expression import and_, or_ from sqlalchemy.sql.expression import and_, or_
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import load_only from sqlalchemy.orm import load_only
from sqlalchemy.exc import StatementError from sqlalchemy.exc import StatementError
import requests import requests
@ -451,8 +452,10 @@ def HandleTagCreate():
items_unknown_to_calibre = add_items_to_shelf(items, shelf) items_unknown_to_calibre = add_items_to_shelf(items, shelf)
if items_unknown_to_calibre: if items_unknown_to_calibre:
log.debug("Received request to add unknown books to a collection. Silently ignoring items.") 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) return make_response(jsonify(str(shelf.uuid)), 201)
@ -484,7 +487,10 @@ def HandleTagUpdate(tag_id):
shelf.name = name shelf.name = name
ub.session.merge(shelf) ub.session.merge(shelf)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return make_response(' ', 200) 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.") log.debug("Received request to add an unknown book to a collection. Silently ignoring item.")
ub.session.merge(shelf) ub.session.merge(shelf)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return make_response('', 201) return make_response('', 201)
@ -577,7 +586,10 @@ def HandleTagRemoveItem(tag_id):
shelf.books.filter(ub.BookShelf.book_id == book.id).delete() shelf.books.filter(ub.BookShelf.book_id == book.id).delete()
except KeyError: except KeyError:
items_unknown_to_calibre.append(item) items_unknown_to_calibre.append(item)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
if items_unknown_to_calibre: if items_unknown_to_calibre:
log.debug("Received request to remove an unknown book to a collecition. Silently ignoring item.") 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 "ChangedTag": tag
}) })
sync_token.tags_last_modified = new_tags_last_modified 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 # 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") abort(400, description="Malformed request data is missing 'ReadingStates' key")
ub.session.merge(kobo_reading_state) ub.session.merge(kobo_reading_state)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return jsonify({ return jsonify({
"RequestResult": "Success", "RequestResult": "Success",
"UpdateResults": [update_results_response], "UpdateResults": [update_results_response],
@ -742,7 +760,10 @@ def get_or_create_reading_state(book_id):
kobo_reading_state.statistics = ub.KoboStatistics() kobo_reading_state.statistics = ub.KoboStatistics()
book_read.kobo_reading_state = kobo_reading_state book_read.kobo_reading_state = kobo_reading_state
ub.session.add(book_read) ub.session.add(book_read)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return book_read.kobo_reading_state return book_read.kobo_reading_state
@ -845,7 +866,10 @@ def HandleBookDeletionRequest(book_uuid):
archived_book.last_modified = datetime.datetime.utcnow() archived_book.last_modified = datetime.datetime.utcnow()
ub.session.merge(archived_book) ub.session.merge(archived_book)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return ("", 204) return ("", 204)

View File

@ -66,6 +66,7 @@ from os import urandom
from flask import g, Blueprint, url_for, abort, request from flask import g, Blueprint, url_for, abort, request
from flask_login import login_user, login_required from flask_login import login_user, login_required
from flask_babel import gettext as _ from flask_babel import gettext as _
from sqlalchemy.exc import OperationalError
from . import logger, ub, lm from . import logger, ub, lm
from .web import render_title_template from .web import render_title_template
@ -147,7 +148,10 @@ def generate_auth_token(user_id):
auth_token.token_type = 1 auth_token.token_type = 1
ub.session.add(auth_token) ub.session.add(auth_token)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return render_title_template( return render_title_template(
"generate_kobo_auth_url.html", "generate_kobo_auth_url.html",
title=_(u"Kobo Setup"), title=_(u"Kobo Setup"),
@ -164,5 +168,8 @@ def delete_auth_token(user_id):
# Invalidate any prevously generated Kobo Auth token for this user. # Invalidate any prevously generated Kobo Auth token for this user.
ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.user_id == user_id)\ ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.user_id == user_id)\
.filter(ub.RemoteAuthToken.token_type==1).delete() .filter(ub.RemoteAuthToken.token_type==1).delete()
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return "" return ""

View File

@ -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_dance.contrib.google import make_google_blueprint, google
from flask_login import login_user, current_user from flask_login import login_user, current_user
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.exc import OperationalError
from . import constants, logger, config, app, ub from . import constants, logger, config, app, ub
from .web import login_required from .web import login_required
@ -109,7 +110,10 @@ if ub.oauth_support:
oauthProvider.provider_name = "google" oauthProvider.provider_name = "google"
oauthProvider.active = False oauthProvider.active = False
ub.session.add(oauthProvider) ub.session.add(oauthProvider)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
oauth_ids = ub.session.query(ub.OAuthProvider).all() oauth_ids = ub.session.query(ub.OAuthProvider).all()
ele1 = dict(provider_name='github', ele1 = dict(provider_name='github',

View File

@ -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 . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages
from .helper import get_download_link, get_book_cover from .helper import get_download_link, get_book_cover
from .pagination import Pagination 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 flask_babel import gettext as _
from babel import Locale as LC from babel import Locale as LC
from babel.core import UnknownLocaleError from babel.core import UnknownLocaleError

View File

@ -322,8 +322,11 @@ def delete_shelf_helper(cur_shelf):
ub.session.delete(cur_shelf) ub.session.delete(cur_shelf)
ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).delete() 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.add(ub.ShelfArchive(uuid=cur_shelf.uuid, user_id=cur_shelf.user_id))
ub.session.commit() try:
log.info("successfully deleted %s", cur_shelf) ub.session.commit()
log.info("successfully deleted %s", cur_shelf)
except OperationalError:
ub.session.rollback()

View File

@ -9,7 +9,7 @@ from shutil import copyfile
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from cps.services.worker import CalibreTask from cps.services.worker import CalibreTask
from cps import calibre_db, db from cps import db
from cps import logger, config from cps import logger, config
from cps.subproc_wrapper import process_open from cps.subproc_wrapper import process_open
from flask_babel import gettext as _ from flask_babel import gettext as _
@ -33,8 +33,9 @@ class TaskConvert(CalibreTask):
def run(self, worker_thread): def run(self, worker_thread):
self.worker_thread = worker_thread self.worker_thread = worker_thread
if config.config_use_google_drive: if config.config_use_google_drive:
cur_book = calibre_db.get_book(self.bookid) worker_db = db.CalibreDB(expire_on_commit=False)
data = calibre_db.get_book_format(self.bookid, self.settings['old_book_format']) 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, df = gdriveutils.getFileFromEbooksFolder(cur_book.path,
data.name + "." + self.settings['old_book_format'].lower()) data.name + "." + self.settings['old_book_format'].lower())
if df: if df:
@ -44,10 +45,12 @@ class TaskConvert(CalibreTask):
if not os.path.exists(os.path.join(config.config_calibre_dir, cur_book.path)): 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)) os.makedirs(os.path.join(config.config_calibre_dir, cur_book.path))
df.GetContentFile(datafile) df.GetContentFile(datafile)
worker_db.session.close()
else: else:
error_message = _(u"%(format)s not found on Google Drive: %(fn)s", error_message = _(u"%(format)s not found on Google Drive: %(fn)s",
format=self.settings['old_book_format'], format=self.settings['old_book_format'],
fn=data.name + "." + self.settings['old_book_format'].lower()) fn=data.name + "." + self.settings['old_book_format'].lower())
worker_db.session.close()
return error_message return error_message
filename = self._convert_ebook_format() filename = self._convert_ebook_format()
@ -71,7 +74,7 @@ class TaskConvert(CalibreTask):
def _convert_ebook_format(self): def _convert_ebook_format(self):
error_message = None error_message = None
local_session = db.CalibreDB().session local_db = db.CalibreDB(expire_on_commit=False)
file_path = self.file_path file_path = self.file_path
book_id = self.bookid book_id = self.bookid
format_old_ext = u'.' + self.settings['old_book_format'].lower() 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 # this will allow send to kindle workflow to continue to work
if os.path.isfile(file_path + format_new_ext): if os.path.isfile(file_path + format_new_ext):
log.info("Book id %d already converted to %s", book_id, 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['path'] = file_path
self.results['title'] = cur_book.title self.results['title'] = cur_book.title
self._handleSuccess() self._handleSuccess()
local_db.session.close()
return os.path.basename(file_path + format_new_ext) return os.path.basename(file_path + format_new_ext)
else: else:
log.info("Book id %d - target format of %s does not exist. Moving forward with convert.", 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) check, error_message = self._convert_calibre(file_path, format_old_ext, format_new_ext)
if check == 0: 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): if os.path.isfile(file_path + format_new_ext):
# self.db_queue.join() # self.db_queue.join()
new_format = db.Data(name=cur_book.data[0].name, new_format = db.Data(name=cur_book.data[0].name,
book_format=self.settings['new_book_format'].upper(), book_format=self.settings['new_book_format'].upper(),
book=book_id, uncompressed_size=os.path.getsize(file_path + format_new_ext)) book=book_id, uncompressed_size=os.path.getsize(file_path + format_new_ext))
try: try:
local_session.merge(new_format) local_db.session.merge(new_format)
local_session.commit() local_db.session.commit()
except SQLAlchemyError as e: except SQLAlchemyError as e:
local_session.rollback() local_db.rollback()
log.error("Database error: %s", e) log.error("Database error: %s", e)
local_db.session.close()
return return
self.results['path'] = cur_book.path self.results['path'] = cur_book.path
self.results['title'] = cur_book.title self.results['title'] = cur_book.title
@ -125,6 +130,7 @@ class TaskConvert(CalibreTask):
return os.path.basename(file_path + format_new_ext) return os.path.basename(file_path + format_new_ext)
else: else:
error_message = _('%(format)s format not found on disk', format=format_new_ext.upper()) 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") log.info("ebook converter failed with error while converting book")
if not error_message: if not error_message:
error_message = _('Ebook converter failed with unknown error') error_message = _('Ebook converter failed with unknown error')

View File

@ -45,7 +45,7 @@ from sqlalchemy import Column, ForeignKey
from sqlalchemy import String, Integer, SmallInteger, Boolean, DateTime, Float, JSON from sqlalchemy import String, Integer, SmallInteger, Boolean, DateTime, Float, JSON
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.attributes import flag_modified 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 werkzeug.security import generate_password_hash
from . import constants from . import constants
@ -677,14 +677,20 @@ def update_download(book_id, user_id):
if not check: if not check:
new_download = Downloads(user_id=user_id, book_id=book_id) new_download = Downloads(user_id=user_id, book_id=book_id)
session.add(new_download) ub.session.add(new_download)
session.commit() try:
ub.session.commit()
except exc.OperationalError:
ub.session.rollback()
# Delete non exisiting downloaded books in calibre-web's own database # Delete non exisiting downloaded books in calibre-web's own database
def delete_download(book_id): def delete_download(book_id):
session.query(Downloads).filter(book_id == Downloads.book_id).delete() ub.session.query(Downloads).filter(book_id == Downloads.book_id).delete()
session.commit() try:
ub.session.commit()
except exc.OperationalError:
ub.session.rollback()
# Generate user Guest (translated text), as anonymous user, no rights # Generate user Guest (translated text), as anonymous user, no rights
def create_anonymous_user(session): def create_anonymous_user(session):
@ -725,7 +731,7 @@ def init_db(app_db_path):
app_DB_path = app_db_path app_DB_path = app_db_path
engine = create_engine(u'sqlite:///{0}'.format(app_db_path), echo=False) engine = create_engine(u'sqlite:///{0}'.format(app_db_path), echo=False)
Session = sessionmaker() Session = scoped_session(sessionmaker())
Session.configure(bind=engine) Session.configure(bind=engine)
session = Session() session = Session()

View File

@ -351,7 +351,6 @@ def import_ldap_users():
username = user_data[user_login_field][0].decode('utf-8') username = user_data[user_login_field][0].decode('utf-8')
# check for duplicate username # 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(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) log.warning("LDAP User %s Already in Database", user_data)
continue continue
@ -432,7 +431,10 @@ def bookmark(book_id, book_format):
ub.Bookmark.book_id == book_id, ub.Bookmark.book_id == book_id,
ub.Bookmark.format == book_format)).delete() ub.Bookmark.format == book_format)).delete()
if not bookmark_key: if not bookmark_key:
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return "", 204 return "", 204
lbookmark = ub.Bookmark(user_id=current_user.id, lbookmark = ub.Bookmark(user_id=current_user.id,
@ -440,7 +442,10 @@ def bookmark(book_id, book_format):
format=book_format, format=book_format,
bookmark_key=bookmark_key) bookmark_key=bookmark_key)
ub.session.merge(lbookmark) ub.session.merge(lbookmark)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return "", 201 return "", 201
@ -465,7 +470,10 @@ def toggle_read(book_id):
kobo_reading_state.statistics = ub.KoboStatistics() kobo_reading_state.statistics = ub.KoboStatistics()
book.kobo_reading_state = kobo_reading_state book.kobo_reading_state = kobo_reading_state
ub.session.merge(book) ub.session.merge(book)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
else: else:
try: try:
calibre_db.update_title_sort(config) 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 = ub.ArchivedBook(user_id=current_user.id, book_id=book_id)
archived_book.is_archived = True archived_book.is_archived = True
ub.session.merge(archived_book) ub.session.merge(archived_book)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
return "" return ""
@ -749,8 +760,6 @@ def render_hot_books(page):
entries.append(downloadBook) entries.append(downloadBook)
else: else:
ub.delete_download(book.Downloads.book_id) 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__() numBooks = entries.__len__()
pagination = Pagination(page, config.config_books_per_page, numBooks) pagination = Pagination(page, config.config_books_per_page, numBooks)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
@ -1086,11 +1095,12 @@ def update_table_settings():
except AttributeError: except AttributeError:
pass pass
ub.session.commit() ub.session.commit()
except InvalidRequestError: except (InvalidRequestError, OperationalError):
log.error("Invalid request received: %r ", request, ) log.error("Invalid request received: %r ", request, )
return "Invalid request", 400 return "Invalid request", 400
return "" return ""
@web.route("/author") @web.route("/author")
@login_required_if_no_ano @login_required_if_no_ano
def author_list(): def author_list():
@ -1676,7 +1686,10 @@ def logout():
def remote_login(): def remote_login():
auth_token = ub.RemoteAuthToken() auth_token = ub.RemoteAuthToken()
ub.session.add(auth_token) 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) 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) 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 # Update token with user information
auth_token.user_id = current_user.id auth_token.user_id = current_user.id
auth_token.verified = True 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") flash(_(u"Success! Please return to your device"), category="success")
log.debug(u"Remote Login token for userid %s verified", auth_token.user_id) log.debug(u"Remote Login token for userid %s verified", auth_token.user_id)
@ -1731,7 +1747,10 @@ def token_verified():
# Token expired # Token expired
elif datetime.now() > auth_token.expiration: elif datetime.now() > auth_token.expiration:
ub.session.delete(auth_token) ub.session.delete(auth_token)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
data['status'] = 'error' data['status'] = 'error'
data['message'] = _(u"Token has expired") data['message'] = _(u"Token has expired")
@ -1744,7 +1763,10 @@ def token_verified():
login_user(user) login_user(user)
ub.session.delete(auth_token) ub.session.delete(auth_token)
ub.session.commit() try:
ub.session.commit()
except OperationalError:
ub.session.rollback()
data['status'] = 'success' data['status'] = 'success'
log.debug(u"Remote Login for userid %s succeded", user.id) log.debug(u"Remote Login for userid %s succeded", user.id)
@ -1836,14 +1858,11 @@ def profile():
ub.session.rollback() ub.session.rollback()
flash(_(u"Found an existing account for this e-mail address."), category="error") 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.") log.debug(u"Found an existing account for this e-mail address.")
'''return render_title_template("user_edit.html", except OperationalError as e:
content=current_user, ub.session.rollback()
translations=translations, log.error("Database error: %s", e)
kobo_support=kobo_support, flash(_(u"Database error: %(error)s.", error=e), category="error")
title=_(u"%(name)s's profile", name=current_user.nickname),
page="me",
registered_oauth=local_oauth_check,
oauth_status=oauth_status)'''
return render_title_template("user_edit.html", return render_title_template("user_edit.html",
translations=translations, translations=translations,
profile=1, profile=1,

File diff suppressed because it is too large Load Diff