diff --git a/cps/admin.py b/cps/admin.py index 0697ad23..93c742df 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -1208,6 +1208,7 @@ def _configuration_update_helper(): return _configuration_result(_('Certfile Location is not Valid, Please Enter Correct Path')) _config_checkbox_int(to_save, "config_uploading") + _config_checkbox_int(to_save, "config_unicode_filename") # 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) diff --git a/cps/config_sql.py b/cps/config_sql.py index f3e82e7e..88107f9b 100644 --- a/cps/config_sql.py +++ b/cps/config_sql.py @@ -133,6 +133,7 @@ class _Settings(_Base): config_calibre = Column(String) config_rarfile_location = Column(String, default=None) config_upload_formats = Column(String, default=','.join(constants.EXTENSIONS_UPLOAD)) + config_unicode_filename =Column(Boolean, default=False) config_updatechannel = Column(Integer, default=constants.UPDATE_STABLE) diff --git a/cps/helper.py b/cps/helper.py index b6ea6760..3f91ca86 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -230,16 +230,14 @@ def get_valid_filename(value, replace_whitespace=True): value = value[:-1]+u'_' value = value.replace("/", "_").replace(":", "_").strip('\0') if use_unidecode: - value = (unidecode.unidecode(value)) + if config.config_unicode_filename: + value = (unidecode.unidecode(value)) else: value = value.replace(u'§', u'SS') value = value.replace(u'ß', u'ss') value = unicodedata.normalize('NFKD', value) re_slugify = re.compile(r'[\W\s-]', re.UNICODE) - if isinstance(value, str): # Python3 str, Python2 unicode - value = re_slugify.sub('', value) - else: - value = unicode(re_slugify.sub('', value)) + value = re_slugify.sub('', value) if replace_whitespace: # *+:\"/<>? are replaced by _ value = re.sub(r'[*+:\\\"/<>?]+', u'_', value, flags=re.U) @@ -248,10 +246,7 @@ def get_valid_filename(value, replace_whitespace=True): value = value[:128].strip() if not value: raise ValueError("Filename cannot be empty") - if sys.version_info.major == 3: - return value - else: - return value.decode('utf-8') + return value def split_authors(values): @@ -838,8 +833,8 @@ def get_download_link(book_id, book_format, client): ub.update_download(book_id, int(current_user.id)) file_name = book.title if len(book.authors) > 0: - file_name = book.authors[0].name + '_' + file_name - file_name = get_valid_filename(file_name) + file_name = file_name + ' - ' + book.authors[0].name + file_name = get_valid_filename(file_name, replace_whitespace=False) headers = Headers() headers["Content-Type"] = mimetypes.types_map.get('.' + book_format, "application/octet-stream") headers["Content-Disposition"] = "attachment; filename=%s.%s; filename*=UTF-8''%s.%s" % ( diff --git a/cps/metadata_provider/google.py b/cps/metadata_provider/google.py index 1c26f74c..167ab8a3 100644 --- a/cps/metadata_provider/google.py +++ b/cps/metadata_provider/google.py @@ -41,7 +41,7 @@ class Google(Metadata): v['tags'] = r['volumeInfo'].get('categories', []) v['rating'] = r['volumeInfo'].get('averageRating', 0) if r['volumeInfo'].get('imageLinks'): - v['cover'] = r['volumeInfo']['imageLinks']['thumbnail'] + v['cover'] = r['volumeInfo']['imageLinks']['thumbnail'].replace("http://", "https://") else: v['cover'] = "/../../../static/generic_cover.jpg" v['source'] = { diff --git a/cps/search_metadata.py b/cps/search_metadata.py index 0e69b570..bba22aab 100644 --- a/cps/search_metadata.py +++ b/cps/search_metadata.py @@ -26,8 +26,10 @@ import inspect from flask import Blueprint, request, Response from flask_login import current_user from flask_login import login_required +from sqlalchemy.orm.attributes import flag_modified +from sqlalchemy.exc import OperationalError, InvalidRequestError -from . import constants, logger +from . import constants, logger, ub from cps.services.Metadata import Metadata meta = Blueprint('metadata', __name__) @@ -63,17 +65,29 @@ def metadata_provider(): active = current_user.view_settings.get('metadata', {}) provider = list() for c in cl: - provider.append({"name": c.__name__, "active": active.get(c.__name__, True), "id": c.__id__}) + provider.append({"name": c.__name__, "active": active.get(c.__id__, True), "id": c.__id__}) return Response(json.dumps(provider), mimetype='application/json') @meta.route("/metadata/provider", methods=['POST']) @login_required def metadata_change_active_provider(): + new_state = request.get_json() active = current_user.view_settings.get('metadata', {}) + active[new_state['id']] = new_state['value'] + current_user.view_settings['metadata'] = active + try: + try: + flag_modified(current_user, "view_settings") + except AttributeError: + pass + ub.session.commit() + except (InvalidRequestError, OperationalError): + log.error("Invalid request received: {}".format(request)) + return "Invalid request", 400 provider = list() for c in cl: - provider.append({"name": c.__name__, "active": active.get(c.__name__, True), "id": c.__id__}) - return Response(json.dumps(provider), mimetype='application/json') + provider.append({"name": c.__name__, "active": active.get(c.__id__, True), "id": c.__id__}) + return "" # Response(json.dumps(provider), mimetype='application/json') @meta.route("/metadata/search", methods=['POST']) @login_required @@ -83,6 +97,6 @@ def metadata_search(): active = current_user.view_settings.get('metadata', {}) if query: for c in cl: - if active.get(c.__name__, True): + if active.get(c.__id__, True): data.extend(c.search(query)) return Response(json.dumps(data), mimetype='application/json') diff --git a/cps/static/css/style.css b/cps/static/css/style.css index 5b7715fd..2bbdf370 100644 --- a/cps/static/css/style.css +++ b/cps/static/css/style.css @@ -123,6 +123,10 @@ table .bg-dark-danger a { color: #fff; } flex-wrap: wrap; } +.row-fluid.text-center { + margin-top: -20px; +} + .container-fluid img { display: block; max-width: 100%; @@ -166,6 +170,10 @@ table .bg-dark-danger a { color: #fff; } box-shadow: 0 5px 8px -6px #777; } +.datepicker.form-control { + position: static; +} + .container-fluid .book .cover span img { position: relative; top: 0; @@ -322,7 +330,7 @@ table .bg-dark-danger:hover { background-color: #c9302c; } table .bg-primary:hover { background-color: #1c5484; } .block-label { display: block; } -.fake-input { +.form-control.fake-input { position: absolute; pointer-events: none; top: 0; diff --git a/cps/static/js/details.js b/cps/static/js/details.js index 81c1a395..525b0008 100644 --- a/cps/static/js/details.js +++ b/cps/static/js/details.js @@ -30,7 +30,7 @@ $("#have_read_cb").on("change", function() { $("#flash_danger").remove(); if (!jQuery.isEmptyObject(data)) { data.forEach(function (item) { - $(".navbar").after('
' + + $(".navbar").after('
' + '
' + item.message + '
' + '
'); }); diff --git a/cps/static/js/get_meta.js b/cps/static/js/get_meta.js index c1d4d5a0..4b7f2873 100644 --- a/cps/static/js/get_meta.js +++ b/cps/static/js/get_meta.js @@ -82,7 +82,6 @@ $(function () { success: function success(data) { // console.log(data); data.forEach(function(provider) { - //$("#metadata_provider").html(""); var checked = ""; if (provider.active) { checked = "checked"; @@ -94,6 +93,17 @@ $(function () { }); } + $(document).on("change", ".pill", function () { + var id = $(this).data("control"); + var val = $(this).prop('checked'); + $.ajax({ + method:"post", + contentType: "application/json; charset=utf-8", + dataType: "json", + url: getPath() + "/metadata/provider", + data: JSON.stringify({id : id, value: val}), + }); + }); $("#meta-search").on("submit", function (e) { e.preventDefault(); diff --git a/cps/static/js/main.js b/cps/static/js/main.js index 69788c2e..7b224976 100644 --- a/cps/static/js/main.js +++ b/cps/static/js/main.js @@ -172,7 +172,7 @@ $("#delete_confirm").click(function() { if (item.format != "") { $("button[data-delete-format='"+item.format+"']").addClass('hidden'); } - $( ".navbar" ).after( '
' + + $( ".navbar" ).after( '
' + '
'+item.message+'
' + '
'); @@ -543,7 +543,7 @@ $(function() { function handle_response(data) { if (!jQuery.isEmptyObject(data)) { data.forEach(function (item) { - $(".navbar").after('
' + + $(".navbar").after('
' + '
' + item.message + '
' + '
'); }); diff --git a/cps/static/js/table.js b/cps/static/js/table.js index a8a35909..ad46025c 100644 --- a/cps/static/js/table.js +++ b/cps/static/js/table.js @@ -744,7 +744,7 @@ function handleListServerResponse (data) { $("#flash_danger").remove(); if (!jQuery.isEmptyObject(data)) { data.forEach(function(item) { - $(".navbar").after('
' + + $(".navbar").after('
' + '
' + item.message + '
' + '
'); }); diff --git a/cps/templates/book_edit.html b/cps/templates/book_edit.html index 20076321..78a5cdc1 100644 --- a/cps/templates/book_edit.html +++ b/cps/templates/book_edit.html @@ -111,8 +111,8 @@ {% endif %}
- - + + @@ -156,11 +156,11 @@ {% if c.datatype == 'datetime' %}
- 0 %} value="{% if book['custom_column_' ~ c.id][0].value %}{{ book['custom_column_' ~ c.id][0].value|formatdateinput}}{% endif %}" {% endif %}> - 0 %} value="{% if book['custom_column_' ~ c.id][0].value %}{{book['custom_column_' ~ c.id][0].value|formatdate}}{% endif %}" {% endif %}> diff --git a/cps/templates/config_db.html b/cps/templates/config_db.html index e0e1bfd1..c5027abf 100644 --- a/cps/templates/config_db.html +++ b/cps/templates/config_db.html @@ -1,6 +1,6 @@ {% extends "layout.html" %} {% block flash %} -