Commit 1e40ffd1 authored by cbartondock's avatar cbartondock

merge changes

parents 83474da7 53ee0aae
This diff is collapsed.
...@@ -74,19 +74,8 @@ def _cover_processing(tmp_file_name, img, extension): ...@@ -74,19 +74,8 @@ def _cover_processing(tmp_file_name, img, extension):
return tmp_cover_name return tmp_cover_name
def _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable):
def _extractCover(tmp_file_name, original_file_extension, rarExecutable): cover_data = None
cover_data = extension = None
if use_comic_meta:
archive = ComicArchive(tmp_file_name, rar_exe_path=rarExecutable)
for index, name in enumerate(archive.getPageNameList()):
ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension in COVER_EXTENSIONS:
cover_data = archive.getPage(index)
break
else:
if original_file_extension.upper() == '.CBZ': if original_file_extension.upper() == '.CBZ':
cf = zipfile.ZipFile(tmp_file_name) cf = zipfile.ZipFile(tmp_file_name)
for name in cf.namelist(): for name in cf.namelist():
...@@ -118,6 +107,22 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable): ...@@ -118,6 +107,22 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
break break
except Exception as e: except Exception as e:
log.debug('Rarfile failed with error: %s', 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
if use_comic_meta:
archive = ComicArchive(tmp_file_name, rar_exe_path=rarExecutable)
for index, name in enumerate(archive.getPageNameList()):
ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension in COVER_EXTENSIONS:
cover_data = archive.getPage(index)
break
else:
cover_data = _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable)
return _cover_processing(tmp_file_name, cover_data, extension) 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 ...@@ -142,7 +147,8 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension, r
file_path=tmp_file_path, file_path=tmp_file_path,
extension=original_file_extension, extension=original_file_extension,
title=loadedMetadata.title or original_file_name, 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), cover=_extractCover(tmp_file_path, original_file_extension, rarExecutable),
description=loadedMetadata.comments or "", description=loadedMetadata.comments or "",
tags="", tags="",
......
...@@ -146,15 +146,16 @@ class _ConfigSQL(object): ...@@ -146,15 +146,16 @@ class _ConfigSQL(object):
self.load() self.load()
change = False change = False
if self.config_converterpath == None: if self.config_converterpath == None: # pylint: disable=access-member-before-definition
change = True change = True
self.config_converterpath = autodetect_calibre_binary() self.config_converterpath = autodetect_calibre_binary()
if self.config_kepubifypath == None: if self.config_kepubifypath == None: # pylint: disable=access-member-before-definition
change = True change = True
self.config_kepubifypath = autodetect_kepubify_binary() 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 change = True
self.config_rarfile_location = autodetect_unrar_binary() self.config_rarfile_location = autodetect_unrar_binary()
if change: if change:
...@@ -181,7 +182,8 @@ class _ConfigSQL(object): ...@@ -181,7 +182,8 @@ class _ConfigSQL(object):
return None return None
return self.config_keyfile return self.config_keyfile
def get_config_ipaddress(self): @staticmethod
def get_config_ipaddress():
return cli.ipadress or "" return cli.ipadress or ""
def _has_role(self, role_flag): def _has_role(self, role_flag):
...@@ -299,6 +301,7 @@ class _ConfigSQL(object): ...@@ -299,6 +301,7 @@ class _ConfigSQL(object):
have_metadata_db = os.path.isfile(db_file) have_metadata_db = os.path.isfile(db_file)
self.db_configured = have_metadata_db self.db_configured = have_metadata_db
constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip().lower() for x in self.config_upload_formats.split(',')] 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) logfile = logger.setup(self.config_logfile, self.config_log_level)
if logfile != self.config_logfile: if logfile != self.config_logfile:
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)
......
...@@ -104,7 +104,7 @@ LDAP_AUTH_SIMPLE = 0 ...@@ -104,7 +104,7 @@ LDAP_AUTH_SIMPLE = 0
DEFAULT_MAIL_SERVER = "mail.example.org" DEFAULT_MAIL_SERVER = "mail.example.org"
DEFAULT_PASSWORD = "admin123" DEFAULT_PASSWORD = "admin123" # nosec # noqa
DEFAULT_PORT = 8083 DEFAULT_PORT = 8083
env_CALIBRE_PORT = os.environ.get("CALIBRE_PORT", DEFAULT_PORT) env_CALIBRE_PORT = os.environ.get("CALIBRE_PORT", DEFAULT_PORT)
try: try:
......
...@@ -156,10 +156,8 @@ class Identifiers(Base): ...@@ -156,10 +156,8 @@ class Identifiers(Base):
return u"https://portal.issn.org/resource/ISSN/{0}".format(self.val) return u"https://portal.issn.org/resource/ISSN/{0}".format(self.val)
elif format_type == "isfdb": elif format_type == "isfdb":
return u"http://www.isfdb.org/cgi-bin/pl.cgi?{0}".format(self.val) return u"http://www.isfdb.org/cgi-bin/pl.cgi?{0}".format(self.val)
elif format_type == "url":
return u"{0}".format(self.val)
else: else:
return u"" return u"{0}".format(self.val)
class Comments(Base): class Comments(Base):
...@@ -386,14 +384,14 @@ class Custom_Columns(Base): ...@@ -386,14 +384,14 @@ class Custom_Columns(Base):
class AlchemyEncoder(json.JSONEncoder): class AlchemyEncoder(json.JSONEncoder):
def default(self, obj): def default(self, o):
if isinstance(obj.__class__, DeclarativeMeta): if isinstance(o.__class__, DeclarativeMeta):
# an SQLAlchemy class # an SQLAlchemy class
fields = {} fields = {}
for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']: for field in [x for x in dir(o) if not x.startswith('_') and x != 'metadata']:
if field == 'books': if field == 'books':
continue continue
data = obj.__getattribute__(field) data = o.__getattribute__(field)
try: try:
if isinstance(data, str): if isinstance(data, str):
data = data.replace("'", "\'") data = data.replace("'", "\'")
...@@ -413,12 +411,12 @@ class AlchemyEncoder(json.JSONEncoder): ...@@ -413,12 +411,12 @@ class AlchemyEncoder(json.JSONEncoder):
else: else:
json.dumps(data) json.dumps(data)
fields[field] = data fields[field] = data
except: except Exception:
fields[field] = "" fields[field] = ""
# a json-encodable dict # a json-encodable dict
return fields return fields
return json.JSONEncoder.default(self, obj) return json.JSONEncoder.default(self, o)
class CalibreDB(): class CalibreDB():
...@@ -565,8 +563,8 @@ class CalibreDB(): ...@@ -565,8 +563,8 @@ class CalibreDB():
def get_book_by_uuid(self, book_uuid): def get_book_by_uuid(self, book_uuid):
return self.session.query(Books).filter(Books.uuid == book_uuid).first() return self.session.query(Books).filter(Books.uuid == book_uuid).first()
def get_book_format(self, book_id, format): def get_book_format(self, book_id, file_format):
return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == format).first() return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == file_format).first()
# Language and content filters for displaying in the UI # Language and content filters for displaying in the UI
def common_filters(self, allow_show_archived=False): def common_filters(self, allow_show_archived=False):
...@@ -744,7 +742,7 @@ class CalibreDB(): ...@@ -744,7 +742,7 @@ class CalibreDB():
if old_session: if old_session:
try: try:
old_session.close() old_session.close()
except: except Exception:
pass pass
if old_session.bind: if old_session.bind:
try: try:
......
...@@ -47,7 +47,7 @@ except ImportError as err: ...@@ -47,7 +47,7 @@ except ImportError as err:
current_milli_time = lambda: int(round(time() * 1000)) current_milli_time = lambda: int(round(time() * 1000))
gdrive_watch_callback_token = 'target=calibreweb-watch_files' gdrive_watch_callback_token = 'target=calibreweb-watch_files' #nosec
@gdrive.route("/authenticate") @gdrive.route("/authenticate")
......
...@@ -134,17 +134,11 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False): ...@@ -134,17 +134,11 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False):
taskMessage=_(u"Registration e-mail for user: %(name)s", name=user_name), taskMessage=_(u"Registration e-mail for user: %(name)s", name=user_name),
text=txt text=txt
)) ))
return return
def check_send_to_kindle(entry): def check_send_to_kindle_without_converter(entry):
"""
returns all available book formats for sending to Kindle
"""
if len(entry.data):
bookformats = list() bookformats = list()
if not config.config_converterpath:
# no converter - only for mobi and pdf formats # no converter - only for mobi and pdf formats
for ele in iter(entry.data): for ele in iter(entry.data):
if ele.uncompressed_size < config.mail_size: if ele.uncompressed_size < config.mail_size:
...@@ -160,7 +154,10 @@ def check_send_to_kindle(entry): ...@@ -160,7 +154,10 @@ def check_send_to_kindle(entry):
bookformats.append({'format': 'Azw', bookformats.append({'format': 'Azw',
'convert': 0, 'convert': 0,
'text': _('Send %(format)s to Kindle', format='Azw')}) 'text': _('Send %(format)s to Kindle', format='Azw')})
else: return bookformats
def check_send_to_kindle_with_converter(entry):
bookformats = list()
formats = list() formats = list()
for ele in iter(entry.data): for ele in iter(entry.data):
if ele.uncompressed_size < config.mail_size: if ele.uncompressed_size < config.mail_size:
...@@ -177,10 +174,9 @@ def check_send_to_kindle(entry): ...@@ -177,10 +174,9 @@ def check_send_to_kindle(entry):
bookformats.append({'format': 'Pdf', bookformats.append({'format': 'Pdf',
'convert': 0, 'convert': 0,
'text': _('Send %(format)s to Kindle', format='Pdf')}) 'text': _('Send %(format)s to Kindle', format='Pdf')})
if config.config_converterpath:
if 'EPUB' in formats and 'MOBI' not in formats: if 'EPUB' in formats and 'MOBI' not in formats:
bookformats.append({'format': 'Mobi', bookformats.append({'format': 'Mobi',
'convert':1, 'convert': 1,
'text': _('Convert %(orig)s to %(format)s and send to Kindle', 'text': _('Convert %(orig)s to %(format)s and send to Kindle',
orig='Epub', orig='Epub',
format='Mobi')}) format='Mobi')})
...@@ -191,6 +187,18 @@ def check_send_to_kindle(entry): ...@@ -191,6 +187,18 @@ def check_send_to_kindle(entry):
orig='Azw3', orig='Azw3',
format='Mobi')}) format='Mobi')})
return bookformats return bookformats
def check_send_to_kindle(entry):
"""
returns all available book formats for sending to Kindle
"""
if len(entry.data):
if not config.config_converterpath:
book_formats = check_send_to_kindle_with_converter(entry)
else:
book_formats = check_send_to_kindle_with_converter(entry)
return book_formats
else: else:
log.error(u'Cannot find book entry %d', entry.id) log.error(u'Cannot find book entry %d', entry.id)
return None return None
...@@ -742,7 +750,7 @@ def format_runtime(runtime): ...@@ -742,7 +750,7 @@ def format_runtime(runtime):
# helper function to apply localize status information in tasklist entries # helper function to apply localize status information in tasklist entries
def render_task_status(tasklist): def render_task_status(tasklist):
renderedtasklist = list() 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(): if user == current_user.nickname or current_user.role_admin():
ret = {} ret = {}
if task.start_time: if task.start_time:
......
...@@ -71,7 +71,7 @@ def get_valid_language_codes(locale, language_names, remainder=None): ...@@ -71,7 +71,7 @@ def get_valid_language_codes(locale, language_names, remainder=None):
languages = list() languages = list()
if "" in language_names: if "" in language_names:
language_names.remove("") 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: if k in language_names:
languages.append(k) languages.append(k)
language_names.remove(k) language_names.remove(k)
......
...@@ -42,8 +42,7 @@ from flask import ( ...@@ -42,8 +42,7 @@ from flask import (
from flask_login import current_user 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_
from sqlalchemy.orm import load_only
from sqlalchemy.exc import StatementError from sqlalchemy.exc import StatementError
import requests import requests
...@@ -893,17 +892,6 @@ def HandleProductsRequest(dummy=None): ...@@ -893,17 +892,6 @@ def HandleProductsRequest(dummy=None):
return redirect_or_proxy_request() return redirect_or_proxy_request()
'''@kobo.errorhandler(404)
def handle_404(err):
# This handler acts as a catch-all for endpoints that we don't have an interest in
# implementing (e.g: v1/analytics/gettests, v1/user/recommendations, etc)
if err:
print('404')
return jsonify(error=str(err)), 404
log.debug("Unknown Request received: %s, method: %s, data: %s", request.base_url, request.method, request.data)
return redirect_or_proxy_request()'''
def make_calibre_web_auth_response(): def make_calibre_web_auth_response():
# As described in kobo_auth.py, CalibreWeb doesn't make use practical use of this auth/device API call for # As described in kobo_auth.py, CalibreWeb doesn't make use practical use of this auth/device API call for
# authentation (nor for authorization). We return a dummy response just to keep the device happy. # authentation (nor for authorization). We return a dummy response just to keep the device happy.
...@@ -947,7 +935,7 @@ def HandleInitRequest(): ...@@ -947,7 +935,7 @@ def HandleInitRequest():
store_response_json = store_response.json() store_response_json = store_response.json()
if "Resources" in store_response_json: if "Resources" in store_response_json:
kobo_resources = store_response_json["Resources"] kobo_resources = store_response_json["Resources"]
except: except Exception:
log.error("Failed to receive or parse response from Kobo's init endpoint. Falling back to un-proxied mode.") log.error("Failed to receive or parse response from Kobo's init endpoint. Falling back to un-proxied mode.")
if not kobo_resources: if not kobo_resources:
kobo_resources = NATIVE_KOBO_RESOURCES() kobo_resources = NATIVE_KOBO_RESOURCES()
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
from __future__ import division, print_function, unicode_literals from __future__ import division, print_function, unicode_literals
from flask import session from flask import session
try: try:
from flask_dance.consumer.backend.sqla import SQLAlchemyBackend, first, _get_real_user from flask_dance.consumer.backend.sqla import SQLAlchemyBackend, first, _get_real_user
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
...@@ -34,8 +33,8 @@ except ImportError: ...@@ -34,8 +33,8 @@ except ImportError:
except ImportError: except ImportError:
pass pass
try:
class OAuthBackend(SQLAlchemyBackend): class OAuthBackend(SQLAlchemyBackend):
""" """
Stores and retrieves OAuth tokens using a relational database through Stores and retrieves OAuth tokens using a relational database through
the `SQLAlchemy`_ ORM. the `SQLAlchemy`_ ORM.
...@@ -162,6 +161,3 @@ try: ...@@ -162,6 +161,3 @@ try:
self.cache.delete(self.make_cache_key( self.cache.delete(self.make_cache_key(
blueprint=blueprint, user=user, user_id=user_id, blueprint=blueprint, user=user, user_id=user_id,
)) ))
except Exception:
pass
...@@ -35,7 +35,10 @@ from sqlalchemy.orm.exc import NoResultFound ...@@ -35,7 +35,10 @@ from sqlalchemy.orm.exc import NoResultFound
from . import constants, logger, config, app, ub 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 = {} oauth_check = {}
......
...@@ -137,8 +137,8 @@ class WebServer(object): ...@@ -137,8 +137,8 @@ class WebServer(object):
return sock, _readable_listen_address(*address) return sock, _readable_listen_address(*address)
@staticmethod
def _get_args_for_reloading(self): def _get_args_for_reloading():
"""Determine how the script was executed, and return the args needed """Determine how the script was executed, and return the args needed
to execute it again in a new process. to execute it again in a new process.
Code from https://github.com/pyload/pyload. Author GammaC0de, voulter Code from https://github.com/pyload/pyload. Author GammaC0de, voulter
......
...@@ -64,7 +64,7 @@ class SyncToken: ...@@ -64,7 +64,7 @@ class SyncToken:
books_last_modified: Datetime representing the last modified book that the device knows about. 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" VERSION = "1-1-0"
LAST_MODIFIED_ADDED_VERSION = "1-1-0" LAST_MODIFIED_ADDED_VERSION = "1-1-0"
MIN_VERSION = "1-0-0" MIN_VERSION = "1-0-0"
...@@ -91,7 +91,7 @@ class SyncToken: ...@@ -91,7 +91,7 @@ class SyncToken:
def __init__( def __init__(
self, self,
raw_kobo_store_token="", raw_kobo_store_token="", # nosec
books_last_created=datetime.min, books_last_created=datetime.min,
books_last_modified=datetime.min, books_last_modified=datetime.min,
archive_last_modified=datetime.min, archive_last_modified=datetime.min,
...@@ -110,7 +110,7 @@ class SyncToken: ...@@ -110,7 +110,7 @@ class SyncToken:
@staticmethod @staticmethod
def from_headers(headers): def from_headers(headers):
sync_token_header = headers.get(SyncToken.SYNC_TOKEN_HEADER, "") sync_token_header = headers.get(SyncToken.SYNC_TOKEN_HEADER, "")
if sync_token_header == "": if sync_token_header == "": # nosec
return SyncToken() return SyncToken()
# On the first sync from a Kobo device, we may receive the SyncToken # On the first sync from a Kobo device, we may receive the SyncToken
......
body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{ body.serieslist.grid-view div.container-fluid > div > div.col-sm-10::before {
display: none; display: none;
} }
.cover .badge{
.cover .badge {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
...@@ -9,14 +10,15 @@ body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{ ...@@ -9,14 +10,15 @@ body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{
background-color: #cc7b19; background-color: #cc7b19;
border-radius: 0; border-radius: 0;
padding: 0 8px; padding: 0 8px;
box-shadow: 0 0 4px rgba(0,0,0,.6); box-shadow: 0 0 4px rgba(0, 0, 0, 0.6);
line-height: 24px; line-height: 24px;
} }
.cover{
box-shadow: 0 0 4px rgba(0,0,0,.6); .cover {
box-shadow: 0 0 4px rgba(0, 0, 0, 0.6);
} }
.cover .read{ .cover .read {
padding: 0 0px; padding: 0 0;
line-height: 15px; line-height: 15px;
} }
...@@ -33,7 +33,6 @@ body { ...@@ -33,7 +33,6 @@ body {
position: relative; position: relative;
cursor: pointer; cursor: pointer;
padding: 4px; padding: 4px;
transition: all 0.2s ease; transition: all 0.2s ease;
} }
...@@ -45,7 +44,7 @@ body { ...@@ -45,7 +44,7 @@ body {
#sidebar a.active, #sidebar a.active,
#sidebar a.active img + span { #sidebar a.active img + span {
background-color: #45B29D; background-color: #45b29d;
} }
#sidebar li img { #sidebar li img {
......
...@@ -66,19 +66,12 @@ body { ...@@ -66,19 +66,12 @@ body {
right: 40px; right: 40px;
} }
xmp, pre {
pre,
plaintext {
display: block; display: block;
font-family: -moz-fixed;
white-space: pre;
margin: 1em 0; margin: 1em 0;
}
pre {
white-space: pre-wrap; white-space: pre-wrap;
word-wrap: break-word; word-wrap: break-word;
font-family: -moz-fixed; font-family: -moz-fixed, sans-serif;
column-count: 2; column-count: 2;
-webkit-columns: 2; -webkit-columns: 2;
-moz-columns: 2; -moz-columns: 2;
......
This diff is collapsed.
This diff is collapsed.
...@@ -710,7 +710,7 @@ $(".navbar-collapse.collapse.in").before('<div class="sidebar-backdrop"></div>') ...@@ -710,7 +710,7 @@ $(".navbar-collapse.collapse.in").before('<div class="sidebar-backdrop"></div>')
// Get rid of leading white space // Get rid of leading white space
recentlyAdded = $("#nav_new a:contains('Recently')").text().trim(); recentlyAdded = $("#nav_new a:contains('Recently')").text().trim();
$("#nav_new a:contains('Recently')").contents().filter(function () { $("#nav_new a:contains('Recently')").contents().filter(function () {
return this.nodeType == 3 return this.nodeType === 3
}).each(function () { }).each(function () {
this.textContent = this.textContent.replace(" Recently Added", recentlyAdded); this.textContent = this.textContent.replace(" Recently Added", recentlyAdded);
}); });
......
/** /**
* Created by SpeedProg on 05.04.2015. * Created by SpeedProg on 05.04.2015.
*/ */
/* global Bloodhound, language, Modernizr, tinymce */ /* global Bloodhound, language, Modernizr, tinymce, getPath */
if ($("#description").length) { if ($("#description").length) {
tinymce.init({ tinymce.init({
...@@ -250,14 +250,14 @@ promisePublishers.done(function() { ...@@ -250,14 +250,14 @@ promisePublishers.done(function() {
}); });
$("#search").on("change input.typeahead:selected", function(event) { $("#search").on("change input.typeahead:selected", function(event) {
if (event.target.type == "search" && event.target.tagName == "INPUT") { if (event.target.type === "search" && event.target.tagName === "INPUT") {
return; return;
} }
var form = $("form").serialize(); var form = $("form").serialize();
$.getJSON( getPath() + "/get_matching_tags", form, function( data ) { $.getJSON( getPath() + "/get_matching_tags", form, function( data ) {
$(".tags_click").each(function() { $(".tags_click").each(function() {
if ($.inArray(parseInt($(this).val(), 10), data.tags) === -1) { if ($.inArray(parseInt($(this).val(), 10), data.tags) === -1) {
if(!$(this).prop("selected")) { if (!$(this).prop("selected")) {
$(this).prop("disabled", true); $(this).prop("disabled", true);
} }
} else { } else {
...@@ -265,10 +265,10 @@ $("#search").on("change input.typeahead:selected", function(event) { ...@@ -265,10 +265,10 @@ $("#search").on("change input.typeahead:selected", function(event) {
} }
}); });
$("#include_tag option:selected").each(function () { $("#include_tag option:selected").each(function () {
$("#exclude_tag").find("[value="+$(this).val()+"]").prop("disabled", true); $("#exclude_tag").find("[value=" + $(this).val() + "]").prop("disabled", true);
}); });
$('#include_tag').selectpicker("refresh"); $("#include_tag").selectpicker("refresh");
$('#exclude_tag').selectpicker("refresh"); $("#exclude_tag").selectpicker("refresh");
}); });
}); });
......
...@@ -36,7 +36,6 @@ $("#desc").click(function() { ...@@ -36,7 +36,6 @@ $("#desc").click(function() {
sortBy: "name", sortBy: "name",
sortAscending: true sortAscending: true
}); });
return;
}); });
$("#asc").click(function() { $("#asc").click(function() {
...@@ -52,19 +51,20 @@ $("#asc").click(function() { ...@@ -52,19 +51,20 @@ $("#asc").click(function() {
sortBy: "name", sortBy: "name",
sortAscending: false sortAscending: false
}); });
return;
}); });
$("#all").click(function() { $("#all").click(function() {
// go through all elements and make them visible // go through all elements and make them visible
$list.isotope({ filter: function() { $list.isotope({ filter: function() {
return true; return true;
} }) }
});
}); });
$(".char").click(function() { $(".char").click(function() {
var character = this.innerText; var character = this.innerText;
$list.isotope({ filter: function() { $list.isotope({ filter: function() {
return this.attributes["data-id"].value.charAt(0).toUpperCase() == character; return this.attributes["data-id"].value.charAt(0).toUpperCase() === character;
} }) }
});
}); });
...@@ -88,7 +88,7 @@ $("#desc").click(function() { ...@@ -88,7 +88,7 @@ $("#desc").click(function() {
// Find count of middle element // Find count of middle element
var count = $(".row:visible").length; var count = $(".row:visible").length;
if (count > 20) { if (count > 20) {
middle = parseInt(count / 2) + (count % 2); middle = parseInt(count / 2, 10) + (count % 2);
//var middle = parseInt(count / 2) + (count % 2); //var middle = parseInt(count / 2) + (count % 2);
// search for the middle of all visible elements // search for the middle of all visible elements
...@@ -135,7 +135,7 @@ $("#asc").click(function() { ...@@ -135,7 +135,7 @@ $("#asc").click(function() {
// Find count of middle element // Find count of middle element
var count = $(".row:visible").length; var count = $(".row:visible").length;
if (count > 20) { 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); //var middle = parseInt(count / 2) + (count % 2);
// search for the middle of all visible elements // search for the middle of all visible elements
......
...@@ -138,8 +138,8 @@ $(function () { ...@@ -138,8 +138,8 @@ $(function () {
seriesTitle = result.series.title; seriesTitle = result.series.title;
} }
var dateFomers = result.pubdate.split("-"); var dateFomers = result.pubdate.split("-");
var publishedYear = parseInt(dateFomers[0]); var publishedYear = parseInt(dateFomers[0], 10);
var publishedMonth = parseInt(dateFomers[1]); var publishedMonth = parseInt(dateFomers[1], 10);
var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); var publishedDate = new Date(publishedYear, publishedMonth - 1, 1);
publishedDate = formatDate(publishedDate); publishedDate = formatDate(publishedDate);
...@@ -194,8 +194,8 @@ $(function () { ...@@ -194,8 +194,8 @@ $(function () {
} else { } else {
dateFomers = result.date_added.split("-"); dateFomers = result.date_added.split("-");
} }
var publishedYear = parseInt(dateFomers[0]); var publishedYear = parseInt(dateFomers[0], 10);
var publishedMonth = parseInt(dateFomers[1]); var publishedMonth = parseInt(dateFomers[1], 10);
var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); var publishedDate = new Date(publishedYear, publishedMonth - 1, 1);
publishedDate = formatDate(publishedDate); publishedDate = formatDate(publishedDate);
......
...@@ -38,10 +38,10 @@ $(document).on("change", "input[type=\"checkbox\"][data-control]", function () { ...@@ -38,10 +38,10 @@ $(document).on("change", "input[type=\"checkbox\"][data-control]", function () {
$(document).on("change", "select[data-control]", function() { $(document).on("change", "select[data-control]", function() {
var $this = $(this); var $this = $(this);
var name = $this.data("control"); var name = $this.data("control");
var showOrHide = parseInt($this.val()); var showOrHide = parseInt($this.val(), 10);
// var showOrHideLast = $("#" + name + " option:last").val() // var showOrHideLast = $("#" + name + " option:last").val()
for (var i = 0; i < $(this)[0].length; i++) { 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) { if (element === showOrHide) {
$("[data-related^=" + name + "][data-related*=-" + element + "]").show(); $("[data-related^=" + name + "][data-related*=-" + element + "]").show();
} else { } else {
...@@ -55,7 +55,7 @@ $(document).on("change", "select[data-control]", function() { ...@@ -55,7 +55,7 @@ $(document).on("change", "select[data-control]", function() {
$(document).on("change", "select[data-controlall]", function() { $(document).on("change", "select[data-controlall]", function() {
var $this = $(this); var $this = $(this);
var name = $this.data("controlall"); var name = $this.data("controlall");
var showOrHide = parseInt($this.val()); var showOrHide = parseInt($this.val(), 10);
if (showOrHide) { if (showOrHide) {
$("[data-related=" + name + "]").show(); $("[data-related=" + name + "]").show();
} else { } else {
...@@ -114,7 +114,7 @@ $(document).ready(function() { ...@@ -114,7 +114,7 @@ $(document).ready(function() {
} }
}); });
function ConfirmDialog(id, dataValue, yesFn, noFn) { function confirmDialog(id, dataValue, yesFn, noFn) {
var $confirm = $("#GeneralDeleteModal"); var $confirm = $("#GeneralDeleteModal");
// var dataValue= e.data('value'); // target.data('value'); // var dataValue= e.data('value'); // target.data('value');
$confirm.modal('show'); $confirm.modal('show');
...@@ -481,7 +481,7 @@ $(function() { ...@@ -481,7 +481,7 @@ $(function() {
}); });
$("#config_delete_kobo_token").click(function() { $("#config_delete_kobo_token").click(function() {
ConfirmDialog( confirmDialog(
$(this).attr('id'), $(this).attr('id'),
$(this).data('value'), $(this).data('value'),
function (value) { function (value) {
...@@ -509,7 +509,7 @@ $(function() { ...@@ -509,7 +509,7 @@ $(function() {
}); });
$("#btndeluser").click(function() { $("#btndeluser").click(function() {
ConfirmDialog( confirmDialog(
$(this).attr('id'), $(this).attr('id'),
$(this).data('value'), $(this).data('value'),
function(value){ function(value){
...@@ -527,7 +527,7 @@ $(function() { ...@@ -527,7 +527,7 @@ $(function() {
}); });
$("#delete_shelf").click(function() { $("#delete_shelf").click(function() {
ConfirmDialog( confirmDialog(
$(this).attr('id'), $(this).attr('id'),
$(this).data('value'), $(this).data('value'),
function(value){ function(value){
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
*/ */
/* exported TableActions, RestrictionActions, EbookActions, responseHandler */ /* exported TableActions, RestrictionActions, EbookActions, responseHandler */
/* global getPath, confirmDialog */
var selections = []; var selections = [];
...@@ -209,7 +210,7 @@ $(function() { ...@@ -209,7 +210,7 @@ $(function() {
striped: false striped: false
}); });
function domain_handle(domainId) { function domainHandle(domainId) {
$.ajax({ $.ajax({
method:"post", method:"post",
url: window.location.pathname + "/../../ajax/deletedomain", url: window.location.pathname + "/../../ajax/deletedomain",
...@@ -236,12 +237,12 @@ $(function() { ...@@ -236,12 +237,12 @@ $(function() {
} }
$("#domain-allow-table").on("click-cell.bs.table", function (field, value, row, $element) { $("#domain-allow-table").on("click-cell.bs.table", function (field, value, row, $element) {
if (value === 2) { if (value === 2) {
ConfirmDialog("btndeletedomain", $element.id, domain_handle); confirmDialog("btndeletedomain", $element.id, domainHandle);
} }
}); });
$("#domain-deny-table").on("click-cell.bs.table", function (field, value, row, $element) { $("#domain-deny-table").on("click-cell.bs.table", function (field, value, row, $element) {
if (value === 2) { if (value === 2) {
ConfirmDialog("btndeletedomain", $element.id, domain_handle); confirmDialog("btndeletedomain", $element.id, domainHandle);
} }
}); });
...@@ -255,12 +256,12 @@ $(function() { ...@@ -255,12 +256,12 @@ $(function() {
$("#h3").addClass("hidden"); $("#h3").addClass("hidden");
$("#h4").addClass("hidden"); $("#h4").addClass("hidden");
}); });
function startTable(type, user_id) { function startTable(type, userId) {
$("#restrict-elements-table").bootstrapTable({ $("#restrict-elements-table").bootstrapTable({
formatNoMatches: function () { formatNoMatches: function () {
return ""; return "";
}, },
url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, url: getPath() + "/ajax/listrestriction/" + type + "/" + userId,
rowStyle: function(row) { rowStyle: function(row) {
// console.log('Reihe :' + row + " Index :" + index); // console.log('Reihe :' + row + " Index :" + index);
if (row.id.charAt(0) === "a") { if (row.id.charAt(0) === "a") {
...@@ -274,13 +275,13 @@ $(function() { ...@@ -274,13 +275,13 @@ $(function() {
$.ajax ({ $.ajax ({
type: "Post", type: "Post",
data: "id=" + row.id + "&type=" + row.type + "&Element=" + encodeURIComponent(row.Element), data: "id=" + row.id + "&type=" + row.type + "&Element=" + encodeURIComponent(row.Element),
url: getPath() + "/ajax/deleterestriction/" + type + "/" + user_id, url: getPath() + "/ajax/deleterestriction/" + type + "/" + userId,
async: true, async: true,
timeout: 900, timeout: 900,
success:function() { success:function() {
$.ajax({ $.ajax({
method:"get", method:"get",
url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, url: getPath() + "/ajax/listrestriction/" + type + "/" + userId,
async: true, async: true,
timeout: 900, timeout: 900,
success:function(data) { success:function(data) {
...@@ -296,7 +297,7 @@ $(function() { ...@@ -296,7 +297,7 @@ $(function() {
$("#restrict-elements-table").removeClass("table-hover"); $("#restrict-elements-table").removeClass("table-hover");
$("#restrict-elements-table").on("editable-save.bs.table", function (e, field, row) { $("#restrict-elements-table").on("editable-save.bs.table", function (e, field, row) {
$.ajax({ $.ajax({
url: getPath() + "/ajax/editrestriction/" + type + "/" + user_id, url: getPath() + "/ajax/editrestriction/" + type + "/" + userId,
type: "Post", type: "Post",
data: row data: row
}); });
...@@ -304,13 +305,13 @@ $(function() { ...@@ -304,13 +305,13 @@ $(function() {
$("[id^=submit_]").click(function() { $("[id^=submit_]").click(function() {
$(this)[0].blur(); $(this)[0].blur();
$.ajax({ $.ajax({
url: getPath() + "/ajax/addrestriction/" + type + "/" + user_id, url: getPath() + "/ajax/addrestriction/" + type + "/" + userId,
type: "Post", type: "Post",
data: $(this).closest("form").serialize() + "&" + $(this)[0].name + "=", data: $(this).closest("form").serialize() + "&" + $(this)[0].name + "=",
success: function () { success: function () {
$.ajax ({ $.ajax ({
method:"get", method:"get",
url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, url: getPath() + "/ajax/listrestriction/" + type + "/" + userId,
async: true, async: true,
timeout: 900, timeout: 900,
success:function(data) { success:function(data) {
...@@ -332,12 +333,12 @@ $(function() { ...@@ -332,12 +333,12 @@ $(function() {
$("#h1").removeClass("hidden"); $("#h1").removeClass("hidden");
}); });
$("#get_user_column_values").on("click", function() { $("#get_user_column_values").on("click", function() {
startTable(3, $(this).data('id')); startTable(3, $(this).data("id"));
$("#h4").removeClass("hidden"); $("#h4").removeClass("hidden");
}); });
$("#get_user_tags").on("click", function() { $("#get_user_tags").on("click", function() {
startTable(2, $(this).data('id')); startTable(2, $(this).data("id"));
$(this)[0].blur(); $(this)[0].blur();
$("#h3").removeClass("hidden"); $("#h3").removeClass("hidden");
}); });
......
...@@ -12,7 +12,6 @@ class TaskUpload(CalibreTask): ...@@ -12,7 +12,6 @@ class TaskUpload(CalibreTask):
def run(self, worker_thread): 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""" """Upload task doesn't have anything to do, it's simply a way to add information to the task list"""
pass
@property @property
def name(self): def name(self):
......
...@@ -138,15 +138,15 @@ class UserBase: ...@@ -138,15 +138,15 @@ class UserBase:
mct = self.allowed_column_value or "" mct = self.allowed_column_value or ""
return [t.strip() for t in mct.split(",")] 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): if not self.view_settings.get(page):
return None 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): if not self.view_settings.get(page):
self.view_settings[page] = dict() self.view_settings[page] = dict()
self.view_settings[page][property] = value self.view_settings[page][prop] = value
try: try:
flag_modified(self, "view_settings") flag_modified(self, "view_settings")
except AttributeError: except AttributeError:
...@@ -437,11 +437,8 @@ class RemoteAuthToken(Base): ...@@ -437,11 +437,8 @@ class RemoteAuthToken(Base):
return '<Token %r>' % self.id return '<Token %r>' % self.id
# Migrate database to current version, has to be updated after every database change. Currently migration from # Add missing tables during migration of database
# everywhere to current should work. Migration is done by checking if relevant columns are existing, and than adding def add_missing_tables(engine, session):
# rows with SQL commands
def migrate_Database(session):
engine = session.bind
if not engine.dialect.has_table(engine.connect(), "book_read_link"): if not engine.dialect.has_table(engine.connect(), "book_read_link"):
ReadBook.__table__.create(bind=engine) ReadBook.__table__.create(bind=engine)
if not engine.dialect.has_table(engine.connect(), "bookmark"): if not engine.dialect.has_table(engine.connect(), "bookmark"):
...@@ -459,6 +456,10 @@ def migrate_Database(session): ...@@ -459,6 +456,10 @@ def migrate_Database(session):
with engine.connect() as conn: with engine.connect() as conn:
conn.execute("insert into registration (domain, allow) values('%.%',1)") conn.execute("insert into registration (domain, allow) values('%.%',1)")
session.commit() session.commit()
# migrate all settings missing in registration table
def migrate_registration_table(engine, session):
try: try:
session.query(exists().where(Registration.allow)).scalar() session.query(exists().where(Registration.allow)).scalar()
session.commit() session.commit()
...@@ -468,27 +469,29 @@ def migrate_Database(session): ...@@ -468,27 +469,29 @@ def migrate_Database(session):
conn.execute("update registration set 'allow' = 1") conn.execute("update registration set 'allow' = 1")
session.commit() session.commit()
try: try:
session.query(exists().where(RemoteAuthToken.token_type)).scalar() # Handle table exists, but no content
session.commit() cnt = session.query(Registration).count()
except exc.OperationalError: # Database is not compatible, some columns are missing if not cnt:
with engine.connect() as conn: with engine.connect() as conn:
conn.execute("ALTER TABLE remote_auth_token ADD column 'token_type' INTEGER DEFAULT 0") conn.execute("insert into registration (domain, allow) values('%.%',1)")
conn.execute("update remote_auth_token set 'token_type' = 0")
session.commit() 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: try:
session.query(exists().where(ReadBook.read_status)).scalar()
except exc.OperationalError:
with engine.connect() as conn: with engine.connect() as conn:
conn.execute("ALTER TABLE book_read_link ADD column 'read_status' INTEGER DEFAULT 0") conn.execute("UPDATE user SET password='' where nickname = 'Guest' and password !=''")
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() session.commit()
except exc.OperationalError:
print('Settings database is not writeable. Exiting...')
sys.exit(2)
def migrate_shelfs(engine, session):
try: try:
session.query(exists().where(Shelf.uuid)).scalar() session.query(exists().where(Shelf.uuid)).scalar()
except exc.OperationalError: except exc.OperationalError:
...@@ -505,21 +508,50 @@ def migrate_Database(session): ...@@ -505,21 +508,50 @@ def migrate_Database(session):
book_shelf.date_added = datetime.datetime.now() book_shelf.date_added = datetime.datetime.now()
session.commit() session.commit()
try: try:
# Handle table exists, but no content session.query(exists().where(BookShelf.order)).scalar()
cnt = session.query(Registration).count() except exc.OperationalError: # Database is not compatible, some columns are missing
if not cnt:
with engine.connect() as conn: with engine.connect() as conn:
conn.execute("insert into registration (domain, allow) values('%.%',1)") conn.execute("ALTER TABLE book_shelf_link ADD column 'order' INTEGER DEFAULT 1")
session.commit() session.commit()
except exc.OperationalError: # Database is not writeable
print('Settings database is not writeable. Exiting...')
sys.exit(2) def migrate_readBook(engine, session):
try: try:
session.query(exists().where(BookShelf.order)).scalar() 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 except exc.OperationalError: # Database is not compatible, some columns are missing
with engine.connect() as conn: with engine.connect() as conn:
conn.execute("ALTER TABLE book_shelf_link ADD column 'order' INTEGER DEFAULT 1") 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() 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: try:
create = False create = False
session.query(exists().where(User.sidebar_view)).scalar() session.query(exists().where(User.sidebar_view)).scalar()
...@@ -578,7 +610,6 @@ def migrate_Database(session): ...@@ -578,7 +610,6 @@ def migrate_Database(session):
"locale VARCHAR(2)," "locale VARCHAR(2),"
"sidebar_view INTEGER," "sidebar_view INTEGER,"
"default_language VARCHAR(3)," "default_language VARCHAR(3),"
# "series_view VARCHAR(10),"
"view_settings VARCHAR," "view_settings VARCHAR,"
"UNIQUE (nickname)," "UNIQUE (nickname),"
"UNIQUE (email))") "UNIQUE (email))")
...@@ -590,15 +621,7 @@ def migrate_Database(session): ...@@ -590,15 +621,7 @@ def migrate_Database(session):
conn.execute("DROP TABLE user") conn.execute("DROP TABLE user")
conn.execute("ALTER TABLE user_id RENAME TO user") conn.execute("ALTER TABLE user_id RENAME TO user")
session.commit() session.commit()
migrate_guest_password(engine, session)
# 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)
def clean_database(session): def clean_database(session):
......
...@@ -267,7 +267,8 @@ class Updater(threading.Thread): ...@@ -267,7 +267,8 @@ class Updater(threading.Thread):
log.debug("Could not remove: %s", item_path) log.debug("Could not remove: %s", item_path)
shutil.rmtree(source, ignore_errors=True) shutil.rmtree(source, ignore_errors=True)
def is_venv(self): @staticmethod
def is_venv():
if (hasattr(sys, 'real_prefix')) or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix): if (hasattr(sys, 'real_prefix')) or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
return os.sep + os.path.relpath(sys.prefix, constants.BASE_DIR) return os.sep + os.path.relpath(sys.prefix, constants.BASE_DIR)
else: else:
......
...@@ -72,7 +72,7 @@ def load_user_from_request(request): ...@@ -72,7 +72,7 @@ def load_user_from_request(request):
def load_user_from_auth_header(header_val): def load_user_from_auth_header(header_val):
if header_val.startswith('Basic '): if header_val.startswith('Basic '):
header_val = header_val.replace('Basic ', '', 1) header_val = header_val.replace('Basic ', '', 1)
basic_username = basic_password = '' basic_username = basic_password = '' # nosec
try: try:
header_val = base64.b64decode(header_val).decode('utf-8') header_val = base64.b64decode(header_val).decode('utf-8')
basic_username = header_val.split(':')[0] basic_username = header_val.split(':')[0]
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment