From 6e8445fed50fe7150c80f12ef958f9a1fe308fa6 Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Mon, 25 Apr 2022 17:00:07 +0200 Subject: [PATCH] Changed schedule start- and end-time to schedule start and duration Localized display of schedule start-time and duration Removed displaying scheduling settings if "APScheduler" is missing Input check for start-time and duration --- cps.py | 2 +- cps/admin.py | 76 +++++++++++++++++++++----------- cps/config_sql.py | 3 +- cps/schedule.py | 26 ++++++----- cps/tasks/database.py | 1 + cps/templates/admin.html | 15 ++++--- cps/templates/schedule_edit.html | 17 ++++--- 7 files changed, 90 insertions(+), 50 deletions(-) diff --git a/cps.py b/cps.py index 17cceb0a..55d9339c 100755 --- a/cps.py +++ b/cps.py @@ -77,7 +77,7 @@ def main(): app.register_blueprint(oauth) # Register scheduled tasks - register_scheduled_tasks() + register_scheduled_tasks() # ToDo only reconnect if reconnect is enabled register_startup_tasks() success = web_server.start() diff --git a/cps/admin.py b/cps/admin.py index 6db36dd2..9dc45096 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -24,13 +24,12 @@ import os import re import base64 import json -import time import operator -from datetime import datetime, timedelta +from datetime import datetime, timedelta, time from functools import wraps from babel import Locale -from babel.dates import format_datetime +from babel.dates import format_datetime, format_time, format_timedelta from flask import Blueprint, flash, redirect, url_for, abort, request, make_response, send_from_directory, g, Response from flask_login import login_required, current_user, logout_user, confirm_login from flask_babel import gettext as _ @@ -58,7 +57,8 @@ feature_support = { 'goodreads': bool(services.goodreads_support), 'kobo': bool(services.kobo), 'updater': constants.UPDATER_AVAILABLE, - 'gmail': bool(services.gmail) + 'gmail': bool(services.gmail), + 'scheduler': schedule.use_APScheduler } try: @@ -184,6 +184,7 @@ def update_thumbnails(): @login_required @admin_required def admin(): + locale = get_locale() version = updater_thread.get_current_version_info() if version is False: commit = _(u'Unknown') @@ -198,15 +199,19 @@ def admin(): form_date -= timedelta(hours=int(commit[20:22]), minutes=int(commit[23:])) elif commit[19] == '-': form_date += timedelta(hours=int(commit[20:22]), minutes=int(commit[23:])) - commit = format_datetime(form_date - tz, format='short', locale=get_locale()) + commit = format_datetime(form_date - tz, format='short', locale=locale) else: commit = version['version'] all_user = ub.session.query(ub.User).all() email_settings = config.get_mail_settings() - kobo_support = feature_support['kobo'] and config.config_kobo_sync + schedule_time = format_time(time(hour=config.schedule_start_time), format="short", locale=locale) + t = timedelta(hours=config.schedule_duration // 60, minutes=config.schedule_duration % 60) + schedule_duration = format_timedelta(t, format="short", threshold=.99, locale=locale) + return render_title_template("admin.html", allUser=all_user, email=email_settings, config=config, commit=commit, - feature_support=feature_support, kobo_support=kobo_support, + feature_support=feature_support, schedule_time=schedule_time, + schedule_duration=schedule_duration, title=_(u"Admin page"), page="admin") @@ -1660,36 +1665,57 @@ def update_mailsettings(): @admin_required def edit_scheduledtasks(): content = config.get_scheduled_task_settings() - return render_title_template("schedule_edit.html", config=content, title=_(u"Edit Scheduled Tasks Settings")) + time_field = list() + duration_field = list() + + locale = get_locale() + for n in range(24): + time_field.append((n , format_time(time(hour=n), format="short", locale=locale))) + for n in range(5, 65, 5): + t = timedelta(hours=n // 60, minutes=n % 60) + duration_field.append((n, format_timedelta(t, format="short", threshold=.99, locale=locale))) + + return render_title_template("schedule_edit.html", config=content, starttime=time_field, duration=duration_field, title=_(u"Edit Scheduled Tasks Settings")) @admi.route("/admin/scheduledtasks", methods=["POST"]) @login_required @admin_required def update_scheduledtasks(): + error = False to_save = request.form.to_dict() - _config_int(to_save, "schedule_start_time") - _config_int(to_save, "schedule_end_time") + if "0" <= to_save.get("schedule_start_time") <= "23": + _config_int(to_save, "schedule_start_time") + else: + flash(_(u"Invalid start time for task specified"), category="error") + error = True + if "0" < to_save.get("schedule_duration") <= "60": + _config_int(to_save, "schedule_duration") + else: + flash(_(u"Invalid duration for task specified"), category="error") + error = True _config_checkbox(to_save, "schedule_generate_book_covers") _config_checkbox(to_save, "schedule_generate_series_covers") + _config_checkbox(to_save, "schedule_reconnect") - try: - config.save() - flash(_(u"Scheduled tasks settings updated"), category="success") + if not error: + try: + config.save() + flash(_(u"Scheduled tasks settings updated"), category="success") - # Cancel any running tasks - schedule.end_scheduled_tasks() + # Cancel any running tasks + schedule.end_scheduled_tasks() - # Re-register tasks with new settings - schedule.register_scheduled_tasks(cli.reconnect_enable) - except IntegrityError as ex: - ub.session.rollback() - log.error("An unknown error occurred while saving scheduled tasks settings") - flash(_(u"An unknown error occurred. Please try again later."), category="error") - except OperationalError: - ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") + # Re-register tasks with new settings + schedule.register_scheduled_tasks(config.schedule_reconnect) + except IntegrityError: + ub.session.rollback() + log.error("An unknown error occurred while saving scheduled tasks settings") + flash(_(u"An unknown error occurred. Please try again later."), category="error") + except OperationalError: + ub.session.rollback() + log.error("Settings DB is not Writeable") + flash(_("Settings DB is not Writeable"), category="error") return edit_scheduledtasks() diff --git a/cps/config_sql.py b/cps/config_sql.py index a8beaabb..f4fbb554 100644 --- a/cps/config_sql.py +++ b/cps/config_sql.py @@ -142,9 +142,10 @@ class _Settings(_Base): config_allow_reverse_proxy_header_login = Column(Boolean, default=False) schedule_start_time = Column(Integer, default=4) - schedule_end_time = Column(Integer, default=6) + schedule_duration = Column(Integer, default=10) schedule_generate_book_covers = Column(Boolean, default=False) schedule_generate_series_covers = Column(Boolean, default=False) + schedule_reconnect = Column(Boolean, default=False) def __repr__(self): return self.__class__.__name__ diff --git a/cps/schedule.py b/cps/schedule.py index 5f8b2e86..72f9b230 100644 --- a/cps/schedule.py +++ b/cps/schedule.py @@ -19,7 +19,7 @@ import datetime from . import config, constants -from .services.background_scheduler import BackgroundScheduler +from .services.background_scheduler import BackgroundScheduler, use_APScheduler from .tasks.database import TaskReconnectDatabase from .tasks.thumbnail import TaskGenerateCoverThumbnails, TaskGenerateSeriesThumbnails, TaskClearCoverThumbnailCache from .services.worker import WorkerThread @@ -27,7 +27,7 @@ from .services.worker import WorkerThread def get_scheduled_tasks(reconnect=True): tasks = list() - + # config.schedule_reconnect or # Reconnect Calibre database (metadata.db) if reconnect: tasks.append([lambda: TaskReconnectDatabase(), 'reconnect', False]) @@ -59,15 +59,14 @@ def register_scheduled_tasks(reconnect=True): scheduler.remove_all_jobs() start = config.schedule_start_time - end = config.schedule_end_time + duration = config.schedule_duration # Register scheduled tasks - if start != end: - scheduler.schedule_tasks(tasks=get_scheduled_tasks(), trigger='cron', hour=start) - scheduler.schedule(func=end_scheduled_tasks, trigger='cron', name="end scheduled task", hour=end) + scheduler.schedule_tasks(tasks=get_scheduled_tasks(), trigger='cron', hour=start) + scheduler.schedule(func=end_scheduled_tasks, trigger='cron', name="end scheduled task", hour=start) # toDo # Kick-off tasks, if they should currently be running - if should_task_be_running(start, end): + if should_task_be_running(start, duration): scheduler.schedule_tasks_immediately(tasks=get_scheduled_tasks(reconnect)) @@ -76,14 +75,17 @@ def register_startup_tasks(): if scheduler: start = config.schedule_start_time - end = config.schedule_end_time + duration = config.schedule_duration # Run scheduled tasks immediately for development and testing # Ignore tasks that should currently be running, as these will be added when registering scheduled tasks - if constants.APP_MODE in ['development', 'test'] and not should_task_be_running(start, end): + if constants.APP_MODE in ['development', 'test'] and not should_task_be_running(start, duration): scheduler.schedule_tasks_immediately(tasks=get_scheduled_tasks(False)) -def should_task_be_running(start, end): - now = datetime.datetime.now().hour - return (start < end and start <= now < end) or (end < start and (now < end or start <= now )) +def should_task_be_running(start, duration): + now = datetime.datetime.now() + start_time = datetime.datetime.now().replace(hour=start, minute=0, second=0, microsecond=0) + end_time = start_time + datetime.timedelta(hours=duration // 60, minutes=duration % 60) + return start_time < now < end_time + # return (start < end and start <= now < end) or (end < start and (now < end or start <= now )) diff --git a/cps/tasks/database.py b/cps/tasks/database.py index e5aa26da..afc4db2c 100644 --- a/cps/tasks/database.py +++ b/cps/tasks/database.py @@ -31,6 +31,7 @@ class TaskReconnectDatabase(CalibreTask): self.listen_address = config.get_config_ipaddress() self.listen_port = config.config_port + def run(self, worker_thread): address = self.listen_address if self.listen_address else 'localhost' port = self.listen_port if self.listen_port else 8083 diff --git a/cps/templates/admin.html b/cps/templates/admin.html index 8b0bbc45..8a20b73e 100644 --- a/cps/templates/admin.html +++ b/cps/templates/admin.html @@ -161,18 +161,18 @@ {{_('Edit UI Configuration')}} - +{% if feature_support['scheduler'] %}

{{_('Scheduled Tasks')}}

{{_('Time at which tasks start to run')}}
-
{{config.schedule_start_time}}:00
+
{{schedule_time}}
-
{{_('Time at which tasks stop running')}}
-
{{config.schedule_end_time}}:00
+
{{_('Maximum tasks duration')}}
+
{{schedule_duration}}
{{_('Generate book cover thumbnails')}}
@@ -182,6 +182,11 @@
{{_('Generate series cover thumbnails')}}
{{ display_bool_setting(config.schedule_generate_series_covers) }}
+
+
{{_('Reconnect to Calibre Library')}}
+
{{ display_bool_setting(config.schedule_reconnect) }}
+
+
{{_('Edit Scheduled Tasks Settings')}} {% if config.schedule_generate_book_covers %} @@ -189,7 +194,7 @@ {% endif %}
- +{% endif %}

{{_('Administration')}}

{{_('Download Debug Package')}} diff --git a/cps/templates/schedule_edit.html b/cps/templates/schedule_edit.html index 599e7997..55658ce7 100644 --- a/cps/templates/schedule_edit.html +++ b/cps/templates/schedule_edit.html @@ -11,16 +11,16 @@
- - + {% for n in duration %} + {% endfor %}
@@ -32,6 +32,11 @@ +
+ + +
+ {{_('Cancel')}}