style: fix all flake8 linter errors across app/ directory
- Run Black formatter and isort on all app/ files - Remove unused imports (F401) across multiple files - Add # noqa: F401 for intentional re-exports in celery_worker.py, tasks/__init__.py, utils.py, frontend.py, views/base.py - Fix f-strings without placeholders (F541) in azure.py, notification.py, check_credentials.py, upload_to_onedrive.py, settings.py - Fix bare except (E722) in upload_to_sftp.py - Fix block comment format (E265) in models.py - Move imports to top of file to fix E402 in celery_app.py, celery_worker.py - Fix line-too-long (E501) by wrapping strings in multiple files - Remove unused variable (F841) in upload_to_nextcloud.py Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -3,31 +3,47 @@ Module for displaying and organizing settings information
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from app.config import settings
|
||||
from app.utils.config_validator.masking import mask_sensitive_value
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def dump_all_settings():
|
||||
"""Log all settings values for diagnostic purposes"""
|
||||
logger.info("--- DUMPING ALL SETTINGS FOR DIAGNOSTIC PURPOSES ---")
|
||||
for key in dir(settings):
|
||||
if not key.startswith('_') and not callable(getattr(settings, key)):
|
||||
if not key.startswith("_") and not callable(getattr(settings, key)):
|
||||
value = getattr(settings, key)
|
||||
# Mask sensitive values in logs
|
||||
if key.lower().find('password') >= 0 or key.lower().find('secret') >= 0 or key.lower().find('token') >= 0 or key.lower().find('key') >= 0:
|
||||
if (
|
||||
key.lower().find("password") >= 0
|
||||
or key.lower().find("secret") >= 0
|
||||
or key.lower().find("token") >= 0
|
||||
or key.lower().find("key") >= 0
|
||||
):
|
||||
if value:
|
||||
if isinstance(value, str) and len(value) > 10:
|
||||
visible_start = max(1, len(value) // 3)
|
||||
visible_end = max(1, len(value) // 4)
|
||||
value = f"{value[:visible_start]}{'*' * (len(value) - visible_start - visible_end)}{value[-visible_end:]}"
|
||||
value = (
|
||||
f"{value[:visible_start]}"
|
||||
f"{'*' * (len(value) - visible_start - visible_end)}"
|
||||
f"{value[-visible_end:]}"
|
||||
)
|
||||
else:
|
||||
value = f"{value[:2]}{'*' * (len(value) - 4)}{value[-2:]}" if isinstance(value, str) and len(value) > 4 else "****"
|
||||
|
||||
value = (
|
||||
f"{value[:2]}{'*' * (len(value) - 4)}{value[-2:]}"
|
||||
if isinstance(value, str) and len(value) > 4
|
||||
else "****"
|
||||
)
|
||||
|
||||
# Special handling for notification URLs
|
||||
if key == 'notification_urls' and value:
|
||||
if key == "notification_urls" and value:
|
||||
try:
|
||||
from app.utils.notification import _mask_sensitive_url
|
||||
|
||||
if isinstance(value, list):
|
||||
masked_urls = [_mask_sensitive_url(url) for url in value]
|
||||
logger.info(f"{key}: {masked_urls}")
|
||||
@@ -36,44 +52,37 @@ def dump_all_settings():
|
||||
continue # Skip the default logging
|
||||
except (ImportError, AttributeError):
|
||||
pass # Fall back to default logging if _mask_sensitive_url is not available
|
||||
|
||||
|
||||
logger.info(f"{key}: {value}")
|
||||
logger.info("--- END OF SETTINGS DUMP ---")
|
||||
|
||||
|
||||
def get_settings_for_display(show_values=False):
|
||||
"""
|
||||
Group settings into logical categories and check if they are configured.
|
||||
Returns a dictionary with categories as keys and lists of setting items as values.
|
||||
Returns a dictionary with categories as keys and lists of setting items as values.
|
||||
Each setting item is a dict with name, value, and is_configured.
|
||||
|
||||
|
||||
If show_values is False, sensitive values are masked.
|
||||
"""
|
||||
# First include system info with version in result
|
||||
result = {
|
||||
"System Info": [
|
||||
{
|
||||
"name": "App Version",
|
||||
"value": settings.version,
|
||||
"is_configured": True
|
||||
},
|
||||
{
|
||||
"name": "Build Date",
|
||||
"value": settings.build_date,
|
||||
"is_configured": True
|
||||
}
|
||||
{"name": "App Version", "value": settings.version, "is_configured": True},
|
||||
{"name": "Build Date", "value": settings.build_date, "is_configured": True},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# Define categories and their settings
|
||||
categories = {
|
||||
"Core": [
|
||||
"debug", # Explicitly include debug setting
|
||||
"debug", # Explicitly include debug setting
|
||||
"external_hostname",
|
||||
"workdir",
|
||||
"database_url",
|
||||
"redis_url",
|
||||
"gotenberg_url",
|
||||
"allow_file_delete" # Added allow_file_delete to Core settings
|
||||
"allow_file_delete", # Added allow_file_delete to Core settings
|
||||
],
|
||||
"Authentication": [
|
||||
"auth_enabled",
|
||||
@@ -83,7 +92,7 @@ def get_settings_for_display(show_values=False):
|
||||
"authentik_client_id",
|
||||
"authentik_client_secret",
|
||||
"authentik_config_url",
|
||||
"oauth_provider_name"
|
||||
"oauth_provider_name",
|
||||
],
|
||||
"Email": [
|
||||
"email_host",
|
||||
@@ -92,7 +101,7 @@ def get_settings_for_display(show_values=False):
|
||||
"email_password",
|
||||
"email_use_tls",
|
||||
"email_sender",
|
||||
"email_default_recipient"
|
||||
"email_default_recipient",
|
||||
],
|
||||
"IMAP": [
|
||||
"imap1_host",
|
||||
@@ -108,47 +117,28 @@ def get_settings_for_display(show_values=False):
|
||||
"imap2_password",
|
||||
"imap2_ssl",
|
||||
"imap2_poll_interval_minutes",
|
||||
"imap2_delete_after_process"
|
||||
],
|
||||
"Dropbox": [
|
||||
"dropbox_app_key",
|
||||
"dropbox_app_secret",
|
||||
"dropbox_folder",
|
||||
"dropbox_refresh_token"
|
||||
],
|
||||
"NextCloud": [
|
||||
"nextcloud_upload_url",
|
||||
"nextcloud_username",
|
||||
"nextcloud_password",
|
||||
"nextcloud_folder"
|
||||
],
|
||||
"Paperless": [
|
||||
"paperless_host",
|
||||
"paperless_ngx_api_token"
|
||||
"imap2_delete_after_process",
|
||||
],
|
||||
"Dropbox": ["dropbox_app_key", "dropbox_app_secret", "dropbox_folder", "dropbox_refresh_token"],
|
||||
"NextCloud": ["nextcloud_upload_url", "nextcloud_username", "nextcloud_password", "nextcloud_folder"],
|
||||
"Paperless": ["paperless_host", "paperless_ngx_api_token"],
|
||||
"Google Drive": [
|
||||
"google_drive_use_oauth",
|
||||
"google_drive_client_id",
|
||||
"google_drive_client_secret",
|
||||
"google_drive_client_secret",
|
||||
"google_drive_refresh_token",
|
||||
"google_drive_credentials_json",
|
||||
"google_drive_folder_id",
|
||||
"google_drive_delegate_to"
|
||||
"google_drive_delegate_to",
|
||||
],
|
||||
"OneDrive": [
|
||||
"onedrive_client_id",
|
||||
"onedrive_client_secret",
|
||||
"onedrive_tenant_id",
|
||||
"onedrive_refresh_token",
|
||||
"onedrive_folder_path"
|
||||
],
|
||||
"WebDAV": [
|
||||
"webdav_url",
|
||||
"webdav_username",
|
||||
"webdav_password",
|
||||
"webdav_folder",
|
||||
"webdav_verify_ssl"
|
||||
"onedrive_folder_path",
|
||||
],
|
||||
"WebDAV": ["webdav_url", "webdav_username", "webdav_password", "webdav_folder", "webdav_verify_ssl"],
|
||||
"SFTP": [
|
||||
"sftp_host",
|
||||
"sftp_port",
|
||||
@@ -156,7 +146,7 @@ def get_settings_for_display(show_values=False):
|
||||
"sftp_password",
|
||||
"sftp_folder",
|
||||
"sftp_private_key",
|
||||
"sftp_private_key_passphrase"
|
||||
"sftp_private_key_passphrase",
|
||||
],
|
||||
"FTP": [
|
||||
"ftp_host",
|
||||
@@ -165,7 +155,7 @@ def get_settings_for_display(show_values=False):
|
||||
"ftp_password",
|
||||
"ftp_folder",
|
||||
"ftp_use_tls",
|
||||
"ftp_allow_plaintext"
|
||||
"ftp_allow_plaintext",
|
||||
],
|
||||
"S3/AWS": [
|
||||
"aws_access_key_id",
|
||||
@@ -174,7 +164,7 @@ def get_settings_for_display(show_values=False):
|
||||
"s3_bucket_name",
|
||||
"s3_folder_prefix",
|
||||
"s3_storage_class",
|
||||
"s3_acl"
|
||||
"s3_acl",
|
||||
],
|
||||
"AI Services": [
|
||||
"openai_api_key",
|
||||
@@ -182,84 +172,84 @@ def get_settings_for_display(show_values=False):
|
||||
"openai_model",
|
||||
"azure_ai_key",
|
||||
"azure_endpoint",
|
||||
"azure_region"
|
||||
],
|
||||
"Monitoring": [
|
||||
"uptime_kuma_url",
|
||||
"uptime_kuma_ping_interval"
|
||||
"azure_region",
|
||||
],
|
||||
"Monitoring": ["uptime_kuma_url", "uptime_kuma_ping_interval"],
|
||||
"Notifications": [
|
||||
"notification_urls",
|
||||
"notify_on_task_failure",
|
||||
"notify_on_credential_failure",
|
||||
"notify_on_credential_failure",
|
||||
"notify_on_startup",
|
||||
"notify_on_shutdown"
|
||||
]
|
||||
"notify_on_shutdown",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# Handle any settings that don't fit into the predefined categories
|
||||
all_settings = set([key for key in dir(settings)
|
||||
if not key.startswith('_') and
|
||||
not callable(getattr(settings, key)) and
|
||||
key not in ["model_computed_fields", "model_config",
|
||||
"model_extra", "model_fields",
|
||||
"model_fields_set"]])
|
||||
|
||||
all_settings = set(
|
||||
[
|
||||
key
|
||||
for key in dir(settings)
|
||||
if not key.startswith("_")
|
||||
and not callable(getattr(settings, key))
|
||||
and key not in ["model_computed_fields", "model_config", "model_extra", "model_fields", "model_fields_set"]
|
||||
]
|
||||
)
|
||||
|
||||
# Ensure 'version' is excluded since we display it separately
|
||||
all_settings.discard("version")
|
||||
|
||||
|
||||
categorized_settings = set()
|
||||
for cat_settings in categories.values():
|
||||
categorized_settings.update(cat_settings)
|
||||
|
||||
|
||||
uncategorized = all_settings - categorized_settings
|
||||
if uncategorized:
|
||||
categories["Other"] = list(uncategorized)
|
||||
|
||||
|
||||
# Build the result
|
||||
for category, setting_keys in categories.items():
|
||||
items = []
|
||||
for key in setting_keys:
|
||||
if hasattr(settings, key):
|
||||
value = getattr(settings, key)
|
||||
|
||||
|
||||
# List of patterns that indicate sensitive values
|
||||
sensitive_patterns = [
|
||||
'password', 'secret', 'token', 'api_key', 'private_key',
|
||||
'credentials', 'access_key', 'ai_key'
|
||||
"password",
|
||||
"secret",
|
||||
"token",
|
||||
"api_key",
|
||||
"private_key",
|
||||
"credentials",
|
||||
"access_key",
|
||||
"ai_key",
|
||||
]
|
||||
|
||||
|
||||
# Check if this is a sensitive value that should be masked
|
||||
is_sensitive = any(
|
||||
pattern in key.lower() for pattern in sensitive_patterns
|
||||
)
|
||||
|
||||
is_sensitive = any(pattern in key.lower() for pattern in sensitive_patterns)
|
||||
|
||||
# Special handling for "auth" to avoid matching prefixes like "authentik"
|
||||
if not is_sensitive and "auth" in key.lower():
|
||||
# Only mark as sensitive if "auth" is a standalone word or at the end
|
||||
# This avoids matching "authentik" as sensitive
|
||||
parts = key.lower().split('_')
|
||||
parts = key.lower().split("_")
|
||||
is_sensitive = any(part == "auth" for part in parts) or key.lower().endswith("auth")
|
||||
|
||||
|
||||
# Mask sensitive values regardless of debug mode
|
||||
# Other values are only hidden if debug mode is off AND show_values is False
|
||||
if (is_sensitive or not show_values) and value:
|
||||
if is_sensitive:
|
||||
value = mask_sensitive_value(value)
|
||||
|
||||
|
||||
# Check if the setting is configured (has a non-None value)
|
||||
# For boolean settings, consider them configured even if False
|
||||
is_configured = value is not None
|
||||
if is_configured and isinstance(value, str):
|
||||
is_configured = len(value) > 0
|
||||
|
||||
items.append({
|
||||
"name": key,
|
||||
"value": value,
|
||||
"is_configured": is_configured
|
||||
})
|
||||
|
||||
|
||||
items.append({"name": key, "value": value, "is_configured": is_configured})
|
||||
|
||||
if items: # Only add categories that have items
|
||||
result[category] = items
|
||||
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user