diff --git a/cps/admin.py b/cps/admin.py index b30d1607..f1f865da 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -164,7 +164,6 @@ def view_configuration(): @login_required @admin_required def update_view_configuration(): - reboot_required = False to_save = request.form.to_dict() _config_string = lambda x: config.set_from_dictionary(to_save, x, lambda y: y.strip() if y else y) @@ -172,7 +171,8 @@ def update_view_configuration(): _config_string("config_calibre_web_title") _config_string("config_columns_to_ignore") - reboot_required |= _config_string("config_title_regex") + if _config_string("config_title_regex"): + calibre_db.update_title_sort(config) _config_int("config_read_column") _config_int("config_theme") @@ -191,10 +191,6 @@ def update_view_configuration(): config.save() flash(_(u"Calibre-Web configuration updated"), category="success") before_request() - if reboot_required: - db.dispose() - ub.dispose() - web_server.stop(True) return view_configuration() @@ -572,7 +568,9 @@ def _configuration_ldap_helper(to_save, gdriveError): reboot_required |= _config_string(to_save, "config_ldap_group_members_field") reboot_required |= _config_checkbox(to_save, "config_ldap_openldap") reboot_required |= _config_int(to_save, "config_ldap_encryption") + reboot_required |= _config_string(to_save, "config_ldap_cacert_path") reboot_required |= _config_string(to_save, "config_ldap_cert_path") + reboot_required |= _config_string(to_save, "config_ldap_key_path") _config_string(to_save, "config_ldap_group_name") if "config_ldap_serv_password" in to_save and to_save["config_ldap_serv_password"] != "": reboot_required |= 1 @@ -612,10 +610,13 @@ def _configuration_ldap_helper(to_save, gdriveError): return reboot_required, _configuration_result(_('LDAP User Object Filter Has Unmatched Parenthesis'), gdriveError) - if config.config_ldap_cert_path and not os.path.isfile(config.config_ldap_cert_path): - return reboot_required, \ - _configuration_result(_('LDAP Certificate Location is not Valid, Please Enter Correct Path'), - gdriveError) + if config.config_ldap_cacert_path or config.config_ldap_cert_path or config.config_ldap_key_path: + if not (os.path.isfile(config.config_ldap_cacert_path) and + os.path.isfile(config.config_ldap_cert_path) and + os.path.isfile(config.config_ldap_key_path)): + return reboot_required, \ + _configuration_result(_('LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path'), + gdriveError) return reboot_required, None @@ -646,7 +647,9 @@ def _configuration_update_helper(): return _configuration_result(_('Certfile Location is not Valid, Please Enter Correct Path'), gdriveError) _config_checkbox_int(to_save, "config_uploading") - _config_checkbox_int(to_save, "config_anonbrowse") + # Reboot on config_anonbrowse with enabled ldap, as decoraters are changed in this case + reboot_required |= (_config_checkbox_int(to_save, "config_anonbrowse") + and config.config_login_type == constants.LOGIN_LDAP) _config_checkbox_int(to_save, "config_public_reg") _config_checkbox_int(to_save, "config_register_email") reboot_required |= _config_checkbox_int(to_save, "config_kobo_sync") diff --git a/cps/config_sql.py b/cps/config_sql.py index 9dcb4528..7363e75c 100644 --- a/cps/config_sql.py +++ b/cps/config_sql.py @@ -108,7 +108,9 @@ class _Settings(_Base): config_ldap_serv_username = Column(String, default='cn=admin,dc=example,dc=org') config_ldap_serv_password = Column(String, default="") config_ldap_encryption = Column(SmallInteger, default=0) + config_ldap_cacert_path = Column(String, default="") config_ldap_cert_path = Column(String, default="") + config_ldap_key_path = Column(String, default="") config_ldap_dn = Column(String, default='dc=example,dc=org') config_ldap_user_object = Column(String, default='uid=%s') config_ldap_openldap = Column(Boolean, default=True) diff --git a/cps/editbooks.py b/cps/editbooks.py index c152a39c..85134bcc 100644 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -935,8 +935,6 @@ def convert_bookformat(book_id): @edit_required def edit_list_book(param): vals = request.form.to_dict() - # calibre_db.update_title_sort(config) - #calibre_db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4())) book = calibre_db.get_book(vals['pk']) if param =='series_index': edit_book_series_index(vals['value'], book) diff --git a/cps/jinjia.py b/cps/jinjia.py index ebb53a30..688d1fba 100644 --- a/cps/jinjia.py +++ b/cps/jinjia.py @@ -25,6 +25,7 @@ from __future__ import division, print_function, unicode_literals import datetime import mimetypes +from uuid import uuid4 from babel.dates import format_date from flask import Blueprint, request, url_for @@ -127,3 +128,8 @@ def formatseriesindex_filter(series_index): return series_index return 0 +@jinjia.app_template_filter('uuidfilter') +def uuidfilter(var): + return uuid4() + + diff --git a/cps/kobo.py b/cps/kobo.py index 8d1168e0..acb51e68 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -47,9 +47,10 @@ from sqlalchemy.exc import StatementError import requests from . import config, logger, kobo_auth, db, calibre_db, helper, shelf as shelf_lib, ub +from .helper import get_download_link from .services import SyncToken as SyncToken from .web import download_required -from .kobo_auth import requires_kobo_auth +from .kobo_auth import requires_kobo_auth, get_auth_token KOBO_FORMATS = {"KEPUB": ["KEPUB"], "EPUB": ["EPUB3", "EPUB"]} KOBO_STOREAPI_URL = "https://storeapi.kobo.com" @@ -274,10 +275,11 @@ def get_download_url_for_book(book, book_format): else: host = request.host - return "{url_scheme}://{url_base}:{url_port}/download/{book_id}/{book_format}".format( + return "{url_scheme}://{url_base}:{url_port}/kobo/{auth_token}/download/{book_id}/{book_format}".format( url_scheme=request.scheme, url_base=host, url_port=config.config_external_port, + auth_token=get_auth_token(), book_id=book.id, book_format=book_format.lower() ) @@ -981,6 +983,14 @@ def HandleInitRequest(): return response +@kobo.route("/download//") +@requires_kobo_auth +@download_required +def download_book(book_id, book_format): + + return get_download_link(book_id, book_format, "kobo") + + def NATIVE_KOBO_RESOURCES(): return { "account_page": "https://secure.kobobooks.com/profile", diff --git a/cps/opds.py b/cps/opds.py index 1eb3c49f..8ec48a46 100644 --- a/cps/opds.py +++ b/cps/opds.py @@ -51,7 +51,7 @@ def requires_basic_auth_if_no_ano(f): if not auth or auth.type != 'basic' or not check_auth(auth.username, auth.password): return authenticate() return f(*args, **kwargs) - if config.config_login_type == constants.LOGIN_LDAP and services.ldap: + if config.config_login_type == constants.LOGIN_LDAP and services.ldap and config.config_anonbrowse != 1: return services.ldap.basic_auth_required(f) return decorated diff --git a/cps/services/simpleldap.py b/cps/services/simpleldap.py index 336b0f2c..d61f3fb6 100644 --- a/cps/services/simpleldap.py +++ b/cps/services/simpleldap.py @@ -20,7 +20,7 @@ from __future__ import division, print_function, unicode_literals import base64 from flask_simpleldap import LDAP, LDAPException - +from flask_simpleldap import ldap as pyLDAP from .. import constants, logger try: @@ -38,6 +38,7 @@ def init_app(app, config): app.config['LDAP_HOST'] = config.config_ldap_provider_url app.config['LDAP_PORT'] = config.config_ldap_port + app.config['LDAP_CUSTOM_OPTIONS'] = {pyLDAP.OPT_REFERRALS: 0} if config.config_ldap_encryption == 2: app.config['LDAP_SCHEMA'] = 'ldaps' else: @@ -54,8 +55,14 @@ def init_app(app, config): app.config['LDAP_USERNAME'] = "" app.config['LDAP_PASSWORD'] = base64.b64decode("") if bool(config.config_ldap_cert_path): - app.config['LDAP_REQUIRE_CERT'] = True - app.config['LDAP_CERT_PATH'] = config.config_ldap_cert_path + app.config['LDAP_CUSTOM_OPTIONS'].update({ + pyLDAP.OPT_X_TLS_REQUIRE_CERT: pyLDAP.OPT_X_TLS_DEMAND, + pyLDAP.OPT_X_TLS_CACERTFILE: config.config_ldap_cacert_path, + pyLDAP.OPT_X_TLS_CERTFILE: config.config_ldap_cert_path, + pyLDAP.OPT_X_TLS_KEYFILE: config.config_ldap_key_path, + pyLDAP.OPT_X_TLS_NEWCTX: 0 + }) + app.config['LDAP_BASE_DN'] = config.config_ldap_dn app.config['LDAP_USER_OBJECT_FILTER'] = config.config_ldap_user_object @@ -67,6 +74,13 @@ def init_app(app, config): try: _ldap.init_app(app) + except ValueError: + if bool(config.config_ldap_cert_path): + app.config['LDAP_CUSTOM_OPTIONS'].pop(pyLDAP.OPT_X_TLS_NEWCTX) + try: + _ldap.init_app(app) + except RuntimeError as e: + log.error(e) except RuntimeError as e: log.error(e) diff --git a/cps/static/js/main.js b/cps/static/js/main.js index f2d7b929..703ecb29 100644 --- a/cps/static/js/main.js +++ b/cps/static/js/main.js @@ -58,6 +58,59 @@ $(document).on("change", "select[data-controlall]", function() { } }); +// Syntax has to be bind not on, otherwise problems with firefox +$(".container-fluid").bind("dragenter dragover", function () { + if($("#btn-upload").length && !$('body').hasClass('shelforder')) { + $(this).css('background', '#e6e6e6'); + } + return false; +}); + +// Syntax has to be bind not on, otherwise problems with firefox +$(".container-fluid").bind("dragleave", function () { + if($("#btn-upload").length && !$('body').hasClass('shelforder')) { + $(this).css('background', ''); + } + return false; +}); + +// Syntax has to be bind not on, otherwise problems with firefox +$(".container-fluid").bind('drop', function (e) { + e.preventDefault() + e.stopPropagation(); + if($("#btn-upload").length) { + var files = e.originalEvent.dataTransfer.files; + var test = $("#btn-upload")[0].accept; + $(this).css('background', ''); + // var final = []; + const dt = new DataTransfer() + jQuery.each(files, function (index, item) { + if (test.indexOf(item.name.substr(item.name.lastIndexOf('.'))) !== -1) { + dt.items.add(item); + } + }); + if (dt.files.length) { + $("#btn-upload")[0].files = dt.files; + $("#form-upload").submit(); + } + } +}); + +$("#btn-upload").change(function() { + $("#form-upload").submit(); +}); + +$(document).ready(function() { + var inp = $('#query').first() + if (inp.length) { + var val = inp.val() + if (val.length) { + inp.val('').blur().focus().val(val) + } + } +}); + + $("#delete_confirm").click(function() { //get data-id attribute of the clicked element var pathname = document.getElementsByTagName("script"), src = pathname[pathname.length - 1].src; @@ -188,7 +241,7 @@ $(function() { } $(".load-more .row").isotope( "appended", $(data), null ); }); - + // fix for infinite scroll on CaliBlur Theme (#981) if ($("body").hasClass("blur")) { $(".col-sm-10").bind("scroll", function () { diff --git a/cps/templates/admin.html b/cps/templates/admin.html index 0e495030..e014935b 100644 --- a/cps/templates/admin.html +++ b/cps/templates/admin.html @@ -44,7 +44,6 @@ {% if (config.config_login_type == 1) %}
{{_('Import LDAP Users')}}
- {% endif %} diff --git a/cps/templates/author.html b/cps/templates/author.html index 63dd175a..7887aa4a 100644 --- a/cps/templates/author.html +++ b/cps/templates/author.html @@ -23,16 +23,12 @@

{{_("In Library")}}

{% endif %}
{% if entries[0] %} diff --git a/cps/templates/book_edit.html b/cps/templates/book_edit.html index 16c02fae..003b33f9 100644 --- a/cps/templates/book_edit.html +++ b/cps/templates/book_edit.html @@ -3,7 +3,7 @@ {% if book %}
- {{ book.title }} + {{ book.title }}
{% if g.user.role_delete_books() %}
diff --git a/cps/templates/config_edit.html b/cps/templates/config_edit.html index 132db5cf..2088223d 100644 --- a/cps/templates/config_edit.html +++ b/cps/templates/config_edit.html @@ -15,8 +15,8 @@
+
- @@ -264,9 +264,26 @@
-
- + +
+ + + + +
+ +
+ + + +
+ +
+ + + +
diff --git a/cps/templates/detail.html b/cps/templates/detail.html index 260ee93a..503d1dbd 100644 --- a/cps/templates/detail.html +++ b/cps/templates/detail.html @@ -4,13 +4,13 @@
- {{ entry.title }} + {{ entry.title }}