diff --git a/cps/db.py b/cps/db.py index 692b012d5..3eec6454d 100644 --- a/cps/db.py +++ b/cps/db.py @@ -384,14 +384,14 @@ class Custom_Columns(Base): class AlchemyEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj.__class__, DeclarativeMeta): + def default(self, o): + if isinstance(o.__class__, DeclarativeMeta): # an SQLAlchemy class fields = {} - for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']: + for field in [x for x in dir(o) if not x.startswith('_') and x != 'metadata']: if field == 'books': continue - data = obj.__getattribute__(field) + data = o.__getattribute__(field) try: if isinstance(data, str): data = data.replace("'", "\'") @@ -411,12 +411,12 @@ class AlchemyEncoder(json.JSONEncoder): else: json.dumps(data) fields[field] = data - except: + except Exception: fields[field] = "" # a json-encodable dict return fields - return json.JSONEncoder.default(self, obj) + return json.JSONEncoder.default(self, o) class CalibreDB(): @@ -563,8 +563,8 @@ class CalibreDB(): def get_book_by_uuid(self, book_uuid): return self.session.query(Books).filter(Books.uuid == book_uuid).first() - def get_book_format(self, book_id, format): - return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == format).first() + def get_book_format(self, book_id, file_format): + return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == file_format).first() # Language and content filters for displaying in the UI def common_filters(self, allow_show_archived=False): @@ -742,7 +742,7 @@ class CalibreDB(): if old_session: try: old_session.close() - except: + except Exception: pass if old_session.bind: try: diff --git a/cps/gdrive.py b/cps/gdrive.py index b1896bbba..950f3ce21 100644 --- a/cps/gdrive.py +++ b/cps/gdrive.py @@ -47,7 +47,7 @@ except ImportError as err: current_milli_time = lambda: int(round(time() * 1000)) -gdrive_watch_callback_token = 'target=calibreweb-watch_files' +gdrive_watch_callback_token = 'target=calibreweb-watch_files' #nosec @gdrive.route("/authenticate") diff --git a/cps/kobo.py b/cps/kobo.py index d019e9188..b5d5397be 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -42,8 +42,7 @@ from flask import ( from flask_login import current_user from werkzeug.datastructures import Headers from sqlalchemy import func -from sqlalchemy.sql.expression import and_, or_ -from sqlalchemy.orm import load_only +from sqlalchemy.sql.expression import and_ from sqlalchemy.exc import StatementError import requests @@ -893,17 +892,6 @@ def HandleProductsRequest(dummy=None): return redirect_or_proxy_request() -'''@kobo.errorhandler(404) -def handle_404(err): - # This handler acts as a catch-all for endpoints that we don't have an interest in - # implementing (e.g: v1/analytics/gettests, v1/user/recommendations, etc) - if err: - print('404') - return jsonify(error=str(err)), 404 - log.debug("Unknown Request received: %s, method: %s, data: %s", request.base_url, request.method, request.data) - return redirect_or_proxy_request()''' - - def make_calibre_web_auth_response(): # As described in kobo_auth.py, CalibreWeb doesn't make use practical use of this auth/device API call for # authentation (nor for authorization). We return a dummy response just to keep the device happy. @@ -947,7 +935,7 @@ def HandleInitRequest(): store_response_json = store_response.json() if "Resources" in store_response_json: kobo_resources = store_response_json["Resources"] - except: + except Exception: log.error("Failed to receive or parse response from Kobo's init endpoint. Falling back to un-proxied mode.") if not kobo_resources: kobo_resources = NATIVE_KOBO_RESOURCES() diff --git a/cps/server.py b/cps/server.py index 87d1b3020..a4027525e 100644 --- a/cps/server.py +++ b/cps/server.py @@ -138,7 +138,7 @@ class WebServer(object): return sock, _readable_listen_address(*address) @staticmethod - def _get_args_for_reloading(self): + def _get_args_for_reloading(): """Determine how the script was executed, and return the args needed to execute it again in a new process. Code from https://github.com/pyload/pyload. Author GammaC0de, voulter diff --git a/cps/static/css/caliBlur_override.css b/cps/static/css/caliBlur_override.css index 2f3dcb586..4c8b6cb07 100644 --- a/cps/static/css/caliBlur_override.css +++ b/cps/static/css/caliBlur_override.css @@ -1,8 +1,8 @@ -body.serieslist.grid-view div.container-fluid > div > div.col-sm-10:before{ +body.serieslist.grid-view div.container-fluid > div > div.col-sm-10::before { display: none; } -.cover .badge{ +.cover .badge { position: absolute; top: 0; left: 0; @@ -10,15 +10,15 @@ body.serieslist.grid-view div.container-fluid > div > div.col-sm-10:before{ background-color: #cc7b19; border-radius: 0; padding: 0 8px; - box-shadow: 0 0 4px rgba(0, 0, 0, .6); + box-shadow: 0 0 4px rgba(0, 0, 0, 0.6); line-height: 24px; } .cover { - box-shadow: 0 0 4px rgba(0, 0, 0, .6); + box-shadow: 0 0 4px rgba(0, 0, 0, 0.6); } .cover .read { - padding: 0px 0px; + padding: 0 0; line-height: 15px; } diff --git a/cps/static/css/main.css b/cps/static/css/main.css index 217f4b811..94b04ce05 100644 --- a/cps/static/css/main.css +++ b/cps/static/css/main.css @@ -370,7 +370,7 @@ input:-moz-placeholder { color: #454545; } } #searchResults li { - margin-bottom:10px; + margin-bottom: 10px; width: 225px; font-family: Georgia, "Times New Roman", Times, serif; list-style: none; diff --git a/cps/static/js/filter_grid.js b/cps/static/js/filter_grid.js index 362c6bfa6..f5ccd3de5 100644 --- a/cps/static/js/filter_grid.js +++ b/cps/static/js/filter_grid.js @@ -36,7 +36,6 @@ $("#desc").click(function() { sortBy: "name", sortAscending: true }); - return; }); $("#asc").click(function() { @@ -52,19 +51,20 @@ $("#asc").click(function() { sortBy: "name", sortAscending: false }); - return; }); $("#all").click(function() { // go through all elements and make them visible $list.isotope({ filter: function() { - return true; - } }) + return true; + } + }); }); $(".char").click(function() { var character = this.innerText; $list.isotope({ filter: function() { - return this.attributes["data-id"].value.charAt(0).toUpperCase() == character; - } }) + return this.attributes["data-id"].value.charAt(0).toUpperCase() == character; + } + }); }); diff --git a/cps/static/js/get_meta.js b/cps/static/js/get_meta.js index d3e0eb46f..04c1d2704 100644 --- a/cps/static/js/get_meta.js +++ b/cps/static/js/get_meta.js @@ -138,8 +138,8 @@ $(function () { seriesTitle = result.series.title; } var dateFomers = result.pubdate.split("-"); - var publishedYear = parseInt(dateFomers[0]); - var publishedMonth = parseInt(dateFomers[1]); + var publishedYear = parseInt(dateFomers[0], 10); + var publishedMonth = parseInt(dateFomers[1], 10); var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); publishedDate = formatDate(publishedDate); @@ -194,8 +194,8 @@ $(function () { } else { dateFomers = result.date_added.split("-"); } - var publishedYear = parseInt(dateFomers[0]); - var publishedMonth = parseInt(dateFomers[1]); + var publishedYear = parseInt(dateFomers[0], 10); + var publishedMonth = parseInt(dateFomers[1], 10); var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); publishedDate = formatDate(publishedDate); diff --git a/cps/static/js/main.js b/cps/static/js/main.js index 834e1b17f..ba6f726f6 100644 --- a/cps/static/js/main.js +++ b/cps/static/js/main.js @@ -114,7 +114,7 @@ $(document).ready(function() { } }); -function ConfirmDialog(id, dataValue, yesFn, noFn) { +function confirmDialog(id, dataValue, yesFn, noFn) { var $confirm = $("#GeneralDeleteModal"); // var dataValue= e.data('value'); // target.data('value'); $confirm.modal('show'); @@ -481,7 +481,7 @@ $(function() { }); $("#config_delete_kobo_token").click(function() { - ConfirmDialog( + confirmDialog( $(this).attr('id'), $(this).data('value'), function (value) { @@ -509,7 +509,7 @@ $(function() { }); $("#btndeluser").click(function() { - ConfirmDialog( + confirmDialog( $(this).attr('id'), $(this).data('value'), function(value){ @@ -527,7 +527,7 @@ $(function() { }); $("#delete_shelf").click(function() { - ConfirmDialog( + confirmDialog( $(this).attr('id'), $(this).data('value'), function(value){ diff --git a/cps/static/js/table.js b/cps/static/js/table.js index f4c4d5fe4..0dd62b2b1 100644 --- a/cps/static/js/table.js +++ b/cps/static/js/table.js @@ -16,7 +16,7 @@ */ /* exported TableActions, RestrictionActions, EbookActions, responseHandler */ -/* global getPath, ConfirmDialog */ +/* global getPath, confirmDialog */ var selections = []; @@ -210,7 +210,7 @@ $(function() { striped: false }); - function domain_handle(domainId) { + function domainHandle(domainId) { $.ajax({ method:"post", url: window.location.pathname + "/../../ajax/deletedomain", @@ -237,12 +237,12 @@ $(function() { } $("#domain-allow-table").on("click-cell.bs.table", function (field, value, row, $element) { if (value === 2) { - ConfirmDialog("btndeletedomain", $element.id, domain_handle); + confirmDialog("btndeletedomain", $element.id, domainHandle); } }); $("#domain-deny-table").on("click-cell.bs.table", function (field, value, row, $element) { if (value === 2) { - ConfirmDialog("btndeletedomain", $element.id, domain_handle); + confirmDialog("btndeletedomain", $element.id, domainHandle); } }); @@ -256,12 +256,12 @@ $(function() { $("#h3").addClass("hidden"); $("#h4").addClass("hidden"); }); - function startTable(type, user_id) { + function startTable(type, userId) { $("#restrict-elements-table").bootstrapTable({ formatNoMatches: function () { return ""; }, - url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/listrestriction/" + type + "/" + userId, rowStyle: function(row) { // console.log('Reihe :' + row + " Index :" + index); if (row.id.charAt(0) === "a") { @@ -275,13 +275,13 @@ $(function() { $.ajax ({ type: "Post", data: "id=" + row.id + "&type=" + row.type + "&Element=" + encodeURIComponent(row.Element), - url: getPath() + "/ajax/deleterestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/deleterestriction/" + type + "/" + userId, async: true, timeout: 900, success:function() { $.ajax({ method:"get", - url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/listrestriction/" + type + "/" + userId, async: true, timeout: 900, success:function(data) { @@ -297,7 +297,7 @@ $(function() { $("#restrict-elements-table").removeClass("table-hover"); $("#restrict-elements-table").on("editable-save.bs.table", function (e, field, row) { $.ajax({ - url: getPath() + "/ajax/editrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/editrestriction/" + type + "/" + userId, type: "Post", data: row }); @@ -305,13 +305,13 @@ $(function() { $("[id^=submit_]").click(function() { $(this)[0].blur(); $.ajax({ - url: getPath() + "/ajax/addrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/addrestriction/" + type + "/" + userId, type: "Post", data: $(this).closest("form").serialize() + "&" + $(this)[0].name + "=", success: function () { $.ajax ({ method:"get", - url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/listrestriction/" + type + "/" + userId, async: true, timeout: 900, success:function(data) { @@ -333,12 +333,12 @@ $(function() { $("#h1").removeClass("hidden"); }); $("#get_user_column_values").on("click", function() { - startTable(3, $(this).data('id')); + startTable(3, $(this).data("id")); $("#h4").removeClass("hidden"); }); $("#get_user_tags").on("click", function() { - startTable(2, $(this).data('id')); + startTable(2, $(this).data("id")); $(this)[0].blur(); $("#h3").removeClass("hidden"); }); diff --git a/cps/ub.py b/cps/ub.py index b97e0670e..967ac0c52 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -610,7 +610,7 @@ def migrate_Database(session): "locale VARCHAR(2)," "sidebar_view INTEGER," "default_language VARCHAR(3)," - "view_settings VARCHAR," + "view_settings VARCHAR," "UNIQUE (nickname)," "UNIQUE (email))") conn.execute("INSERT INTO user_id(id, nickname, email, role, password, kindle_mail,locale," diff --git a/cps/updater.py b/cps/updater.py index 5ef060efe..a9dcfa03b 100644 --- a/cps/updater.py +++ b/cps/updater.py @@ -272,7 +272,8 @@ class Updater(threading.Thread): log.debug("Could not remove: %s", item_path) shutil.rmtree(source, ignore_errors=True) - def is_venv(self): + @staticmethod + def is_venv(): if (hasattr(sys, 'real_prefix')) or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix): return os.sep + os.path.relpath(sys.prefix, constants.BASE_DIR) else: diff --git a/cps/web.py b/cps/web.py index 0349b3327..c62177fcd 100644 --- a/cps/web.py +++ b/cps/web.py @@ -373,23 +373,9 @@ def render_books_list(data, sort, book_id, page): order = get_sort_function(sort, data) if data == "rated": - if current_user.check_visibility(constants.SIDEBAR_BEST_RATED): - entries, random, pagination = calibre_db.fill_indexpage(page, 0, - db.Books, - db.Books.ratings.any(db.Ratings.rating > 9), - order) - return render_title_template('index.html', random=random, entries=entries, pagination=pagination, - id=book_id, title=_(u"Top Rated Books"), page="rated") - else: - abort(404) + return render_rated_books(page, book_id, order=order) elif data == "discover": - if current_user.check_visibility(constants.SIDEBAR_RANDOM): - entries, __, pagination = calibre_db.fill_indexpage(page, 0, 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, id=book_id, - title=_(u"Discover (Random Books)"), page="discover") - else: - abort(404) + return render_discover_books(page, book_id) elif data == "unread": return render_read_books(page, False, order=order) elif data == "read": @@ -429,6 +415,27 @@ def render_books_list(data, sort, book_id, page): title=_(u"Books"), page=website) +def render_rated_books(page, book_id, order): + if current_user.check_visibility(constants.SIDEBAR_BEST_RATED): + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db.Books.ratings.any(db.Ratings.rating > 9), + order) + return render_title_template('index.html', random=random, entries=entries, pagination=pagination, + id=book_id, title=_(u"Top Rated Books"), page="rated") + else: + abort(404) + + +def render_discover_books(page, book_id): + if current_user.check_visibility(constants.SIDEBAR_RANDOM): + entries, __, pagination = calibre_db.fill_indexpage(page, 0, 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, id=book_id, + title=_(u"Discover (Random Books)"), page="discover") + else: + abort(404) + def render_hot_books(page): if current_user.check_visibility(constants.SIDEBAR_HOT): if current_user.show_detail_random(): @@ -990,6 +997,149 @@ def advanced_search(): return redirect(url_for('web.books_list', data="advsearch", sort_param='stored', query="")) +def adv_search_custom_columns(cc, term, q): + for c in cc: + custom_query = term.get('custom_column_' + str(c.id)) + if custom_query != '' and custom_query is not None: + if c.datatype == 'bool': + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value == (custom_query == "True"))) + elif c.datatype == 'int' or c.datatype == 'float': + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value == custom_query)) + elif c.datatype == 'rating': + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value == int(float(custom_query) * 2))) + else: + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + func.lower(db.cc_classes[c.id].value).ilike("%" + custom_query + "%"))) + return q + + +def adv_search_language(q, include_languages_inputs, exclude_languages_inputs): + if current_user.filter_language() != "all": + q = q.filter(db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())) + else: + for language in include_languages_inputs: + q = q.filter(db.Books.languages.any(db.Languages.id == language)) + for language in exclude_languages_inputs: + q = q.filter(not_(db.Books.series.any(db.Languages.id == language))) + return q + + +def adv_search_ratings(q, rating_high, rating_low): + if rating_high: + rating_high = int(rating_high) * 2 + q = q.filter(db.Books.ratings.any(db.Ratings.rating <= rating_high)) + if rating_low: + rating_low = int(rating_low) * 2 + q = q.filter(db.Books.ratings.any(db.Ratings.rating >= rating_low)) + return q + + +def adv_search_read_status(q, read_status): + if read_status: + if config.config_read_column: + if read_status == "True": + q = q.join(db.cc_classes[config.config_read_column], isouter=True) \ + .filter(db.cc_classes[config.config_read_column].value == True) + else: + q = q.join(db.cc_classes[config.config_read_column], isouter=True) \ + .filter(coalesce(db.cc_classes[config.config_read_column].value, False) != True) + else: + if read_status == "True": + q = q.join(ub.ReadBook, db.Books.id == ub.ReadBook.book_id, isouter=True) \ + .filter(ub.ReadBook.user_id == int(current_user.id), + ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED) + else: + q = q.join(ub.ReadBook, db.Books.id == ub.ReadBook.book_id, isouter=True) \ + .filter(ub.ReadBook.user_id == int(current_user.id), + coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED) + return q + + +def adv_search_extension(q, include_extension_inputs, exclude_extension_inputs): + for extension in include_extension_inputs: + q = q.filter(db.Books.data.any(db.Data.format == extension)) + for extension in exclude_extension_inputs: + q = q.filter(not_(db.Books.data.any(db.Data.format == extension))) + return q + + +def adv_search_tag(q, include_tag_inputs, exclude_tag_inputs): + for tag in include_tag_inputs: + q = q.filter(db.Books.tags.any(db.Tags.id == tag)) + for tag in exclude_tag_inputs: + q = q.filter(not_(db.Books.tags.any(db.Tags.id == tag))) + return q + + +def adv_search_serie(q, include_series_inputs, exclude_series_inputs): + for serie in include_series_inputs: + q = q.filter(db.Books.series.any(db.Series.id == serie)) + for serie in exclude_series_inputs: + q = q.filter(not_(db.Books.series.any(db.Series.id == serie))) + return q + + +def extend_search_term(searchterm, + author_name, + book_title, + publisher, + pub_start, + pub_end, + include_tag_inputs, + exclude_tag_inputs, + include_series_inputs, + exclude_series_inputs, + include_languages_inputs, + rating_high, + rating_low, + read_status, + include_extension_inputs, + exclude_extension_inputs + ): + searchterm.extend((author_name.replace('|', ','), book_title, publisher)) + if pub_start: + try: + searchterm.extend([_(u"Published after ") + + format_date(datetime.strptime(pub_start, "%Y-%m-%d"), + format='medium', locale=get_locale())]) + except ValueError: + pub_start = u"" + if pub_end: + try: + searchterm.extend([_(u"Published before ") + + format_date(datetime.strptime(pub_end, "%Y-%m-%d"), + format='medium', locale=get_locale())]) + except ValueError: + pub_start = u"" + tag_names = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(include_tag_inputs)).all() + searchterm.extend(tag.name for tag in tag_names) + tag_names = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(exclude_tag_inputs)).all() + searchterm.extend(tag.name for tag in tag_names) + serie_names = calibre_db.session.query(db.Series).filter(db.Series.id.in_(include_series_inputs)).all() + searchterm.extend(serie.name for serie in serie_names) + serie_names = calibre_db.session.query(db.Series).filter(db.Series.id.in_(exclude_series_inputs)).all() + searchterm.extend(serie.name for serie in serie_names) + language_names = calibre_db.session.query(db.Languages). \ + filter(db.Languages.id.in_(include_languages_inputs)).all() + if language_names: + language_names = calibre_db.speaking_language(language_names) + searchterm.extend(language.name for language in language_names) + if rating_high: + searchterm.extend([_(u"Rating <= %(rating)s", rating=rating_high)]) + if rating_low: + searchterm.extend([_(u"Rating >= %(rating)s", rating=rating_low)]) + if read_status: + searchterm.extend([_(u"Read Status = %(status)s", status=read_status)]) + searchterm.extend(ext for ext in include_extension_inputs) + searchterm.extend(ext for ext in exclude_extension_inputs) + # handle custom columns + searchterm = " + ".join(filter(None, searchterm)) + return searchterm, pub_start, pub_end + + def render_adv_search_results(term, offset=None, order=None, limit=None): order = order or [db.Books.sort] pagination = None @@ -1034,47 +1184,22 @@ def render_adv_search_results(term, offset=None, order=None, limit=None): include_languages_inputs or exclude_languages_inputs or author_name or book_title or \ publisher or pub_start or pub_end or rating_low or rating_high or description or cc_present or \ include_extension_inputs or exclude_extension_inputs or read_status: - searchterm.extend((author_name.replace('|', ','), book_title, publisher)) - if pub_start: - try: - searchterm.extend([_(u"Published after ") + - format_date(datetime.strptime(pub_start, "%Y-%m-%d"), - format='medium', locale=get_locale())]) - except ValueError: - pub_start = u"" - if pub_end: - try: - searchterm.extend([_(u"Published before ") + - format_date(datetime.strptime(pub_end, "%Y-%m-%d"), - format='medium', locale=get_locale())]) - except ValueError: - pub_start = u"" - tag_names = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(include_tag_inputs)).all() - searchterm.extend(tag.name for tag in tag_names) - tag_names = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(exclude_tag_inputs)).all() - searchterm.extend(tag.name for tag in tag_names) - serie_names = calibre_db.session.query(db.Series).filter(db.Series.id.in_(include_series_inputs)).all() - searchterm.extend(serie.name for serie in serie_names) - serie_names = calibre_db.session.query(db.Series).filter(db.Series.id.in_(exclude_series_inputs)).all() - searchterm.extend(serie.name for serie in serie_names) - language_names = calibre_db.session.query(db.Languages).\ - filter(db.Languages.id.in_(include_languages_inputs)).all() - if language_names: - language_names = calibre_db.speaking_language(language_names) - searchterm.extend(language.name for language in language_names) - if rating_high: - searchterm.extend([_(u"Rating <= %(rating)s", rating=rating_high)]) - if rating_low: - searchterm.extend([_(u"Rating >= %(rating)s", rating=rating_low)]) - if read_status: - searchterm.extend([_(u"Read Status = %(status)s", status=read_status)]) - searchterm.extend(ext for ext in include_extension_inputs) - searchterm.extend(ext for ext in exclude_extension_inputs) - # handle custom columns - #for c in cc: - # if term.get('custom_column_' + str(c.id)): - # searchterm.extend([(u"%s: %s" % (c.name, term.get('custom_column_' + str(c.id))))]) - searchterm = " + ".join(filter(None, searchterm)) + searchterm, pub_start, pub_end = extend_search_term(searchterm, + author_name, + book_title, + publisher, + pub_start, + pub_end, + include_tag_inputs, + exclude_tag_inputs, + include_series_inputs, + exclude_series_inputs, + include_languages_inputs, + rating_high, + rating_low, + read_status, + include_extension_inputs, + exclude_extension_inputs) q = q.filter() if author_name: q = q.filter(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + author_name + "%"))) @@ -1084,73 +1209,24 @@ def render_adv_search_results(term, offset=None, order=None, limit=None): q = q.filter(db.Books.pubdate >= pub_start) if pub_end: q = q.filter(db.Books.pubdate <= pub_end) - if read_status: - if config.config_read_column: - if read_status=="True": - q = q.join(db.cc_classes[config.config_read_column], isouter=True) \ - .filter(db.cc_classes[config.config_read_column].value == True) - else: - q = q.join(db.cc_classes[config.config_read_column], isouter=True) \ - .filter(coalesce(db.cc_classes[config.config_read_column].value, False) != True) - else: - if read_status == "True": - q = q.join(ub.ReadBook, db.Books.id==ub.ReadBook.book_id, isouter=True)\ - .filter(ub.ReadBook.user_id == int(current_user.id), - ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED) - else: - q = q.join(ub.ReadBook, db.Books.id == ub.ReadBook.book_id, isouter=True) \ - .filter(ub.ReadBook.user_id == int(current_user.id), - coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED) + q = adv_search_read_status(q, read_status) if publisher: q = q.filter(db.Books.publishers.any(func.lower(db.Publishers.name).ilike("%" + publisher + "%"))) - for tag in include_tag_inputs: - q = q.filter(db.Books.tags.any(db.Tags.id == tag)) - for tag in exclude_tag_inputs: - q = q.filter(not_(db.Books.tags.any(db.Tags.id == tag))) - for serie in include_series_inputs: - q = q.filter(db.Books.series.any(db.Series.id == serie)) - for serie in exclude_series_inputs: - q = q.filter(not_(db.Books.series.any(db.Series.id == serie))) - for extension in include_extension_inputs: - q = q.filter(db.Books.data.any(db.Data.format == extension)) - for extension in exclude_extension_inputs: - q = q.filter(not_(db.Books.data.any(db.Data.format == extension))) - if current_user.filter_language() != "all": - q = q.filter(db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())) - else: - for language in include_languages_inputs: - q = q.filter(db.Books.languages.any(db.Languages.id == language)) - for language in exclude_languages_inputs: - q = q.filter(not_(db.Books.series.any(db.Languages.id == language))) - if rating_high: - rating_high = int(rating_high) * 2 - q = q.filter(db.Books.ratings.any(db.Ratings.rating <= rating_high)) - if rating_low: - rating_low = int(rating_low) * 2 - q = q.filter(db.Books.ratings.any(db.Ratings.rating >= rating_low)) + q = adv_search_tag(q, include_tag_inputs, exclude_tag_inputs) + q = adv_search_serie(q, include_series_inputs, exclude_series_inputs) + q = adv_search_extension(q, include_extension_inputs, exclude_extension_inputs) + q = adv_search_language(q, include_languages_inputs, exclude_languages_inputs) + q = adv_search_ratings(q, rating_high, rating_low) + if description: q = q.filter(db.Books.comments.any(func.lower(db.Comments.text).ilike("%" + description + "%"))) # search custom culumns - for c in cc: - custom_query = term.get('custom_column_' + str(c.id)) - if custom_query != '' and custom_query is not None: - if c.datatype == 'bool': - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - db.cc_classes[c.id].value == (custom_query == "True"))) - elif c.datatype == 'int' or c.datatype == 'float': - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - db.cc_classes[c.id].value == custom_query)) - elif c.datatype == 'rating': - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - db.cc_classes[c.id].value == int(float(custom_query) * 2))) - else: - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - func.lower(db.cc_classes[c.id].value).ilike("%" + custom_query + "%"))) + q = adv_search_custom_columns(cc, term, q) + q = q.order_by(*order).all() flask_session['query'] = json.dumps(term) ub.store_ids(q) - # entries, result_count, pagination = calibre_db.get_search_results(term, offset, order, limit) result_count = len(q) if offset != None and limit != None: offset = int(offset) @@ -1409,16 +1485,7 @@ def logout(): # ################################### Users own configuration ######################################################### -def change_profile(kobo_support, local_oauth_check, oauth_status, translations, languages): - to_save = request.form.to_dict() - current_user.random_books = 0 - if current_user.role_passwd() or current_user.role_admin(): - if "password" in to_save and to_save["password"]: - current_user.password = generate_password_hash(to_save["password"]) - if "kindle_mail" in to_save and to_save["kindle_mail"] != current_user.kindle_mail: - current_user.kindle_mail = to_save["kindle_mail"] - if "allowed_tags" in to_save and to_save["allowed_tags"] != current_user.allowed_tags: - current_user.allowed_tags = to_save["allowed_tags"].strip() +def change_profile_email(to_save, kobo_support, local_oauth_check, oauth_status): if "email" in to_save and to_save["email"] != current_user.email: if config.config_public_reg and not check_valid_domain(to_save["email"]): flash(_(u"E-mail is not from valid domain"), category="error") @@ -1427,6 +1494,8 @@ def change_profile(kobo_support, local_oauth_check, oauth_status, translations, kobo_support=kobo_support, registered_oauth=local_oauth_check, oauth_status=oauth_status) current_user.email = to_save["email"] + +def change_profile_nickname(to_save, kobo_support, local_oauth_check, translations, languages): if "nickname" in to_save and to_save["nickname"] != current_user.nickname: # Query User nickname, if not existing, change if not ub.session.query(ub.User).filter(ub.User.nickname == to_save["nickname"]).scalar(): @@ -1442,6 +1511,20 @@ def change_profile(kobo_support, local_oauth_check, oauth_status, translations, title=_(u"Edit User %(nick)s", nick=current_user.nickname), page="edituser") + + +def change_profile(kobo_support, local_oauth_check, oauth_status, translations, languages): + to_save = request.form.to_dict() + current_user.random_books = 0 + if current_user.role_passwd() or current_user.role_admin(): + if "password" in to_save and to_save["password"]: + current_user.password = generate_password_hash(to_save["password"]) + if "kindle_mail" in to_save and to_save["kindle_mail"] != current_user.kindle_mail: + current_user.kindle_mail = to_save["kindle_mail"] + if "allowed_tags" in to_save and to_save["allowed_tags"] != current_user.allowed_tags: + current_user.allowed_tags = to_save["allowed_tags"].strip() + change_profile_email(to_save, kobo_support, local_oauth_check, oauth_status) + change_profile_nickname(to_save, kobo_support, local_oauth_check, translations, languages) if "show_random" in to_save and to_save["show_random"] == "on": current_user.random_books = 1 if "default_language" in to_save: