mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-11-04 01:03:02 +00:00 
			
		
		
		
	Added Scheduled Tasks Settings
This commit is contained in:
		
							
								
								
									
										62
									
								
								cps/admin.py
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								cps/admin.py
									
									
									
									
									
								
							@@ -159,23 +159,6 @@ def shutdown():
 | 
			
		||||
    return json.dumps(showtext), 400
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/clear-cache")
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
def clear_cache():
 | 
			
		||||
    cache_type = request.args.get('cache_type'.strip())
 | 
			
		||||
    showtext = {}
 | 
			
		||||
 | 
			
		||||
    if cache_type == constants.CACHE_TYPE_THUMBNAILS:
 | 
			
		||||
        log.info('clearing cover thumbnail cache')
 | 
			
		||||
        showtext['text'] = _(u'Cleared cover thumbnail cache')
 | 
			
		||||
        helper.clear_cover_thumbnail_cache()
 | 
			
		||||
        return json.dumps(showtext)
 | 
			
		||||
 | 
			
		||||
    showtext['text'] = _(u'Unknown command')
 | 
			
		||||
    return json.dumps(showtext)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/admin/view")
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
@@ -205,6 +188,7 @@ def admin():
 | 
			
		||||
                                 feature_support=feature_support, kobo_support=kobo_support,
 | 
			
		||||
                                 title=_(u"Admin page"), page="admin")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/admin/dbconfig", methods=["GET", "POST"])
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
@@ -245,6 +229,7 @@ def ajax_db_config():
 | 
			
		||||
def calibreweb_alive():
 | 
			
		||||
    return "", 200
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/admin/viewconfig")
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
@@ -257,6 +242,7 @@ def view_configuration():
 | 
			
		||||
                                 restrictColumns=restrict_columns,
 | 
			
		||||
                                 title=_(u"UI Configuration"), page="uiconfig")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/admin/usertable")
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
@@ -339,6 +325,7 @@ def list_users():
 | 
			
		||||
    response.headers["Content-Type"] = "application/json; charset=utf-8"
 | 
			
		||||
    return response
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/ajax/deleteuser", methods=['POST'])
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
@@ -372,6 +359,7 @@ def delete_user():
 | 
			
		||||
    success.extend(errors)
 | 
			
		||||
    return Response(json.dumps(success), mimetype='application/json')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/ajax/getlocale")
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
@@ -517,6 +505,7 @@ def update_table_settings():
 | 
			
		||||
        return "Invalid request", 400
 | 
			
		||||
    return ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_valid_read_column(column):
 | 
			
		||||
    if column != "0":
 | 
			
		||||
        if not calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.id == column) \
 | 
			
		||||
@@ -524,6 +513,7 @@ def check_valid_read_column(column):
 | 
			
		||||
            return False
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_valid_restricted_column(column):
 | 
			
		||||
    if column != "0":
 | 
			
		||||
        if not calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.id == column) \
 | 
			
		||||
@@ -532,7 +522,6 @@ def check_valid_restricted_column(column):
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/admin/viewconfig", methods=["POST"])
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
@@ -564,7 +553,6 @@ def update_view_configuration():
 | 
			
		||||
    _config_int(to_save, "config_books_per_page")
 | 
			
		||||
    _config_int(to_save, "config_authors_max")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    config.config_default_role = constants.selected_roles(to_save)
 | 
			
		||||
    config.config_default_role &= ~constants.ROLE_ANONYMOUS
 | 
			
		||||
 | 
			
		||||
@@ -1210,6 +1198,7 @@ def _db_configuration_update_helper():
 | 
			
		||||
    config.save()
 | 
			
		||||
    return _db_configuration_result(None, gdrive_error)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _configuration_update_helper():
 | 
			
		||||
    reboot_required = False
 | 
			
		||||
    to_save = request.form.to_dict()
 | 
			
		||||
@@ -1299,6 +1288,7 @@ def _configuration_update_helper():
 | 
			
		||||
 | 
			
		||||
    return _configuration_result(None, reboot_required)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _configuration_result(error_flash=None, reboot=False):
 | 
			
		||||
    resp = {}
 | 
			
		||||
    if error_flash:
 | 
			
		||||
@@ -1388,6 +1378,7 @@ def _handle_new_user(to_save, content, languages, translations, kobo_support):
 | 
			
		||||
        log.error("Settings DB is not Writeable")
 | 
			
		||||
        flash(_("Settings DB is not Writeable"), category="error")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _delete_user(content):
 | 
			
		||||
    if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN,
 | 
			
		||||
                                        ub.User.id != content.id).count():
 | 
			
		||||
@@ -1572,6 +1563,39 @@ def update_mailsettings():
 | 
			
		||||
    return edit_mailsettings()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/admin/scheduledtasks")
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
def edit_scheduledtasks():
 | 
			
		||||
    content = config.get_scheduled_task_settings()
 | 
			
		||||
    return render_title_template("schedule_edit.html", content=content, title=_(u"Edit Scheduled Tasks Settings"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/admin/scheduledtasks", methods=["POST"])
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
def update_scheduledtasks():
 | 
			
		||||
    to_save = request.form.to_dict()
 | 
			
		||||
    _config_int(to_save, "schedule_start_time")
 | 
			
		||||
    _config_int(to_save, "schedule_end_time")
 | 
			
		||||
    _config_checkbox(to_save, "schedule_generate_book_covers")
 | 
			
		||||
    _config_checkbox(to_save, "schedule_generate_series_covers")
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        config.save()
 | 
			
		||||
        flash(_(u"Scheduled tasks settings updated"), category="success")
 | 
			
		||||
    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")
 | 
			
		||||
 | 
			
		||||
    return edit_scheduledtasks()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admi.route("/admin/user/<int:user_id>", methods=["GET", "POST"])
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
 
 | 
			
		||||
@@ -140,6 +140,11 @@ class _Settings(_Base):
 | 
			
		||||
    config_reverse_proxy_login_header_name = Column(String)
 | 
			
		||||
    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_generate_book_covers = Column(Boolean, default=False)
 | 
			
		||||
    schedule_generate_series_covers = Column(Boolean, default=False)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return self.__class__.__name__
 | 
			
		||||
 | 
			
		||||
@@ -170,7 +175,6 @@ class _ConfigSQL(object):
 | 
			
		||||
        if change:
 | 
			
		||||
            self.save()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _read_from_storage(self):
 | 
			
		||||
        if self._settings is None:
 | 
			
		||||
            log.debug("_ConfigSQL._read_from_storage")
 | 
			
		||||
@@ -254,6 +258,8 @@ class _ConfigSQL(object):
 | 
			
		||||
        return bool((self.mail_server != constants.DEFAULT_MAIL_SERVER and self.mail_server_type == 0)
 | 
			
		||||
                    or (self.mail_gmail_token != {} and self.mail_server_type == 1))
 | 
			
		||||
 | 
			
		||||
    def get_scheduled_task_settings(self):
 | 
			
		||||
        return {k:v for k, v in self.__dict__.items() if k.startswith('schedule_')}
 | 
			
		||||
 | 
			
		||||
    def set_from_dictionary(self, dictionary, field, convertor=None, default=None, encode=None):
 | 
			
		||||
        """Possibly updates a field of this object.
 | 
			
		||||
@@ -289,7 +295,6 @@ class _ConfigSQL(object):
 | 
			
		||||
                storage[k] = v
 | 
			
		||||
        return storage
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def load(self):
 | 
			
		||||
        '''Load all configuration values from the underlying storage.'''
 | 
			
		||||
        s = self._read_from_storage()  # type: _Settings
 | 
			
		||||
@@ -407,6 +412,7 @@ def autodetect_calibre_binary():
 | 
			
		||||
            return element
 | 
			
		||||
    return ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def autodetect_unrar_binary():
 | 
			
		||||
    if sys.platform == "win32":
 | 
			
		||||
        calibre_path = ["C:\\program files\\WinRar\\unRAR.exe",
 | 
			
		||||
@@ -418,6 +424,7 @@ def autodetect_unrar_binary():
 | 
			
		||||
            return element
 | 
			
		||||
    return ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def autodetect_kepubify_binary():
 | 
			
		||||
    if sys.platform == "win32":
 | 
			
		||||
        calibre_path = ["C:\\program files\\kepubify\\kepubify-windows-64Bit.exe",
 | 
			
		||||
@@ -429,6 +436,7 @@ def autodetect_kepubify_binary():
 | 
			
		||||
            return element
 | 
			
		||||
    return ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _migrate_database(session):
 | 
			
		||||
    # make sure the table is created, if it does not exist
 | 
			
		||||
    _Base.metadata.create_all(session.bind)
 | 
			
		||||
@@ -452,6 +460,7 @@ def load_configuration(session):
 | 
			
		||||
    #    session.commit()
 | 
			
		||||
    return conf
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_flask_session_key(session):
 | 
			
		||||
    flask_settings = session.query(_Flask_Settings).one_or_none()
 | 
			
		||||
    if flask_settings == None:
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@
 | 
			
		||||
from __future__ import division, print_function, unicode_literals
 | 
			
		||||
 | 
			
		||||
from .services.background_scheduler import BackgroundScheduler
 | 
			
		||||
from .services.worker import WorkerThread
 | 
			
		||||
from .tasks.database import TaskReconnectDatabase
 | 
			
		||||
from .tasks.thumbnail import TaskGenerateCoverThumbnails, TaskGenerateSeriesThumbnails
 | 
			
		||||
 | 
			
		||||
@@ -28,13 +27,19 @@ def register_jobs():
 | 
			
		||||
    scheduler = BackgroundScheduler()
 | 
			
		||||
 | 
			
		||||
    if scheduler:
 | 
			
		||||
        # Reconnect metadata.db once every 12 hours
 | 
			
		||||
        scheduler.add_task(user=None, task=lambda: TaskReconnectDatabase(), trigger='cron', hour='4,16')
 | 
			
		||||
        # Reconnect Calibre database (metadata.db)
 | 
			
		||||
        scheduler.schedule_task(user=None, task=lambda: TaskReconnectDatabase(), trigger='cron', hour='4,16')
 | 
			
		||||
 | 
			
		||||
        # Generate all missing book cover thumbnails once every 24 hours
 | 
			
		||||
        scheduler.add_task(user=None, task=lambda: TaskGenerateCoverThumbnails(), trigger='cron', hour=4)
 | 
			
		||||
        # Generate all missing book cover thumbnails
 | 
			
		||||
        scheduler.schedule_task(user=None, task=lambda: TaskGenerateCoverThumbnails(), trigger='cron', hour=4)
 | 
			
		||||
 | 
			
		||||
        # Generate all missing series thumbnails
 | 
			
		||||
        scheduler.schedule_task(user=None, task=lambda: TaskGenerateSeriesThumbnails(), trigger='cron', hour=4)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def register_startup_jobs():
 | 
			
		||||
    WorkerThread.add(None, TaskGenerateCoverThumbnails())
 | 
			
		||||
    # WorkerThread.add(None, TaskGenerateSeriesThumbnails())
 | 
			
		||||
    scheduler = BackgroundScheduler()
 | 
			
		||||
 | 
			
		||||
    if scheduler:
 | 
			
		||||
        scheduler.schedule_task_immediately(None, task=lambda: TaskGenerateCoverThumbnails())
 | 
			
		||||
        scheduler.schedule_task_immediately(None, task=lambda: TaskGenerateSeriesThumbnails())
 | 
			
		||||
 
 | 
			
		||||
@@ -40,25 +40,31 @@ class BackgroundScheduler:
 | 
			
		||||
 | 
			
		||||
        if cls._instance is None:
 | 
			
		||||
            cls._instance = super(BackgroundScheduler, cls).__new__(cls)
 | 
			
		||||
 | 
			
		||||
            scheduler = BScheduler()
 | 
			
		||||
            atexit.register(lambda: scheduler.shutdown())
 | 
			
		||||
 | 
			
		||||
            cls.log = logger.create()
 | 
			
		||||
            cls.scheduler = scheduler
 | 
			
		||||
            cls.scheduler = BScheduler()
 | 
			
		||||
            cls.scheduler.start()
 | 
			
		||||
 | 
			
		||||
            atexit.register(lambda: cls.scheduler.shutdown())
 | 
			
		||||
 | 
			
		||||
        return cls._instance
 | 
			
		||||
 | 
			
		||||
    def add(self, func, trigger, **trigger_args):
 | 
			
		||||
    def _add(self, func, trigger, **trigger_args):
 | 
			
		||||
        if use_APScheduler:
 | 
			
		||||
            return self.scheduler.add_job(func=func, trigger=trigger, **trigger_args)
 | 
			
		||||
 | 
			
		||||
    def add_task(self, user, task, trigger, **trigger_args):
 | 
			
		||||
    # Expects a lambda expression for the task, so that the task isn't instantiated before the task is scheduled
 | 
			
		||||
    def schedule_task(self, user, task, trigger, **trigger_args):
 | 
			
		||||
        if use_APScheduler:
 | 
			
		||||
            def scheduled_task():
 | 
			
		||||
                worker_task = task()
 | 
			
		||||
                self.log.info(f'Running scheduled task in background: {worker_task.name} - {worker_task.message}')
 | 
			
		||||
                WorkerThread.add(user, worker_task)
 | 
			
		||||
 | 
			
		||||
            return self.add(func=scheduled_task, trigger=trigger, **trigger_args)
 | 
			
		||||
            return self._add(func=scheduled_task, trigger=trigger, **trigger_args)
 | 
			
		||||
 | 
			
		||||
    # Expects a lambda expression for the task, so that the task isn't instantiated before the task is scheduled
 | 
			
		||||
    def schedule_task_immediately(self, user, task):
 | 
			
		||||
        if use_APScheduler:
 | 
			
		||||
            def scheduled_task():
 | 
			
		||||
                WorkerThread.add(user, task())
 | 
			
		||||
 | 
			
		||||
            return self._add(func=scheduled_task, trigger='date')
 | 
			
		||||
 
 | 
			
		||||
@@ -167,9 +167,9 @@ class TaskGenerateCoverThumbnails(CalibreTask):
 | 
			
		||||
                try:
 | 
			
		||||
                    stream = urlopen(web_content_link)
 | 
			
		||||
                    with Image(file=stream) as img:
 | 
			
		||||
                        height = self.get_thumbnail_height(thumbnail)
 | 
			
		||||
                        height = get_resize_height(thumbnail.resolution)
 | 
			
		||||
                        if img.height > height:
 | 
			
		||||
                            width = self.get_thumbnail_width(height, img)
 | 
			
		||||
                            width = get_resize_width(thumbnail.resolution, img.width, img.height)
 | 
			
		||||
                            img.resize(width=width, height=height, filter='lanczos')
 | 
			
		||||
                            img.format = thumbnail.format
 | 
			
		||||
                            filename = self.cache.get_cache_file_path(thumbnail.filename,
 | 
			
		||||
@@ -212,16 +212,6 @@ class TaskGenerateSeriesThumbnails(CalibreTask):
 | 
			
		||||
            constants.COVER_THUMBNAIL_MEDIUM
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    # get all series
 | 
			
		||||
    # get all books in series with covers and count >= 4 books
 | 
			
		||||
    # get the dimensions from the first book in the series & pop the first book from the series list of books
 | 
			
		||||
    # randomly select three other books in the series
 | 
			
		||||
 | 
			
		||||
    # resize the covers in the sequence?
 | 
			
		||||
    # create an image sequence from the 4 selected books of the series
 | 
			
		||||
    # join pairs of books in the series with wand's concat
 | 
			
		||||
    # join the two sets of pairs with wand's
 | 
			
		||||
 | 
			
		||||
    def run(self, worker_thread):
 | 
			
		||||
        if self.calibre_db.session and use_IM:
 | 
			
		||||
            all_series = self.get_series_with_four_plus_books()
 | 
			
		||||
 
 | 
			
		||||
@@ -156,6 +156,31 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <h2>{{_('Scheduled Tasks')}}</h2>
 | 
			
		||||
        <div class="col-xs-12 col-sm-12">
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col-xs-6 col-sm-3">{{_('Time at which tasks start to run')}}</div>
 | 
			
		||||
            <div class="col-xs-6 col-sm-3">{{config.schedule_start_time}}:00</div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col-xs-6 col-sm-3">{{_('Time at which tasks stop running')}}</div>
 | 
			
		||||
            <div class="col-xs-6 col-sm-3">{{config.schedule_end_time}}:00</div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col-xs-6 col-sm-3">{{_('Generate book cover thumbnails')}}</div>
 | 
			
		||||
            <div class="col-xs-6 col-sm-3">{{ display_bool_setting(config.schedule_generate_book_covers) }}</div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col-xs-6 col-sm-3">{{_('Generate series cover thumbnails')}}</div>
 | 
			
		||||
            <div class="col-xs-6 col-sm-3">{{ display_bool_setting(config.schedule_generate_series_covers) }}</div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      <a class="btn btn-default scheduledtasks" id="admin_edit_scheduled_tasks" href="{{url_for('admin.edit_scheduledtasks')}}">{{_('Edit Scheduled Tasks Settings')}}</a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="row form-group">
 | 
			
		||||
    <h2>{{_('Administration')}}</h2>
 | 
			
		||||
    <a class="btn btn-default" id="debug" href="{{url_for('admin.download_debug')}}">{{_('Download Debug Package')}}</a>
 | 
			
		||||
@@ -163,7 +188,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="row form-group">
 | 
			
		||||
    <div class="btn btn-default" id="restart_database" data-toggle="modal" data-target="#StatusDialog">{{_('Reconnect Calibre Database')}}</div>
 | 
			
		||||
    <div class="btn btn-default" id="clear_cover_thumbnail_cache" data-toggle="modal" data-target="#ClearCacheDialog">{{_('Clear Cover Thumbnail Cache')}}</div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="row form-group">
 | 
			
		||||
    <div class="btn btn-default" id="admin_restart" data-toggle="modal" data-target="#RestartDialog">{{_('Restart')}}</div>
 | 
			
		||||
@@ -248,21 +272,4 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div id="ClearCacheDialog" class="modal fade" role="dialog">
 | 
			
		||||
  <div class="modal-dialog modal-sm">
 | 
			
		||||
    <!-- Modal content-->
 | 
			
		||||
    <div class="modal-content">
 | 
			
		||||
      <div class="modal-header bg-info"></div>
 | 
			
		||||
      <div class="modal-body text-center">
 | 
			
		||||
        <p>{{_('Are you sure you want to clear the cover thumbnail cache?')}}</p>
 | 
			
		||||
        <div id="spinner3" class="spinner" style="display:none;">
 | 
			
		||||
          <img id="img-spinner3" src="{{ url_for('static', filename='css/libs/images/loading-icon.gif') }}"/>
 | 
			
		||||
        </div>
 | 
			
		||||
        <p></p>
 | 
			
		||||
        <button type="button" class="btn btn-default" id="clear_cache" >{{_('OK')}}</button>
 | 
			
		||||
        <button type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								cps/templates/schedule_edit.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								cps/templates/schedule_edit.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
{% extends "layout.html" %}
 | 
			
		||||
{% block header %}
 | 
			
		||||
<link href="{{ url_for('static', filename='css/libs/bootstrap-table.min.css') }}" rel="stylesheet">
 | 
			
		||||
<link href="{{ url_for('static', filename='css/libs/bootstrap-editable.css') }}" rel="stylesheet">
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% block body %}
 | 
			
		||||
<div class="discover">
 | 
			
		||||
  <h1>{{title}}</h1>
 | 
			
		||||
  <form role="form" class="col-md-10 col-lg-6" method="POST" autocomplete="off">
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <label for="schedule_start_time">{{_('Time at which tasks start to run')}}</label>
 | 
			
		||||
      <select name="schedule_start_time" id="schedule_start_time" class="form-control">
 | 
			
		||||
        {% for n in range(24) %}
 | 
			
		||||
          <option value="{{n}}" {% if content.schedule_start_time == n %}selected{% endif %}>{{n}}{{_(':00')}}</option>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
      </select>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <label for="schedule_end_time">{{_('Time at which tasks stop running')}}</label>
 | 
			
		||||
      <select name="schedule_end_time" id="schedule_end_time" class="form-control">
 | 
			
		||||
        {% for n in range(24) %}
 | 
			
		||||
          <option value="{{n}}" {% if content.schedule_end_time == n %}selected{% endif %}>{{n}}{{_(':00')}}</option>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
      </select>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <input type="checkbox" id="schedule_generate_book_covers" name="schedule_generate_book_covers" checked>
 | 
			
		||||
      <label for="schedule_generate_book_covers">{{_('Generate Book Cover Thumbnails')}}</label>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <input type="checkbox" id="schedule_generate_series_covers" name="schedule_generate_series_covers" {% if config.schedule_generate_series_covers %}checked{% endif %}>
 | 
			
		||||
      <label for="schedule_generate_series_covers">{{_('Generate Series Cover Thumbnails')}}</label>
 | 
			
		||||
    </div>
 | 
			
		||||
    <button type="submit" name="submit" value="submit" class="btn btn-default">{{_('Save')}}</button>
 | 
			
		||||
    <a href="{{ url_for('admin.admin') }}" id="email_back" class="btn btn-default">{{_('Cancel')}}</a>
 | 
			
		||||
  </form>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Reference in New Issue
	
	Block a user