diff --git a/=2.4.0 b/=2.4.0 deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/ConfigurationGuide.md b/docs/ConfigurationGuide.md index 131324e4..632d4b9c 100644 --- a/docs/ConfigurationGuide.md +++ b/docs/ConfigurationGuide.md @@ -1107,6 +1107,22 @@ For detailed setup instructions, see the [OneDrive Setup Guide](OneDriveSetup.md For detailed setup instructions, see the [Amazon S3 Setup Guide](AmazonS3Setup.md). +### iCloud Drive (Apple) + +| **Variable** | **Description** | +|---------------------------------|-------------------------------------------------------| +| `ICLOUD_USERNAME` | Apple ID email address | +| `ICLOUD_PASSWORD` | App-specific password (generate at [appleid.apple.com](https://appleid.apple.com/account/manage)) | +| `ICLOUD_FOLDER` | Target folder path in iCloud Drive (e.g. `Documents/Uploads`) | +| `ICLOUD_COOKIE_DIRECTORY` | Optional directory for session cookie persistence (default: `~/.pyicloud`) | + +> **Note:** Apple does not provide a public REST API for iCloud Drive. This +> integration uses the [pyicloud](https://github.com/picklepete/pyicloud) +> library which relies on an unofficial, reverse-engineered protocol. Because +> most Apple IDs have two-factor authentication enabled, you **must** generate +> an [app-specific password](https://support.apple.com/en-us/102654) and use +> it as `ICLOUD_PASSWORD`. + ### Notification System | **Variable** | **Description** | diff --git a/docs/StorageArchitecture.md b/docs/StorageArchitecture.md index 0e24bd1b..af055406 100644 --- a/docs/StorageArchitecture.md +++ b/docs/StorageArchitecture.md @@ -348,6 +348,7 @@ in task messages or logs. | `PAPERLESS` | Paperless-ngx REST API, API token | | `EMAIL` | SMTP/STARTTLS, file as attachment | | `RCLONE` | `rclone copyto` subprocess, per-user rclone config | +| `ICLOUD` | pyicloud library, Apple ID + app-specific password | ### Multiple Destinations diff --git a/tests/test_send_to_all.py b/tests/test_send_to_all.py index 1a4bc947..2faad8fa 100644 --- a/tests/test_send_to_all.py +++ b/tests/test_send_to_all.py @@ -9,6 +9,7 @@ from app.tasks.send_to_all import ( _should_upload_to_email, _should_upload_to_ftp, _should_upload_to_google_drive, + _should_upload_to_icloud, _should_upload_to_nextcloud, _should_upload_to_onedrive, _should_upload_to_paperless, @@ -145,6 +146,22 @@ class TestShouldUploadFunctions: assert _should_upload_to_s3() is True + @patch("app.tasks.send_to_all.settings") + def test_should_upload_to_icloud_configured(self, mock_settings): + """Test iCloud upload check.""" + mock_settings.icloud_username = "user@example.com" + mock_settings.icloud_password = "app-specific-password" + + assert _should_upload_to_icloud() is True + + @patch("app.tasks.send_to_all.settings") + def test_should_upload_to_icloud_not_configured(self, mock_settings): + """Test iCloud upload check when not configured.""" + mock_settings.icloud_username = None + mock_settings.icloud_password = None + + assert _should_upload_to_icloud() is False + @pytest.mark.unit class TestGetConfiguredServicesFromValidator: