Some code cosmetics
This commit is contained in:
parent
e4e27662f5
commit
725fc658f8
70
cps/comic.py
70
cps/comic.py
|
@ -74,6 +74,41 @@ def _cover_processing(tmp_file_name, img, extension):
|
|||
return tmp_cover_name
|
||||
|
||||
|
||||
def _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable):
|
||||
cover_data = None
|
||||
if original_file_extension.upper() == '.CBZ':
|
||||
cf = zipfile.ZipFile(tmp_file_name)
|
||||
for name in cf.namelist():
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
if extension in COVER_EXTENSIONS:
|
||||
cover_data = cf.read(name)
|
||||
break
|
||||
elif original_file_extension.upper() == '.CBT':
|
||||
cf = tarfile.TarFile(tmp_file_name)
|
||||
for name in cf.getnames():
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
if extension in COVER_EXTENSIONS:
|
||||
cover_data = cf.extractfile(name).read()
|
||||
break
|
||||
elif original_file_extension.upper() == '.CBR' and use_rarfile:
|
||||
try:
|
||||
rarfile.UNRAR_TOOL = rarExecutable
|
||||
cf = rarfile.RarFile(tmp_file_name)
|
||||
for name in cf.getnames():
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
if extension in COVER_EXTENSIONS:
|
||||
cover_data = cf.read(name)
|
||||
break
|
||||
except Exception as e:
|
||||
log.debug('Rarfile failed with error: %s', e)
|
||||
return cover_data
|
||||
|
||||
|
||||
def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
|
||||
cover_data = extension = None
|
||||
|
@ -87,37 +122,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
|
|||
cover_data = archive.getPage(index)
|
||||
break
|
||||
else:
|
||||
if original_file_extension.upper() == '.CBZ':
|
||||
cf = zipfile.ZipFile(tmp_file_name)
|
||||
for name in cf.namelist():
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
if extension in COVER_EXTENSIONS:
|
||||
cover_data = cf.read(name)
|
||||
break
|
||||
elif original_file_extension.upper() == '.CBT':
|
||||
cf = tarfile.TarFile(tmp_file_name)
|
||||
for name in cf.getnames():
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
if extension in COVER_EXTENSIONS:
|
||||
cover_data = cf.extractfile(name).read()
|
||||
break
|
||||
elif original_file_extension.upper() == '.CBR' and use_rarfile:
|
||||
try:
|
||||
rarfile.UNRAR_TOOL = rarExecutable
|
||||
cf = rarfile.RarFile(tmp_file_name)
|
||||
for name in cf.getnames():
|
||||
ext = os.path.splitext(name)
|
||||
if len(ext) > 1:
|
||||
extension = ext[1].lower()
|
||||
if extension in COVER_EXTENSIONS:
|
||||
cover_data = cf.read(name)
|
||||
break
|
||||
except Exception as e:
|
||||
log.debug('Rarfile failed with error: %s', e)
|
||||
cover_data = _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable)
|
||||
return _cover_processing(tmp_file_name, cover_data, extension)
|
||||
|
||||
|
||||
|
@ -142,7 +147,8 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension, r
|
|||
file_path=tmp_file_path,
|
||||
extension=original_file_extension,
|
||||
title=loadedMetadata.title or original_file_name,
|
||||
author=" & ".join([credit["person"] for credit in loadedMetadata.credits if credit["role"] == "Writer"]) or u'Unknown',
|
||||
author=" & ".join([credit["person"]
|
||||
for credit in loadedMetadata.credits if credit["role"] == "Writer"]) or u'Unknown',
|
||||
cover=_extractCover(tmp_file_path, original_file_extension, rarExecutable),
|
||||
description=loadedMetadata.comments or "",
|
||||
tags="",
|
||||
|
|
|
@ -146,15 +146,16 @@ class _ConfigSQL(object):
|
|||
self.load()
|
||||
|
||||
change = False
|
||||
if self.config_converterpath == None:
|
||||
if self.config_converterpath == None: # pylint: disable=access-member-before-definition
|
||||
change = True
|
||||
self.config_converterpath = autodetect_calibre_binary()
|
||||
|
||||
if self.config_kepubifypath == None:
|
||||
if self.config_kepubifypath == None: # pylint: disable=access-member-before-definition
|
||||
|
||||
change = True
|
||||
self.config_kepubifypath = autodetect_kepubify_binary()
|
||||
|
||||
if self.config_rarfile_location == None:
|
||||
if self.config_rarfile_location == None: # pylint: disable=access-member-before-definition
|
||||
change = True
|
||||
self.config_rarfile_location = autodetect_unrar_binary()
|
||||
if change:
|
||||
|
@ -181,7 +182,8 @@ class _ConfigSQL(object):
|
|||
return None
|
||||
return self.config_keyfile
|
||||
|
||||
def get_config_ipaddress(self):
|
||||
@staticmethod
|
||||
def get_config_ipaddress():
|
||||
return cli.ipadress or ""
|
||||
|
||||
def _has_role(self, role_flag):
|
||||
|
@ -299,6 +301,7 @@ class _ConfigSQL(object):
|
|||
have_metadata_db = os.path.isfile(db_file)
|
||||
self.db_configured = have_metadata_db
|
||||
constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip().lower() for x in self.config_upload_formats.split(',')]
|
||||
# pylint: disable=access-member-before-definition
|
||||
logfile = logger.setup(self.config_logfile, self.config_log_level)
|
||||
if logfile != self.config_logfile:
|
||||
log.warning("Log path %s not valid, falling back to default", self.config_logfile)
|
||||
|
|
|
@ -104,7 +104,7 @@ LDAP_AUTH_SIMPLE = 0
|
|||
|
||||
DEFAULT_MAIL_SERVER = "mail.example.org"
|
||||
|
||||
DEFAULT_PASSWORD = "admin123"
|
||||
DEFAULT_PASSWORD = "admin123" # nosec # noqa
|
||||
DEFAULT_PORT = 8083
|
||||
env_CALIBRE_PORT = os.environ.get("CALIBRE_PORT", DEFAULT_PORT)
|
||||
try:
|
||||
|
|
104
cps/helper.py
104
cps/helper.py
|
@ -134,63 +134,71 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False):
|
|||
taskMessage=_(u"Registration e-mail for user: %(name)s", name=user_name),
|
||||
text=txt
|
||||
))
|
||||
|
||||
return
|
||||
|
||||
|
||||
def check_send_to_kindle_without_converter(entry):
|
||||
bookformats = list()
|
||||
# no converter - only for mobi and pdf formats
|
||||
for ele in iter(entry.data):
|
||||
if ele.uncompressed_size < config.mail_size:
|
||||
if 'MOBI' in ele.format:
|
||||
bookformats.append({'format': 'Mobi',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Mobi')})
|
||||
if 'PDF' in ele.format:
|
||||
bookformats.append({'format': 'Pdf',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Pdf')})
|
||||
if 'AZW' in ele.format:
|
||||
bookformats.append({'format': 'Azw',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Azw')})
|
||||
return bookformats
|
||||
|
||||
def check_send_to_kindle_with_converter(entry):
|
||||
bookformats = list()
|
||||
formats = list()
|
||||
for ele in iter(entry.data):
|
||||
if ele.uncompressed_size < config.mail_size:
|
||||
formats.append(ele.format)
|
||||
if 'MOBI' in formats:
|
||||
bookformats.append({'format': 'Mobi',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Mobi')})
|
||||
if 'AZW' in formats:
|
||||
bookformats.append({'format': 'Azw',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Azw')})
|
||||
if 'PDF' in formats:
|
||||
bookformats.append({'format': 'Pdf',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Pdf')})
|
||||
if 'EPUB' in formats and 'MOBI' not in formats:
|
||||
bookformats.append({'format': 'Mobi',
|
||||
'convert': 1,
|
||||
'text': _('Convert %(orig)s to %(format)s and send to Kindle',
|
||||
orig='Epub',
|
||||
format='Mobi')})
|
||||
if 'AZW3' in formats and not 'MOBI' in formats:
|
||||
bookformats.append({'format': 'Mobi',
|
||||
'convert': 2,
|
||||
'text': _('Convert %(orig)s to %(format)s and send to Kindle',
|
||||
orig='Azw3',
|
||||
format='Mobi')})
|
||||
return bookformats
|
||||
|
||||
|
||||
def check_send_to_kindle(entry):
|
||||
"""
|
||||
returns all available book formats for sending to Kindle
|
||||
"""
|
||||
if len(entry.data):
|
||||
bookformats = list()
|
||||
if not config.config_converterpath:
|
||||
# no converter - only for mobi and pdf formats
|
||||
for ele in iter(entry.data):
|
||||
if ele.uncompressed_size < config.mail_size:
|
||||
if 'MOBI' in ele.format:
|
||||
bookformats.append({'format': 'Mobi',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Mobi')})
|
||||
if 'PDF' in ele.format:
|
||||
bookformats.append({'format': 'Pdf',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Pdf')})
|
||||
if 'AZW' in ele.format:
|
||||
bookformats.append({'format': 'Azw',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Azw')})
|
||||
book_formats = check_send_to_kindle_with_converter(entry)
|
||||
else:
|
||||
formats = list()
|
||||
for ele in iter(entry.data):
|
||||
if ele.uncompressed_size < config.mail_size:
|
||||
formats.append(ele.format)
|
||||
if 'MOBI' in formats:
|
||||
bookformats.append({'format': 'Mobi',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Mobi')})
|
||||
if 'AZW' in formats:
|
||||
bookformats.append({'format': 'Azw',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Azw')})
|
||||
if 'PDF' in formats:
|
||||
bookformats.append({'format': 'Pdf',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to Kindle', format='Pdf')})
|
||||
if config.config_converterpath:
|
||||
if 'EPUB' in formats and 'MOBI' not in formats:
|
||||
bookformats.append({'format': 'Mobi',
|
||||
'convert':1,
|
||||
'text': _('Convert %(orig)s to %(format)s and send to Kindle',
|
||||
orig='Epub',
|
||||
format='Mobi')})
|
||||
if 'AZW3' in formats and not 'MOBI' in formats:
|
||||
bookformats.append({'format': 'Mobi',
|
||||
'convert': 2,
|
||||
'text': _('Convert %(orig)s to %(format)s and send to Kindle',
|
||||
orig='Azw3',
|
||||
format='Mobi')})
|
||||
return bookformats
|
||||
book_formats = check_send_to_kindle_with_converter(entry)
|
||||
return book_formats
|
||||
else:
|
||||
log.error(u'Cannot find book entry %d', entry.id)
|
||||
return None
|
||||
|
@ -742,7 +750,7 @@ def format_runtime(runtime):
|
|||
# helper function to apply localize status information in tasklist entries
|
||||
def render_task_status(tasklist):
|
||||
renderedtasklist = list()
|
||||
for num, user, added, task in tasklist:
|
||||
for __, user, added, task in tasklist:
|
||||
if user == current_user.nickname or current_user.role_admin():
|
||||
ret = {}
|
||||
if task.start_time:
|
||||
|
|
|
@ -71,7 +71,7 @@ def get_valid_language_codes(locale, language_names, remainder=None):
|
|||
languages = list()
|
||||
if "" in language_names:
|
||||
language_names.remove("")
|
||||
for k, v in get_language_names(locale).items():
|
||||
for k, __ in get_language_names(locale).items():
|
||||
if k in language_names:
|
||||
languages.append(k)
|
||||
language_names.remove(k)
|
||||
|
|
238
cps/oauth.py
238
cps/oauth.py
|
@ -19,7 +19,6 @@
|
|||
from __future__ import division, print_function, unicode_literals
|
||||
from flask import session
|
||||
|
||||
|
||||
try:
|
||||
from flask_dance.consumer.backend.sqla import SQLAlchemyBackend, first, _get_real_user
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
@ -34,134 +33,131 @@ except ImportError:
|
|||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
class OAuthBackend(SQLAlchemyBackend):
|
||||
"""
|
||||
Stores and retrieves OAuth tokens using a relational database through
|
||||
the `SQLAlchemy`_ ORM.
|
||||
|
||||
.. _SQLAlchemy: https://www.sqlalchemy.org/
|
||||
"""
|
||||
def __init__(self, model, session, provider_id,
|
||||
user=None, user_id=None, user_required=None, anon_user=None,
|
||||
cache=None):
|
||||
self.provider_id = provider_id
|
||||
super(OAuthBackend, self).__init__(model, session, user, user_id, user_required, anon_user, cache)
|
||||
class OAuthBackend(SQLAlchemyBackend):
|
||||
"""
|
||||
Stores and retrieves OAuth tokens using a relational database through
|
||||
the `SQLAlchemy`_ ORM.
|
||||
|
||||
def get(self, blueprint, user=None, user_id=None):
|
||||
if self.provider_id + '_oauth_token' in session and session[self.provider_id + '_oauth_token'] != '':
|
||||
return session[self.provider_id + '_oauth_token']
|
||||
# check cache
|
||||
cache_key = self.make_cache_key(blueprint=blueprint, user=user, user_id=user_id)
|
||||
token = self.cache.get(cache_key)
|
||||
if token:
|
||||
return token
|
||||
|
||||
# if not cached, make database queries
|
||||
query = (
|
||||
self.session.query(self.model)
|
||||
.filter_by(provider=self.provider_id)
|
||||
)
|
||||
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
|
||||
u = first(_get_real_user(ref, self.anon_user)
|
||||
for ref in (user, self.user, blueprint.config.get("user")))
|
||||
|
||||
use_provider_user_id = False
|
||||
if self.provider_id + '_oauth_user_id' in session and session[self.provider_id + '_oauth_user_id'] != '':
|
||||
query = query.filter_by(provider_user_id=session[self.provider_id + '_oauth_user_id'])
|
||||
use_provider_user_id = True
|
||||
|
||||
if self.user_required and not u and not uid and not use_provider_user_id:
|
||||
# raise ValueError("Cannot get OAuth token without an associated user")
|
||||
return None
|
||||
# check for user ID
|
||||
if hasattr(self.model, "user_id") and uid:
|
||||
query = query.filter_by(user_id=uid)
|
||||
# check for user (relationship property)
|
||||
elif hasattr(self.model, "user") and u:
|
||||
query = query.filter_by(user=u)
|
||||
# if we have the property, but not value, filter by None
|
||||
elif hasattr(self.model, "user_id"):
|
||||
query = query.filter_by(user_id=None)
|
||||
# run query
|
||||
try:
|
||||
token = query.one().token
|
||||
except NoResultFound:
|
||||
token = None
|
||||
|
||||
# cache the result
|
||||
self.cache.set(cache_key, token)
|
||||
.. _SQLAlchemy: https://www.sqlalchemy.org/
|
||||
"""
|
||||
def __init__(self, model, session, provider_id,
|
||||
user=None, user_id=None, user_required=None, anon_user=None,
|
||||
cache=None):
|
||||
self.provider_id = provider_id
|
||||
super(OAuthBackend, self).__init__(model, session, user, user_id, user_required, anon_user, cache)
|
||||
|
||||
def get(self, blueprint, user=None, user_id=None):
|
||||
if self.provider_id + '_oauth_token' in session and session[self.provider_id + '_oauth_token'] != '':
|
||||
return session[self.provider_id + '_oauth_token']
|
||||
# check cache
|
||||
cache_key = self.make_cache_key(blueprint=blueprint, user=user, user_id=user_id)
|
||||
token = self.cache.get(cache_key)
|
||||
if token:
|
||||
return token
|
||||
|
||||
def set(self, blueprint, token, user=None, user_id=None):
|
||||
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
|
||||
u = first(_get_real_user(ref, self.anon_user)
|
||||
for ref in (user, self.user, blueprint.config.get("user")))
|
||||
# if not cached, make database queries
|
||||
query = (
|
||||
self.session.query(self.model)
|
||||
.filter_by(provider=self.provider_id)
|
||||
)
|
||||
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
|
||||
u = first(_get_real_user(ref, self.anon_user)
|
||||
for ref in (user, self.user, blueprint.config.get("user")))
|
||||
|
||||
if self.user_required and not u and not uid:
|
||||
raise ValueError("Cannot set OAuth token without an associated user")
|
||||
use_provider_user_id = False
|
||||
if self.provider_id + '_oauth_user_id' in session and session[self.provider_id + '_oauth_user_id'] != '':
|
||||
query = query.filter_by(provider_user_id=session[self.provider_id + '_oauth_user_id'])
|
||||
use_provider_user_id = True
|
||||
|
||||
# if there was an existing model, delete it
|
||||
existing_query = (
|
||||
self.session.query(self.model)
|
||||
.filter_by(provider=self.provider_id)
|
||||
)
|
||||
# check for user ID
|
||||
has_user_id = hasattr(self.model, "user_id")
|
||||
if has_user_id and uid:
|
||||
existing_query = existing_query.filter_by(user_id=uid)
|
||||
# check for user (relationship property)
|
||||
has_user = hasattr(self.model, "user")
|
||||
if has_user and u:
|
||||
existing_query = existing_query.filter_by(user=u)
|
||||
# queue up delete query -- won't be run until commit()
|
||||
existing_query.delete()
|
||||
# create a new model for this token
|
||||
kwargs = {
|
||||
"provider": self.provider_id,
|
||||
"token": token,
|
||||
}
|
||||
if has_user_id and uid:
|
||||
kwargs["user_id"] = uid
|
||||
if has_user and u:
|
||||
kwargs["user"] = u
|
||||
self.session.add(self.model(**kwargs))
|
||||
# commit to delete and add simultaneously
|
||||
self.session.commit()
|
||||
# invalidate cache
|
||||
self.cache.delete(self.make_cache_key(
|
||||
blueprint=blueprint, user=user, user_id=user_id
|
||||
))
|
||||
if self.user_required and not u and not uid and not use_provider_user_id:
|
||||
# raise ValueError("Cannot get OAuth token without an associated user")
|
||||
return None
|
||||
# check for user ID
|
||||
if hasattr(self.model, "user_id") and uid:
|
||||
query = query.filter_by(user_id=uid)
|
||||
# check for user (relationship property)
|
||||
elif hasattr(self.model, "user") and u:
|
||||
query = query.filter_by(user=u)
|
||||
# if we have the property, but not value, filter by None
|
||||
elif hasattr(self.model, "user_id"):
|
||||
query = query.filter_by(user_id=None)
|
||||
# run query
|
||||
try:
|
||||
token = query.one().token
|
||||
except NoResultFound:
|
||||
token = None
|
||||
|
||||
def delete(self, blueprint, user=None, user_id=None):
|
||||
query = (
|
||||
self.session.query(self.model)
|
||||
.filter_by(provider=self.provider_id)
|
||||
)
|
||||
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
|
||||
u = first(_get_real_user(ref, self.anon_user)
|
||||
for ref in (user, self.user, blueprint.config.get("user")))
|
||||
# cache the result
|
||||
self.cache.set(cache_key, token)
|
||||
|
||||
if self.user_required and not u and not uid:
|
||||
raise ValueError("Cannot delete OAuth token without an associated user")
|
||||
return token
|
||||
|
||||
# check for user ID
|
||||
if hasattr(self.model, "user_id") and uid:
|
||||
query = query.filter_by(user_id=uid)
|
||||
# check for user (relationship property)
|
||||
elif hasattr(self.model, "user") and u:
|
||||
query = query.filter_by(user=u)
|
||||
# if we have the property, but not value, filter by None
|
||||
elif hasattr(self.model, "user_id"):
|
||||
query = query.filter_by(user_id=None)
|
||||
# run query
|
||||
query.delete()
|
||||
self.session.commit()
|
||||
# invalidate cache
|
||||
self.cache.delete(self.make_cache_key(
|
||||
blueprint=blueprint, user=user, user_id=user_id,
|
||||
))
|
||||
def set(self, blueprint, token, user=None, user_id=None):
|
||||
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
|
||||
u = first(_get_real_user(ref, self.anon_user)
|
||||
for ref in (user, self.user, blueprint.config.get("user")))
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
if self.user_required and not u and not uid:
|
||||
raise ValueError("Cannot set OAuth token without an associated user")
|
||||
|
||||
# if there was an existing model, delete it
|
||||
existing_query = (
|
||||
self.session.query(self.model)
|
||||
.filter_by(provider=self.provider_id)
|
||||
)
|
||||
# check for user ID
|
||||
has_user_id = hasattr(self.model, "user_id")
|
||||
if has_user_id and uid:
|
||||
existing_query = existing_query.filter_by(user_id=uid)
|
||||
# check for user (relationship property)
|
||||
has_user = hasattr(self.model, "user")
|
||||
if has_user and u:
|
||||
existing_query = existing_query.filter_by(user=u)
|
||||
# queue up delete query -- won't be run until commit()
|
||||
existing_query.delete()
|
||||
# create a new model for this token
|
||||
kwargs = {
|
||||
"provider": self.provider_id,
|
||||
"token": token,
|
||||
}
|
||||
if has_user_id and uid:
|
||||
kwargs["user_id"] = uid
|
||||
if has_user and u:
|
||||
kwargs["user"] = u
|
||||
self.session.add(self.model(**kwargs))
|
||||
# commit to delete and add simultaneously
|
||||
self.session.commit()
|
||||
# invalidate cache
|
||||
self.cache.delete(self.make_cache_key(
|
||||
blueprint=blueprint, user=user, user_id=user_id
|
||||
))
|
||||
|
||||
def delete(self, blueprint, user=None, user_id=None):
|
||||
query = (
|
||||
self.session.query(self.model)
|
||||
.filter_by(provider=self.provider_id)
|
||||
)
|
||||
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
|
||||
u = first(_get_real_user(ref, self.anon_user)
|
||||
for ref in (user, self.user, blueprint.config.get("user")))
|
||||
|
||||
if self.user_required and not u and not uid:
|
||||
raise ValueError("Cannot delete OAuth token without an associated user")
|
||||
|
||||
# check for user ID
|
||||
if hasattr(self.model, "user_id") and uid:
|
||||
query = query.filter_by(user_id=uid)
|
||||
# check for user (relationship property)
|
||||
elif hasattr(self.model, "user") and u:
|
||||
query = query.filter_by(user=u)
|
||||
# if we have the property, but not value, filter by None
|
||||
elif hasattr(self.model, "user_id"):
|
||||
query = query.filter_by(user_id=None)
|
||||
# run query
|
||||
query.delete()
|
||||
self.session.commit()
|
||||
# invalidate cache
|
||||
self.cache.delete(self.make_cache_key(
|
||||
blueprint=blueprint, user=user, user_id=user_id,
|
||||
))
|
||||
|
|
|
@ -35,7 +35,10 @@ from sqlalchemy.orm.exc import NoResultFound
|
|||
|
||||
from . import constants, logger, config, app, ub
|
||||
|
||||
from .oauth import OAuthBackend, backend_resultcode
|
||||
try:
|
||||
from .oauth import OAuthBackend, backend_resultcode
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
|
||||
oauth_check = {}
|
||||
|
|
|
@ -137,7 +137,7 @@ class WebServer(object):
|
|||
|
||||
return sock, _readable_listen_address(*address)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _get_args_for_reloading(self):
|
||||
"""Determine how the script was executed, and return the args needed
|
||||
to execute it again in a new process.
|
||||
|
|
|
@ -64,7 +64,7 @@ class SyncToken:
|
|||
books_last_modified: Datetime representing the last modified book that the device knows about.
|
||||
"""
|
||||
|
||||
SYNC_TOKEN_HEADER = "x-kobo-synctoken"
|
||||
SYNC_TOKEN_HEADER = "x-kobo-synctoken" # nosec
|
||||
VERSION = "1-1-0"
|
||||
LAST_MODIFIED_ADDED_VERSION = "1-1-0"
|
||||
MIN_VERSION = "1-0-0"
|
||||
|
@ -91,7 +91,7 @@ class SyncToken:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
raw_kobo_store_token="",
|
||||
raw_kobo_store_token="", # nosec
|
||||
books_last_created=datetime.min,
|
||||
books_last_modified=datetime.min,
|
||||
archive_last_modified=datetime.min,
|
||||
|
@ -110,7 +110,7 @@ class SyncToken:
|
|||
@staticmethod
|
||||
def from_headers(headers):
|
||||
sync_token_header = headers.get(SyncToken.SYNC_TOKEN_HEADER, "")
|
||||
if sync_token_header == "":
|
||||
if sync_token_header == "": # nosec
|
||||
return SyncToken()
|
||||
|
||||
# On the first sync from a Kobo device, we may receive the SyncToken
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{
|
||||
display: none;
|
||||
}
|
||||
.cover .badge{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
color: #fff;
|
||||
background-color: #cc7b19;
|
||||
border-radius: 0;
|
||||
padding: 0 8px;
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.6);
|
||||
line-height: 24px;
|
||||
}
|
||||
.cover{
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.6);
|
||||
body.serieslist.grid-view div.container-fluid > div > div.col-sm-10:before{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cover .read{
|
||||
padding: 0 0px;
|
||||
line-height: 15px;
|
||||
.cover .badge{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
color: #fff;
|
||||
background-color: #cc7b19;
|
||||
border-radius: 0;
|
||||
padding: 0 8px;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, .6);
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.cover {
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, .6);
|
||||
}
|
||||
|
||||
.cover .read {
|
||||
padding: 0px 0px;
|
||||
line-height: 15px;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ body {
|
|||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
|
@ -45,7 +44,7 @@ body {
|
|||
|
||||
#sidebar a.active,
|
||||
#sidebar a.active img + span {
|
||||
background-color: #45B29D;
|
||||
background-color: #45b29d;
|
||||
}
|
||||
|
||||
#sidebar li img {
|
||||
|
@ -99,7 +98,7 @@ body {
|
|||
background-color: #ccc;
|
||||
}
|
||||
|
||||
#progress .bar-read {
|
||||
#progress .bar-read {
|
||||
color: #fff;
|
||||
background-color: #45b29d;
|
||||
}
|
||||
|
|
|
@ -490,7 +490,6 @@ input:-moz-placeholder { color: #454545; }
|
|||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
// width: 50%;
|
||||
width: 630px;
|
||||
height: auto;
|
||||
z-index: 2000;
|
||||
|
@ -593,7 +592,6 @@ input:-moz-placeholder { color: #454545; }
|
|||
}
|
||||
|
||||
.md-content > .closer {
|
||||
//font-size: 18px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
.tooltip.bottom .tooltip-inner {
|
||||
font-size: 13px;
|
||||
font-family: Open Sans Semibold,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
font-family: Open Sans Semibold, Helvetica Neue, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
padding: 3px 10px;
|
||||
|
@ -48,25 +48,25 @@ body {
|
|||
|
||||
body h2 {
|
||||
font-weight: normal;
|
||||
color:#444;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d; }
|
||||
a, .danger, .book-remove, .editable-empty, .editable-empty:hover { color: #45b29d; }
|
||||
|
||||
.book-remove:hover { color: #23527c; }
|
||||
|
||||
.btn-default a { color: #444; }
|
||||
|
||||
.btn-default a:hover {
|
||||
color: #45b29d;
|
||||
text-decoration: None;
|
||||
color: #45b29d;
|
||||
text-decoration: None;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: #45b29d;
|
||||
color: #45b29d;
|
||||
}
|
||||
|
||||
.editable-click, a.editable-click, a.editable-click:hover { border-bottom: None; }
|
||||
.editable-click, a.editable-click, a.editable-click:hover { border-bottom: None; }
|
||||
|
||||
.navigation .nav-head {
|
||||
text-transform: uppercase;
|
||||
|
@ -119,7 +119,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
|
|||
max-height: 100%;
|
||||
}
|
||||
|
||||
.container-fluid .discover{ margin-bottom: 50px; }
|
||||
.container-fluid .discover { margin-bottom: 50px; }
|
||||
.container-fluid .new-books { border-top: 1px solid #ccc; }
|
||||
.container-fluid .new-books h2 { margin: 50px 0 0 0; }
|
||||
.container-fluid .book {
|
||||
|
@ -174,9 +174,10 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
|
|||
.container-fluid .book .meta .rating { margin-top: 5px; }
|
||||
.rating .glyphicon-star-empty { color: #444; }
|
||||
.rating .glyphicon-star.good { color: #444; }
|
||||
.rating-clear .glyphicon-remove { color: #333 }
|
||||
.rating-clear .glyphicon-remove { color: #333; }
|
||||
|
||||
.container-fluid .author .author-hidden, .container-fluid .author .author-hidden-divider { display: none; }
|
||||
.container-fluid .author .author-hidden,
|
||||
.container-fluid .author .author-hidden-divider { display: none; }
|
||||
|
||||
.navbar-brand {
|
||||
font-family: 'Grand Hotel', cursive;
|
||||
|
@ -190,7 +191,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
|
|||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.more-stuff>li { margin-bottom: 10px; }
|
||||
.more-stuff > li { margin-bottom: 10px; }
|
||||
.navbar-collapse.in .navbar-nav { margin: 0; }
|
||||
|
||||
span.glyphicon.glyphicon-tags {
|
||||
|
@ -211,17 +212,17 @@ span.glyphicon.glyphicon-tags {
|
|||
box-shadow: 0 5px 8px -6px #777;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle .icon-bar {background-color: #000; }
|
||||
.navbar-default .navbar-toggle {border-color: #000; }
|
||||
.navbar-default .navbar-toggle .icon-bar { background-color: #000; }
|
||||
.navbar-default .navbar-toggle { border-color: #000; }
|
||||
.cover { margin-bottom: 10px; }
|
||||
|
||||
.cover .badge{
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
color: #000;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
color: #000;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.cover .read{
|
||||
left: auto;
|
||||
|
@ -231,14 +232,14 @@ span.glyphicon.glyphicon-tags {
|
|||
display: inline-block;
|
||||
padding: 2px;
|
||||
}
|
||||
.cover-height { max-height: 100px;}
|
||||
.cover-height { max-height: 100px; }
|
||||
|
||||
.col-sm-2 a .cover-small {
|
||||
margin: 5px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.btn-file {position: relative; overflow: hidden;}
|
||||
.btn-file { position: relative; overflow: hidden; }
|
||||
|
||||
.btn-file input[type=file] {
|
||||
position: absolute;
|
||||
|
@ -256,22 +257,42 @@ span.glyphicon.glyphicon-tags {
|
|||
display: block;
|
||||
}
|
||||
|
||||
.btn-toolbar .btn,.discover .btn { margin-bottom: 5px; }
|
||||
.button-link {color: #fff; }
|
||||
.btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary{ background-color: #1C5484; }
|
||||
.btn-primary.disabled, .btn-primary[disabled], fieldset[disabled] .btn-primary, .btn-primary.disabled:hover, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary:hover, .btn-primary.disabled:focus, .btn-primary[disabled]:focus, fieldset[disabled] .btn-primary:focus, .btn-primary.disabled:active, .btn-primary[disabled]:active, fieldset[disabled] .btn-primary:active, .btn-primary.disabled.active, .btn-primary[disabled].active, fieldset[disabled] .btn-primary.active { background-color: #89B9E2; }
|
||||
.btn-toolbar>.btn+.btn, .btn-toolbar>.btn-group+.btn, .btn-toolbar>.btn+.btn-group, .btn-toolbar>.btn-group+.btn-group { margin-left: 0; }
|
||||
.panel-body {background-color: #f5f5f5; }
|
||||
.spinner {margin: 0 41%; }
|
||||
.spinner2 {margin: 0 41%; }
|
||||
.btn-toolbar .btn,
|
||||
.discover .btn { margin-bottom: 5px; }
|
||||
.button-link { color: #fff; }
|
||||
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus,
|
||||
.btn-primary:active,
|
||||
.btn-primary.active,
|
||||
.open .dropdown-toggle.btn-primary { background-color: #1c5484; }
|
||||
|
||||
.btn-primary.disabled,
|
||||
.btn-primary[disabled],
|
||||
fieldset[disabled] .btn-primary,
|
||||
.btn-primary.disabled:hover,
|
||||
.btn-primary[disabled]:hover,
|
||||
fieldset[disabled] .btn-primary:hover,
|
||||
.btn-primary.disabled:focus,
|
||||
.btn-primary[disabled]:focus,
|
||||
fieldset[disabled] .btn-primary:focus, .btn-primary.disabled:active, .btn-primary[disabled]:active, fieldset[disabled] .btn-primary:active, .btn-primary.disabled.active, .btn-primary[disabled].active, fieldset[disabled] .btn-primary.active { background-color: #89B9E2; }
|
||||
|
||||
.btn-toolbar > .btn+.btn,
|
||||
.btn-toolbar > .btn-group+.btn,
|
||||
.btn-toolbar > .btn+.btn-group,
|
||||
.btn-toolbar > .btn-group+.btn-group { margin-left: 0; }
|
||||
|
||||
.panel-body { background-color: #f5f5f5; }
|
||||
.spinner { margin: 0 41%; }
|
||||
.spinner2 { margin: 0 41%; }
|
||||
.intend-form { margin-left:20px; }
|
||||
table .bg-dark-danger {background-color: #d9534f; color: #fff; }
|
||||
table .bg-dark-danger a {color: #fff; }
|
||||
table .bg-dark-danger:hover {background-color: #c9302c; }
|
||||
table .bg-primary:hover {background-color: #1C5484; }
|
||||
table .bg-primary a {color: #fff; }
|
||||
.block-label {display: block;}
|
||||
.fake-input {position: absolute; pointer-events: none; top: 0; }
|
||||
table .bg-dark-danger { background-color: #d9534f; color: #fff; }
|
||||
table .bg-dark-danger a { color: #fff; }
|
||||
table .bg-dark-danger:hover { background-color: #c9302c; }
|
||||
table .bg-primary:hover { background-color: #1c5484; }
|
||||
table .bg-primary a { color: #fff; }
|
||||
.block-label { display: block; }
|
||||
.fake-input { position: absolute; pointer-events: none; top: 0; }
|
||||
|
||||
input.pill { position: absolute; opacity: 0; }
|
||||
|
||||
|
|
|
@ -677,7 +677,7 @@ $(".navbar-collapse.collapse.in").before('<div class="sidebar-backdrop"></div>')
|
|||
// Get rid of leading white space
|
||||
recentlyAdded = $("#nav_new a:contains('Recently')").text().trim();
|
||||
$("#nav_new a:contains('Recently')").contents().filter(function () {
|
||||
return this.nodeType == 3
|
||||
return this.nodeType === 3
|
||||
}).each(function () {
|
||||
this.textContent = this.textContent.replace(" Recently Added", recentlyAdded);
|
||||
});
|
||||
|
|
|
@ -88,7 +88,7 @@ $("#desc").click(function() {
|
|||
// Find count of middle element
|
||||
var count = $(".row:visible").length;
|
||||
if (count > 20) {
|
||||
middle = parseInt(count / 2) + (count % 2);
|
||||
middle = parseInt(count / 2, 10) + (count % 2);
|
||||
|
||||
//var middle = parseInt(count / 2) + (count % 2);
|
||||
// search for the middle of all visible elements
|
||||
|
@ -135,7 +135,7 @@ $("#asc").click(function() {
|
|||
// Find count of middle element
|
||||
var count = $(".row:visible").length;
|
||||
if (count > 20) {
|
||||
var middle = parseInt(count / 2) + (count % 2);
|
||||
var middle = parseInt(count / 2, 10) + (count % 2);
|
||||
|
||||
//var middle = parseInt(count / 2) + (count % 2);
|
||||
// search for the middle of all visible elements
|
||||
|
|
|
@ -38,10 +38,10 @@ $(document).on("change", "input[type=\"checkbox\"][data-control]", function () {
|
|||
$(document).on("change", "select[data-control]", function() {
|
||||
var $this = $(this);
|
||||
var name = $this.data("control");
|
||||
var showOrHide = parseInt($this.val());
|
||||
var showOrHide = parseInt($this.val(), 10);
|
||||
// var showOrHideLast = $("#" + name + " option:last").val()
|
||||
for (var i = 0; i < $(this)[0].length; i++) {
|
||||
var element = parseInt($(this)[0][i].value);
|
||||
var element = parseInt($(this)[0][i].value, 10);
|
||||
if (element === showOrHide) {
|
||||
$("[data-related^=" + name + "][data-related*=-" + element + "]").show();
|
||||
} else {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
/* exported TableActions, RestrictionActions, EbookActions, responseHandler */
|
||||
/* global getPath, ConfirmDialog */
|
||||
|
||||
var selections = [];
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ class TaskUpload(CalibreTask):
|
|||
|
||||
def run(self, worker_thread):
|
||||
"""Upload task doesn't have anything to do, it's simply a way to add information to the task list"""
|
||||
pass
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
|
119
cps/ub.py
119
cps/ub.py
|
@ -138,15 +138,15 @@ class UserBase:
|
|||
mct = self.allowed_column_value or ""
|
||||
return [t.strip() for t in mct.split(",")]
|
||||
|
||||
def get_view_property(self, page, property):
|
||||
def get_view_property(self, page, prop):
|
||||
if not self.view_settings.get(page):
|
||||
return None
|
||||
return self.view_settings[page].get(property)
|
||||
return self.view_settings[page].get(prop)
|
||||
|
||||
def set_view_property(self, page, property, value):
|
||||
def set_view_property(self, page, prop, value):
|
||||
if not self.view_settings.get(page):
|
||||
self.view_settings[page] = dict()
|
||||
self.view_settings[page][property] = value
|
||||
self.view_settings[page][prop] = value
|
||||
try:
|
||||
flag_modified(self, "view_settings")
|
||||
except AttributeError:
|
||||
|
@ -437,11 +437,8 @@ class RemoteAuthToken(Base):
|
|||
return '<Token %r>' % self.id
|
||||
|
||||
|
||||
# Migrate database to current version, has to be updated after every database change. Currently migration from
|
||||
# everywhere to current should work. Migration is done by checking if relevant columns are existing, and than adding
|
||||
# rows with SQL commands
|
||||
def migrate_Database(session):
|
||||
engine = session.bind
|
||||
# Add missing tables during migration of database
|
||||
def add_missing_tables(engine, session):
|
||||
if not engine.dialect.has_table(engine.connect(), "book_read_link"):
|
||||
ReadBook.__table__.create(bind=engine)
|
||||
if not engine.dialect.has_table(engine.connect(), "bookmark"):
|
||||
|
@ -459,6 +456,10 @@ def migrate_Database(session):
|
|||
with engine.connect() as conn:
|
||||
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
||||
session.commit()
|
||||
|
||||
|
||||
# migrate all settings missing in registration table
|
||||
def migrate_registration_table(engine, session):
|
||||
try:
|
||||
session.query(exists().where(Registration.allow)).scalar()
|
||||
session.commit()
|
||||
|
@ -468,27 +469,29 @@ def migrate_Database(session):
|
|||
conn.execute("update registration set 'allow' = 1")
|
||||
session.commit()
|
||||
try:
|
||||
session.query(exists().where(RemoteAuthToken.token_type)).scalar()
|
||||
session.commit()
|
||||
except exc.OperationalError: # Database is not compatible, some columns are missing
|
||||
with engine.connect() as conn:
|
||||
conn.execute("ALTER TABLE remote_auth_token ADD column 'token_type' INTEGER DEFAULT 0")
|
||||
conn.execute("update remote_auth_token set 'token_type' = 0")
|
||||
session.commit()
|
||||
# Handle table exists, but no content
|
||||
cnt = session.query(Registration).count()
|
||||
if not cnt:
|
||||
with engine.connect() as conn:
|
||||
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
||||
session.commit()
|
||||
except exc.OperationalError: # Database is not writeable
|
||||
print('Settings database is not writeable. Exiting...')
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
# Remove login capability of user Guest
|
||||
def migrate_guest_password(engine, session):
|
||||
try:
|
||||
session.query(exists().where(ReadBook.read_status)).scalar()
|
||||
except exc.OperationalError:
|
||||
with engine.connect() as conn:
|
||||
conn.execute("ALTER TABLE book_read_link ADD column 'read_status' INTEGER DEFAULT 0")
|
||||
conn.execute("UPDATE book_read_link SET 'read_status' = 1 WHERE is_read")
|
||||
conn.execute("ALTER TABLE book_read_link ADD column 'last_modified' DATETIME")
|
||||
conn.execute("ALTER TABLE book_read_link ADD column 'last_time_started_reading' DATETIME")
|
||||
conn.execute("ALTER TABLE book_read_link ADD column 'times_started_reading' INTEGER DEFAULT 0")
|
||||
conn.execute("UPDATE user SET password='' where nickname = 'Guest' and password !=''")
|
||||
session.commit()
|
||||
test = session.query(ReadBook).filter(ReadBook.last_modified == None).all()
|
||||
for book in test:
|
||||
book.last_modified = datetime.datetime.utcnow()
|
||||
session.commit()
|
||||
except exc.OperationalError:
|
||||
print('Settings database is not writeable. Exiting...')
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
def migrate_shelfs(engine, session):
|
||||
try:
|
||||
session.query(exists().where(Shelf.uuid)).scalar()
|
||||
except exc.OperationalError:
|
||||
|
@ -504,22 +507,51 @@ def migrate_Database(session):
|
|||
for book_shelf in session.query(BookShelf).all():
|
||||
book_shelf.date_added = datetime.datetime.now()
|
||||
session.commit()
|
||||
try:
|
||||
# Handle table exists, but no content
|
||||
cnt = session.query(Registration).count()
|
||||
if not cnt:
|
||||
with engine.connect() as conn:
|
||||
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
||||
session.commit()
|
||||
except exc.OperationalError: # Database is not writeable
|
||||
print('Settings database is not writeable. Exiting...')
|
||||
sys.exit(2)
|
||||
try:
|
||||
session.query(exists().where(BookShelf.order)).scalar()
|
||||
except exc.OperationalError: # Database is not compatible, some columns are missing
|
||||
with engine.connect() as conn:
|
||||
conn.execute("ALTER TABLE book_shelf_link ADD column 'order' INTEGER DEFAULT 1")
|
||||
session.commit()
|
||||
|
||||
|
||||
def migrate_readBook(engine, session):
|
||||
try:
|
||||
session.query(exists().where(ReadBook.read_status)).scalar()
|
||||
except exc.OperationalError:
|
||||
with engine.connect() as conn:
|
||||
conn.execute("ALTER TABLE book_read_link ADD column 'read_status' INTEGER DEFAULT 0")
|
||||
conn.execute("UPDATE book_read_link SET 'read_status' = 1 WHERE is_read")
|
||||
conn.execute("ALTER TABLE book_read_link ADD column 'last_modified' DATETIME")
|
||||
conn.execute("ALTER TABLE book_read_link ADD column 'last_time_started_reading' DATETIME")
|
||||
conn.execute("ALTER TABLE book_read_link ADD column 'times_started_reading' INTEGER DEFAULT 0")
|
||||
session.commit()
|
||||
test = session.query(ReadBook).filter(ReadBook.last_modified == None).all()
|
||||
for book in test:
|
||||
book.last_modified = datetime.datetime.utcnow()
|
||||
session.commit()
|
||||
|
||||
|
||||
def migrate_remoteAuthToken(engine, session):
|
||||
try:
|
||||
session.query(exists().where(RemoteAuthToken.token_type)).scalar()
|
||||
session.commit()
|
||||
except exc.OperationalError: # Database is not compatible, some columns are missing
|
||||
with engine.connect() as conn:
|
||||
conn.execute("ALTER TABLE remote_auth_token ADD column 'token_type' INTEGER DEFAULT 0")
|
||||
conn.execute("update remote_auth_token set 'token_type' = 0")
|
||||
session.commit()
|
||||
|
||||
# Migrate database to current version, has to be updated after every database change. Currently migration from
|
||||
# everywhere to current should work. Migration is done by checking if relevant columns are existing, and than adding
|
||||
# rows with SQL commands
|
||||
def migrate_Database(session):
|
||||
engine = session.bind
|
||||
add_missing_tables(engine, session)
|
||||
migrate_registration_table(engine, session)
|
||||
migrate_readBook(engine, session)
|
||||
migrate_remoteAuthToken(engine, session)
|
||||
migrate_shelfs(engine, session)
|
||||
try:
|
||||
create = False
|
||||
session.query(exists().where(User.sidebar_view)).scalar()
|
||||
|
@ -578,8 +610,7 @@ def migrate_Database(session):
|
|||
"locale VARCHAR(2),"
|
||||
"sidebar_view INTEGER,"
|
||||
"default_language VARCHAR(3),"
|
||||
# "series_view VARCHAR(10),"
|
||||
"view_settings VARCHAR,"
|
||||
"view_settings VARCHAR,"
|
||||
"UNIQUE (nickname),"
|
||||
"UNIQUE (email))")
|
||||
conn.execute("INSERT INTO user_id(id, nickname, email, role, password, kindle_mail,locale,"
|
||||
|
@ -590,15 +621,7 @@ def migrate_Database(session):
|
|||
conn.execute("DROP TABLE user")
|
||||
conn.execute("ALTER TABLE user_id RENAME TO user")
|
||||
session.commit()
|
||||
|
||||
# Remove login capability of user Guest
|
||||
try:
|
||||
with engine.connect() as conn:
|
||||
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(2)
|
||||
migrate_guest_password(engine, session)
|
||||
|
||||
|
||||
def clean_database(session):
|
||||
|
|
|
@ -72,7 +72,7 @@ def load_user_from_request(request):
|
|||
def load_user_from_auth_header(header_val):
|
||||
if header_val.startswith('Basic '):
|
||||
header_val = header_val.replace('Basic ', '', 1)
|
||||
basic_username = basic_password = ''
|
||||
basic_username = basic_password = '' # nosec
|
||||
try:
|
||||
header_val = base64.b64decode(header_val).decode('utf-8')
|
||||
basic_username = header_val.split(':')[0]
|
||||
|
|
147
cps/web.py
147
cps/web.py
|
@ -216,7 +216,7 @@ def update_view():
|
|||
for param in to_save[element]:
|
||||
current_user.set_view_property(element, param, to_save[element][param])
|
||||
except Exception as e:
|
||||
log.error("Could not save view_settings: %r %r: e", request, to_save, e)
|
||||
log.error("Could not save view_settings: %r %r: %e", request, to_save, e)
|
||||
return "Invalid request", 400
|
||||
return "1", 200
|
||||
|
||||
|
@ -340,7 +340,7 @@ def get_matching_tags():
|
|||
return json_dumps
|
||||
|
||||
|
||||
def render_books_list(data, sort, book_id, page):
|
||||
def get_sort_function(sort, data):
|
||||
order = [db.Books.timestamp.desc()]
|
||||
if sort == 'stored':
|
||||
sort = current_user.get_view_property(data, 'stored')
|
||||
|
@ -366,6 +366,11 @@ def render_books_list(data, sort, book_id, page):
|
|||
order = [db.Books.series_index.asc()]
|
||||
if sort == 'seriesdesc':
|
||||
order = [db.Books.series_index.desc()]
|
||||
return order
|
||||
|
||||
|
||||
def render_books_list(data, sort, book_id, page):
|
||||
order = get_sort_function(sort, data)
|
||||
|
||||
if data == "rated":
|
||||
if current_user.check_visibility(constants.SIDEBAR_BEST_RATED):
|
||||
|
@ -453,18 +458,11 @@ def render_hot_books(page):
|
|||
|
||||
def render_downloaded_books(page, order):
|
||||
if current_user.check_visibility(constants.SIDEBAR_DOWNLOAD):
|
||||
# order = order or []
|
||||
if current_user.show_detail_random():
|
||||
random = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) \
|
||||
.order_by(func.random()).limit(config.config_random_books)
|
||||
else:
|
||||
random = false()
|
||||
# off = int(int(config.config_books_per_page) * (page - 1))
|
||||
'''entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db_filter,
|
||||
order,
|
||||
ub.ReadBook, db.Books.id==ub.ReadBook.book_id)'''
|
||||
|
||||
entries, __, pagination = calibre_db.fill_indexpage(page,
|
||||
0,
|
||||
|
@ -748,7 +746,7 @@ def list_books():
|
|||
search = request.args.get("search")
|
||||
total_count = calibre_db.session.query(db.Books).count()
|
||||
if search:
|
||||
entries, filtered_count, pagination = calibre_db.get_search_results(search, off, order, limit)
|
||||
entries, filtered_count, __ = calibre_db.get_search_results(search, off, order, limit)
|
||||
else:
|
||||
entries, __, __ = calibre_db.fill_indexpage((int(off) / (int(limit)) + 1), limit, db.Books, True, order)
|
||||
filtered_count = total_count
|
||||
|
@ -1411,12 +1409,71 @@ def logout():
|
|||
|
||||
|
||||
# ################################### Users own configuration #########################################################
|
||||
def change_profile(kobo_support, local_oauth_check, oauth_status, translations, languages):
|
||||
to_save = request.form.to_dict()
|
||||
current_user.random_books = 0
|
||||
if current_user.role_passwd() or current_user.role_admin():
|
||||
if "password" in to_save and to_save["password"]:
|
||||
current_user.password = generate_password_hash(to_save["password"])
|
||||
if "kindle_mail" in to_save and to_save["kindle_mail"] != current_user.kindle_mail:
|
||||
current_user.kindle_mail = to_save["kindle_mail"]
|
||||
if "allowed_tags" in to_save and to_save["allowed_tags"] != current_user.allowed_tags:
|
||||
current_user.allowed_tags = to_save["allowed_tags"].strip()
|
||||
if "email" in to_save and to_save["email"] != current_user.email:
|
||||
if config.config_public_reg and not check_valid_domain(to_save["email"]):
|
||||
flash(_(u"E-mail is not from valid domain"), category="error")
|
||||
return render_title_template("user_edit.html", content=current_user,
|
||||
title=_(u"%(name)s's profile", name=current_user.nickname), page="me",
|
||||
kobo_support=kobo_support,
|
||||
registered_oauth=local_oauth_check, oauth_status=oauth_status)
|
||||
current_user.email = to_save["email"]
|
||||
if "nickname" in to_save and to_save["nickname"] != current_user.nickname:
|
||||
# Query User nickname, if not existing, change
|
||||
if not ub.session.query(ub.User).filter(ub.User.nickname == to_save["nickname"]).scalar():
|
||||
current_user.nickname = to_save["nickname"]
|
||||
else:
|
||||
flash(_(u"This username is already taken"), category="error")
|
||||
return render_title_template("user_edit.html",
|
||||
translations=translations,
|
||||
languages=languages,
|
||||
kobo_support=kobo_support,
|
||||
new_user=0, content=current_user,
|
||||
registered_oauth=local_oauth_check,
|
||||
title=_(u"Edit User %(nick)s",
|
||||
nick=current_user.nickname),
|
||||
page="edituser")
|
||||
if "show_random" in to_save and to_save["show_random"] == "on":
|
||||
current_user.random_books = 1
|
||||
if "default_language" in to_save:
|
||||
current_user.default_language = to_save["default_language"]
|
||||
if "locale" in to_save:
|
||||
current_user.locale = to_save["locale"]
|
||||
|
||||
val = 0
|
||||
for key, __ in to_save.items():
|
||||
if key.startswith('show'):
|
||||
val += int(key[5:])
|
||||
current_user.sidebar_view = val
|
||||
if "Show_detail_random" in to_save:
|
||||
current_user.sidebar_view += constants.DETAIL_RANDOM
|
||||
|
||||
try:
|
||||
ub.session.commit()
|
||||
flash(_(u"Profile updated"), category="success")
|
||||
log.debug(u"Profile updated")
|
||||
except IntegrityError:
|
||||
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.")
|
||||
except OperationalError as e:
|
||||
ub.session.rollback()
|
||||
log.error("Database error: %s", e)
|
||||
flash(_(u"Database error: %(error)s.", error=e), category="error")
|
||||
|
||||
|
||||
@web.route("/me", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def profile():
|
||||
# downloads = list()
|
||||
languages = calibre_db.speaking_language()
|
||||
translations = babel.list_translations() + [LC('en')]
|
||||
kobo_support = feature_support['kobo'] and config.config_kobo_sync
|
||||
|
@ -1427,74 +1484,8 @@ def profile():
|
|||
oauth_status = None
|
||||
local_oauth_check = {}
|
||||
|
||||
'''entries, __, pagination = calibre_db.fill_indexpage(page,
|
||||
0,
|
||||
db.Books,
|
||||
ub.Downloads.user_id == int(current_user.id), # True,
|
||||
[],
|
||||
ub.Downloads, db.Books.id == ub.Downloads.book_id)'''
|
||||
|
||||
if request.method == "POST":
|
||||
to_save = request.form.to_dict()
|
||||
current_user.random_books = 0
|
||||
if current_user.role_passwd() or current_user.role_admin():
|
||||
if "password" in to_save and to_save["password"]:
|
||||
current_user.password = generate_password_hash(to_save["password"])
|
||||
if "kindle_mail" in to_save and to_save["kindle_mail"] != current_user.kindle_mail:
|
||||
current_user.kindle_mail = to_save["kindle_mail"]
|
||||
if "allowed_tags" in to_save and to_save["allowed_tags"] != current_user.allowed_tags:
|
||||
current_user.allowed_tags = to_save["allowed_tags"].strip()
|
||||
if "email" in to_save and to_save["email"] != current_user.email:
|
||||
if config.config_public_reg and not check_valid_domain(to_save["email"]):
|
||||
flash(_(u"E-mail is not from valid domain"), category="error")
|
||||
return render_title_template("user_edit.html", content=current_user,
|
||||
title=_(u"%(name)s's profile", name=current_user.nickname), page="me",
|
||||
kobo_support=kobo_support,
|
||||
registered_oauth=local_oauth_check, oauth_status=oauth_status)
|
||||
current_user.email = to_save["email"]
|
||||
if "nickname" in to_save and to_save["nickname"] != current_user.nickname:
|
||||
# Query User nickname, if not existing, change
|
||||
if not ub.session.query(ub.User).filter(ub.User.nickname == to_save["nickname"]).scalar():
|
||||
current_user.nickname = to_save["nickname"]
|
||||
else:
|
||||
flash(_(u"This username is already taken"), category="error")
|
||||
return render_title_template("user_edit.html",
|
||||
translations=translations,
|
||||
languages=languages,
|
||||
kobo_support=kobo_support,
|
||||
new_user=0, content=current_user,
|
||||
registered_oauth=local_oauth_check,
|
||||
title=_(u"Edit User %(nick)s",
|
||||
nick=current_user.nickname),
|
||||
page="edituser")
|
||||
if "show_random" in to_save and to_save["show_random"] == "on":
|
||||
current_user.random_books = 1
|
||||
if "default_language" in to_save:
|
||||
current_user.default_language = to_save["default_language"]
|
||||
if "locale" in to_save:
|
||||
current_user.locale = to_save["locale"]
|
||||
|
||||
val = 0
|
||||
for key, __ in to_save.items():
|
||||
if key.startswith('show'):
|
||||
val += int(key[5:])
|
||||
current_user.sidebar_view = val
|
||||
if "Show_detail_random" in to_save:
|
||||
current_user.sidebar_view += constants.DETAIL_RANDOM
|
||||
|
||||
try:
|
||||
ub.session.commit()
|
||||
flash(_(u"Profile updated"), category="success")
|
||||
log.debug(u"Profile updated")
|
||||
except IntegrityError:
|
||||
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.")
|
||||
except OperationalError as e:
|
||||
ub.session.rollback()
|
||||
log.error("Database error: %s", e)
|
||||
flash(_(u"Database error: %(error)s.", error=e), category="error")
|
||||
|
||||
change_profile(kobo_support, local_oauth_check, oauth_status, translations, languages)
|
||||
return render_title_template("user_edit.html",
|
||||
translations=translations,
|
||||
profile=1,
|
||||
|
|
Loading…
Reference in New Issue
Block a user