+
{% endif %}
{% endif %}
diff --git a/cps/templates/index.xml b/cps/templates/index.xml
index 7ab305aa..f7e8d6f0 100644
--- a/cps/templates/index.xml
+++ b/cps/templates/index.xml
@@ -2,13 +2,12 @@
urn:uuid:2853dacf-ed79-42f5-8e8a-a7bb3d1ae6a2
{{ current_time }}
-
-
+
-
{{instance}}
{{instance}}
@@ -16,88 +15,88 @@
{{_('Hot Books')}}
-
- {{url_for('feed_hot')}}
+
+ {{url_for('opds.feed_hot')}}
{{ current_time }}
{{_('Popular publications from this catalog based on Downloads.')}}
{{_('Best rated Books')}}
-
- {{url_for('feed_best_rated')}}
+
+ {{url_for('opds.feed_best_rated')}}
{{ current_time }}
{{_('Popular publications from this catalog based on Rating.')}}
{{_('New Books')}}
-
- {{url_for('feed_new')}}
+
+ {{url_for('opds.feed_new')}}
{{ current_time }}
{{_('The latest Books')}}
{{_('Random Books')}}
-
- {{url_for('feed_discover')}}
+
+ {{url_for('opds.feed_discover')}}
{{ current_time }}
{{_('Show Random Books')}}
{% if not current_user.is_anonymous %}
{{_('Read Books')}}
-
- {{url_for('feed_read_books')}}
+
+ {{url_for('opds.feed_read_books')}}
{{ current_time }}
{{_('Read Books')}}
- {% endif %}
{{_('Unread Books')}}
-
- {{url_for('feed_unread_books')}}
+
+ {{url_for('opds.feed_unread_books')}}
{{ current_time }}
{{_('Unread Books')}}
+ {% endif %}
{{_('Authors')}}
-
- {{url_for('feed_authorindex')}}
+
+ {{url_for('opds.feed_authorindex')}}
{{ current_time }}
{{_('Books ordered by Author')}}
{{_('Publishers')}}
-
- {{url_for('feed_publisherindex')}}
+
+ {{url_for('opds.feed_publisherindex')}}
{{ current_time }}
{{_('Books ordered by publisher')}}
{{_('Category list')}}
-
- {{url_for('feed_categoryindex')}}
+
+ {{url_for('opds.feed_categoryindex')}}
{{ current_time }}
{{_('Books ordered by category')}}
{{_('Series list')}}
-
- {{url_for('feed_seriesindex')}}
+
+ {{url_for('opds.feed_seriesindex')}}
{{ current_time }}
{{_('Books ordered by series')}}
{{_('Public Shelves')}}
-
- {{url_for('feed_shelfindex', public="public")}}
+
+ {{url_for('opds.feed_shelfindex', public="public")}}
{{ current_time }}
{{_('Books organized in public shelfs, visible to everyone')}}
{% if not current_user.is_anonymous %}
{{_('Your Shelves')}}
-
- {{url_for('feed_shelfindex')}}
+
+ {{url_for('opds.feed_shelfindex')}}
{{ current_time }}
{{_("User's own shelfs, only visible to the current user himself")}}
diff --git a/cps/templates/json.txt b/cps/templates/json.txt
index fa5239b1..c068b1b4 100644
--- a/cps/templates/json.txt
+++ b/cps/templates/json.txt
@@ -1,53 +1,53 @@
{
- "pubdate": "{{entry.pubdate}}",
- "title": "{{entry.title}}",
+ "pubdate": "{{entry.pubdate}}",
+ "title": "{{entry.title}}",
"format_metadata": {
- {% for format in entry.data %}
+ {% for format in entry.data %}
"{{format.format}}": {
- "mtime": "{{entry.last_modified}}",
- "size": {{format.uncompressed_size}},
+ "mtime": "{{entry.last_modified}}",
+ "size": {{format.uncompressed_size}},
"path": ""
}{% if not loop.last %},{% endif %}
{% endfor %}
- },
+ },
"formats": [
- {% for format in entry.data %}
+ {% for format in entry.data %}
"{{format.format}}"{% if not loop.last %},{% endif %}
- {% endfor %}
- ],
- "series": null,
- "cover": "{{url_for('feed_get_cover', book_id=entry.id)}}",
+ {% endfor %}
+ ],
+ "series": null,
+ "cover": "{{url_for('opds.feed_get_cover', book_id=entry.id)}}",
"languages": [
- {% for lang in entry.languages %}
+ {% for lang in entry.languages %}
"{{lang.lang_code}}"{% if not loop.last %},{% endif %}
{% endfor %}
- ],
+ ],
"comments": "{% if entry.comments|length > 0 %}{{entry.comments[0].text.replace('"', '\\"')|safe}}{% endif %}",
"tags": [
{% for tag in entry.tags %}
"{{tag.name}}"{% if not loop.last %},{% endif %}
- {% endfor %}
- ],
- "application_id": {{entry.id}},
- "series_index": {% if entry.series|length > 0 %}"{{entry.series_index}}"{% else %}null{% endif %},
- "last_modified": "{{entry.last_modified}}",
- "author_sort": "{{entry.author_sort}}",
- "uuid": "{{entry.uuid}}",
- "timestamp": "{{entry.timestamp}}",
- "thumbnail": "{{url_for('feed_get_cover', book_id=entry.id)}}",
+ {% endfor %}
+ ],
+ "application_id": {{entry.id}},
+ "series_index": {% if entry.series|length > 0 %}"{{entry.series_index}}"{% else %}null{% endif %},
+ "last_modified": "{{entry.last_modified}}",
+ "author_sort": "{{entry.author_sort}}",
+ "uuid": "{{entry.uuid}}",
+ "timestamp": "{{entry.timestamp}}",
+ "thumbnail": "{{url_for('opds.feed_get_cover', book_id=entry.id)}}",
"main_format": {
- "{{entry.data[0].format|lower}}": "{{ url_for('get_opds_download_link', book_id=entry.id, book_format=entry.data[0].format|lower)}}"
+ "{{entry.data[0].format|lower}}": "{{ url_for('opds.get_opds_download_link', book_id=entry.id, book_format=entry.data[0].format|lower)}}"
},
"rating":{% if entry.ratings.__len__() > 0 %} "{{entry.ratings[0].rating}}.0"{% else %}0.0{% endif %},
"authors": [
{% for author in entry.authors %}
"{{author.name.replace('|',',')}}"{% if not loop.last %},{% endif %}
- {% endfor %}
- ],
+ {% endfor %}
+ ],
"other_formats": {
{% if entry.data.__len__() > 1 %}
{% for format in entry.data[1:] %}
- "{{format.format|lower}}": "{{ url_for('get_opds_download_link', book_id=entry.id, book_format=format.format|lower)}}"{% if not loop.last %},{% endif %}
+ "{{format.format|lower}}": "{{ url_for('opds.get_opds_download_link', book_id=entry.id, book_format=format.format|lower)}}"{% if not loop.last %},{% endif %}
{% endfor %}
{% endif %} },
"title_sort": "{{entry.sort}}"
diff --git a/cps/templates/layout.html b/cps/templates/layout.html
index ef83e842..897c6cb6 100644
--- a/cps/templates/layout.html
+++ b/cps/templates/layout.html
@@ -161,7 +161,7 @@
{% if g.user.is_authenticated or g.user.is_anonymous %}
{{_('Public Shelves')}}
{% for shelf in g.public_shelfes %}
- {{shelf.name|shortentitle(40)}}
+ {{shelf.name|shortentitle(40)}}
{% endfor %}
{{_('Your Shelves')}}
{% for shelf in g.user.shelf %}
diff --git a/cps/templates/osd.xml b/cps/templates/osd.xml
index b88e6823..bb741bb5 100644
--- a/cps/templates/osd.xml
+++ b/cps/templates/osd.xml
@@ -6,9 +6,9 @@
Janeczku
https://github.com/janeczku/calibre-web
+ template="{{url_for('opds.search')}}?query={searchTerms}"/>
+ template="{{url_for('opds.feed_normal_search')}}?query={searchTerms}"/>
open
{{lang}}
UTF-8
diff --git a/cps/ub.py b/cps/ub.py
index 59f0b613..dbc42ac4 100644
--- a/cps/ub.py
+++ b/cps/ub.py
@@ -23,7 +23,6 @@ from sqlalchemy import exc
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
from flask_login import AnonymousUserMixin
-from flask_dance.consumer.backend.sqla import OAuthConsumerMixin
import sys
import os
import logging
@@ -34,8 +33,11 @@ from binascii import hexlify
import cli
try:
+ from flask_dance.consumer.backend.sqla import OAuthConsumerMixin
import ldap
+ oauth_support = True
except ImportError:
+ oauth_support = False
pass
engine = create_engine('sqlite:///{0}'.format(cli.settingspath), echo=False)
@@ -207,11 +209,11 @@ class User(UserBase, Base):
default_language = Column(String(3), default="all")
mature_content = Column(Boolean, default=True)
-
-class OAuth(OAuthConsumerMixin, Base):
- provider_user_id = Column(String(256))
- user_id = Column(Integer, ForeignKey(User.id))
- user = relationship(User)
+if oauth_support:
+ class OAuth(OAuthConsumerMixin, Base):
+ provider_user_id = Column(String(256))
+ user_id = Column(Integer, ForeignKey(User.id))
+ user = relationship(User)
# Class for anonymous user is derived from User base and completly overrides methods and properties for the
@@ -834,7 +836,7 @@ def delete_download(book_id):
session.commit()
# Generate user Guest (translated text), as anoymous user, no rights
-def create_anonymous_user(session):
+def create_anonymous_user():
user = User()
user.nickname = "Guest"
user.email = 'no@email'
diff --git a/cps/updater.py b/cps/updater.py
index b01646a0..e5dd6bae 100644
--- a/cps/updater.py
+++ b/cps/updater.py
@@ -18,11 +18,10 @@
# along with this program. If not, see .
-from cps import config, get_locale
+from cps import config, get_locale, Server, app
import threading
import zipfile
import requests
-import logging
import time
from io import BytesIO
import os
@@ -35,7 +34,6 @@ import json
from flask_babel import gettext as _
from babel.dates import format_datetime
-import server
def is_sha1(sha1):
if len(sha1) != 40:
@@ -69,39 +67,45 @@ class Updater(threading.Thread):
def run(self):
try:
self.status = 1
- r = requests.get(self._get_request_path(), stream=True)
+ app.logger.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')
z = zipfile.ZipFile(BytesIO(r.content))
self.status = 3
+ app.logger.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
- logging.getLogger('cps.web').info(u'Extracted contents of zipfile not found in temp folder')
+ app.logger.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)
self.status = 6
+ app.logger.debug(u'Preparing restart of server')
time.sleep(2)
- server.Server.setRestartTyp(True)
- server.Server.stopServer()
+ Server.setRestartTyp(True)
+ Server.stopServer()
self.status = 7
time.sleep(2)
except requests.exceptions.HTTPError as ex:
- logging.getLogger('cps.web').info( u'HTTP Error' + ' ' + str(ex))
+ app.logger.info( u'HTTP Error' + ' ' + str(ex))
self.status = 8
except requests.exceptions.ConnectionError:
- logging.getLogger('cps.web').info(u'Connection error')
+ app.logger.info(u'Connection error')
self.status = 9
except requests.exceptions.Timeout:
- logging.getLogger('cps.web').info(u'Timeout while establishing connection')
+ app.logger.info(u'Timeout while establishing connection')
self.status = 10
except requests.exceptions.RequestException:
self.status = 11
- logging.getLogger('cps.web').info(u'General error')
+ app.logger.info(u'General error')
def get_update_status(self):
return self.status
@@ -149,14 +153,14 @@ class Updater(threading.Thread):
if sys.platform == "win32" or sys.platform == "darwin":
change_permissions = False
else:
- logging.getLogger('cps.web').debug('Update on OS-System : ' + sys.platform)
+ app.logger.debug('Update on OS-System : ' + 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)
- logging.getLogger('cps.web').debug('Create-Dir: '+dst_dir)
+ app.logger.debug('Create-Dir: '+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)
@@ -166,20 +170,20 @@ class Updater(threading.Thread):
if os.path.exists(dst_file):
if change_permissions:
permission = os.stat(dst_file)
- logging.getLogger('cps.web').debug('Remove file before copy: '+dst_file)
+ app.logger.debug('Remove file before copy: '+dst_file)
os.remove(dst_file)
else:
if change_permissions:
permission = new_permissions
shutil.move(src_file, dst_dir)
- logging.getLogger('cps.web').debug('Move File '+src_file+' to '+dst_dir)
+ app.logger.debug('Move File '+src_file+' to '+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)
- logging.getLogger('cps.web').debug('Fail change permissions of ' + str(dst_file) + '. Before: '
+ 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))
return
@@ -215,15 +219,15 @@ class Updater(threading.Thread):
for item in remove_items:
item_path = os.path.join(destination, item[1:])
if os.path.isdir(item_path):
- logging.getLogger('cps.web').debug("Delete dir " + item_path)
+ app.logger.debug("Delete dir " + item_path)
shutil.rmtree(item_path, ignore_errors=True)
else:
try:
- logging.getLogger('cps.web').debug("Delete file " + item_path)
+ app.logger.debug("Delete file " + item_path)
# log_from_thread("Delete file " + item_path)
os.remove(item_path)
except Exception:
- logging.getLogger('cps.web').debug("Could not remove:" + item_path)
+ app.logger.debug("Could not remove:" + item_path)
shutil.rmtree(source, ignore_errors=True)
def _nightly_version_info(self):
@@ -263,7 +267,8 @@ class Updater(threading.Thread):
status['update'] = True
try:
- r = requests.get(repository_url + '/git/commits/' + commit['object']['sha'])
+ headers = {'Accept': 'application/vnd.github.v3+json'}
+ r = requests.get(repository_url + '/git/commits/' + commit['object']['sha'], headers=headers)
r.raise_for_status()
update_data = r.json()
except requests.exceptions.HTTPError as e:
@@ -310,7 +315,8 @@ class Updater(threading.Thread):
# check if we are more than one update behind if so, go up the tree
if parent_commit['sha'] != status['current_commit_hash']:
try:
- r = requests.get(parent_commit['url'])
+ headers = {'Accept': 'application/vnd.github.v3+json'}
+ r = requests.get(parent_commit['url'], headers=headers)
r.raise_for_status()
parent_data = r.json()
@@ -368,7 +374,8 @@ class Updater(threading.Thread):
# check if we are more than one update behind if so, go up the tree
if commit['sha'] != status['current_commit_hash']:
try:
- r = requests.get(parent_commit['url'])
+ headers = {'Accept': 'application/vnd.github.v3+json'}
+ r = requests.get(parent_commit['url'], headers=headers)
r.raise_for_status()
parent_data = r.json()
@@ -492,7 +499,8 @@ class Updater(threading.Thread):
else:
status['current_commit_hash'] = version['version']
try:
- r = requests.get(repository_url)
+ headers = {'Accept': 'application/vnd.github.v3+json'}
+ r = requests.get(repository_url, headers=headers)
commit = r.json()
r.raise_for_status()
except requests.exceptions.HTTPError as e:
diff --git a/cps/web.py b/cps/web.py
index 91cc8ff0..ef87712f 100644
--- a/cps/web.py
+++ b/cps/web.py
@@ -47,18 +47,19 @@ from cps import lm, babel, ub, config, get_locale, language_table, app
from pagination import Pagination
from sqlalchemy.sql.expression import text
-from oauth_bb import oauth_check, register_user_with_oauth, logout_oauth_user, get_oauth_status
-
-'''try:
- oauth_support = True
+feature_support = dict()
+try:
+ from oauth_bb import oauth_check, register_user_with_oauth, logout_oauth_user, get_oauth_status
+ feature_support['oauth'] = True
except ImportError:
- oauth_support = False'''
+ feature_support['oauth'] = False
+ oauth_check = {}
try:
import ldap
- ldap_support = True
+ feature_support['ldap'] = True
except ImportError:
- ldap_support = False
+ feature_support['ldap'] = False
try:
from googleapiclient.errors import HttpError
@@ -67,15 +68,15 @@ except ImportError:
try:
from goodreads.client import GoodreadsClient
- goodreads_support = True
+ feature_support['goodreads'] = True
except ImportError:
- goodreads_support = False
+ feature_support['goodreads'] = False
try:
import Levenshtein
- levenshtein_support = True
+ feature_support['levenshtein'] = True
except ImportError:
- levenshtein_support = False
+ feature_support['levenshtein'] = False
try:
from functools import reduce, wraps
@@ -84,9 +85,9 @@ except ImportError:
try:
import rarfile
- rar_support=True
+ feature_support['rar'] = True
except ImportError:
- rar_support=False
+ feature_support['rar'] = False
try:
from natsort import natsorted as sort
@@ -95,18 +96,17 @@ except ImportError:
try:
from urllib.parse import quote
- from imp import reload
except ImportError:
from urllib import quote
-
from flask import Blueprint
# Global variables
EXTENSIONS_AUDIO = {'mp3', 'm4a', 'm4b'}
-# EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] + (['rar','cbr'] if rar_support else []))
+'''EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] +
+ (['rar','cbr'] if feature_support['rar'] else []))'''
# custom error page
@@ -346,8 +346,8 @@ def before_request():
g.allow_upload = config.config_uploading
g.current_theme = config.config_theme
g.public_shelfes = ub.session.query(ub.Shelf).filter(ub.Shelf.is_public == 1).order_by(ub.Shelf.name).all()
- if not config.db_configured and request.endpoint not in ('web.basic_configuration', 'login') and '/static/' not in request.path:
- return redirect(url_for('web.basic_configuration'))
+ if not config.db_configured and request.endpoint not in ('admin.basic_configuration', 'login') and '/static/' not in request.path:
+ return redirect(url_for('admin.basic_configuration'))
@web.route("/ajax/emailstat")
@@ -373,7 +373,7 @@ def get_comic_book(book_id, book_format, page):
if bookformat.format.lower() == book_format.lower():
cbr_file = os.path.join(config.config_calibre_dir, book.path, bookformat.name) + "." + book_format
if book_format in ("cbr", "rar"):
- if rar_support == True:
+ if feature_support['rar'] == True:
rarfile.UNRAR_TOOL = config.config_rarfile_location
try:
rf = rarfile.RarFile(cbr_file)
@@ -636,7 +636,7 @@ def author(book_id, page):
author_info = None
other_books = []
- if goodreads_support and config.config_use_goodreads:
+ if feature_support['goodreads'] and config.config_use_goodreads:
try:
gc = GoodreadsClient(config.config_goodreads_api_key, config.config_goodreads_api_secret)
author_info = gc.find_author(author_name=name)
@@ -688,7 +688,7 @@ def get_unique_other_books(library_books, author_books):
author_books)
# Fuzzy match book titles
- if levenshtein_support:
+ if feature_support['levenshtein']:
library_titles = reduce(lambda acc, book: acc + [book.title], library_books, [])
other_books = filter(lambda author_book: not filter(
lambda library_book:
@@ -1215,7 +1215,7 @@ def read_book(book_id, book_format):
# copyfile(cbr_file, tmp_file)
return render_title_template('readcbr.html', comicfile=all_name, title=_(u"Read a Book"),
extension=fileext)
- '''if rar_support == True:
+ '''if feature_support['rar']:
extensionList = ["cbr","cbt","cbz"]
else:
extensionList = ["cbt","cbz"]
@@ -1292,7 +1292,7 @@ def register():
try:
ub.session.add(content)
ub.session.commit()
- if oauth_support:
+ if feature_support['oauth']:
register_user_with_oauth(content)
helper.send_registration_mail(to_save["email"], to_save["nickname"], password)
except Exception:
@@ -1310,7 +1310,7 @@ def register():
flash(_(u"This username or e-mail address is already in use."), category="error")
return render_title_template('register.html', title=_(u"register"), page="register")
- if oauth_support:
+ if feature_support['oauth']:
register_user_with_oauth()
return render_title_template('register.html', config=config, title=_(u"register"), page="register")
@@ -1318,7 +1318,7 @@ def register():
@web.route('/login', methods=['GET', 'POST'])
def login():
if not config.db_configured:
- return redirect(url_for('web.basic_configuration'))
+ return redirect(url_for('admin.basic_configuration'))
if current_user is not None and current_user.is_authenticated:
return redirect(url_for('web.index'))
if request.method == "POST":
@@ -1358,7 +1358,7 @@ def login():
def logout():
if current_user is not None and current_user.is_authenticated:
logout_user()
- if oauth_support:
+ if feature_support['oauth']:
logout_oauth_user()
return redirect(url_for('web.login'))
@@ -1370,7 +1370,7 @@ def remote_login():
ub.session.add(auth_token)
ub.session.commit()
- verify_url = url_for('verify_token', token=auth_token.auth_token, _external=true)
+ verify_url = url_for('web.verify_token', token=auth_token.auth_token, _external=true)
return render_title_template('remote_login.html', title=_(u"login"), token=auth_token.auth_token,
verify_url=verify_url, page="remotelogin")
@@ -1385,7 +1385,7 @@ def verify_token(token):
# Token not found
if auth_token is None:
flash(_(u"Token not found"), category="error")
- return redirect(url_for('index'))
+ return redirect(url_for('web.index'))
# Token expired
if datetime.datetime.now() > auth_token.expiration:
@@ -1393,7 +1393,7 @@ def verify_token(token):
ub.session.commit()
flash(_(u"Token has expired"), category="error")
- return redirect(url_for('index'))
+ return redirect(url_for('web.index'))
# Update token with user information
auth_token.user_id = current_user.id
@@ -1401,7 +1401,7 @@ def verify_token(token):
ub.session.commit()
flash(_(u"Success! Please return to your device"), category="success")
- return redirect(url_for('index'))
+ return redirect(url_for('web.index'))
@web.route('/ajax/verify_token', methods=['POST'])
@@ -1472,7 +1472,10 @@ def profile():
downloads = list()
languages = speaking_language()
translations = babel.list_translations() + [LC('en')]
- oauth_status = get_oauth_status()
+ if feature_support['oauth']:
+ oauth_status = get_oauth_status()
+ else:
+ oauth_status = None
for book in content.downloads:
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
if downloadBook:
@@ -1535,9 +1538,11 @@ def profile():
ub.session.rollback()
flash(_(u"Found an existing account for this e-mail address."), category="error")
return render_title_template("user_edit.html", content=content, downloads=downloads,
- title=_(u"%(name)s's profile", name=current_user.nickname, registered_oauth=oauth_check, oauth_status=oauth_status))
+ title=_(u"%(name)s's profile", name=current_user.nickname,
+ registered_oauth=oauth_check, oauth_status=oauth_status))
flash(_(u"Profile updated"), category="success")
return render_title_template("user_edit.html", translations=translations, profile=1, languages=languages,
- content=content, downloads=downloads, title=_(u"%(name)s's profile",
- name=current_user.nickname), page="me", registered_oauth=oauth_check, oauth_status=oauth_status)
+ content=content, downloads=downloads, title=_(u"%(name)s's profile",
+ name=current_user.nickname), page="me", registered_oauth=oauth_check,
+ oauth_status=oauth_status)
diff --git a/cps/worker.py b/cps/worker.py
index c0c68833..77df162c 100644
--- a/cps/worker.py
+++ b/cps/worker.py
@@ -27,14 +27,12 @@ import socket
import sys
import os
from email.generator import Generator
-from cps import config, db # , app
-# import web
+from cps import config, db, app
from flask_babel import gettext as _
import re
-# import gdriveutils as gd
+import gdriveutils as gd
from subproc_wrapper import process_open
-
try:
from StringIO import StringIO
from email.MIMEBase import MIMEBase
@@ -90,8 +88,8 @@ def get_attachment(bookpath, filename):
data = file_.read()
file_.close()
except IOError as e:
- # web.app.logger.exception(e) # traceback.print_exc()
- # web.app.logger.error(u'The requested file could not be read. Maybe wrong permissions?')
+ app.logger.exception(e) # traceback.print_exc()
+ app.logger.error(u'The requested file could not be read. Maybe wrong permissions?')
return None
attachment = MIMEBase('application', 'octet-stream')
@@ -116,8 +114,7 @@ class emailbase():
def send(self, strg):
"""Send `strg' to the server."""
- if self.debuglevel > 0:
- print('send:', repr(strg[:300]), file=sys.stderr)
+ app.logger.debug('send:' + repr(strg[:300]))
if hasattr(self, 'sock') and self.sock:
try:
if self.transferSize:
@@ -141,6 +138,9 @@ class emailbase():
else:
raise smtplib.SMTPServerDisconnected('please run connect() first')
+ def _print_debug(self, *args):
+ app.logger.debug(args)
+
def getTransferStatus(self):
if self.transferSize:
lock2 = threading.Lock()
@@ -254,14 +254,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):
- # web.app.logger.info("Book id %d already converted to %s", bookid, format_new_ext)
+ app.logger.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:
- web.app.logger.info("Book id %d - target format of %s does not exist. Moving forward with convert.", bookid, format_new_ext)
+ app.logger.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):
@@ -274,22 +274,22 @@ class WorkerThread(threading.Thread):
if format_old_ext == '.epub' and format_new_ext == '.mobi':
if config.config_ebookconverter == 1:
'''if os.name == 'nt':
- command = web.ub.config.config_converterpath + u' "' + file_path + u'.epub"'
+ command = config.config_converterpath + u' "' + file_path + u'.epub"'
if sys.version_info < (3, 0):
command = command.encode(sys.getfilesystemencoding())
else:'''
command = [config.config_converterpath, file_path + u'.epub']
- quotes = (1)
+ quotes = [1]
if config.config_ebookconverter == 2:
# Linux py2.7 encode as list without quotes no empty element for parameters
# linux py3.x no encode and as list without quotes no empty element for parameters
# windows py2.7 encode as string with quotes empty element for parameters is okay
# windows py 3.x no encode and as string with quotes empty element for parameters is okay
# separate handling for windows and linux
- quotes = (1,2)
+ quotes = [1,2]
'''if os.name == 'nt':
- command = web.ub.config.config_converterpath + u' "' + file_path + format_old_ext + u'" "' + \
- file_path + format_new_ext + u'" ' + web.ub.config.config_calibre
+ command = config.config_converterpath + u' "' + file_path + format_old_ext + u'" "' + \
+ file_path + format_new_ext + u'" ' + config.config_calibre
if sys.version_info < (3, 0):
command = command.encode(sys.getfilesystemencoding())
else:'''
@@ -317,13 +317,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())
- web.app.logger.debug("convert_kindlegen: " + nextline)
+ app.logger.debug("convert_kindlegen: " + 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')
- web.app.logger.debug(nextline.strip('\r\n'))
+ app.logger.debug(nextline.strip('\r\n'))
# parse progress string from calibre-converter
progress = re.search("(\d+)%\s.*", nextline)
if progress:
@@ -353,7 +353,7 @@ class WorkerThread(threading.Thread):
return file_path + format_new_ext
else:
error_message = format_new_ext.upper() + ' format not found on disk'
- # web.app.logger.info("ebook converter failed with error while converting book")
+ app.logger.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)
@@ -414,7 +414,6 @@ class WorkerThread(threading.Thread):
def _send_raw_email(self):
self.queue[self.current]['starttime'] = datetime.now()
self.UIqueue[self.current]['formStarttime'] = self.queue[self.current]['starttime']
- # self.queue[self.current]['status'] = STAT_STARTED
self.UIqueue[self.current]['stat'] = STAT_STARTED
obj=self.queue[self.current]
# create MIME message
@@ -446,8 +445,11 @@ class WorkerThread(threading.Thread):
# send email
timeout = 600 # set timeout to 5mins
- org_stderr = sys.stderr
- sys.stderr = StderrLogger()
+ # redirect output to logfile on python2 pn python3 debugoutput is caught with overwritten
+ # _print_debug function
+ if sys.version_info < (3, 0):
+ org_smtpstderr = smtplib.stderr
+ smtplib.stderr = StderrLogger()
if use_ssl == 2:
self.asyncSMTP = email_SSL(obj['settings']["mail_server"], obj['settings']["mail_port"], timeout)
@@ -455,7 +457,7 @@ class WorkerThread(threading.Thread):
self.asyncSMTP = email(obj['settings']["mail_server"], obj['settings']["mail_port"], timeout)
# link to logginglevel
- if web.ub.config.config_log_level != logging.DEBUG:
+ if config.config_log_level != logging.DEBUG:
self.asyncSMTP.set_debuglevel(0)
else:
self.asyncSMTP.set_debuglevel(1)
@@ -466,7 +468,9 @@ class WorkerThread(threading.Thread):
self.asyncSMTP.sendmail(obj['settings']["mail_from"], obj['recipent'], msg)
self.asyncSMTP.quit()
self._handleSuccess()
- sys.stderr = org_stderr
+
+ if sys.version_info < (3, 0):
+ smtplib.stderr = org_smtpstderr
except (MemoryError) as e:
self._handleError(u'Error sending email: ' + e.message)
@@ -497,7 +501,7 @@ class WorkerThread(threading.Thread):
return retVal
def _handleError(self, error_message):
- web.app.logger.error(error_message)
+ app.logger.error(error_message)
# self.queue[self.current]['status'] = STAT_FAIL
self.UIqueue[self.current]['stat'] = STAT_FAIL
self.UIqueue[self.current]['progress'] = "100 %"
@@ -519,13 +523,12 @@ class StderrLogger(object):
buffer = ''
def __init__(self):
- self.logger = web.app.logger
+ self.logger = app.logger
def write(self, message):
try:
if message == '\n':
- self.logger.debug(self.buffer)
- print(self.buffer)
+ self.logger.debug(self.buffer.replace("\n","\\n"))
self.buffer = ''
else:
self.buffer += message
diff --git a/optional-requirements.txt b/optional-requirements.txt
index 399acec4..9b740f6c 100644
--- a/optional-requirements.txt
+++ b/optional-requirements.txt
@@ -11,12 +11,19 @@ PyDrive==1.3.1
PyYAML==3.12
rsa==3.4.2
six==1.10.0
+
# goodreads
goodreads>=0.3.2
python-Levenshtein>=0.12.0
+
# ldap login
python_ldap>=3.0.0
+
# other
lxml>=3.8.0
rarfile>=2.7
natsort>=2.2.0
+
+# Oauth Login
+flask-dance>=0.13.0
+sqlalchemy_utils>=0.33.5
diff --git a/requirements.txt b/requirements.txt
index 2b13eb54..3fb23ea3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,5 +13,3 @@ SQLAlchemy>=1.1.0
tornado>=4.1
Wand>=0.4.4
unidecode>=0.04.19
-flask-dance>=0.13.0
-sqlalchemy_utils>=0.33.5
diff --git a/test/Calibre-Web TestSummary.html b/test/Calibre-Web TestSummary.html
index 97d89880..32ddf212 100644
--- a/test/Calibre-Web TestSummary.html
+++ b/test/Calibre-Web TestSummary.html
@@ -30,15 +30,15 @@
@@ -577,97 +577,92 @@
-
+
test_email_ssl.test_SSL_Python27
4
- 4
- 0
+ 1
0
+ 3
0
Detail
-
+
test_SSL_None_setup_error
-
+
-
-
+
test_SSL_STARTTLS_setup_error
-
+
-
-
+
test_SSL_only
-
+
-
-
pt3.4: Incomming connection 127.0.0.1:44864
+ pt3.4: Incomming connection 127.0.0.1:40856
Received: EHLO
Received: AUTH
User: name@host.com, Password: 10234
Received: MAIL
Received: RCPT
Received: DATA
-('Receiving message from:', ('127.0.0.1', 44864))
-('Message addressed from:', '<name@host.com> size=508')
+('Receiving message from:', ('127.0.0.1', 40856))
+('Message addressed from:', '<name@host.com> size=507')
('Message addressed to :', ['a1@b.com'])
-('Message length :', 507)
+('Message length :', 506)
Received: QUIT
@@ -708,93 +703,89 @@ Received: QUIT
-
+
test_email_ssl.test_SSL_Python36
4
- 3
- 1
0
+ 1
+ 3
0
Detail
-
+
test_SSL_None_setup_error
-
+
-
-
+
test_SSL_STARTTLS_setup_error
-
+
-
-
+
test_SSL_only
-
+
-
-
+
test_anonymous.test_anonymous_Python27
- 10
- 10
+ 1
0
0
0
+ 1
- Detail
+ Detail
-
+
- test_anonymous_change_visibility_authors
+ test_anonymous_user
- PASS
-
-
-
- test_anonymous_change_visibility_category
+
+
+
+
+
+
+
- PASS
-
-
- test_anonymous_change_visibility_hot
-
- PASS
-
-
-
- test_anonymous_change_visibility_language
-
- PASS
-
-
-
- test_anonymous_change_visibility_publisher
-
- PASS
-
-
-
- test_anonymous_change_visibility_rated
-
- PASS
-
-
-
- test_anonymous_change_visibility_series
-
- PASS
-
-
-
- test_anonymous_change_visibility_sorted
-
- PASS
-
-
-
- test_anonymous_impossible_settings
-
- PASS
-
-
-
- test_anonymous_locale_select
-
- PASS
-
-
+
test_anonymous.test_anonymous_Python36
- 10
- 10
+ 1
0
0
0
+ 1
- Detail
+ Detail
-
+
- test_anonymous_change_visibility_authors
+ test_anonymous_user
- PASS
-
-
-
- test_anonymous_change_visibility_category
+
+
+
+
+
+
+
- PASS
-
-
-
- test_anonymous_change_visibility_hot
-
- PASS
-
-
-
- test_anonymous_change_visibility_language
-
- PASS
-
-
-
- test_anonymous_change_visibility_publisher
-
- PASS
-
-
-
- test_anonymous_change_visibility_rated
-
- PASS
-
-
-
- test_anonymous_change_visibility_series
-
- PASS
-
-
-
- test_anonymous_change_visibility_sorted
-
- PASS
-
-
-
- test_anonymous_impossible_settings
-
- PASS
-
-
-
- test_anonymous_locale_select
-
- PASS
test_user_template.test_user_template_Python27
@@ -1982,24 +1899,24 @@ AssertionError: logfile config value is not empty after reseting to default
test_cli.test_cli_Python27
- 7
6
+ 5
0
0
1
- Detail
+ Detail
- test_cli_SSL_files
+ test_already_started
PASS
- test_cli_already_started
+ test_cli_SSL_files
PASS
@@ -2015,61 +1932,55 @@ AssertionError: logfile config value is not empty after reseting to default
PASS
-
-
- test_cli_environ_port_setting
-
- PASS
-
-
+
test_cli_gdrive_location
-
+
-
-
+
- test_cli_server_Stop
+ test_environ_port_setting
PASS
test_cli.test_cli_Python36
- 7
6
+ 5
0
0
1
- Detail
+ Detail
- test_cli_SSL_files
+ test_already_started
PASS
- test_cli_already_started
+ test_cli_SSL_files
PASS
@@ -2085,48 +1996,42 @@ AssertionError: logfile config value is not empty after reseting to default
PASS
-
-
- test_cli_environ_port_setting
-
- PASS
-
-
+
test_cli_gdrive_location
-
+
-
-
+
- test_cli_server_Stop
+ test_environ_port_setting
PASS
-
+
test_shelf.test_shelf_Python27
7
6
- 0
- 0
1
+ 0
+ 0
Detail
@@ -2161,23 +2066,26 @@ AssertionError: logfile config value is not empty after reseting to default
PASS
-
+
test_shelf_database_change
-
+
-
-
+
test_shelf.test_shelf_Python36
7
6
- 0
- 0
1
+ 0
+ 0
Detail
@@ -2231,23 +2139,26 @@ AssertionError: logfile config value is not empty after reseting to default
PASS
-
+
test_shelf_database_change
-
+
-
-
+
test_login.test_login_Python27
+ 7
6
- 6
- 0
+ 1
0
0
- Detail
+ Detail
@@ -2291,31 +2202,57 @@ AssertionError: logfile config value is not empty after reseting to default
- test_login_protected
+ test_login_locale_select
PASS
-
+
+
+ test_login_protected
+
+
+
+
+
+
+
+
+
+
+
test_login_unicode_user_space_end_passwort
PASS
-
+
test_login_user_with_space_passwort_end_space
PASS
-
+
test_login.test_login_Python36
+ 7
6
- 6
- 0
+ 1
0
0
- Detail
+ Detail
@@ -2337,79 +2274,109 @@ AssertionError: logfile config value is not empty after reseting to defaultPASS
+
+ test_login_locale_select
+
+ PASS
+
+
test_login_protected
- PASS
-
-
-
- test_login_unicode_user_space_end_passwort
-
- PASS
-
-
-
- test_login_user_with_space_passwort_end_space
-
- PASS
-
-
- test_ebook_convert.test_ebook_convert_Python27
- 11
- 11
- 0
- 0
- 0
-
- Detail
-
-
-
-
- test_SSL_smtp_setup_error
-
-
+
-
-
+
+
+ test_login_unicode_user_space_end_passwort
+
+ PASS
+
+
+
+ test_login_user_with_space_passwort_end_space
+
+ PASS
+
+
+ test_ebook_convert.test_ebook_convert_Python27
+ 11
+ 2
+ 2
+ 7
+ 0
+
+ Detail
+
+
+
+
+ test_SSL_smtp_setup_error
+
+
+
+
+
+
+
+
+
+
+
test_STARTTLS_smtp_setup_error
-
+
-
-
+
test_convert_email
-
+
-
-
+
test_convert_failed_and_email
-
+
-
-
+
test_convert_only
-
+
-
-
+
test_convert_parameter
- PASS
+
+
+
+
+
+
+
+
-
+
test_convert_wrong_excecutable
- PASS
+
+
+
+
+
+
+
+
-
+
test_email_failed
-
+
-
-
+
test_email_only
-
+
-
PASS
-
+
test_ebook_convert.test_ebook_convert_Python36
11
- 9
2
- 0
+ 3
+ 6
0
Detail
-
+
test_SSL_smtp_setup_error
-
+
-
-
+
test_STARTTLS_smtp_setup_error
-
+
-
-
+
test_convert_email
-
+
-
-
+
test_convert_failed_and_email
-
+
-
-
+
test_convert_only
-
+
-
-
+
test_convert_parameter
- PASS
+
+
+
+
+
+
+
+
-
+
test_convert_wrong_excecutable
- PASS
+
+
+
+
+
+
+
+
-
+
test_email_failed
-
+
-
ft20.10: Traceback (most recent call last):
- File "/home/matthias/Entwicklung/calibre-web-test/test/test_ebook_convert.py", line 404, in test_email_only
+ File "/home/matthias/Entwicklung/calibre-web-test/test/test_ebook_convert.py", line 400, in test_email_only
self.assertEqual(ret[-1]['result'], 'Finished')
AssertionError: 'Waiting' != 'Finished'
@@ -3859,142 +3780,126 @@ AssertionError: 'The camicdemo' != '\n '
-
+
test_email_STARTTLS.test_STARTTLS_Python27
2
+ 0
+ 0
2
0
- 0
- 0
Detail
-
+
test_STARTTLS
-
+
-
-
+
test_STARTTLS_SSL_setup_error
-
+
-
-
+
test_email_STARTTLS.test_STARTTLS_Python36
2
+ 0
+ 0
2
0
- 0
- 0
Detail
-
+
test_STARTTLS
-
+
-
-
+
test_STARTTLS_SSL_setup_error
-
+
-