{{_(title)}}
-
{% if entries[0] %}
diff --git a/cps/ub.py b/cps/ub.py
index 9253dafe..b8d44375 100644
--- a/cps/ub.py
+++ b/cps/ub.py
@@ -18,78 +18,35 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-from sqlalchemy import *
-from sqlalchemy import exc
-from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import *
-from flask_login import AnonymousUserMixin
+from __future__ import division, print_function, unicode_literals
import sys
import os
-import logging
-from werkzeug.security import generate_password_hash
-import json
import datetime
+import json
from binascii import hexlify
-import cli
+
from flask import g
from flask_babel import gettext as _
-
+from flask_login import AnonymousUserMixin
try:
from flask_dance.consumer.backend.sqla import OAuthConsumerMixin
oauth_support = True
except ImportError:
oauth_support = False
+from sqlalchemy import create_engine, exc, exists
+from sqlalchemy import Column, ForeignKey
+from sqlalchemy import String, Integer, SmallInteger, Boolean, DateTime
+from sqlalchemy.orm import relationship, sessionmaker
+from sqlalchemy.ext.declarative import declarative_base
+from werkzeug.security import generate_password_hash
try:
import ldap
except ImportError:
pass
-ROLE_USER = 0
-ROLE_ADMIN = 1
-ROLE_DOWNLOAD = 2
-ROLE_UPLOAD = 4
-ROLE_EDIT = 8
-ROLE_PASSWD = 16
-ROLE_ANONYMOUS = 32
-ROLE_EDIT_SHELFS = 64
-ROLE_DELETE_BOOKS = 128
-ROLE_VIEWER = 256
-
-
-DETAIL_RANDOM = 1
-SIDEBAR_LANGUAGE = 2
-SIDEBAR_SERIES = 4
-SIDEBAR_CATEGORY = 8
-SIDEBAR_HOT = 16
-SIDEBAR_RANDOM = 32
-SIDEBAR_AUTHOR = 64
-SIDEBAR_BEST_RATED = 128
-SIDEBAR_READ_AND_UNREAD = 256
-SIDEBAR_RECENT = 512
-SIDEBAR_SORTED = 1024
-MATURE_CONTENT = 2048
-SIDEBAR_PUBLISHER = 4096
-SIDEBAR_RATING = 8192
-SIDEBAR_FORMAT = 16384
-
-UPDATE_STABLE = 0
-AUTO_UPDATE_STABLE = 1
-UPDATE_NIGHTLY = 2
-AUTO_UPDATE_NIGHTLY = 4
-
-LOGIN_STANDARD = 0
-LOGIN_LDAP = 1
-LOGIN_OAUTH_GITHUB = 2
-LOGIN_OAUTH_GOOGLE = 3
-
-DEFAULT_PASS = "admin123"
-try:
- DEFAULT_PORT = int(os.environ.get("CALIBRE_PORT", 8083))
-except ValueError:
- print ('Environmentvariable CALIBRE_PORT is set to an invalid value: ' +
- os.environ.get("CALIBRE_PORT", 8083) + ', faling back to default (8083)')
- DEFAULT_PORT = 8083
+from . import constants, logger, cli
+
session = None
@@ -109,47 +66,47 @@ def get_sidebar_config(kwargs=None):
content = 'conf' in kwargs
sidebar = list()
sidebar.append({"glyph": "glyphicon-book", "text": _('Recently Added'), "link": 'web.index', "id": "new",
- "visibility": SIDEBAR_RECENT, 'public': True, "page": "root",
+ "visibility": constants.SIDEBAR_RECENT, 'public': True, "page": "root",
"show_text": _('Show recent books'), "config_show":True})
sidebar.append({"glyph": "glyphicon-fire", "text": _('Hot Books'), "link": 'web.books_list', "id": "hot",
- "visibility": SIDEBAR_HOT, 'public': True, "page": "hot", "show_text": _('Show hot books'),
+ "visibility": constants.SIDEBAR_HOT, 'public': True, "page": "hot", "show_text": _('Show hot books'),
"config_show":True})
sidebar.append(
{"glyph": "glyphicon-star", "text": _('Best rated Books'), "link": 'web.books_list', "id": "rated",
- "visibility": SIDEBAR_BEST_RATED, 'public': True, "page": "rated",
+ "visibility": constants.SIDEBAR_BEST_RATED, 'public': True, "page": "rated",
"show_text": _('Show best rated books'), "config_show":True})
sidebar.append({"glyph": "glyphicon-eye-open", "text": _('Read Books'), "link": 'web.books_list', "id": "read",
- "visibility": SIDEBAR_READ_AND_UNREAD, 'public': (not g.user.is_anonymous), "page": "read",
+ "visibility": constants.SIDEBAR_READ_AND_UNREAD, 'public': (not g.user.is_anonymous), "page": "read",
"show_text": _('Show read and unread'), "config_show": content})
sidebar.append(
{"glyph": "glyphicon-eye-close", "text": _('Unread Books'), "link": 'web.books_list', "id": "unread",
- "visibility": SIDEBAR_READ_AND_UNREAD, 'public': (not g.user.is_anonymous), "page": "unread",
+ "visibility": constants.SIDEBAR_READ_AND_UNREAD, 'public': (not g.user.is_anonymous), "page": "unread",
"show_text": _('Show unread'), "config_show":False})
sidebar.append({"glyph": "glyphicon-random", "text": _('Discover'), "link": 'web.books_list', "id": "rand",
- "visibility": SIDEBAR_RANDOM, 'public': True, "page": "discover",
+ "visibility": constants.SIDEBAR_RANDOM, 'public': True, "page": "discover",
"show_text": _('Show random books'), "config_show":True})
sidebar.append({"glyph": "glyphicon-inbox", "text": _('Categories'), "link": 'web.category_list', "id": "cat",
- "visibility": SIDEBAR_CATEGORY, 'public': True, "page": "category",
+ "visibility": constants.SIDEBAR_CATEGORY, 'public': True, "page": "category",
"show_text": _('Show category selection'), "config_show":True})
sidebar.append({"glyph": "glyphicon-bookmark", "text": _('Series'), "link": 'web.series_list', "id": "serie",
- "visibility": SIDEBAR_SERIES, 'public': True, "page": "series",
+ "visibility": constants.SIDEBAR_SERIES, 'public': True, "page": "series",
"show_text": _('Show series selection'), "config_show":True})
sidebar.append({"glyph": "glyphicon-user", "text": _('Authors'), "link": 'web.author_list', "id": "author",
- "visibility": SIDEBAR_AUTHOR, 'public': True, "page": "author",
+ "visibility": constants.SIDEBAR_AUTHOR, 'public': True, "page": "author",
"show_text": _('Show author selection'), "config_show":True})
sidebar.append(
{"glyph": "glyphicon-text-size", "text": _('Publishers'), "link": 'web.publisher_list', "id": "publisher",
- "visibility": SIDEBAR_PUBLISHER, 'public': True, "page": "publisher",
+ "visibility": constants.SIDEBAR_PUBLISHER, 'public': True, "page": "publisher",
"show_text": _('Show publisher selection'), "config_show":True})
sidebar.append({"glyph": "glyphicon-flag", "text": _('Languages'), "link": 'web.language_overview', "id": "lang",
- "visibility": SIDEBAR_LANGUAGE, 'public': (g.user.filter_language() == 'all'),
+ "visibility": constants.SIDEBAR_LANGUAGE, 'public': (g.user.filter_language() == 'all'),
"page": "language",
"show_text": _('Show language selection'), "config_show":True})
sidebar.append({"glyph": "glyphicon-star-empty", "text": _('Ratings'), "link": 'web.ratings_list', "id": "rate",
- "visibility": SIDEBAR_RATING, 'public': True,
+ "visibility": constants.SIDEBAR_RATING, 'public': True,
"page": "rating", "show_text": _('Show ratings selection'), "config_show":True})
sidebar.append({"glyph": "glyphicon-file", "text": _('File formats'), "link": 'web.formats_list', "id": "format",
- "visibility": SIDEBAR_FORMAT, 'public': True,
+ "visibility": constants.SIDEBAR_FORMAT, 'public': True,
"page": "format", "show_text": _('Show file formats selection'), "config_show":True})
return sidebar
@@ -161,51 +118,35 @@ class UserBase:
def is_authenticated(self):
return True
+ def _has_role(self, role_flag):
+ return constants.has_flag(self.role, role_flag)
+
def role_admin(self):
- if self.role is not None:
- return True if self.role & ROLE_ADMIN == ROLE_ADMIN else False
- else:
- return False
+ return self._has_role(constants.ROLE_ADMIN)
def role_download(self):
- if self.role is not None:
- return True if self.role & ROLE_DOWNLOAD == ROLE_DOWNLOAD else False
- else:
- return False
+ return self._has_role(constants.ROLE_DOWNLOAD)
def role_upload(self):
- return bool((self.role is not None)and(self.role & ROLE_UPLOAD == ROLE_UPLOAD))
+ return self._has_role(constants.ROLE_UPLOAD)
def role_edit(self):
- if self.role is not None:
- return True if self.role & ROLE_EDIT == ROLE_EDIT else False
- else:
- return False
+ return self._has_role(constants.ROLE_EDIT)
def role_passwd(self):
- if self.role is not None:
- return True if self.role & ROLE_PASSWD == ROLE_PASSWD else False
- else:
- return False
+ return self._has_role(constants.ROLE_PASSWD)
def role_anonymous(self):
- if self.role is not None:
- return True if self.role & ROLE_ANONYMOUS == ROLE_ANONYMOUS else False
- else:
- return False
+ return self._has_role(constants.ROLE_ANONYMOUS)
def role_edit_shelfs(self):
- if self.role is not None:
- return True if self.role & ROLE_EDIT_SHELFS == ROLE_EDIT_SHELFS else False
- else:
- return False
+ return self._has_role(constants.ROLE_EDIT_SHELFS)
def role_delete_books(self):
- return bool((self.role is not None)and(self.role & ROLE_DELETE_BOOKS == ROLE_DELETE_BOOKS))
-
+ return self._has_role(constants.ROLE_DELETE_BOOKS)
def role_viewer(self):
- return bool((self.role is not None)and(self.role & ROLE_VIEWER == ROLE_VIEWER))
+ return self._has_role(constants.ROLE_VIEWER)
@property
def is_active(self):
@@ -222,10 +163,10 @@ class UserBase:
return self.default_language
def check_visibility(self, value):
- return bool((self.sidebar_view is not None) and (self.sidebar_view & value == value))
+ return constants.has_flag(self.sidebar_view, value)
def show_detail_random(self):
- return bool((self.sidebar_view is not None)and(self.sidebar_view & DETAIL_RANDOM == DETAIL_RANDOM))
+ return self.check_visibility(constants.DETAIL_RANDOM)
def __repr__(self):
return '' % self.nickname
@@ -246,7 +187,7 @@ class User(UserBase, Base):
id = Column(Integer, primary_key=True)
nickname = Column(String(64), unique=True)
email = Column(String(120), unique=True, default="")
- role = Column(SmallInteger, default=ROLE_USER)
+ role = Column(SmallInteger, default=constants.ROLE_USER)
password = Column(String)
kindle_mail = Column(String(120), default="")
shelf = relationship('Shelf', backref='user', lazy='dynamic', order_by='Shelf.name')
@@ -270,7 +211,7 @@ class Anonymous(AnonymousUserMixin, UserBase):
self.loadSettings()
def loadSettings(self):
- data = session.query(User).filter(User.role.op('&')(ROLE_ANONYMOUS) == ROLE_ANONYMOUS).first() # type: User
+ data = session.query(User).filter(User.role.op('&')(constants.ROLE_ANONYMOUS) == constants.ROLE_ANONYMOUS).first() # type: User
settings = session.query(Settings).first()
self.nickname = data.nickname
self.role = data.role
@@ -308,7 +249,7 @@ class Shelf(Base):
user_id = Column(Integer, ForeignKey('user.id'))
def __repr__(self):
- return '' % self.name
+ return '' % (self.id, self.name)
# Baseclass representing Relationship between books and Shelfs in Calibre-Web in app.db (N:M)
@@ -379,7 +320,7 @@ class Settings(Base):
mail_password = Column(String)
mail_from = Column(String)
config_calibre_dir = Column(String)
- config_port = Column(Integer, default=DEFAULT_PORT)
+ config_port = Column(Integer, default=constants.DEFAULT_PORT)
config_certfile = Column(String)
config_keyfile = Column(String)
config_calibre_web_title = Column(String, default=u'Calibre-Web')
@@ -388,7 +329,7 @@ class Settings(Base):
config_authors_max = Column(Integer, default=0)
config_read_column = Column(Integer, default=0)
config_title_regex = Column(String, default=u'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+')
- config_log_level = Column(SmallInteger, default=logging.INFO)
+ config_log_level = Column(SmallInteger, default=logger.DEFAULT_LOG_LEVEL)
config_uploading = Column(SmallInteger, default=0)
config_anonbrowse = Column(SmallInteger, default=0)
config_public_reg = Column(SmallInteger, default=0)
@@ -445,8 +386,6 @@ class RemoteAuthToken(Base):
# Class holds all application specific settings in calibre-web
class Config:
def __init__(self):
- self.config_main_dir = os.path.join(os.path.normpath(os.path.dirname(
- os.path.realpath(__file__)) + os.sep + ".." + os.sep))
self.db_configured = None
self.config_logfile = None
self.loadSettings()
@@ -497,19 +436,12 @@ class Config:
# self.config_use_google_oauth = data.config_use_google_oauth
self.config_google_oauth_client_id = data.config_google_oauth_client_id
self.config_google_oauth_client_secret = data.config_google_oauth_client_secret
- if data.config_mature_content_tags:
- self.config_mature_content_tags = data.config_mature_content_tags
- else:
- self.config_mature_content_tags = u''
- if data.config_logfile:
- self.config_logfile = data.config_logfile
+ self.config_mature_content_tags = data.config_mature_content_tags or u''
+ self.config_logfile = data.config_logfile or u''
self.config_rarfile_location = data.config_rarfile_location
self.config_theme = data.config_theme
self.config_updatechannel = data.config_updatechannel
-
- @property
- def get_main_dir(self):
- return self.config_main_dir
+ logger.setup(self.config_logfile, self.config_log_level)
@property
def get_update_channel(self):
@@ -533,72 +465,41 @@ class Config:
else:
return self.config_keyfile
- def get_config_logfile(self):
- if not self.config_logfile:
- return os.path.join(self.get_main_dir, "calibre-web.log")
- else:
- if os.path.dirname(self.config_logfile):
- return self.config_logfile
- else:
- return os.path.join(self.get_main_dir, self.config_logfile)
+ def _has_role(self, role_flag):
+ return constants.has_flag(self.config_default_role, role_flag)
def role_admin(self):
- if self.config_default_role is not None:
- return True if self.config_default_role & ROLE_ADMIN == ROLE_ADMIN else False
- else:
- return False
+ return self._has_role(constants.ROLE_ADMIN)
def role_download(self):
- if self.config_default_role is not None:
- return True if self.config_default_role & ROLE_DOWNLOAD == ROLE_DOWNLOAD else False
- else:
- return False
+ return self._has_role(constants.ROLE_DOWNLOAD)
def role_viewer(self):
- if self.config_default_role is not None:
- return True if self.config_default_role & ROLE_VIEWER == ROLE_VIEWER else False
- else:
- return False
+ return self._has_role(constants.ROLE_VIEWER)
def role_upload(self):
- if self.config_default_role is not None:
- return True if self.config_default_role & ROLE_UPLOAD == ROLE_UPLOAD else False
- else:
- return False
+ return self._has_role(constants.ROLE_UPLOAD)
def role_edit(self):
- if self.config_default_role is not None:
- return True if self.config_default_role & ROLE_EDIT == ROLE_EDIT else False
- else:
- return False
+ return self._has_role(constants.ROLE_EDIT)
def role_passwd(self):
- if self.config_default_role is not None:
- return True if self.config_default_role & ROLE_PASSWD == ROLE_PASSWD else False
- else:
- return False
+ return self._has_role(constants.ROLE_PASSWD)
def role_edit_shelfs(self):
- if self.config_default_role is not None:
- return True if self.config_default_role & ROLE_EDIT_SHELFS == ROLE_EDIT_SHELFS else False
- else:
- return False
+ return self._has_role(constants.ROLE_EDIT_SHELFS)
def role_delete_books(self):
- return bool((self.config_default_role is not None) and
- (self.config_default_role & ROLE_DELETE_BOOKS == ROLE_DELETE_BOOKS))
-
- def show_detail_random(self):
- return bool((self.config_default_show is not None) and
- (self.config_default_show & DETAIL_RANDOM == DETAIL_RANDOM))
+ return self._has_role(constants.ROLE_DELETE_BOOKS)
def show_element_new_user(self, value):
- return bool((self.config_default_show is not None) and
- (self.config_default_show & value == value))
+ return constants.has_flag(self.config_default_show, value)
+
+ def show_detail_random(self):
+ return self.show_element_new_user(constants.DETAIL_RANDOM)
def show_mature_content(self):
- return bool((self.config_default_show is not None) and
- (self.config_default_show & MATURE_CONTENT == MATURE_CONTENT))
+ return self.show_element_new_user(constants.MATURE_CONTENT)
def mature_content_tags(self):
if sys.version_info > (3, 0): # Python3 str, Python2 unicode
@@ -608,16 +509,7 @@ class Config:
return list(map(lstrip, self.config_mature_content_tags.split(",")))
def get_Log_Level(self):
- ret_value = ""
- if self.config_log_level == logging.INFO:
- ret_value = 'INFO'
- elif self.config_log_level == logging.DEBUG:
- ret_value = 'DEBUG'
- elif self.config_log_level == logging.WARNING:
- ret_value = 'WARNING'
- elif self.config_log_level == logging.ERROR:
- ret_value = 'ERROR'
- return ret_value
+ return logger.get_level_name(self.config_log_level)
# Migrate database to current version, has to be updated after every database change. Currently migration from
@@ -696,9 +588,9 @@ def migrate_Database():
conn.execute("UPDATE user SET 'sidebar_view' = (random_books* :side_random + language_books * :side_lang "
"+ series_books * :side_series + category_books * :side_category + hot_books * "
":side_hot + :side_autor + :detail_random)"
- ,{'side_random': SIDEBAR_RANDOM, 'side_lang': SIDEBAR_LANGUAGE, 'side_series': SIDEBAR_SERIES,
- 'side_category': SIDEBAR_CATEGORY, 'side_hot': SIDEBAR_HOT, 'side_autor': SIDEBAR_AUTHOR,
- 'detail_random': DETAIL_RANDOM})
+ ,{'side_random': constants.SIDEBAR_RANDOM, 'side_lang': constants.SIDEBAR_LANGUAGE, 'side_series': constants.SIDEBAR_SERIES,
+ 'side_category': constants.SIDEBAR_CATEGORY, 'side_hot': constants.SIDEBAR_HOT, 'side_autor': constants.SIDEBAR_AUTHOR,
+ 'detail_random': constants.DETAIL_RANDOM})
session.commit()
try:
session.query(exists().where(User.mature_content)).scalar()
@@ -706,7 +598,7 @@ def migrate_Database():
conn = engine.connect()
conn.execute("ALTER TABLE user ADD column `mature_content` INTEGER DEFAULT 1")
- if session.query(User).filter(User.role.op('&')(ROLE_ANONYMOUS) == ROLE_ANONYMOUS).first() is None:
+ if session.query(User).filter(User.role.op('&')(constants.ROLE_ANONYMOUS) == constants.ROLE_ANONYMOUS).first() is None:
create_anonymous_user()
try:
session.query(exists().where(Settings.config_remote_login)).scalar()
@@ -850,7 +742,7 @@ def create_anonymous_user():
user = User()
user.nickname = "Guest"
user.email = 'no@email'
- user.role = ROLE_ANONYMOUS
+ user.role = constants.ROLE_ANONYMOUS
user.password = ''
session.add(user)
@@ -864,13 +756,10 @@ def create_anonymous_user():
def create_admin_user():
user = User()
user.nickname = "admin"
- user.role = ROLE_USER + ROLE_ADMIN + ROLE_DOWNLOAD + ROLE_UPLOAD + ROLE_EDIT + ROLE_DELETE_BOOKS + ROLE_PASSWD +\
- ROLE_VIEWER
- user.sidebar_view = DETAIL_RANDOM + SIDEBAR_LANGUAGE + SIDEBAR_SERIES + SIDEBAR_CATEGORY + SIDEBAR_HOT + \
- SIDEBAR_RANDOM + SIDEBAR_AUTHOR + SIDEBAR_BEST_RATED + SIDEBAR_READ_AND_UNREAD + SIDEBAR_RECENT + \
- SIDEBAR_SORTED + MATURE_CONTENT + SIDEBAR_PUBLISHER + SIDEBAR_RATING + SIDEBAR_FORMAT
+ user.role = constants.ADMIN_USER_ROLES
+ user.sidebar_view = constants.ADMIN_USER_SIDEBAR
- user.password = generate_password_hash(DEFAULT_PASS)
+ user.password = generate_password_hash(constants.DEFAULT_PASSWORD)
session.add(user)
try:
diff --git a/cps/updater.py b/cps/updater.py
index d7ec63b0..3b679a51 100644
--- a/cps/updater.py
+++ b/cps/updater.py
@@ -17,22 +17,28 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-
-from . import config, get_locale, Server, app
-import threading
-import zipfile
+from __future__ import division, print_function, unicode_literals
+import sys
+import os
+import datetime
+import json
import requests
+import shutil
+import threading
import time
+import zipfile
from io import BytesIO
-import os
-import sys
-import shutil
-from ub import UPDATE_STABLE
from tempfile import gettempdir
-import datetime
-import json
-from flask_babel import gettext as _
+
from babel.dates import format_datetime
+from flask_babel import gettext as _
+
+from . import constants, logger, config, get_locale, Server
+
+
+log = logger.create()
+_REPOSITORY_API_URL = 'https://api.github.com/repos/janeczku/calibre-web'
+
def is_sha1(sha1):
@@ -53,13 +59,13 @@ class Updater(threading.Thread):
self.updateIndex = None
def get_current_version_info(self):
- if config.get_update_channel == UPDATE_STABLE:
+ if config.get_update_channel == constants.UPDATE_STABLE:
return self._stable_version_info()
else:
return self._nightly_version_info()
def get_available_updates(self, request_method):
- if config.get_update_channel == UPDATE_STABLE:
+ if config.get_update_channel == constants.UPDATE_STABLE:
return self._stable_available_updates(request_method)
else:
return self._nightly_available_updates(request_method)
@@ -67,45 +73,45 @@ class Updater(threading.Thread):
def run(self):
try:
self.status = 1
- app.logger.debug(u'Download update file')
+ log.debug(u'Download update file')
headers = {'Accept': 'application/vnd.github.v3+json'}
r = requests.get(self._get_request_path(), stream=True, headers=headers)
r.raise_for_status()
self.status = 2
- app.logger.debug(u'Opening zipfile')
+ log.debug(u'Opening zipfile')
z = zipfile.ZipFile(BytesIO(r.content))
self.status = 3
- app.logger.debug(u'Extracting zipfile')
+ log.debug(u'Extracting zipfile')
tmp_dir = gettempdir()
z.extractall(tmp_dir)
foldername = os.path.join(tmp_dir, z.namelist()[0])[:-1]
if not os.path.isdir(foldername):
self.status = 11
- app.logger.info(u'Extracted contents of zipfile not found in temp folder')
+ log.info(u'Extracted contents of zipfile not found in temp folder')
return
self.status = 4
- app.logger.debug(u'Replacing files')
- self.update_source(foldername, config.get_main_dir)
+ log.debug(u'Replacing files')
+ self.update_source(foldername, constants.BASE_DIR)
self.status = 6
- app.logger.debug(u'Preparing restart of server')
+ log.debug(u'Preparing restart of server')
time.sleep(2)
Server.setRestartTyp(True)
Server.stopServer()
self.status = 7
time.sleep(2)
except requests.exceptions.HTTPError as ex:
- app.logger.info( u'HTTP Error' + ' ' + str(ex))
+ log.info(u'HTTP Error %s', ex)
self.status = 8
except requests.exceptions.ConnectionError:
- app.logger.info(u'Connection error')
+ log.info(u'Connection error')
self.status = 9
except requests.exceptions.Timeout:
- app.logger.info(u'Timeout while establishing connection')
+ log.info(u'Timeout while establishing connection')
self.status = 10
except requests.exceptions.RequestException:
self.status = 11
- app.logger.info(u'General error')
+ log.info(u'General error')
def get_update_status(self):
return self.status
@@ -153,14 +159,14 @@ class Updater(threading.Thread):
if sys.platform == "win32" or sys.platform == "darwin":
change_permissions = False
else:
- app.logger.debug('Update on OS-System : ' + sys.platform)
+ log.debug('Update on OS-System : %s', sys.platform)
new_permissions = os.stat(root_dst_dir)
# print new_permissions
for src_dir, __, files in os.walk(root_src_dir):
dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
if not os.path.exists(dst_dir):
os.makedirs(dst_dir)
- app.logger.debug('Create-Dir: '+dst_dir)
+ log.debug('Create-Dir: %s', dst_dir)
if change_permissions:
# print('Permissions: User '+str(new_permissions.st_uid)+' Group '+str(new_permissions.st_uid))
os.chown(dst_dir, new_permissions.st_uid, new_permissions.st_gid)
@@ -170,22 +176,22 @@ class Updater(threading.Thread):
if os.path.exists(dst_file):
if change_permissions:
permission = os.stat(dst_file)
- app.logger.debug('Remove file before copy: '+dst_file)
+ log.debug('Remove file before copy: %s', dst_file)
os.remove(dst_file)
else:
if change_permissions:
permission = new_permissions
shutil.move(src_file, dst_dir)
- app.logger.debug('Move File '+src_file+' to '+dst_dir)
+ log.debug('Move File %s to %s', src_file, dst_dir)
if change_permissions:
try:
os.chown(dst_file, permission.st_uid, permission.st_gid)
except (Exception) as e:
# ex = sys.exc_info()
old_permissions = os.stat(dst_file)
- app.logger.debug('Fail change permissions of ' + str(dst_file) + '. Before: '
- + str(old_permissions.st_uid) + ':' + str(old_permissions.st_gid) + ' After: '
- + str(permission.st_uid) + ':' + str(permission.st_gid) + ' error: '+str(e))
+ log.debug('Fail change permissions of %s. Before: %s:%s After %s:%s error: %s',
+ dst_file, old_permissions.st_uid, old_permissions.st_gid,
+ permission.st_uid, permission.st_gid, e)
return
def update_source(self, source, destination):
@@ -219,15 +225,15 @@ class Updater(threading.Thread):
for item in remove_items:
item_path = os.path.join(destination, item[1:])
if os.path.isdir(item_path):
- app.logger.debug("Delete dir " + item_path)
+ log.debug("Delete dir %s", item_path)
shutil.rmtree(item_path, ignore_errors=True)
else:
try:
- app.logger.debug("Delete file " + item_path)
+ log.debug("Delete file %s", item_path)
# log_from_thread("Delete file " + item_path)
os.remove(item_path)
except Exception:
- app.logger.debug("Could not remove:" + item_path)
+ log.debug("Could not remove: %s", item_path)
shutil.rmtree(source, ignore_errors=True)
@classmethod
@@ -243,12 +249,12 @@ class Updater(threading.Thread):
@classmethod
def _stable_version_info(self):
- return {'version': '0.6.4 Beta'} # Current version
+ return constants.STABLE_VERSION # Current version
def _nightly_available_updates(self, request_method):
tz = datetime.timedelta(seconds=time.timezone if (time.localtime().tm_isdst == 0) else time.altzone)
if request_method == "GET":
- repository_url = 'https://api.github.com/repos/janeczku/calibre-web'
+ repository_url = _REPOSITORY_API_URL
status, commit = self._load_remote_data(repository_url +'/git/refs/heads/master')
parents = []
if status['message'] != '':
@@ -348,7 +354,7 @@ class Updater(threading.Thread):
if request_method == "GET":
parents = []
# repository_url = 'https://api.github.com/repos/flatpak/flatpak/releases' # test URL
- repository_url = 'https://api.github.com/repos/janeczku/calibre-web/releases?per_page=100'
+ repository_url = _REPOSITORY_API_URL + '/releases?per_page=100'
status, commit = self._load_remote_data(repository_url)
if status['message'] != '':
return json.dumps(status)
@@ -434,10 +440,10 @@ class Updater(threading.Thread):
return json.dumps(status)
def _get_request_path(self):
- if config.get_update_channel == UPDATE_STABLE:
+ if config.get_update_channel == constants.UPDATE_STABLE:
return self.updateFile
else:
- return 'https://api.github.com/repos/janeczku/calibre-web/zipball/master'
+ return _REPOSITORY_API_URL + '/zipball/master'
def _load_remote_data(self, repository_url):
status = {
diff --git a/cps/uploader.py b/cps/uploader.py
index 235c215c..17816d0a 100644
--- a/cps/uploader.py
+++ b/cps/uploader.py
@@ -17,13 +17,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-
-from tempfile import gettempdir
-import hashlib
+from __future__ import division, print_function, unicode_literals
import os
+import hashlib
+from tempfile import gettempdir
+
from flask_babel import gettext as _
-import comic
-from . import app
+
+from . import logger, comic
+from .constants import BookMeta
+
+
+log = logger.create()
+
try:
from lxml.etree import LXML_VERSION as lxmlversion
@@ -36,7 +42,7 @@ try:
from wand.exceptions import PolicyError
use_generic_pdf_cover = False
except (ImportError, RuntimeError) as e:
- app.logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
+ log.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
use_generic_pdf_cover = True
try:
@@ -44,29 +50,29 @@ try:
from PyPDF2 import __version__ as PyPdfVersion
use_pdf_meta = True
except ImportError as e:
- app.logger.warning('cannot import PyPDF2, extracting pdf metadata will not work: %s', e)
+ log.warning('cannot import PyPDF2, extracting pdf metadata will not work: %s', e)
use_pdf_meta = False
try:
- import epub
+ from . import epub
use_epub_meta = True
except ImportError as e:
- app.logger.warning('cannot import epub, extracting epub metadata will not work: %s', e)
+ log.warning('cannot import epub, extracting epub metadata will not work: %s', e)
use_epub_meta = False
try:
- import fb2
+ from . import fb2
use_fb2_meta = True
except ImportError as e:
- app.logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
+ log.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
use_fb2_meta = False
try:
from PIL import Image
from PIL import __version__ as PILversion
use_PIL = True
-except ImportError:
- app.logger.warning('cannot import Pillow, using png and webp images as cover will not work: %s', e)
+except ImportError as e:
+ log.warning('cannot import Pillow, using png and webp images as cover will not work: %s', e)
use_generic_pdf_cover = True
use_PIL = False
@@ -88,7 +94,7 @@ def process(tmp_file_path, original_file_name, original_file_extension):
meta = comic.get_comic_info(tmp_file_path, original_file_name, original_file_extension)
except Exception as ex:
- app.logger.warning('cannot parse metadata, using default: %s', ex)
+ log.warning('cannot parse metadata, using default: %s', ex)
if meta and meta.title.strip() and meta.author.strip():
return meta
@@ -192,10 +198,10 @@ def pdf_preview(tmp_file_path, tmp_dir):
img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name
except PolicyError as ex:
- app.logger.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex)
+ log.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex)
return None
except Exception as ex:
- app.logger.warning('Cannot extract cover image, using default: %s', ex)
+ log.warning('Cannot extract cover image, using default: %s', ex)
return None
diff --git a/cps/web.py b/cps/web.py
index f02c6006..5c2151f6 100644
--- a/cps/web.py
+++ b/cps/web.py
@@ -21,35 +21,39 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-from . import mimetypes, global_WorkerThread, searched_ids, lm, babel, ub, config, get_locale, language_table, app, db
-from .helper import common_filters, get_search_results, fill_indexpage, speaking_language, check_valid_domain, \
- order_authors, get_typeahead, render_task_status, json_serial, get_unique_other_books, get_cc_columns, \
- get_book_cover, get_download_link, send_mail, generate_random_password, send_registration_mail, \
- check_send_to_kindle, check_read_formats, lcase
-from flask import render_template, request, redirect, send_from_directory, make_response, g, flash, abort, url_for
-from flask_login import login_user, logout_user, login_required, current_user
-from werkzeug.exceptions import default_exceptions
-from werkzeug.security import generate_password_hash, check_password_hash
-from werkzeug.datastructures import Headers
-from redirect import redirect_back
-from pagination import Pagination
+from __future__ import division, print_function, unicode_literals
+import os
+import base64
+import datetime
+import json
+import mimetypes
+
from babel import Locale as LC
from babel.dates import format_date
from babel.core import UnknownLocaleError
+from flask import Blueprint
+from flask import render_template, request, redirect, send_from_directory, make_response, g, flash, abort, url_for
from flask_babel import gettext as _
-from sqlalchemy.sql.expression import text, func, true, false, not_
+from flask_login import login_user, logout_user, login_required, current_user
from sqlalchemy.exc import IntegrityError
-import base64
-import os.path
-import json
-import datetime
-import isoLanguages
-from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download
+from sqlalchemy.sql.expression import text, func, true, false, not_, and_
+from werkzeug.exceptions import default_exceptions
+from werkzeug.datastructures import Headers
+from werkzeug.security import generate_password_hash, check_password_hash
+from . import constants, logger, isoLanguages
+from . import global_WorkerThread, searched_ids, lm, babel, db, ub, config, get_locale, app, language_table
+from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download
+from .helper import common_filters, get_search_results, fill_indexpage, speaking_language, check_valid_domain, \
+ order_authors, get_typeahead, render_task_status, json_serial, get_unique_other_books, get_cc_columns, \
+ get_book_cover, get_download_link, send_mail, generate_random_password, send_registration_mail, \
+ check_send_to_kindle, check_read_formats, lcase
+from .pagination import Pagination
+from .redirect import redirect_back
feature_support = dict()
try:
- from oauth_bb import oauth_check, register_user_with_oauth, logout_oauth_user, get_oauth_status
+ from .oauth_bb import oauth_check, register_user_with_oauth, logout_oauth_user, get_oauth_status
feature_support['oauth'] = True
except ImportError:
feature_support['oauth'] = False
@@ -72,32 +76,17 @@ try:
except ImportError:
pass # We're not using Python 3
-try:
- import rarfile
- feature_support['rar'] = True
-except ImportError:
- feature_support['rar'] = False
+# try:
+# import rarfile
+# feature_support['rar'] = True
+# except ImportError:
+# feature_support['rar'] = False
try:
from natsort import natsorted as sort
except ImportError:
sort = sorted # Just use regular sort then, may cause issues with badly named pages in cbz/cbr files
-from flask import Blueprint
-
-# Global variables
-
-EXTENSIONS_AUDIO = {'mp3', 'm4a', 'm4b'}
-
-EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx',
- 'fb2', 'html', 'rtf', 'odt', 'mp3', 'm4a', 'm4b'}
-
-
-'''EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] +
- (['rar','cbr'] if feature_support['rar'] else []))'''
-
-
-# with app.app_context():
# custom error page
def error_http(error):
@@ -116,6 +105,7 @@ for ex in default_exceptions:
web = Blueprint('web', __name__)
+log = logger.create()
# ################################### Login logic and rights management ###############################################
@@ -238,7 +228,7 @@ def edit_required(f):
# Returns the template for rendering and includes the instance name
def render_title_template(*args, **kwargs):
sidebar=ub.get_sidebar_config(kwargs)
- return render_template(instance=config.config_calibre_web_title, sidebar=sidebar, accept=EXTENSIONS_UPLOAD,
+ return render_template(instance=config.config_calibre_web_title, sidebar=sidebar, accept=constants.EXTENSIONS_UPLOAD,
*args, **kwargs)
@@ -272,9 +262,9 @@ def get_email_status_json():
@login_required
def bookmark(book_id, book_format):
bookmark_key = request.form["bookmark"]
- ub.session.query(ub.Bookmark).filter(ub.and_(ub.Bookmark.user_id == int(current_user.id),
- ub.Bookmark.book_id == book_id,
- ub.Bookmark.format == book_format)).delete()
+ ub.session.query(ub.Bookmark).filter(and_(ub.Bookmark.user_id == int(current_user.id),
+ ub.Bookmark.book_id == book_id,
+ ub.Bookmark.format == book_format)).delete()
if not bookmark_key:
ub.session.commit()
return "", 204
@@ -292,8 +282,8 @@ def bookmark(book_id, book_format):
@login_required
def toggle_read(book_id):
if not config.config_read_column:
- book = ub.session.query(ub.ReadBook).filter(ub.and_(ub.ReadBook.user_id == int(current_user.id),
- ub.ReadBook.book_id == book_id)).first()
+ book = ub.session.query(ub.ReadBook).filter(and_(ub.ReadBook.user_id == int(current_user.id),
+ ub.ReadBook.book_id == book_id)).first()
if book:
book.is_read = not book.is_read
else:
@@ -318,8 +308,7 @@ def toggle_read(book_id):
db.session.add(new_cc)
db.session.commit()
except KeyError:
- app.logger.error(
- u"Custom Column No.%d is not exisiting in calibre database" % config.config_read_column)
+ log.error(u"Custom Column No.%d is not exisiting in calibre database", config.config_read_column)
return ""
'''
@@ -342,10 +331,10 @@ def get_comic_book(book_id, book_format, page):
extract = lambda page: rf.read(names[page])
except:
# rarfile not valid
- app.logger.error('Unrar binary not found, or unable to decompress file ' + cbr_file)
+ log.error('Unrar binary not found, or unable to decompress file %s', cbr_file)
return "", 204
else:
- app.logger.info('Unrar is not supported please install python rarfile extension')
+ log.info('Unrar is not supported please install python rarfile extension')
# no support means return nothing
return "", 204
elif book_format in ("cbz", "zip"):
@@ -357,7 +346,7 @@ def get_comic_book(book_id, book_format, page):
names=sort(tf.getnames())
extract = lambda page: tf.extractfile(names[page]).read()
else:
- app.logger.error('unsupported comic format')
+ log.error('unsupported comic format')
return "", 204
if sys.version_info.major >= 3:
@@ -477,7 +466,7 @@ def books_list(data, sort, book_id, page):
order = [db.Books.timestamp]
if data == "rated":
- if current_user.check_visibility(ub.SIDEBAR_BEST_RATED):
+ if current_user.check_visibility(constants.SIDEBAR_BEST_RATED):
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.ratings.any(db.Ratings.rating > 9),
order)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
@@ -485,7 +474,7 @@ def books_list(data, sort, book_id, page):
else:
abort(404)
elif data == "discover":
- if current_user.check_visibility(ub.SIDEBAR_RANDOM):
+ if current_user.check_visibility(constants.SIDEBAR_RANDOM):
entries, __, pagination = fill_indexpage(page, db.Books, True, [func.randomblob(2)])
pagination = Pagination(1, config.config_books_per_page, config.config_books_per_page)
return render_title_template('discover.html', entries=entries, pagination=pagination,
@@ -517,7 +506,7 @@ def books_list(data, sort, book_id, page):
def render_hot_books(page):
- if current_user.check_visibility(ub.SIDEBAR_HOT):
+ if current_user.check_visibility(constants.SIDEBAR_HOT):
if current_user.show_detail_random():
random = db.session.query(db.Books).filter(common_filters()) \
.order_by(func.random()).limit(config.config_random_books)
@@ -564,7 +553,7 @@ def render_author_books(page, book_id, order):
other_books = get_unique_other_books(entries.all(), author_info.books)
except Exception:
# Skip goodreads, if site is down/inaccessible
- app.logger.error('Goodreads website is down/inaccessible')
+ log.error('Goodreads website is down/inaccessible')
return render_title_template('author.html', entries=entries, pagination=pagination,
title=name, author=author_info, other_books=other_books, page="author")
@@ -630,7 +619,7 @@ def render_category_books(page, book_id, order):
@web.route("/author")
@login_required_if_no_ano
def author_list():
- if current_user.check_visibility(ub.SIDEBAR_AUTHOR):
+ if current_user.check_visibility(constants.SIDEBAR_AUTHOR):
entries = db.session.query(db.Authors, func.count('books_authors_link.book').label('count'))\
.join(db.books_authors_link).join(db.Books).filter(common_filters())\
.group_by(text('books_authors_link.author')).order_by(db.Authors.sort).all()
@@ -648,7 +637,7 @@ def author_list():
@web.route("/publisher")
@login_required_if_no_ano
def publisher_list():
- if current_user.check_visibility(ub.SIDEBAR_PUBLISHER):
+ if current_user.check_visibility(constants.SIDEBAR_PUBLISHER):
entries = db.session.query(db.Publishers, func.count('books_publishers_link.book').label('count'))\
.join(db.books_publishers_link).join(db.Books).filter(common_filters())\
.group_by(text('books_publishers_link.publisher')).order_by(db.Publishers.sort).all()
@@ -664,7 +653,7 @@ def publisher_list():
@web.route("/series")
@login_required_if_no_ano
def series_list():
- if current_user.check_visibility(ub.SIDEBAR_SERIES):
+ if current_user.check_visibility(constants.SIDEBAR_SERIES):
entries = db.session.query(db.Series, func.count('books_series_link.book').label('count'))\
.join(db.books_series_link).join(db.Books).filter(common_filters())\
.group_by(text('books_series_link.series')).order_by(db.Series.sort).all()
@@ -680,7 +669,7 @@ def series_list():
@web.route("/ratings")
@login_required_if_no_ano
def ratings_list():
- if current_user.check_visibility(ub.SIDEBAR_RATING):
+ if current_user.check_visibility(constants.SIDEBAR_RATING):
entries = db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'),
(db.Ratings.rating/2).label('name'))\
.join(db.books_ratings_link).join(db.Books).filter(common_filters())\
@@ -694,7 +683,7 @@ def ratings_list():
@web.route("/formats")
@login_required_if_no_ano
def formats_list():
- if current_user.check_visibility(ub.SIDEBAR_FORMAT):
+ if current_user.check_visibility(constants.SIDEBAR_FORMAT):
entries = db.session.query(db.Data, func.count('data.book').label('count'),db.Data.format.label('format'))\
.join(db.Books).filter(common_filters())\
.group_by(db.Data.format).order_by(db.Data.format).all()
@@ -707,7 +696,7 @@ def formats_list():
@web.route("/language")
@login_required_if_no_ano
def language_overview():
- if current_user.check_visibility(ub.SIDEBAR_LANGUAGE):
+ if current_user.check_visibility(constants.SIDEBAR_LANGUAGE):
charlist = list()
if current_user.filter_language() == u"all":
languages = speaking_language()
@@ -753,7 +742,7 @@ def language(name, page):
@web.route("/category")
@login_required_if_no_ano
def category_list():
- if current_user.check_visibility(ub.SIDEBAR_CATEGORY):
+ if current_user.check_visibility(constants.SIDEBAR_CATEGORY):
entries = db.session.query(db.Tags, func.count('books_tags_link.book').label('count'))\
.join(db.books_tags_link).join(db.Books).order_by(db.Tags.name).filter(common_filters())\
.group_by(text('books_tags_link.tag')).all()
@@ -945,7 +934,7 @@ def render_read_books(page, are_read, as_xml=False, order=None):
.filter(db.cc_classes[config.config_read_column].value is True).all()
readBookIds = [x.book for x in readBooks]
except KeyError:
- app.logger.error(u"Custom Column No.%d is not existing in calibre database" % config.config_read_column)
+ log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column)
readBookIds = []
if are_read:
@@ -988,7 +977,7 @@ def serve_book(book_id, book_format):
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper())\
.first()
- app.logger.info('Serving book: %s', data.name)
+ log.info('Serving book: %s', data.name)
if config.config_use_google_drive:
headers = Headers()
try:
@@ -1058,7 +1047,7 @@ def register():
content.password = generate_password_hash(password)
content.role = config.config_default_role
content.sidebar_view = config.config_default_show
- content.mature_content = bool(config.config_default_show & ub.MATURE_CONTENT)
+ content.mature_content = bool(config.config_default_show & constants.MATURE_CONTENT)
try:
ub.session.add(content)
ub.session.commit()
@@ -1071,8 +1060,7 @@ def register():
return render_title_template('register.html', title=_(u"register"), page="register")
else:
flash(_(u"Your e-mail is not allowed to register"), category="error")
- app.logger.info('Registering failed for user "' + to_save['nickname'] + '" e-mail adress: ' +
- to_save["email"])
+ log.info('Registering failed for user "%s" e-mail adress: %s', to_save['nickname'], to_save["email"])
return render_title_template('register.html', title=_(u"register"), page="register")
flash(_(u"Confirmation e-mail was send to your e-mail account."), category="success")
return redirect(url_for('web.login'))
@@ -1104,10 +1092,10 @@ def login():
return redirect_back(url_for("web.index"))
except ldap.INVALID_CREDENTIALS:
ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr)
- app.logger.info('LDAP Login failed for user "' + form['username'] + '" IP-adress: ' + ipAdress)
+ log.info('LDAP Login failed for user "%s" IP-adress: %s', form['username'], ipAdress)
flash(_(u"Wrong Username or Password"), category="error")
except ldap.SERVER_DOWN:
- app.logger.info('LDAP Login failed, LDAP Server down')
+ log.info('LDAP Login failed, LDAP Server down')
flash(_(u"Could not login. LDAP server down, please contact your administrator"), category="error")
else:
if user and check_password_hash(user.password, form['password']) and user.nickname is not "Guest":
@@ -1116,7 +1104,7 @@ def login():
return redirect_back(url_for("web.index"))
else:
ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr)
- app.logger.info('Login failed for user "' + form['username'] + '" IP-adress: ' + ipAdress)
+ log.info('Login failed for user "%s" IP-adress: %s', form['username'], ipAdress)
flash(_(u"Wrong Username or Password"), category="error")
next_url = url_for('web.index')
@@ -1263,7 +1251,7 @@ def profile():
val += int(key[5:])
current_user.sidebar_view = val
if "Show_detail_random" in to_save:
- current_user.sidebar_view += ub.DETAIL_RANDOM
+ current_user.sidebar_view += constants.DETAIL_RANDOM
current_user.mature_content = "Show_mature_content" in to_save
@@ -1297,9 +1285,9 @@ def read_book(book_id, book_format):
# check if book has bookmark
bookmark = None
if current_user.is_authenticated:
- bookmark = ub.session.query(ub.Bookmark).filter(ub.and_(ub.Bookmark.user_id == int(current_user.id),
- ub.Bookmark.book_id == book_id,
- ub.Bookmark.format == book_format.upper())).first()
+ bookmark = ub.session.query(ub.Bookmark).filter(and_(ub.Bookmark.user_id == int(current_user.id),
+ ub.Bookmark.book_id == book_id,
+ ub.Bookmark.format == book_format.upper())).first()
if book_format.lower() == "epub":
return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book"), bookmark=bookmark)
elif book_format.lower() == "pdf":
@@ -1350,15 +1338,14 @@ def show_book(book_id):
if not current_user.is_anonymous:
if not config.config_read_column:
matching_have_read_book = ub.session.query(ub.ReadBook).\
- filter(ub.and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == book_id)).all()
+ filter(and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == book_id)).all()
have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].is_read
else:
try:
matching_have_read_book = getattr(entries, 'custom_column_'+str(config.config_read_column))
have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].value
except KeyError:
- app.logger.error(
- u"Custom Column No.%d is not exisiting in calibre database" % config.config_read_column)
+ log.error("Custom Column No.%d is not exisiting in calibre database", config.config_read_column)
have_read = None
else:
@@ -1373,7 +1360,7 @@ def show_book(book_id):
audioentries = []
for media_format in entries.data:
- if media_format.format.lower() in EXTENSIONS_AUDIO:
+ if media_format.format.lower() in constants.EXTENSIONS_AUDIO:
audioentries.append(media_format.format.lower())
return render_title_template('detail.html', entry=entries, audioentries=audioentries, cc=cc,
diff --git a/cps/worker.py b/cps/worker.py
index 8da30885..3d5f058a 100644
--- a/cps/worker.py
+++ b/cps/worker.py
@@ -17,21 +17,15 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-from __future__ import print_function
-import smtplib
-import threading
-from datetime import datetime
-import logging
-import time
-import socket
+from __future__ import division, print_function, unicode_literals
import sys
import os
-from email.generator import Generator
-from . import config, db, app
-from flask_babel import gettext as _
import re
-from .gdriveutils import getFileFromEbooksFolder, updateGdriveCalibreFromLocal
-from .subproc_wrapper import process_open
+import smtplib
+import socket
+import time
+import threading
+from datetime import datetime
try:
from StringIO import StringIO
@@ -47,6 +41,14 @@ except ImportError:
from email import encoders
from email.utils import formatdate
from email.utils import make_msgid
+from email.generator import Generator
+from flask_babel import gettext as _
+
+from . import logger, config, db, gdriveutils
+from .subproc_wrapper import process_open
+
+
+log = logger.create()
chunksize = 8192
# task 'status' consts
@@ -70,7 +72,7 @@ def get_attachment(bookpath, filename):
"""Get file as MIMEBase message"""
calibrepath = config.config_calibre_dir
if config.config_use_google_drive:
- df = getFileFromEbooksFolder(bookpath, filename)
+ df = gdriveutils.getFileFromEbooksFolder(bookpath, filename)
if df:
datafile = os.path.join(calibrepath, bookpath, filename)
if not os.path.exists(os.path.join(calibrepath, bookpath)):
@@ -88,8 +90,8 @@ def get_attachment(bookpath, filename):
data = file_.read()
file_.close()
except IOError as e:
- app.logger.exception(e) # traceback.print_exc()
- app.logger.error(u'The requested file could not be read. Maybe wrong permissions?')
+ log.exception(e) # traceback.print_exc()
+ log.error(u'The requested file could not be read. Maybe wrong permissions?')
return None
attachment = MIMEBase('application', 'octet-stream')
@@ -114,7 +116,7 @@ class emailbase():
def send(self, strg):
"""Send `strg' to the server."""
- app.logger.debug('send:' + repr(strg[:300]))
+ log.debug('send: %r', strg[:300])
if hasattr(self, 'sock') and self.sock:
try:
if self.transferSize:
@@ -139,7 +141,7 @@ class emailbase():
raise smtplib.SMTPServerDisconnected('please run connect() first')
def _print_debug(self, *args):
- app.logger.debug(args)
+ log.debug(args)
def getTransferStatus(self):
if self.transferSize:
@@ -236,7 +238,7 @@ class WorkerThread(threading.Thread):
filename = self._convert_ebook_format()
if filename:
if config.config_use_google_drive:
- updateGdriveCalibreFromLocal()
+ gdriveutils.updateGdriveCalibreFromLocal()
if curr_task == TASK_CONVERT:
self.add_email(self.queue[self.current]['settings']['subject'], self.queue[self.current]['path'],
filename, self.queue[self.current]['settings'], self.queue[self.current]['kindle'],
@@ -254,14 +256,14 @@ class WorkerThread(threading.Thread):
# if it does - mark the conversion task as complete and return a success
# this will allow send to kindle workflow to continue to work
if os.path.isfile(file_path + format_new_ext):
- app.logger.info("Book id %d already converted to %s", bookid, format_new_ext)
+ log.info("Book id %d already converted to %s", bookid, format_new_ext)
cur_book = db.session.query(db.Books).filter(db.Books.id == bookid).first()
self.queue[self.current]['path'] = file_path
self.queue[self.current]['title'] = cur_book.title
self._handleSuccess()
return file_path + format_new_ext
else:
- app.logger.info("Book id %d - target format of %s does not exist. Moving forward with convert.", bookid, format_new_ext)
+ log.info("Book id %d - target format of %s does not exist. Moving forward with convert.", bookid, format_new_ext)
# check if converter-executable is existing
if not os.path.exists(config.config_converterpath):
@@ -317,13 +319,13 @@ class WorkerThread(threading.Thread):
if conv_error:
error_message = _(u"Kindlegen failed with Error %(error)s. Message: %(message)s",
error=conv_error.group(1), message=conv_error.group(2).strip())
- app.logger.debug("convert_kindlegen: " + nextline)
+ log.debug("convert_kindlegen: %s", nextline)
else:
while p.poll() is None:
nextline = p.stdout.readline()
if os.name == 'nt' and sys.version_info < (3, 0):
nextline = nextline.decode('windows-1252')
- app.logger.debug(nextline.strip('\r\n'))
+ log.debug(nextline.strip('\r\n'))
# parse progress string from calibre-converter
progress = re.search("(\d+)%\s.*", nextline)
if progress:
@@ -353,7 +355,7 @@ class WorkerThread(threading.Thread):
return file_path + format_new_ext
else:
error_message = format_new_ext.upper() + ' format not found on disk'
- app.logger.info("ebook converter failed with error while converting book")
+ log.info("ebook converter failed with error while converting book")
if not error_message:
error_message = 'Ebook converter failed with unknown error'
self._handleError(error_message)
@@ -449,7 +451,7 @@ class WorkerThread(threading.Thread):
# _print_debug function
if sys.version_info < (3, 0):
org_smtpstderr = smtplib.stderr
- smtplib.stderr = StderrLogger()
+ smtplib.stderr = logger.StderrLogger('worker.smtp')
if use_ssl == 2:
self.asyncSMTP = email_SSL(obj['settings']["mail_server"], obj['settings']["mail_port"], timeout)
@@ -457,9 +459,7 @@ class WorkerThread(threading.Thread):
self.asyncSMTP = email(obj['settings']["mail_server"], obj['settings']["mail_port"], timeout)
# link to logginglevel
- if config.config_log_level != logging.DEBUG:
- self.asyncSMTP.set_debuglevel(0)
- else:
+ if logger.is_debug_enabled():
self.asyncSMTP.set_debuglevel(1)
if use_ssl == 1:
self.asyncSMTP.starttls()
@@ -501,7 +501,7 @@ class WorkerThread(threading.Thread):
return retVal
def _handleError(self, error_message):
- app.logger.error(error_message)
+ log.error(error_message)
self.UIqueue[self.current]['stat'] = STAT_FAIL
self.UIqueue[self.current]['progress'] = "100 %"
self.UIqueue[self.current]['runtime'] = self._formatRuntime(
@@ -513,22 +513,3 @@ class WorkerThread(threading.Thread):
self.UIqueue[self.current]['progress'] = "100 %"
self.UIqueue[self.current]['runtime'] = self._formatRuntime(
datetime.now() - self.queue[self.current]['starttime'])
-
-
-# Enable logging of smtp lib debug output
-class StderrLogger(object):
-
- buffer = ''
-
- def __init__(self):
- self.logger = app.logger
-
- def write(self, message):
- try:
- if message == '\n':
- self.logger.debug(self.buffer.replace("\n","\\n"))
- self.buffer = ''
- else:
- self.buffer += message
- except:
- self.logger.debug("Logging Error")