From ae73246878a03761e07290a53488eaa4175bbdd5 Mon Sep 17 00:00:00 2001 From: Dmitrii Iurco Date: Tue, 21 Apr 2026 03:46:31 -0400 Subject: [PATCH] fix: propagate Settings config changes to service managers and live pages - PUT /api/config now calls service_manager.update_config() for each service so changes write to the service's own config file, not just cell_config.json - email_manager.get_status() now reads smtp_port/imap_port/domain from its config file (defaults: 587/993/cell.local) and includes them in the response - calendar_manager.get_status() includes configured port (default 5232) - file_manager.get_status() uses configured port from service config - Email.jsx reads imap_port/smtp_port from API status instead of hardcoding - Settings service sections show "port changes require container restart" note Co-Authored-By: Claude Sonnet 4.6 --- api/app.py | 28 +++++++++++++++++++++------- api/calendar_manager.py | 15 ++++++++++++--- api/email_manager.py | 28 ++++++++++++++++++++-------- api/file_manager.py | 5 ++++- webui/src/pages/Email.jsx | 4 ++-- webui/src/pages/Settings.jsx | 3 ++- 6 files changed, 61 insertions(+), 22 deletions(-) diff --git a/api/app.py b/api/app.py index 1e0ccb0..f2db060 100644 --- a/api/app.py +++ b/api/app.py @@ -403,15 +403,29 @@ def update_config(): config_manager.configs['_identity'] = stored config_manager._save_all_configs() - # Update service configurations + # Map service names to their manager instances + _svc_managers = { + 'network': network_manager, + 'wireguard': wireguard_manager, + 'email': email_manager, + 'calendar': calendar_manager, + 'files': file_manager, + 'routing': routing_manager, + 'vault': app.vault_manager, + } + + # Update service configurations in both config_manager and service managers for service, config in data.items(): if service in config_manager.service_schemas: - success = config_manager.update_service_config(service, config) - if success: - service_bus.publish_event(EventType.CONFIG_CHANGED, service, { - 'service': service, - 'config': config - }) + config_manager.update_service_config(service, config) + # Propagate to the service manager's own config file + mgr = _svc_managers.get(service) + if mgr: + mgr.update_config(config) + service_bus.publish_event(EventType.CONFIG_CHANGED, service, { + 'service': service, + 'config': config + }) logger.info(f"Updated config: {data}") return jsonify({"message": "Configuration updated successfully"}) diff --git a/api/calendar_manager.py b/api/calendar_manager.py index ed800b4..ba33c48 100644 --- a/api/calendar_manager.py +++ b/api/calendar_manager.py @@ -29,19 +29,27 @@ class CalendarManager(BaseServiceManager): self.safe_makedirs(self.calendar_data_dir) self.safe_makedirs(self.radicale_dir) + def _get_configured_port(self) -> int: + cfg = self.get_config() + if isinstance(cfg, dict) and 'error' not in cfg: + return cfg.get('port', 5232) + return 5232 + def get_status(self) -> Dict[str, Any]: """Get calendar service status""" try: + port = self._get_configured_port() # Check if we're running in Docker environment import os is_docker = os.path.exists('/.dockerenv') or os.environ.get('DOCKER_CONTAINER') == 'true' - + if is_docker: # Check if calendar container is actually running container_running = self._check_calendar_container_status() status = { 'running': container_running, 'status': 'online' if container_running else 'offline', + 'port': port, 'users_count': 0, 'calendars_count': 0, 'events_count': 0, @@ -53,16 +61,17 @@ class CalendarManager(BaseServiceManager): users = self._load_users() calendars = self._load_calendars() events = self._load_events() - + status = { 'running': service_running, 'status': 'online' if service_running else 'offline', + 'port': port, 'users_count': len(users), 'calendars_count': len(calendars), 'events_count': len(events), 'timestamp': datetime.utcnow().isoformat() } - + return status except Exception as e: return self.handle_error(e, "get_status") diff --git a/api/email_manager.py b/api/email_manager.py index da30830..71510e5 100644 --- a/api/email_manager.py +++ b/api/email_manager.py @@ -33,15 +33,25 @@ class EmailManager(BaseServiceManager): self.safe_makedirs(self.dovecot_dir) self.safe_makedirs(os.path.dirname(self.domain_config_file)) + def _get_service_config(self) -> Dict[str, Any]: + """Read configured ports/domain from service config file.""" + cfg = self.get_config() + if isinstance(cfg, dict) and 'error' not in cfg: + return cfg + return {} + def get_status(self) -> Dict[str, Any]: """Get email service status""" try: - # Check if we're running in Docker environment + svc_cfg = self._get_service_config() + smtp_port = svc_cfg.get('smtp_port', 587) + imap_port = svc_cfg.get('imap_port', 993) + domain = svc_cfg.get('domain') or self._get_domain_config().get('domain', 'cell.local') + import os is_docker = os.path.exists('/.dockerenv') or os.environ.get('DOCKER_CONTAINER') == 'true' - + if is_docker: - # Check if email container is actually running container_running = self._check_email_container_status() status = { 'running': container_running, @@ -49,24 +59,26 @@ class EmailManager(BaseServiceManager): 'smtp_running': container_running, 'imap_running': container_running, 'users_count': 0, - 'domain': 'cell.local', + 'domain': domain, + 'smtp_port': smtp_port, + 'imap_port': imap_port, 'timestamp': datetime.utcnow().isoformat() } else: - # Check actual service status in production smtp_running = self._check_smtp_status() imap_running = self._check_imap_status() - status = { 'running': smtp_running and imap_running, 'status': 'online' if (smtp_running and imap_running) else 'offline', 'smtp_running': smtp_running, 'imap_running': imap_running, 'users_count': len(self._load_users()), - 'domain': self._get_domain_config().get('domain', 'unknown'), + 'domain': domain, + 'smtp_port': smtp_port, + 'imap_port': imap_port, 'timestamp': datetime.utcnow().isoformat() } - + return status except Exception as e: return self.handle_error(e, "get_status") diff --git a/api/file_manager.py b/api/file_manager.py index 5f11653..314c61b 100644 --- a/api/file_manager.py +++ b/api/file_manager.py @@ -481,13 +481,16 @@ umask = 022 import os is_docker = os.path.exists('/.dockerenv') or os.environ.get('DOCKER_CONTAINER') == 'true' + svc_cfg = self.get_config() + configured_port = svc_cfg.get('port', 80) if isinstance(svc_cfg, dict) and 'error' not in svc_cfg else 80 + if is_docker: # Check if file container is actually running container_running = self._check_file_container_status() status = { 'running': container_running, 'status': 'online' if container_running else 'offline', - 'webdav_status': {'running': container_running, 'port': 8080}, + 'webdav_status': {'running': container_running, 'port': configured_port}, 'users_count': 0, 'total_storage_used': {'bytes': 0, 'human_readable': '0 B'}, 'timestamp': datetime.utcnow().isoformat() diff --git a/webui/src/pages/Email.jsx b/webui/src/pages/Email.jsx index d162dd5..9dacb5e 100644 --- a/webui/src/pages/Email.jsx +++ b/webui/src/pages/Email.jsx @@ -79,7 +79,7 @@ function Email() {
- +
@@ -93,7 +93,7 @@ function Email() {
- +
diff --git a/webui/src/pages/Settings.jsx b/webui/src/pages/Settings.jsx index 3cc6d9c..90ff079 100644 --- a/webui/src/pages/Settings.jsx +++ b/webui/src/pages/Settings.jsx @@ -495,7 +495,8 @@ function Settings() { return (
updateServiceConfig(key, d)} /> -
+
+ Port/directory changes take effect after container restart.