diff --git a/cps/__init__.py b/cps/__init__.py old mode 100755 new mode 100644 diff --git a/cps/admin.py b/cps/admin.py old mode 100755 new mode 100644 diff --git a/cps/redirect.py b/cps/redirect.py old mode 100755 new mode 100644 diff --git a/cps/search.py b/cps/search.py index 4ae8a5d72..6054ec9ec 100644 --- a/cps/search.py +++ b/cps/search.py @@ -24,6 +24,7 @@ from flask_babel import format_date from flask_babel import gettext as _ from sqlalchemy.sql.expression import func, not_, and_, or_, text, true from sqlalchemy.sql.functions import coalesce +from sqlalchemy import exists from . import logger, db, calibre_db, config, ub from .usermanagement import login_required_if_no_ano @@ -81,16 +82,27 @@ def adv_search_custom_columns(cc, term, q): if custom_end: q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( func.datetime(db.cc_classes[c.id].value) <= func.datetime(custom_end))) + elif c.datatype in ["int", "float"]: + custom_low = term.get('custom_column_' + str(c.id) + '_low') + custom_high = term.get('custom_column_' + str(c.id) + '_high') + if custom_low: + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value >= custom_low)) + if custom_high: + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value <= custom_high)) else: 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': + if c.datatype == 'bool': + if custom_query != "Any": + if custom_query == "": + q = q.filter(~getattr(db.Books, 'custom_column_' + str(c.id)). + any(db.cc_classes[c.id].value >= 0)) + else: + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value == bool(custom_query == "True"))) + elif custom_query != '' and custom_query is not None: + if 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: @@ -129,10 +141,10 @@ def adv_search_read_status(read_status): db_filter = coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED else: try: - if read_status == "True": - db_filter = db.cc_classes[config.config_read_column].value == True + if read_status == "": + db_filter = coalesce(db.cc_classes[config.config_read_column].value, 2) == 2 else: - db_filter = coalesce(db.cc_classes[config.config_read_column].value, False) != True + db_filter = db.cc_classes[config.config_read_column].value == bool(read_status == "True") except (KeyError, AttributeError, IndexError): log.error("Custom Column No.{} does not exist in calibre database".format(config.config_read_column)) flash(_("Custom Column No.%(column)d does not exist in calibre database", @@ -275,10 +287,23 @@ def render_adv_search_results(term, offset=None, order=None, limit=None): cc_present = True if column_end: search_term.extend(["{} <= {}".format(c.name, - format_date(datetime.strptime(column_end, "%Y-%m-%d").date(), + format_date(datetime.strptime(column_end, "%Y-%m-%d").date(), format='medium') )]) cc_present = True + if c.datatype in ["int", "float"]: + column_low = term.get('custom_column_' + str(c.id) + '_low') + column_high = term.get('custom_column_' + str(c.id) + '_high') + if column_low: + search_term.extend(["{} >= {}".format(c.name, column_low)]) + cc_present = True + if column_high: + search_term.extend(["{} <= {}".format(c.name,column_high)]) + cc_present = True + elif c.datatype == "bool": + if term.get('custom_column_' + str(c.id)) != "Any": + search_term.extend([("{}: {}".format(c.name, term.get('custom_column_' + str(c.id))))]) + cc_present = True elif term.get('custom_column_' + str(c.id)): search_term.extend([("{}: {}".format(c.name, term.get('custom_column_' + str(c.id))))]) cc_present = True diff --git a/cps/static/js/main.js b/cps/static/js/main.js index 6b183b07a..fc18890c5 100644 --- a/cps/static/js/main.js +++ b/cps/static/js/main.js @@ -160,15 +160,18 @@ $(document).ready(function() { $(".session").click(function() { window.sessionStorage.setItem("back", window.location.pathname); + window.sessionStorage.setItem("search", window.location.search); }); $("#back").click(function() { var loc = sessionStorage.getItem("back"); + var param = sessionStorage.getItem("search"); if (!loc) { loc = $(this).data("back"); } sessionStorage.removeItem("back"); - window.location.href = loc; + sessionStorage.removeItem("search"); + window.location.href = loc + param; }); diff --git a/cps/tasks_status.py b/cps/tasks_status.py index 49feb67c2..268200d4e 100644 --- a/cps/tasks_status.py +++ b/cps/tasks_status.py @@ -82,6 +82,7 @@ def render_task_status(tasklist): ret['task_id'] = task.id ret['stat'] = task.stat ret['is_cancellable'] = task.is_cancellable + ret['error'] = task.error rendered_tasklist.append(ret) diff --git a/cps/templates/search_form.html b/cps/templates/search_form.html index cf2fac04b..cdce85a5c 100644 --- a/cps/templates/search_form.html +++ b/cps/templates/search_form.html @@ -158,21 +158,41 @@ {% if cc|length > 0 %} {% for c in cc %}
+ {% if c.datatype == 'bool' %} {% endif %} {% if c.datatype == 'int' %} - +
+
+ + +
+
+ + +
+
{% endif %} - {% if c.datatype == 'float' %} - +
+
+ + +
+
+ + +
+
+ {% endif %} {% if c.datatype == 'datetime' %} diff --git a/cps/templates/tasks.html b/cps/templates/tasks.html index 4d645aa52..83d4e8045 100644 --- a/cps/templates/tasks.html +++ b/cps/templates/tasks.html @@ -16,6 +16,7 @@ {{_('Progress')}} {{_('Run Time')}} {{_('Start Time')}} + {{_('Message')}} {% if current_user.role_admin() %} {{_('Actions')}} {% endif %} diff --git a/test/Calibre-Web TestSummary_Linux.html b/test/Calibre-Web TestSummary_Linux.html index b21f11ff9..6f805974a 100644 --- a/test/Calibre-Web TestSummary_Linux.html +++ b/test/Calibre-Web TestSummary_Linux.html @@ -37,20 +37,20 @@
-

Start Time: 2024-07-29 06:08:20

+

Start Time: 2024-08-02 21:21:17

-

Stop Time: 2024-07-29 13:40:23

+

Stop Time: 2024-08-03 04:29:18

-

Duration: 6h 9 min

+

Duration: 5h 53 min

@@ -234,11 +234,11 @@ - + TestBackupMetadata 21 - 20 - 1 + 21 + 0 0 0 @@ -248,33 +248,11 @@ - +
TestBackupMetadata - test_backup_all
- -
- FAIL -
- - - - + PASS @@ -484,12 +462,12 @@ AssertionError: 'Finished' != 'Failed' - + TestCli 13 - 11 + 13 + 0 0 - 2 0 Detail @@ -588,31 +566,11 @@ AssertionError: 'Finished' != 'Failed' - +
TestCli - test_no_database
- -
- ERROR -
- - - - + PASS @@ -626,53 +584,22 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestCli - test_writeonly_static_files
- -
- ERROR -
- - - - + PASS - + TestCliGdrivedb 4 - 3 + 4 + 0 0 - 1 0 Detail @@ -708,31 +635,11 @@ bail@chrome://remote/content/marionette/sync.sys.mjs:211:19 - +
TestCliGdrivedb - test_no_database
- -
- ERROR -
- - - - + PASS @@ -795,12 +702,12 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - + TestEbookConvertCalibre 15 - 15 - 0 - 0 + 12 + 2 + 1 0 Detail @@ -809,11 +716,33 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestEbookConvertCalibre - test_calibre_log
- PASS + +
+ FAIL +
+ + + + @@ -845,11 +774,31 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestEbookConvertCalibre - test_convert_only
- PASS + +
+ ERROR +
+ + + + @@ -899,11 +848,33 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestEbookConvertCalibre - test_email_only
- PASS + +
+ FAIL +
+ + + + @@ -945,12 +916,12 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - + TestEbookConvertCalibreGDrive 7 - 7 - 0 - 0 + 3 + 3 + 1 0 Detail @@ -959,29 +930,95 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestEbookConvertCalibreGDrive - test_convert_email
- PASS + +
+ FAIL +
+ + + + - +
TestEbookConvertCalibreGDrive - test_convert_failed_and_email
- PASS + +
+ ERROR +
+ + + + - +
TestEbookConvertCalibreGDrive - test_convert_only
- PASS + +
+ FAIL +
+ + + + @@ -1004,11 +1041,33 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestEbookConvertCalibreGDrive - test_email_only
- PASS + +
+ FAIL +
+ + + + @@ -1023,12 +1082,12 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - + TestEbookConvertKepubify 3 - 3 - 0 + 2 0 + 1 0 Detail @@ -1046,11 +1105,31 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestEbookConvertKepubify - test_convert_only
- PASS + +
+ ERROR +
+ + + + @@ -1065,11 +1144,11 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - + TestEbookConvertGDriveKepubify 3 - 3 - 0 + 2 + 1 0 0 @@ -1088,11 +1167,33 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestEbookConvertGDriveKepubify - test_convert_only
- PASS + +
+ FAIL +
+ + + + @@ -1107,11 +1208,11 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - + TestEditAdditionalBooks 20 - 17 - 1 + 18 + 0 0 2 @@ -1282,31 +1383,11 @@ OSError: [Errno 39] Directory not empty: '/home/ozzie/Dusty/script/alternate - +
TestEditAdditionalBooks - test_writeonly_path
- -
- FAIL -
- - - - + PASS @@ -1730,12 +1811,12 @@ AssertionError: False is not true - + TestEditAuthors 9 5 - 4 0 + 4 0 Detail @@ -1753,26 +1834,26 @@ AssertionError: False is not true - +
TestEditAuthors - test_change_capital_one_author_one_book
- FAIL + ERROR
-