adds timezone config option

This commit is contained in:
Michael Beck 2025-06-13 11:47:41 +02:00
parent 7fd403bd40
commit 8f064cda34
4 changed files with 151 additions and 3 deletions

View File

@ -2,7 +2,7 @@
from flask import Blueprint, render_template, redirect, url_for, request, flash, jsonify, current_app
from ..db import db
# Import the new model
from ..models import VolumeConfig, ScheduleConfig, ActivityLog, DownloadPathConfig, PaperMetadata
from ..models import VolumeConfig, ScheduleConfig, ActivityLog, DownloadPathConfig, PaperMetadata, TimezoneConfig
from ..defaults import MAX_VOLUME
import os # Import os for path validation
import sys
@ -129,6 +129,54 @@ def _update_download_path(new_path):
return False, f"Error updating download path: {str(e)}", None
def _update_timezone(new_timezone):
"""
Helper function to update timezone configuration.
Args:
new_timezone (str): The new timezone
Returns:
tuple: (success, message, timezone_config)
"""
try:
# Basic validation: check if it's a non-empty string
if not new_timezone or not isinstance(new_timezone, str):
return False, "Timezone cannot be empty.", None
# Validate timezone using pytz
try:
import pytz
pytz.timezone(new_timezone) # This will raise an exception if invalid
except ImportError:
# If pytz is not available, do basic validation
if '/' not in new_timezone:
return False, "Invalid timezone format. Use format like 'Europe/Berlin'.", None
except pytz.exceptions.UnknownTimeZoneError:
return False, f"Unknown timezone: {new_timezone}. Use format like 'Europe/Berlin'.", None
config = TimezoneConfig.query.first()
if not config:
config = TimezoneConfig(timezone=new_timezone)
db.session.add(config)
else:
old_value = config.timezone
config.timezone = new_timezone
ActivityLog.log_config_change(
config_key="scheduler_timezone",
old_value=old_value,
new_value=new_timezone,
description="Updated scheduler timezone"
)
db.session.commit()
return True, "Timezone updated successfully!", config
except Exception as e:
db.session.rollback()
return False, f"Error updating timezone: {str(e)}", None
def _update_schedule(schedule_data):
"""
Helper function to update schedule configuration.
@ -211,11 +259,19 @@ def general():
db.session.add(download_path_config)
db.session.commit()
# Fetch timezone config
timezone_config = TimezoneConfig.query.first()
if not timezone_config:
timezone_config = TimezoneConfig() # Use default from model
db.session.add(timezone_config)
db.session.commit()
return render_template(
"config/index.html.jinja",
active_tab="general",
volume_config=volume_config,
download_path_config=download_path_config, # Pass to template
timezone_config=timezone_config, # Pass to template
max_volume=MAX_VOLUME,
app_title="Configuration"
)
@ -369,9 +425,10 @@ def generate_test_papers():
@bp.route("/update/general", methods=["POST"])
def update_general():
"""Update general configuration (Volume and Download Path)."""
"""Update general configuration (Volume, Download Path, and Timezone)."""
volume_success, volume_message = True, ""
path_success, path_message = True, ""
timezone_success, timezone_message = True, ""
# Update Volume
new_volume = request.form.get("total_volume")
@ -391,6 +448,15 @@ def update_general():
else:
flash(path_message, "error")
# Update Timezone
new_timezone = request.form.get("timezone")
if new_timezone is not None:
timezone_success, timezone_message, _ = _update_timezone(new_timezone)
if timezone_success:
flash(timezone_message, "success")
else:
flash(timezone_message, "error")
return redirect(url_for("config.general"))

View File

@ -343,6 +343,41 @@ class ScraperModuleConfig(db.Model):
db.session.commit()
return config
class TimezoneConfig(db.Model):
"""Model to store the configured timezone for the scheduler."""
id = db.Column(db.Integer, primary_key=True)
timezone = db.Column(db.String(50), default="Europe/Berlin")
@classmethod
def get_current_timezone(cls):
"""Get the currently configured timezone."""
config = cls.query.first()
if not config:
config = cls(timezone="Europe/Berlin")
db.session.add(config)
db.session.commit()
return config.timezone
@classmethod
def set_timezone(cls, timezone_name):
"""Set the timezone configuration."""
config = cls.query.first()
if not config:
config = cls(timezone=timezone_name)
db.session.add(config)
else:
old_value = config.timezone
config.timezone = timezone_name
ActivityLog.log_config_change(
config_key="scheduler_timezone",
old_value=old_value,
new_value=timezone_name,
description="Updated scheduler timezone configuration"
)
db.session.commit()
return config
def init_schedule_config():
"""Initialize ScheduleConfig with default values if empty"""
if ScheduleConfig.query.count() == 0:
@ -380,3 +415,9 @@ def init_schedule_config():
default_path = DownloadPathConfig(path="/path/to/dummy/papers")
db.session.add(default_path)
db.session.commit()
# Initialize TimezoneConfig if it doesn't exist
if TimezoneConfig.query.count() == 0:
default_timezone = TimezoneConfig(timezone="Europe/Berlin")
db.session.add(default_timezone)
db.session.commit()

View File

@ -293,12 +293,16 @@ class ScraperScheduler:
'misfire_grace_time': 30 # 30 seconds grace period for missed jobs
}
# Get timezone from database configuration
from .models import TimezoneConfig
configured_timezone = TimezoneConfig.get_current_timezone()
# Create the scheduler
_scheduler = BackgroundScheduler(
jobstores=jobstores,
executors=executors,
job_defaults=job_defaults,
timezone=None # Use system timezone instead of UTC
timezone=configured_timezone # Use configurable timezone from database
)
# Add event listeners

View File

@ -38,6 +38,43 @@
</div>
</div>
<div class="form-section">
<h6>Scheduler Timezone</h6>
<p class="text-muted">Configure the timezone for the APScheduler to use for job
scheduling.</p>
<div class="mb-3">
<label for="timezone" class="form-label">Timezone:</label>
<select class="form-control" id="timezone" name="timezone" required>
<option value="UTC" {% if timezone_config.timezone=='UTC' %}selected{% endif %}>
UTC</option>
<option value="Europe/Berlin" {% if timezone_config.timezone=='Europe/Berlin'
%}selected{% endif %}>Europe/Berlin (CET/CEST)</option>
<option value="Europe/London" {% if timezone_config.timezone=='Europe/London'
%}selected{% endif %}>Europe/London (GMT/BST)</option>
<option value="Europe/Paris" {% if timezone_config.timezone=='Europe/Paris'
%}selected{% endif %}>Europe/Paris (CET/CEST)</option>
<option value="Europe/Rome" {% if timezone_config.timezone=='Europe/Rome'
%}selected{% endif %}>Europe/Rome (CET/CEST)</option>
<option value="US/Eastern" {% if timezone_config.timezone=='US/Eastern'
%}selected{% endif %}>US/Eastern (EST/EDT)</option>
<option value="US/Central" {% if timezone_config.timezone=='US/Central'
%}selected{% endif %}>US/Central (CST/CDT)</option>
<option value="US/Mountain" {% if timezone_config.timezone=='US/Mountain'
%}selected{% endif %}>US/Mountain (MST/MDT)</option>
<option value="US/Pacific" {% if timezone_config.timezone=='US/Pacific'
%}selected{% endif %}>US/Pacific (PST/PDT)</option>
<option value="Asia/Tokyo" {% if timezone_config.timezone=='Asia/Tokyo'
%}selected{% endif %}>Asia/Tokyo (JST)</option>
<option value="Asia/Shanghai" {% if timezone_config.timezone=='Asia/Shanghai'
%}selected{% endif %}>Asia/Shanghai (CST)</option>
<option value="Australia/Sydney" {% if
timezone_config.timezone=='Australia/Sydney' %}selected{% endif %}>
Australia/Sydney (AEST/AEDT)</option>
</select>
<div class="form-text">Current: {{ timezone_config.timezone }}</div>
</div>
</div>
<div class="form-section">
<h6>System Settings</h6>
<p class="text-muted">Configure general system behavior.</p>