feat(storage): add explicit enable/disable flag for each global storage destination
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -49,18 +49,30 @@ class Settings(BaseSettings):
|
|||||||
debug: bool = False # Default to False
|
debug: bool = False # Default to False
|
||||||
|
|
||||||
# Making Dropbox optional
|
# Making Dropbox optional
|
||||||
|
dropbox_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable Dropbox as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
dropbox_app_key: Optional[str] = None
|
dropbox_app_key: Optional[str] = None
|
||||||
dropbox_app_secret: Optional[str] = None
|
dropbox_app_secret: Optional[str] = None
|
||||||
dropbox_folder: Optional[str] = None
|
dropbox_folder: Optional[str] = None
|
||||||
dropbox_refresh_token: Optional[str] = None
|
dropbox_refresh_token: Optional[str] = None
|
||||||
|
|
||||||
# Making Nextcloud optional
|
# Making Nextcloud optional
|
||||||
|
nextcloud_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable Nextcloud as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
nextcloud_upload_url: Optional[str] = None
|
nextcloud_upload_url: Optional[str] = None
|
||||||
nextcloud_username: Optional[str] = None
|
nextcloud_username: Optional[str] = None
|
||||||
nextcloud_password: Optional[str] = None
|
nextcloud_password: Optional[str] = None
|
||||||
nextcloud_folder: Optional[str] = None
|
nextcloud_folder: Optional[str] = None
|
||||||
|
|
||||||
# Making Paperless optional
|
# Making Paperless optional
|
||||||
|
paperless_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable Paperless-ngx as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
paperless_ngx_api_token: Optional[str] = None
|
paperless_ngx_api_token: Optional[str] = None
|
||||||
paperless_host: Optional[str] = None
|
paperless_host: Optional[str] = None
|
||||||
paperless_custom_field_absender: Optional[str] = None # Name of the "absender" custom field in Paperless
|
paperless_custom_field_absender: Optional[str] = None # Name of the "absender" custom field in Paperless
|
||||||
@@ -394,6 +406,10 @@ class Settings(BaseSettings):
|
|||||||
imap2_delete_after_process: bool = False
|
imap2_delete_after_process: bool = False
|
||||||
|
|
||||||
# Google Drive settings
|
# Google Drive settings
|
||||||
|
google_drive_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable Google Drive as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
google_drive_credentials_json: Optional[str] = ""
|
google_drive_credentials_json: Optional[str] = ""
|
||||||
google_drive_folder_id: Optional[str] = ""
|
google_drive_folder_id: Optional[str] = ""
|
||||||
google_drive_delegate_to: Optional[str] = "" # Optional delegated user email
|
google_drive_delegate_to: Optional[str] = "" # Optional delegated user email
|
||||||
@@ -405,6 +421,10 @@ class Settings(BaseSettings):
|
|||||||
google_drive_refresh_token: Optional[str] = ""
|
google_drive_refresh_token: Optional[str] = ""
|
||||||
|
|
||||||
# WebDAV settings
|
# WebDAV settings
|
||||||
|
webdav_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable WebDAV as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
webdav_url: Optional[str] = None
|
webdav_url: Optional[str] = None
|
||||||
webdav_username: Optional[str] = None
|
webdav_username: Optional[str] = None
|
||||||
webdav_password: Optional[str] = None
|
webdav_password: Optional[str] = None
|
||||||
@@ -412,6 +432,10 @@ class Settings(BaseSettings):
|
|||||||
webdav_verify_ssl: bool = True
|
webdav_verify_ssl: bool = True
|
||||||
|
|
||||||
# FTP settings
|
# FTP settings
|
||||||
|
ftp_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable FTP as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
ftp_host: Optional[str] = None
|
ftp_host: Optional[str] = None
|
||||||
ftp_port: Optional[int] = 21
|
ftp_port: Optional[int] = 21
|
||||||
ftp_username: Optional[str] = None
|
ftp_username: Optional[str] = None
|
||||||
@@ -421,6 +445,10 @@ class Settings(BaseSettings):
|
|||||||
ftp_allow_plaintext: bool = True # Default to allowing plaintext fallback
|
ftp_allow_plaintext: bool = True # Default to allowing plaintext fallback
|
||||||
|
|
||||||
# SFTP settings
|
# SFTP settings
|
||||||
|
sftp_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable SFTP as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
sftp_host: Optional[str] = None
|
sftp_host: Optional[str] = None
|
||||||
sftp_port: Optional[int] = 22
|
sftp_port: Optional[int] = 22
|
||||||
sftp_username: Optional[str] = None
|
sftp_username: Optional[str] = None
|
||||||
@@ -442,6 +470,10 @@ class Settings(BaseSettings):
|
|||||||
email_default_recipient: Optional[str] = None
|
email_default_recipient: Optional[str] = None
|
||||||
|
|
||||||
# Email destination settings (dedicated SMTP for document delivery – decoupled from shared email above)
|
# Email destination settings (dedicated SMTP for document delivery – decoupled from shared email above)
|
||||||
|
dest_email_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable Email as an upload destination. Set to False to disable document delivery via email even when credentials are configured.",
|
||||||
|
)
|
||||||
dest_email_host: Optional[str] = None
|
dest_email_host: Optional[str] = None
|
||||||
dest_email_port: Optional[int] = 587
|
dest_email_port: Optional[int] = 587
|
||||||
dest_email_username: Optional[str] = None
|
dest_email_username: Optional[str] = None
|
||||||
@@ -451,6 +483,10 @@ class Settings(BaseSettings):
|
|||||||
dest_email_default_recipient: Optional[str] = None # Fallback recipient for document delivery
|
dest_email_default_recipient: Optional[str] = None # Fallback recipient for document delivery
|
||||||
|
|
||||||
# OneDrive settings
|
# OneDrive settings
|
||||||
|
onedrive_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable OneDrive as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
onedrive_client_id: Optional[str] = None
|
onedrive_client_id: Optional[str] = None
|
||||||
onedrive_client_secret: Optional[str] = None
|
onedrive_client_secret: Optional[str] = None
|
||||||
onedrive_tenant_id: Optional[str] = "common" # Default to "common" for personal accounts
|
onedrive_tenant_id: Optional[str] = "common" # Default to "common" for personal accounts
|
||||||
@@ -458,6 +494,10 @@ class Settings(BaseSettings):
|
|||||||
onedrive_folder_path: Optional[str] = None
|
onedrive_folder_path: Optional[str] = None
|
||||||
|
|
||||||
# AWS S3 settings
|
# AWS S3 settings
|
||||||
|
s3_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable Amazon S3 as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
aws_access_key_id: Optional[str] = None
|
aws_access_key_id: Optional[str] = None
|
||||||
aws_secret_access_key: Optional[str] = None
|
aws_secret_access_key: Optional[str] = None
|
||||||
aws_region: Optional[str] = "us-east-1" # Default region
|
aws_region: Optional[str] = "us-east-1" # Default region
|
||||||
@@ -467,6 +507,10 @@ class Settings(BaseSettings):
|
|||||||
s3_acl: Optional[str] = "private" # Default ACL
|
s3_acl: Optional[str] = "private" # Default ACL
|
||||||
|
|
||||||
# iCloud Drive settings
|
# iCloud Drive settings
|
||||||
|
icloud_enabled: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description="Enable iCloud Drive as an upload destination. Set to False to disable uploads even when credentials are configured.",
|
||||||
|
)
|
||||||
icloud_username: Optional[str] = None # Apple ID email address
|
icloud_username: Optional[str] = None # Apple ID email address
|
||||||
icloud_password: Optional[str] = None # App-specific password (required for 2FA accounts)
|
icloud_password: Optional[str] = None # App-specific password (required for 2FA accounts)
|
||||||
icloud_folder: Optional[str] = None # Target folder path in iCloud Drive (e.g. "Documents/Uploads")
|
icloud_folder: Optional[str] = None # Target folder path in iCloud Drive (e.g. "Documents/Uploads")
|
||||||
|
|||||||
+51
-13
@@ -26,18 +26,32 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def _should_upload_to_dropbox():
|
def _should_upload_to_dropbox():
|
||||||
return bool(settings.dropbox_app_key and settings.dropbox_app_secret and settings.dropbox_refresh_token)
|
return bool(
|
||||||
|
getattr(settings, "dropbox_enabled", True)
|
||||||
|
and settings.dropbox_app_key
|
||||||
|
and settings.dropbox_app_secret
|
||||||
|
and settings.dropbox_refresh_token
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_upload_to_nextcloud():
|
def _should_upload_to_nextcloud():
|
||||||
return bool(settings.nextcloud_upload_url and settings.nextcloud_username and settings.nextcloud_password)
|
return bool(
|
||||||
|
getattr(settings, "nextcloud_enabled", True)
|
||||||
|
and settings.nextcloud_upload_url
|
||||||
|
and settings.nextcloud_username
|
||||||
|
and settings.nextcloud_password
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_upload_to_paperless():
|
def _should_upload_to_paperless():
|
||||||
return bool(settings.paperless_ngx_api_token and settings.paperless_host)
|
return bool(
|
||||||
|
getattr(settings, "paperless_enabled", True) and settings.paperless_ngx_api_token and settings.paperless_host
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_upload_to_google_drive():
|
def _should_upload_to_google_drive():
|
||||||
|
if not getattr(settings, "google_drive_enabled", True):
|
||||||
|
return False
|
||||||
# Check for OAuth configuration
|
# Check for OAuth configuration
|
||||||
if getattr(settings, "google_drive_use_oauth", False):
|
if getattr(settings, "google_drive_use_oauth", False):
|
||||||
return bool(
|
return bool(
|
||||||
@@ -52,20 +66,33 @@ def _should_upload_to_google_drive():
|
|||||||
|
|
||||||
|
|
||||||
def _should_upload_to_webdav():
|
def _should_upload_to_webdav():
|
||||||
return bool(settings.webdav_url and settings.webdav_username and settings.webdav_password)
|
return bool(
|
||||||
|
getattr(settings, "webdav_enabled", True)
|
||||||
|
and settings.webdav_url
|
||||||
|
and settings.webdav_username
|
||||||
|
and settings.webdav_password
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_upload_to_ftp():
|
def _should_upload_to_ftp():
|
||||||
return bool(settings.ftp_host and settings.ftp_username and settings.ftp_password)
|
return bool(
|
||||||
|
getattr(settings, "ftp_enabled", True) and settings.ftp_host and settings.ftp_username and settings.ftp_password
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_upload_to_sftp():
|
def _should_upload_to_sftp():
|
||||||
return bool(settings.sftp_host and settings.sftp_username and (settings.sftp_password or settings.sftp_private_key))
|
return bool(
|
||||||
|
getattr(settings, "sftp_enabled", True)
|
||||||
|
and settings.sftp_host
|
||||||
|
and settings.sftp_username
|
||||||
|
and (settings.sftp_password or settings.sftp_private_key)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_upload_to_email():
|
def _should_upload_to_email():
|
||||||
return bool(
|
return bool(
|
||||||
settings.dest_email_host
|
getattr(settings, "dest_email_enabled", True)
|
||||||
|
and settings.dest_email_host
|
||||||
and settings.dest_email_username
|
and settings.dest_email_username
|
||||||
and settings.dest_email_password
|
and settings.dest_email_password
|
||||||
and settings.dest_email_default_recipient
|
and settings.dest_email_default_recipient
|
||||||
@@ -73,22 +100,32 @@ def _should_upload_to_email():
|
|||||||
|
|
||||||
|
|
||||||
def _should_upload_to_onedrive():
|
def _should_upload_to_onedrive():
|
||||||
return bool(settings.onedrive_client_id and settings.onedrive_client_secret and settings.onedrive_refresh_token)
|
return bool(
|
||||||
|
getattr(settings, "onedrive_enabled", True)
|
||||||
|
and settings.onedrive_client_id
|
||||||
|
and settings.onedrive_client_secret
|
||||||
|
and settings.onedrive_refresh_token
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_upload_to_s3():
|
def _should_upload_to_s3():
|
||||||
return bool(settings.s3_bucket_name and settings.aws_access_key_id and settings.aws_secret_access_key)
|
return bool(
|
||||||
|
getattr(settings, "s3_enabled", True)
|
||||||
|
and settings.s3_bucket_name
|
||||||
|
and settings.aws_access_key_id
|
||||||
|
and settings.aws_secret_access_key
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_upload_to_icloud():
|
def _should_upload_to_icloud():
|
||||||
return bool(settings.icloud_username and settings.icloud_password)
|
return bool(getattr(settings, "icloud_enabled", True) and settings.icloud_username and settings.icloud_password)
|
||||||
|
|
||||||
|
|
||||||
def get_configured_services_from_validator():
|
def get_configured_services_from_validator():
|
||||||
"""
|
"""
|
||||||
Use the config validator to determine which services are configured properly.
|
Use the config validator to determine which services are configured and enabled.
|
||||||
Returns a dictionary with service names as keys and boolean values indicating
|
Returns a dictionary with service names as keys and boolean values indicating
|
||||||
whether they're properly configured.
|
whether they're properly configured AND explicitly enabled.
|
||||||
"""
|
"""
|
||||||
providers = get_provider_status()
|
providers = get_provider_status()
|
||||||
|
|
||||||
@@ -109,7 +146,8 @@ def get_configured_services_from_validator():
|
|||||||
result = {}
|
result = {}
|
||||||
for provider_name, internal_name in service_map.items():
|
for provider_name, internal_name in service_map.items():
|
||||||
if provider_name in providers:
|
if provider_name in providers:
|
||||||
result[internal_name] = providers[provider_name].get("configured", False)
|
provider = providers[provider_name]
|
||||||
|
result[internal_name] = provider.get("configured", False) and provider.get("enabled", True)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
and getattr(settings, "dropbox_app_secret", None)
|
and getattr(settings, "dropbox_app_secret", None)
|
||||||
and getattr(settings, "dropbox_refresh_token", None)
|
and getattr(settings, "dropbox_refresh_token", None)
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "dropbox_enabled", True),
|
||||||
"description": "Upload files to Dropbox cloud storage",
|
"description": "Upload files to Dropbox cloud storage",
|
||||||
"details": {
|
"details": {
|
||||||
"folder": getattr(settings, "dropbox_folder", "Not set"),
|
"folder": getattr(settings, "dropbox_folder", "Not set"),
|
||||||
@@ -161,7 +161,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
"configured": bool(
|
"configured": bool(
|
||||||
getattr(settings, "dest_email_host", None) and getattr(settings, "dest_email_default_recipient", None)
|
getattr(settings, "dest_email_host", None) and getattr(settings, "dest_email_default_recipient", None)
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "dest_email_enabled", True),
|
||||||
"description": "Send documents via email",
|
"description": "Send documents via email",
|
||||||
"details": {
|
"details": {
|
||||||
"host": getattr(settings, "dest_email_host", "Not set"),
|
"host": getattr(settings, "dest_email_host", "Not set"),
|
||||||
@@ -183,7 +183,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
and getattr(settings, "ftp_username", None)
|
and getattr(settings, "ftp_username", None)
|
||||||
and getattr(settings, "ftp_password", None)
|
and getattr(settings, "ftp_password", None)
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "ftp_enabled", True),
|
||||||
"description": "Upload files to FTP server",
|
"description": "Upload files to FTP server",
|
||||||
"details": {
|
"details": {
|
||||||
"host": getattr(settings, "ftp_host", "Not set"),
|
"host": getattr(settings, "ftp_host", "Not set"),
|
||||||
@@ -214,7 +214,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
"name": "Google Drive",
|
"name": "Google Drive",
|
||||||
"icon": "fa-brands fa-google-drive",
|
"icon": "fa-brands fa-google-drive",
|
||||||
"configured": is_configured and bool(getattr(settings, "google_drive_folder_id", None)),
|
"configured": is_configured and bool(getattr(settings, "google_drive_folder_id", None)),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "google_drive_enabled", True),
|
||||||
"description": "Store documents in Google Drive",
|
"description": "Store documents in Google Drive",
|
||||||
"details": {
|
"details": {
|
||||||
"auth_type": "OAuth" if use_oauth else "Service Account",
|
"auth_type": "OAuth" if use_oauth else "Service Account",
|
||||||
@@ -250,7 +250,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
and getattr(settings, "nextcloud_username", None)
|
and getattr(settings, "nextcloud_username", None)
|
||||||
and getattr(settings, "nextcloud_password", None)
|
and getattr(settings, "nextcloud_password", None)
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "nextcloud_enabled", True),
|
||||||
"description": "Store documents in NextCloud",
|
"description": "Store documents in NextCloud",
|
||||||
"details": {
|
"details": {
|
||||||
"url": getattr(settings, "nextcloud_upload_url", "Not set"),
|
"url": getattr(settings, "nextcloud_upload_url", "Not set"),
|
||||||
@@ -270,7 +270,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
and getattr(settings, "onedrive_client_secret", None)
|
and getattr(settings, "onedrive_client_secret", None)
|
||||||
and getattr(settings, "onedrive_refresh_token", None)
|
and getattr(settings, "onedrive_refresh_token", None)
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "onedrive_enabled", True),
|
||||||
"description": "Store documents in Microsoft OneDrive",
|
"description": "Store documents in Microsoft OneDrive",
|
||||||
"details": {
|
"details": {
|
||||||
"client_id": getattr(settings, "onedrive_client_id", "Not set"),
|
"client_id": getattr(settings, "onedrive_client_id", "Not set"),
|
||||||
@@ -288,7 +288,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
"configured": bool(
|
"configured": bool(
|
||||||
getattr(settings, "paperless_host", None) and getattr(settings, "paperless_ngx_api_token", None)
|
getattr(settings, "paperless_host", None) and getattr(settings, "paperless_ngx_api_token", None)
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "paperless_enabled", True),
|
||||||
"description": "Document management system for digital archives",
|
"description": "Document management system for digital archives",
|
||||||
"details": {
|
"details": {
|
||||||
"host": getattr(settings, "paperless_host", "Not set"),
|
"host": getattr(settings, "paperless_host", "Not set"),
|
||||||
@@ -305,7 +305,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
and getattr(settings, "aws_access_key_id", None)
|
and getattr(settings, "aws_access_key_id", None)
|
||||||
and getattr(settings, "aws_secret_access_key", None)
|
and getattr(settings, "aws_secret_access_key", None)
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "s3_enabled", True),
|
||||||
"description": "Store documents in S3-compatible object storage",
|
"description": "Store documents in S3-compatible object storage",
|
||||||
"details": {
|
"details": {
|
||||||
"bucket": getattr(settings, "s3_bucket_name", "Not set"),
|
"bucket": getattr(settings, "s3_bucket_name", "Not set"),
|
||||||
@@ -327,7 +327,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
and getattr(settings, "sftp_username", None)
|
and getattr(settings, "sftp_username", None)
|
||||||
and (getattr(settings, "sftp_password", None) or getattr(settings, "sftp_private_key", None))
|
and (getattr(settings, "sftp_password", None) or getattr(settings, "sftp_private_key", None))
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "sftp_enabled", True),
|
||||||
"description": "Upload files to SFTP server",
|
"description": "Upload files to SFTP server",
|
||||||
"details": {
|
"details": {
|
||||||
"host": getattr(settings, "sftp_host", "Not set"),
|
"host": getattr(settings, "sftp_host", "Not set"),
|
||||||
@@ -362,7 +362,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
and getattr(settings, "webdav_username", None)
|
and getattr(settings, "webdav_username", None)
|
||||||
and getattr(settings, "webdav_password", None)
|
and getattr(settings, "webdav_password", None)
|
||||||
),
|
),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "webdav_enabled", True),
|
||||||
"description": "Store documents on WebDAV servers",
|
"description": "Store documents on WebDAV servers",
|
||||||
"details": {
|
"details": {
|
||||||
"url": getattr(settings, "webdav_url", "Not set"),
|
"url": getattr(settings, "webdav_url", "Not set"),
|
||||||
@@ -378,7 +378,7 @@ def get_provider_status() -> dict[str, dict[str, object]]:
|
|||||||
"name": "iCloud Drive",
|
"name": "iCloud Drive",
|
||||||
"icon": "fa-brands fa-apple",
|
"icon": "fa-brands fa-apple",
|
||||||
"configured": bool(getattr(settings, "icloud_username", None) and getattr(settings, "icloud_password", None)),
|
"configured": bool(getattr(settings, "icloud_username", None) and getattr(settings, "icloud_password", None)),
|
||||||
"enabled": True,
|
"enabled": getattr(settings, "icloud_enabled", True),
|
||||||
"description": "Store documents in Apple iCloud Drive",
|
"description": "Store documents in Apple iCloud Drive",
|
||||||
"details": {
|
"details": {
|
||||||
"username": getattr(settings, "icloud_username", "Not set"),
|
"username": getattr(settings, "icloud_username", "Not set"),
|
||||||
|
|||||||
@@ -495,6 +495,14 @@ SETTING_METADATA = {
|
|||||||
"options": ["us", "eu"],
|
"options": ["us", "eu"],
|
||||||
},
|
},
|
||||||
# Storage Providers - Dropbox
|
# Storage Providers - Dropbox
|
||||||
|
"dropbox_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable Dropbox as an upload destination. When disabled, no documents will be sent to Dropbox even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"dropbox_app_key": {
|
"dropbox_app_key": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "Dropbox app key for OAuth authentication",
|
"description": "Dropbox app key for OAuth authentication",
|
||||||
@@ -528,6 +536,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - Nextcloud
|
# Storage Providers - Nextcloud
|
||||||
|
"nextcloud_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable Nextcloud as an upload destination. When disabled, no documents will be sent to Nextcloud even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"nextcloud_upload_url": {
|
"nextcloud_upload_url": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "Nextcloud WebDAV upload URL",
|
"description": "Nextcloud WebDAV upload URL",
|
||||||
@@ -561,6 +577,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - Paperless-ngx
|
# Storage Providers - Paperless-ngx
|
||||||
|
"paperless_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable Paperless-ngx as an upload destination. When disabled, no documents will be sent to Paperless-ngx even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"paperless_ngx_api_token": {
|
"paperless_ngx_api_token": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "Paperless-ngx API authentication token",
|
"description": "Paperless-ngx API authentication token",
|
||||||
@@ -578,6 +602,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - Google Drive
|
# Storage Providers - Google Drive
|
||||||
|
"google_drive_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable Google Drive as an upload destination. When disabled, no documents will be sent to Google Drive even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"google_drive_credentials_json": {
|
"google_drive_credentials_json": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "Google Drive service account credentials JSON",
|
"description": "Google Drive service account credentials JSON",
|
||||||
@@ -635,6 +667,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - OneDrive
|
# Storage Providers - OneDrive
|
||||||
|
"onedrive_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable OneDrive as an upload destination. When disabled, no documents will be sent to OneDrive even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"onedrive_client_id": {
|
"onedrive_client_id": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "OneDrive OAuth client ID",
|
"description": "OneDrive OAuth client ID",
|
||||||
@@ -676,6 +716,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - WebDAV
|
# Storage Providers - WebDAV
|
||||||
|
"webdav_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable WebDAV as an upload destination. When disabled, no documents will be sent to WebDAV even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"webdav_url": {
|
"webdav_url": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "WebDAV server URL",
|
"description": "WebDAV server URL",
|
||||||
@@ -717,6 +765,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - FTP
|
# Storage Providers - FTP
|
||||||
|
"ftp_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable FTP as an upload destination. When disabled, no documents will be sent to FTP even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"ftp_host": {
|
"ftp_host": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "FTP server hostname or IP address",
|
"description": "FTP server hostname or IP address",
|
||||||
@@ -774,6 +830,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - SFTP
|
# Storage Providers - SFTP
|
||||||
|
"sftp_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable SFTP as an upload destination. When disabled, no documents will be sent to SFTP even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"sftp_host": {
|
"sftp_host": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "SFTP server hostname or IP address",
|
"description": "SFTP server hostname or IP address",
|
||||||
@@ -839,6 +903,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - iCloud Drive
|
# Storage Providers - iCloud Drive
|
||||||
|
"icloud_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable iCloud Drive as an upload destination. When disabled, no documents will be sent to iCloud Drive even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"icloud_username": {
|
"icloud_username": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "Apple ID email address for iCloud Drive authentication",
|
"description": "Apple ID email address for iCloud Drive authentication",
|
||||||
@@ -872,6 +944,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Storage Providers - AWS S3
|
# Storage Providers - AWS S3
|
||||||
|
"s3_enabled": {
|
||||||
|
"category": "Storage Providers",
|
||||||
|
"description": "Enable Amazon S3 as an upload destination. When disabled, no documents will be sent to S3 even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"aws_access_key_id": {
|
"aws_access_key_id": {
|
||||||
"category": "Storage Providers",
|
"category": "Storage Providers",
|
||||||
"description": "AWS access key ID for S3",
|
"description": "AWS access key ID for S3",
|
||||||
@@ -1005,6 +1085,14 @@ SETTING_METADATA = {
|
|||||||
"restart_required": False,
|
"restart_required": False,
|
||||||
},
|
},
|
||||||
# Email Destination Settings (dedicated SMTP for document delivery)
|
# Email Destination Settings (dedicated SMTP for document delivery)
|
||||||
|
"dest_email_enabled": {
|
||||||
|
"category": "Email Destination",
|
||||||
|
"description": "Enable Email as an upload destination. When disabled, no documents will be delivered via email even if credentials are configured.",
|
||||||
|
"type": "boolean",
|
||||||
|
"sensitive": False,
|
||||||
|
"required": False,
|
||||||
|
"restart_required": False,
|
||||||
|
},
|
||||||
"dest_email_host": {
|
"dest_email_host": {
|
||||||
"category": "Email Destination",
|
"category": "Email Destination",
|
||||||
"description": "SMTP server hostname for document delivery (separate from shared email settings)",
|
"description": "SMTP server hostname for document delivery (separate from shared email settings)",
|
||||||
|
|||||||
+143
-4
@@ -163,6 +163,121 @@ class TestShouldUploadFunctions:
|
|||||||
assert _should_upload_to_icloud() is False
|
assert _should_upload_to_icloud() is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
class TestShouldUploadEnabledFlag:
|
||||||
|
"""Test that the _should_upload_to_* functions respect the explicit enabled flag."""
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_dropbox_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test Dropbox upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.dropbox_enabled = False
|
||||||
|
mock_settings.dropbox_app_key = "key"
|
||||||
|
mock_settings.dropbox_app_secret = "secret"
|
||||||
|
mock_settings.dropbox_refresh_token = "token"
|
||||||
|
|
||||||
|
assert _should_upload_to_dropbox() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_nextcloud_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test Nextcloud upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.nextcloud_enabled = False
|
||||||
|
mock_settings.nextcloud_upload_url = "https://nextcloud.example.com"
|
||||||
|
mock_settings.nextcloud_username = "user"
|
||||||
|
mock_settings.nextcloud_password = "pass"
|
||||||
|
|
||||||
|
assert _should_upload_to_nextcloud() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_paperless_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test Paperless upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.paperless_enabled = False
|
||||||
|
mock_settings.paperless_ngx_api_token = "token"
|
||||||
|
mock_settings.paperless_host = "https://paperless.example.com"
|
||||||
|
|
||||||
|
assert _should_upload_to_paperless() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_google_drive_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test Google Drive upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.google_drive_enabled = False
|
||||||
|
mock_settings.google_drive_use_oauth = False
|
||||||
|
mock_settings.google_drive_credentials_json = '{"type": "service_account"}'
|
||||||
|
mock_settings.google_drive_folder_id = "folder_id"
|
||||||
|
|
||||||
|
assert _should_upload_to_google_drive() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_webdav_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test WebDAV upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.webdav_enabled = False
|
||||||
|
mock_settings.webdav_url = "https://webdav.example.com"
|
||||||
|
mock_settings.webdav_username = "user"
|
||||||
|
mock_settings.webdav_password = "pass"
|
||||||
|
|
||||||
|
assert _should_upload_to_webdav() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_ftp_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test FTP upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.ftp_enabled = False
|
||||||
|
mock_settings.ftp_host = "ftp.example.com"
|
||||||
|
mock_settings.ftp_username = "user"
|
||||||
|
mock_settings.ftp_password = "pass"
|
||||||
|
|
||||||
|
assert _should_upload_to_ftp() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_sftp_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test SFTP upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.sftp_enabled = False
|
||||||
|
mock_settings.sftp_host = "sftp.example.com"
|
||||||
|
mock_settings.sftp_username = "user"
|
||||||
|
mock_settings.sftp_password = "pass"
|
||||||
|
mock_settings.sftp_private_key = None
|
||||||
|
|
||||||
|
assert _should_upload_to_sftp() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_email_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test email upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.dest_email_enabled = False
|
||||||
|
mock_settings.dest_email_host = "smtp.example.com"
|
||||||
|
mock_settings.dest_email_username = "user"
|
||||||
|
mock_settings.dest_email_password = "pass"
|
||||||
|
mock_settings.dest_email_default_recipient = "recipient@example.com"
|
||||||
|
|
||||||
|
assert _should_upload_to_email() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_onedrive_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test OneDrive upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.onedrive_enabled = False
|
||||||
|
mock_settings.onedrive_client_id = "client_id"
|
||||||
|
mock_settings.onedrive_client_secret = "client_secret"
|
||||||
|
mock_settings.onedrive_refresh_token = "refresh_token"
|
||||||
|
|
||||||
|
assert _should_upload_to_onedrive() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_s3_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test S3 upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.s3_enabled = False
|
||||||
|
mock_settings.s3_bucket_name = "my-bucket"
|
||||||
|
mock_settings.aws_access_key_id = "key_id"
|
||||||
|
mock_settings.aws_secret_access_key = "secret_key"
|
||||||
|
|
||||||
|
assert _should_upload_to_s3() is False
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.settings")
|
||||||
|
def test_icloud_disabled_with_credentials(self, mock_settings):
|
||||||
|
"""Test iCloud upload is blocked when disabled even with valid credentials."""
|
||||||
|
mock_settings.icloud_enabled = False
|
||||||
|
mock_settings.icloud_username = "user@example.com"
|
||||||
|
mock_settings.icloud_password = "app-specific-password"
|
||||||
|
|
||||||
|
assert _should_upload_to_icloud() is False
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
class TestGetConfiguredServicesFromValidator:
|
class TestGetConfiguredServicesFromValidator:
|
||||||
"""Test get_configured_services_from_validator function."""
|
"""Test get_configured_services_from_validator function."""
|
||||||
@@ -171,9 +286,9 @@ class TestGetConfiguredServicesFromValidator:
|
|||||||
def test_returns_configured_services(self, mock_get_status):
|
def test_returns_configured_services(self, mock_get_status):
|
||||||
"""Test that configured services are returned correctly."""
|
"""Test that configured services are returned correctly."""
|
||||||
mock_get_status.return_value = {
|
mock_get_status.return_value = {
|
||||||
"Dropbox": {"configured": True},
|
"Dropbox": {"configured": True, "enabled": True},
|
||||||
"NextCloud": {"configured": False},
|
"NextCloud": {"configured": False, "enabled": True},
|
||||||
"S3 Storage": {"configured": True},
|
"S3 Storage": {"configured": True, "enabled": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
result = get_configured_services_from_validator()
|
result = get_configured_services_from_validator()
|
||||||
@@ -186,7 +301,7 @@ class TestGetConfiguredServicesFromValidator:
|
|||||||
def test_handles_missing_providers(self, mock_get_status):
|
def test_handles_missing_providers(self, mock_get_status):
|
||||||
"""Test handling when some providers are not in status."""
|
"""Test handling when some providers are not in status."""
|
||||||
mock_get_status.return_value = {
|
mock_get_status.return_value = {
|
||||||
"Dropbox": {"configured": True},
|
"Dropbox": {"configured": True, "enabled": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
result = get_configured_services_from_validator()
|
result = get_configured_services_from_validator()
|
||||||
@@ -194,6 +309,30 @@ class TestGetConfiguredServicesFromValidator:
|
|||||||
assert result["dropbox"] is True
|
assert result["dropbox"] is True
|
||||||
# Other services not in result
|
# Other services not in result
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.get_provider_status")
|
||||||
|
def test_configured_but_disabled_service_not_active(self, mock_get_status):
|
||||||
|
"""Test that a configured but disabled service is not returned as active."""
|
||||||
|
mock_get_status.return_value = {
|
||||||
|
"Dropbox": {"configured": True, "enabled": False},
|
||||||
|
"S3 Storage": {"configured": True, "enabled": True},
|
||||||
|
}
|
||||||
|
|
||||||
|
result = get_configured_services_from_validator()
|
||||||
|
|
||||||
|
assert result["dropbox"] is False
|
||||||
|
assert result["s3"] is True
|
||||||
|
|
||||||
|
@patch("app.tasks.send_to_all.get_provider_status")
|
||||||
|
def test_missing_enabled_field_defaults_to_true_for_backward_compatibility(self, mock_get_status):
|
||||||
|
"""Test that missing 'enabled' key defaults to True (backward compatible)."""
|
||||||
|
mock_get_status.return_value = {
|
||||||
|
"Dropbox": {"configured": True},
|
||||||
|
}
|
||||||
|
|
||||||
|
result = get_configured_services_from_validator()
|
||||||
|
|
||||||
|
assert result["dropbox"] is True
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
class TestSendToAllDestinations:
|
class TestSendToAllDestinations:
|
||||||
|
|||||||
Reference in New Issue
Block a user