Add Google Drive authorization processing and error handling templates
- Implemented `google_drive_callback.html` for processing Google Drive authorization, including UI for success and error states. - Added JavaScript functionality for exchanging authorization codes, saving settings, and handling folder selection. - Created `google_drive_callback_error.html` to display error messages during the authorization process.
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
"""
|
||||
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)):
|
||||
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 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:]}"
|
||||
else:
|
||||
value = f"{value[:2]}{'*' * (len(value) - 4)}{value[-2:]}" if isinstance(value, str) and len(value) > 4 else "****"
|
||||
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.
|
||||
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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Define categories and their settings
|
||||
categories = {
|
||||
"Core": [
|
||||
"debug", # Explicitly include debug setting
|
||||
"external_hostname",
|
||||
"workdir",
|
||||
"database_url",
|
||||
"redis_url",
|
||||
"gotenberg_url",
|
||||
"allow_file_delete" # Added allow_file_delete to Core settings
|
||||
],
|
||||
"Authentication": [
|
||||
"auth_enabled",
|
||||
"authentik_client_id",
|
||||
"authentik_client_secret",
|
||||
"authentik_config_url"
|
||||
],
|
||||
"Email": [
|
||||
"email_host",
|
||||
"email_port",
|
||||
"email_username",
|
||||
"email_password",
|
||||
"email_use_tls",
|
||||
"email_sender",
|
||||
"email_default_recipient"
|
||||
],
|
||||
"IMAP": [
|
||||
"imap1_host",
|
||||
"imap1_port",
|
||||
"imap1_username",
|
||||
"imap1_password",
|
||||
"imap1_ssl",
|
||||
"imap1_poll_interval_minutes",
|
||||
"imap1_delete_after_process",
|
||||
"imap2_host",
|
||||
"imap2_port",
|
||||
"imap2_username",
|
||||
"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"
|
||||
],
|
||||
"Google Drive": [
|
||||
"google_drive_use_oauth",
|
||||
"google_drive_client_id",
|
||||
"google_drive_client_secret",
|
||||
"google_drive_refresh_token",
|
||||
"google_drive_credentials_json",
|
||||
"google_drive_folder_id",
|
||||
"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"
|
||||
],
|
||||
"SFTP": [
|
||||
"sftp_host",
|
||||
"sftp_port",
|
||||
"sftp_username",
|
||||
"sftp_password",
|
||||
"sftp_folder",
|
||||
"sftp_private_key",
|
||||
"sftp_private_key_passphrase"
|
||||
],
|
||||
"FTP": [
|
||||
"ftp_host",
|
||||
"ftp_port",
|
||||
"ftp_username",
|
||||
"ftp_password",
|
||||
"ftp_folder",
|
||||
"ftp_use_tls",
|
||||
"ftp_allow_plaintext"
|
||||
],
|
||||
"S3/AWS": [
|
||||
"aws_access_key_id",
|
||||
"aws_secret_access_key",
|
||||
"aws_region",
|
||||
"s3_bucket_name",
|
||||
"s3_folder_prefix",
|
||||
"s3_storage_class",
|
||||
"s3_acl"
|
||||
],
|
||||
"AI Services": [
|
||||
"openai_api_key",
|
||||
"openai_base_url",
|
||||
"openai_model",
|
||||
"azure_ai_key",
|
||||
"azure_endpoint",
|
||||
"azure_region"
|
||||
],
|
||||
"Monitoring": [
|
||||
"uptime_kuma_url",
|
||||
"uptime_kuma_ping_interval"
|
||||
]
|
||||
}
|
||||
|
||||
# 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"]])
|
||||
|
||||
# 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'
|
||||
]
|
||||
|
||||
# Check if this is a sensitive value that should be masked
|
||||
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('_')
|
||||
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
|
||||
})
|
||||
|
||||
if items: # Only add categories that have items
|
||||
result[category] = items
|
||||
|
||||
return result
|
||||
Reference in New Issue
Block a user