diff --git a/cps.py b/cps.py index 16d84957..ca7d7230 100755 --- a/cps.py +++ b/cps.py @@ -23,8 +23,12 @@ import os # Insert local directories into path -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'vendor')) +if sys.version_info < (3, 0): + sys.path.append(os.path.dirname(os.path.abspath(__file__.decode('utf-8')))) + sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__.decode('utf-8'))), 'vendor')) +else: + sys.path.append(os.path.dirname(os.path.abspath(__file__))) + sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'vendor')) from cps import create_app diff --git a/cps/__init__.py b/cps/__init__.py index 50bd1781..6b8815e9 100755 --- a/cps/__init__.py +++ b/cps/__init__.py @@ -87,8 +87,8 @@ global_WorkerThread = WorkerThread() from .server import WebServer web_server = WebServer() -from .ldap import Ldap -ldap = Ldap() +from .ldap_login import Ldap +ldap1 = Ldap() babel = Babel() @@ -97,6 +97,12 @@ log = logger.create() def create_app(): app.wsgi_app = ReverseProxied(app.wsgi_app) + # For python2 convert path to unicode + if sys.version_info < (3, 0): + app.static_folder = app.static_folder.decode('utf-8') + app.root_path = app.root_path.decode('utf-8') + app.instance_path = app.instance_path .decode('utf-8') + cache_buster.init_cache_busting(app) log.info('Starting Calibre Web...') @@ -106,7 +112,7 @@ def create_app(): web_server.init_app(app, config) db.setup_db() babel.init_app(app) - ldap.init_app(app) + ldap1.init_app(app) global_WorkerThread.start() return app diff --git a/cps/admin.py b/cps/admin.py index 449c5684..4984e2f0 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -40,7 +40,7 @@ from sqlalchemy import and_ from sqlalchemy.exc import IntegrityError from werkzeug.security import generate_password_hash -from . import constants, logger, ldap +from . import constants, logger, ldap1 from . import db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils from .helper import speaking_language, check_valid_domain, check_unrar, send_test_mail, generate_random_password, \ send_registration_mail @@ -48,7 +48,7 @@ from .gdriveutils import is_gdrive_ready, gdrive_support, downloadFile, deleteDa from .web import admin_required, render_title_template, before_request, unconfigured, login_required_if_no_ano feature_support = dict() -feature_support['ldap'] = ldap.ldap_supported() +feature_support['ldap'] = ldap1.ldap_supported() try: from goodreads.client import GoodreadsClient diff --git a/cps/cli.py b/cps/cli.py index 1bda9c93..de12be5a 100644 --- a/cps/cli.py +++ b/cps/cli.py @@ -82,6 +82,18 @@ parser.add_argument('-i', metavar='ip-adress', help='Server IP-Adress to listen' parser.add_argument('-s', metavar='user:pass', help='Sets specific username to new password') args = parser.parse_args() +if sys.version_info < (3, 0): + if args.p: + args.p = args.p.decode('utf-8') + if args.g: + args.g = args.g.decode('utf-8') + if args.k: + args.k = args.k.decode('utf-8') + if args.c: + args.c = args.c.decode('utf-8') + if args.s: + args.s = args.s.decode('utf-8') + settingspath = args.p or os.path.join(_CONFIG_DIR, "app.db") gdpath = args.g or os.path.join(_CONFIG_DIR, "gdrive.db") diff --git a/cps/constants.py b/cps/constants.py index aaf0cd21..fce91312 100644 --- a/cps/constants.py +++ b/cps/constants.py @@ -24,7 +24,12 @@ from collections import namedtuple # Base dir is parent of current file, necessary if called from different folder -BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),os.pardir)) +if sys.version_info < (3, 0): + BASE_DIR = os.path.abspath(os.path.join( + os.path.dirname(os.path.abspath(__file__)),os.pardir)).decode('utf-8') +else: + BASE_DIR = os.path.abspath(os.path.join( + os.path.dirname(os.path.abspath(__file__)),os.pardir)) STATIC_DIR = os.path.join(BASE_DIR, 'cps', 'static') TEMPLATES_DIR = os.path.join(BASE_DIR, 'cps', 'templates') TRANSLATIONS_DIR = os.path.join(BASE_DIR, 'cps', 'translations') diff --git a/cps/db.py b/cps/db.py index 2cd959ad..5429e93c 100755 --- a/cps/db.py +++ b/cps/db.py @@ -342,7 +342,7 @@ def setup_db(): try: if not os.path.exists(dbpath): raise - engine = create_engine('sqlite:///' + dbpath, + engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False, isolation_level="SERIALIZABLE", connect_args={'check_same_thread': False}) diff --git a/cps/ldap.py b/cps/ldap_login.py similarity index 95% rename from cps/ldap.py rename to cps/ldap_login.py index 0688475a..dcded6f6 100644 --- a/cps/ldap.py +++ b/cps/ldap_login.py @@ -16,10 +16,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import division, print_function, unicode_literals import base64 try: - from flask_simpleldap import LDAP, LDAPException + from flask_simpleldap import LDAP # , LDAPException ldap_support = True except ImportError: ldap_support = False diff --git a/cps/opds.py b/cps/opds.py index 2ba95635..ee3e86fc 100644 --- a/cps/opds.py +++ b/cps/opds.py @@ -31,7 +31,7 @@ from flask_login import current_user from sqlalchemy.sql.expression import func, text, or_, and_ from werkzeug.security import check_password_hash -from . import logger, config, db, ub, ldap +from . import logger, config, db, ub, ldap1 from .helper import fill_indexpage, get_download_link, get_book_cover from .pagination import Pagination from .web import common_filters, get_search_results, render_read_books, download_required @@ -40,14 +40,14 @@ from .web import common_filters, get_search_results, render_read_books, download opds = Blueprint('opds', __name__) log = logger.create() -ldap_support = ldap.ldap_supported() +ldap_support = ldap1.ldap_supported() def requires_basic_auth_if_no_ano(f): @wraps(f) def decorated(*args, **kwargs): if config.config_login_type == 1 and ldap_support: - return ldap.ldap.basic_auth_required(*args, **kwargs) + return ldap1.ldap.basic_auth_required(*args, **kwargs) auth = request.authorization if config.config_anonbrowse != 1: if not auth or not check_auth(auth.username, auth.password): @@ -57,15 +57,6 @@ def requires_basic_auth_if_no_ano(f): return decorated -'''def basic_auth_required_check(condition): - print("susi") - def decorator(f): - if condition and ldap_support: - return ldap.ldap.basic_auth_required(f) - return requires_basic_auth_if_no_ano(f) - return decorator''' - - @opds.route("/opds/") @requires_basic_auth_if_no_ano def feed_index(): diff --git a/cps/server.py b/cps/server.py index 70efcacd..5945b332 100644 --- a/cps/server.py +++ b/cps/server.py @@ -25,7 +25,7 @@ import signal import socket try: - from gevent.pyiwsgi import WSGIServer + from gevent.pywsgi import WSGIServer from gevent.pool import Pool from gevent import __version__ as _version VERSION = {'Gevent': 'v' + _version} diff --git a/cps/ub.py b/cps/ub.py index 9d04a908..02623448 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -40,18 +40,12 @@ 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''' - from . import constants, logger, cli session = None - -engine = create_engine('sqlite:///{0}'.format(cli.settingspath), echo=False) +engine = create_engine(u'sqlite:///{0}'.format(cli.settingspath), echo=False) Base = declarative_base() diff --git a/cps/web.py b/cps/web.py index 3f8964d4..491fbbf6 100644 --- a/cps/web.py +++ b/cps/web.py @@ -41,7 +41,7 @@ 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, ldap +from . import constants, logger, isoLanguages, ldap1 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, \ @@ -52,7 +52,7 @@ from .pagination import Pagination from .redirect import redirect_back feature_support = dict() -feature_support['ldap'] = ldap.ldap_supported() +feature_support['ldap'] = ldap1.ldap_supported() try: from .oauth_bb import oauth_check, register_user_with_oauth, logout_oauth_user, get_oauth_status @@ -1093,17 +1093,17 @@ def login(): .first() if config.config_login_type == 1 and user and feature_support['ldap']: try: - if ldap.ldap.bind_user(form['username'], form['password']) is not None: + if ldap1.ldap.bind_user(form['username'], form['password']) is not None: login_user(user, remember=True) flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success") return redirect_back(url_for("web.index")) - except ldap.ldap.INVALID_CREDENTIALS as e: + except ldap1.ldap.INVALID_CREDENTIALS as e: log.error('Login Error: ' + str(e)) ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr) log.info('LDAP Login failed for user "%s" IP-adress: %s', form['username'], ipAdress) flash(_(u"Wrong Username or Password"), category="error") - except ldap.ldap.SERVER_DOWN: + except ldap1.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") '''except LDAPException as exception: diff --git a/cps/worker.py b/cps/worker.py index a33ad99d..345d79bb 100644 --- a/cps/worker.py +++ b/cps/worker.py @@ -326,6 +326,8 @@ class WorkerThread(threading.Thread): nextline = p.stdout.readline() if os.name == 'nt' and sys.version_info < (3, 0): nextline = nextline.decode('windows-1252') + elif os.name == 'posix' and sys.version_info < (3, 0): + nextline = nextline.decode('utf-8') log.debug(nextline.strip('\r\n')) # parse progress string from calibre-converter progress = re.search("(\d+)%\s.*", nextline) diff --git a/test/Calibre-Web TestSummary.html b/test/Calibre-Web TestSummary.html index 571c1fb1..b1ef2283 100644 --- a/test/Calibre-Web TestSummary.html +++ b/test/Calibre-Web TestSummary.html @@ -30,15 +30,15 @@
-

Start Time: 2019-05-12 18:51:22.511134

+

Start Time: 2019-06-22 21:54:40.897700

-

Stop Time: 2019-05-12 19:42:21.577115

+

Stop Time: 2019-06-22 22:37:09.413469

-

Duration: 0:50:59.065981

+

Duration: 0:42:28.515769

@@ -574,8 +574,8 @@ ret['edit_enable'] = bool(tree.find("//*[@class='glyphicon glyphicon-edit']")) /home/matthias/Entwicklung/calibre-web-test/test/ui_helper.py:709: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead. ret['read']= bool(tree.find("//*[@id='have_read_cb']")) -Incomming connection 127.0.0.1:45556 -127.0.0.1:45556 Timeouted +Incomming connection 127.0.0.1:45524 +127.0.0.1:45524 Timeouted
@@ -598,8 +598,8 @@ Incomming connection 127.0.0.1:45556 aria-hidden="true">×
-
pt3.2: Incomming connection 127.0.0.1:45562
-127.0.0.1:45562 Timeouted
+
pt3.2: Incomming connection 127.0.0.1:45526
+127.0.0.1:45526 Timeouted
@@ -622,17 +622,17 @@ Incomming connection 127.0.0.1:45556 aria-hidden="true">×
-
pt3.3: Incomming connection 127.0.0.1:45564
+                
pt3.3: Incomming connection 127.0.0.1:45528
 Received: EHLO
 Received: AUTH
 User: name@host.com, Password: 10234
 Received: MAIL
 Received: RCPT
 Received: DATA
-('Receiving message from:', ('127.0.0.1', 45564))
-('Message addressed from:', '<name@host.com> size=507')
+('Receiving message from:', ('127.0.0.1', 45528))
+('Message addressed from:', '<name@host.com> size=508')
 ('Message addressed to  :', ['a1@b.com'])
-('Message length        :', 506)
+('Message length        :', 507)
 Received: QUIT
@@ -656,17 +656,17 @@ Received: QUIT aria-hidden="true">×
-
pt3.4: Incomming connection 127.0.0.1:45566
+                
pt3.4: Incomming connection 127.0.0.1:45530
 Received: EHLO
 Received: AUTH
 User: name@host.com, Password: 10234
 Received: MAIL
 Received: RCPT
 Received: DATA
-('Receiving message from:', ('127.0.0.1', 45566))
-('Message addressed from:', '<name@host.com> size=30377')
+('Receiving message from:', ('127.0.0.1', 45530))
+('Message addressed from:', '<name@host.com> size=30379')
 ('Message addressed to  :', ['a1@b.com'])
-('Message length        :', 30376)
+('Message length        :', 30378)
 Received: QUIT
@@ -701,8 +701,8 @@ Received: QUIT aria-hidden="true">×
-
pt4.1: Incomming connection 127.0.0.1:45674
-127.0.0.1:45674 Timeouted
+
pt4.1: Incomming connection 127.0.0.1:45622
+127.0.0.1:45622 Timeouted
@@ -725,8 +725,8 @@ Received: QUIT aria-hidden="true">×
-
pt4.2: Incomming connection 127.0.0.1:45680
-127.0.0.1:45680 Timeouted
+
pt4.2: Incomming connection 127.0.0.1:45624
+127.0.0.1:45624 Timeouted
@@ -749,14 +749,14 @@ Received: QUIT aria-hidden="true">×
-
pt4.3: Incomming connection 127.0.0.1:45682
+                
pt4.3: Incomming connection 127.0.0.1:45626
 Received: EHLO
 Received: AUTH
 User: name@host.com, Password: 10234
 Received: MAIL
 Received: RCPT
 Received: DATA
-('Receiving message from:', ('127.0.0.1', 45682))
+('Receiving message from:', ('127.0.0.1', 45626))
 ('Message addressed from:', '<name@host.com> size=523')
 ('Message addressed to  :', ['a1@b.com'])
 ('Message length        :', 506)
@@ -783,14 +783,14 @@ Received: QUIT
aria-hidden="true">×
-
pt4.4: Incomming connection 127.0.0.1:45684
+                
pt4.4: Incomming connection 127.0.0.1:45628
 Received: EHLO
 Received: AUTH
 User: name@host.com, Password: 10234
 Received: MAIL
 Received: RCPT
 Received: DATA
-('Receiving message from:', ('127.0.0.1', 45684))
+('Receiving message from:', ('127.0.0.1', 45628))
 ('Message addressed from:', '<name@host.com> size=30788')
 ('Message addressed to  :', ['a1@b.com'])
 ('Message length        :', 30378)
@@ -801,78 +801,118 @@ Received: QUIT
- - test_logging.test_logging_Python27 - 5 + + unittest.suite._ErrorHolder + 3 + 0 + 0 3 - 1 0 - 1 - Detail + Detail - + -
test_debug_log
- - PASS - - - -
test_failed_login
- - PASS - - - -
test_failed_register
+
test_logging_Python27)
- SKIP + ERROR
-
- test_anonymous.test_anonymous_Python27 + test_anonymous.test_anonymous_Python36 10 10 0 @@ -1545,79 +1585,1386 @@ AssertionError: logfile config value is not empty after reseting to default PASS - - test_anonymous.test_anonymous_Python36 - 10 - 10 - 0 + + test_user_template.test_user_template_Python27 + 25 0 0 + 22 + 3 - Detail + Detail - + -
test_guest_about
+
test_author_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_change_visibility_category
+
test_author_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_change_visibility_hot
+
test_best_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_change_visibility_language
+
test_best_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_change_visibility_publisher
+
test_category_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_change_visibility_rated
+
test_category_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_change_visibility_series
+
test_detail_random_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_random_books_available
+
test_detail_random_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_visibility_read
+
test_hot_user_template
+ + +
+ ERROR +
+ + + - PASS - + -
test_guest_visibility_sidebar
+
test_hot_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_language_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_language_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_limit_book_languages
+ + +
+ SKIP +
+ + + + + + + +
test_mature_content_settings
+ + +
+ SKIP +
+ + + + + + + +
test_publisher_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_publisher_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_random_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_random_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_read_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_read_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_recent_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_recent_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_series_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_series_user_template
+ + +
+ ERROR +
+ + + + + + + +
test_ui_language_settings
+ + +
+ SKIP +
+ + + - PASS - test_user_template.test_user_template_Python27 + test_user_template.test_user_template_Python36 14 11 0 @@ -1762,186 +3109,6 @@ AssertionError: logfile config value is not empty after reseting to default - - test_user_template.test_user_template_Python36 - 14 - 11 - 0 - 0 - 3 - - Detail - - - - -
test_author_user_template
- - PASS - - - -
test_best_user_template
- - PASS - - - -
test_category_user_template
- - PASS - - - -
test_detail_random_user_template
- - PASS - - - -
test_hot_user_template
- - PASS - - - -
test_language_user_template
- - PASS - - - -
test_limit_book_languages
- - -
- SKIP -
- - - - - - - -
test_mature_content_settings
- - -
- SKIP -
- - - - - - - -
test_publisher_user_template
- - PASS - - - -
test_random_user_template
- - PASS - - - -
test_read_user_template
- - PASS - - - -
test_recent_user_template
- - PASS - - - -
test_series_user_template
- - PASS - - - -
test_ui_language_settings
- - -
- SKIP -
- - - - - - - test_updater.test_updater - 1 - 0 - 0 - 0 - 1 - - Detail - - - - -
test_updater
- - -
- SKIP -
- - - - - test_cli.test_cli_Python27 6 @@ -1950,57 +3117,57 @@ AssertionError: logfile config value is not empty after reseting to default0 1 - Detail + Detail - +
test_already_started
PASS - +
test_cli_SSL_files
PASS - +
test_cli_different_folder
PASS - +
test_cli_different_settings_database
PASS - +
test_cli_gdrive_location
- SKIP + SKIP
-