From 9d817a5ce9d9f372a1008ab5ba9645dd42f90abc Mon Sep 17 00:00:00 2001 From: Sean Morley Date: Thu, 5 Jun 2025 14:28:37 -0400 Subject: [PATCH] feat: add Immich server connection validation and error handling in integration settings --- backend/server/integrations/views.py | 137 +++++++++++++++++++++- frontend/src/locales/de.json | 13 +- frontend/src/locales/en.json | 7 +- frontend/src/locales/es.json | 13 +- frontend/src/locales/fr.json | 13 +- frontend/src/locales/it.json | 13 +- frontend/src/locales/ko.json | 13 +- frontend/src/locales/nl.json | 13 +- frontend/src/locales/no.json | 13 +- frontend/src/locales/pl.json | 13 +- frontend/src/locales/sv.json | 13 +- frontend/src/locales/zh.json | 13 +- frontend/src/routes/settings/+page.svelte | 68 +++++++---- 13 files changed, 303 insertions(+), 39 deletions(-) diff --git a/backend/server/integrations/views.py b/backend/server/integrations/views.py index e4253fd..72327f8 100644 --- a/backend/server/integrations/views.py +++ b/backend/server/integrations/views.py @@ -361,11 +361,76 @@ class ImmichIntegrationViewSet(viewsets.ModelViewSet): def get_queryset(self): return ImmichIntegration.objects.filter(user=self.request.user) + def _validate_immich_connection(self, server_url, api_key): + """ + Validate connection to Immich server before saving integration. + Returns tuple: (is_valid, corrected_server_url, error_message) + """ + if not server_url or not api_key: + return False, server_url, "Server URL and API key are required" + + # Ensure server_url has proper format + if not server_url.startswith(('http://', 'https://')): + server_url = f"https://{server_url}" + + # Remove trailing slash if present + original_server_url = server_url.rstrip('/') + + # Try both with and without /api prefix + test_configs = [ + (original_server_url, f"{original_server_url}/users/me"), + (f"{original_server_url}/api", f"{original_server_url}/api/users/me") + ] + + headers = { + 'X-API-Key': api_key, + 'Content-Type': 'application/json' + } + + for corrected_url, test_endpoint in test_configs: + try: + response = requests.get( + test_endpoint, + headers=headers, + timeout=10, # 10 second timeout + verify=True # SSL verification + ) + + if response.status_code == 200: + try: + json_response = response.json() + # Validate expected Immich user response structure + required_fields = ['id', 'email', 'name', 'isAdmin', 'createdAt'] + if all(field in json_response for field in required_fields): + return True, corrected_url, None + else: + continue # Try next endpoint + except (ValueError, KeyError): + continue # Try next endpoint + elif response.status_code == 401: + return False, original_server_url, "Invalid API key or unauthorized access" + elif response.status_code == 403: + return False, original_server_url, "Access forbidden - check API key permissions" + # Continue to next endpoint for 404 errors + + except requests.exceptions.ConnectTimeout: + return False, original_server_url, "Connection timeout - server may be unreachable" + except requests.exceptions.ConnectionError: + return False, original_server_url, "Cannot connect to server - check URL and network connectivity" + except requests.exceptions.SSLError: + return False, original_server_url, "SSL certificate error - check server certificate" + except requests.exceptions.RequestException as e: + return False, original_server_url, f"Connection failed: {str(e)}" + except Exception as e: + return False, original_server_url, f"Unexpected error: {str(e)}" + + # If we get here, none of the endpoints worked + return False, original_server_url, "Immich server endpoint not found - check server URL" + def create(self, request): """ RESTful POST method for creating a new Immich integration. """ - # Check if the user already has an integration user_integrations = ImmichIntegration.objects.filter(user=request.user) if user_integrations.exists(): @@ -380,11 +445,76 @@ class ImmichIntegrationViewSet(viewsets.ModelViewSet): serializer = self.serializer_class(data=request.data) if serializer.is_valid(): - serializer.save(user=request.user) + # Validate Immich server connection before saving + server_url = serializer.validated_data.get('server_url') + api_key = serializer.validated_data.get('api_key') + + is_valid, corrected_server_url, error_message = self._validate_immich_connection(server_url, api_key) + + if not is_valid: + return Response( + { + 'message': f'Cannot connect to Immich server: {error_message}', + 'error': True, + 'code': 'immich.connection_failed', + 'details': error_message + }, + status=status.HTTP_400_BAD_REQUEST + ) + + # If validation passes, save the integration with the corrected URL + serializer.save(user=request.user, server_url=corrected_server_url) return Response( serializer.data, status=status.HTTP_201_CREATED ) + + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST + ) + + def update(self, request, pk=None): + """ + RESTful PUT method for updating an existing Immich integration. + """ + integration = ImmichIntegration.objects.filter(user=request.user, id=pk).first() + if not integration: + return Response( + { + 'message': 'Integration not found.', + 'error': True, + 'code': 'immich.integration_not_found' + }, + status=status.HTTP_404_NOT_FOUND + ) + + serializer = self.serializer_class(integration, data=request.data, partial=True) + if serializer.is_valid(): + # Validate Immich server connection before updating + server_url = serializer.validated_data.get('server_url', integration.server_url) + api_key = serializer.validated_data.get('api_key', integration.api_key) + + is_valid, corrected_server_url, error_message = self._validate_immich_connection(server_url, api_key) + + if not is_valid: + return Response( + { + 'message': f'Cannot connect to Immich server: {error_message}', + 'error': True, + 'code': 'immich.connection_failed', + 'details': error_message + }, + status=status.HTTP_400_BAD_REQUEST + ) + + # If validation passes, save the integration with the corrected URL + serializer.save(server_url=corrected_server_url) + return Response( + serializer.data, + status=status.HTTP_200_OK + ) + return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST @@ -411,10 +541,9 @@ class ImmichIntegrationViewSet(viewsets.ModelViewSet): }, status=status.HTTP_200_OK ) - + def list(self, request, *args, **kwargs): # If the user has an integration, we only want to return that integration - user_integrations = ImmichIntegration.objects.filter(user=request.user) if user_integrations.exists(): integration = user_integrations.first() diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index db6b6af..e5324b1 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -669,7 +669,15 @@ "api_key_placeholder": "Geben Sie Ihren Immich -API -Schlüssel ein", "enable_integration": "Integration aktivieren", "immich_integration_desc": "Schließen Sie Ihren Immich -Photo -Management -Server an", - "need_help": "Benötigen Sie Hilfe bei der Einrichtung? \nSchauen Sie sich das an" + "need_help": "Benötigen Sie Hilfe bei der Einrichtung? \nSchauen Sie sich das an", + "connection_error": "Fehler, die eine Verbindung zum Immich -Server herstellen", + "copy_locally": "Kopieren Sie Bilder lokal", + "copy_locally_desc": "Kopieren Sie Bilder auf den Server für den Offline -Zugriff. \nNutzt mehr Speicherplatz.", + "error_saving_image": "Fehler speichern Bild", + "integration_already_exists": "Es gibt bereits eine Immichintegration. \nSie können jeweils nur eine Integration haben.", + "integration_not_found": "Immich -Integration nicht gefunden. \nBitte erstellen Sie eine neue Integration.", + "network_error": "Netzwerkfehler beim Verbindung mit dem Immich -Server. \nBitte überprüfen Sie Ihre Verbindung und versuchen Sie es erneut.", + "validation_error": "Bei der Validierung der Immichintegration trat ein Fehler auf. \nBitte überprüfen Sie Ihre Server -URL- und API -Schlüssel." }, "recomendations": { "address": "Adresse", @@ -712,5 +720,8 @@ "type": "Typ", "villa": "Villa", "current_timezone": "Aktuelle Zeitzone" + }, + "google_maps": { + "google_maps_integration_desc": "Verbinden Sie Ihr Google Maps-Konto, um hochwertige Suchergebnisse und Empfehlungen für Standort zu erhalten." } } diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index af4d624..079641d 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -702,7 +702,12 @@ "need_help": "Need help setting this up? Check out the", "copy_locally": "Copy Images Locally", "copy_locally_desc": "Copy images to the server for offline access. Uses more disk space.", - "error_saving_image": "Error saving image" + "error_saving_image": "Error saving image", + "connection_error": "Error connecting to Immich server", + "integration_already_exists": "An Immich integration already exists. You can only have one integration at a time.", + "integration_not_found": "Immich integration not found. Please create a new integration.", + "validation_error": "An error occurred while validating the Immich integration. Please check your server URL and API key.", + "network_error": "Network error while connecting to the Immich server. Please check your connection and try again." }, "google_maps": { "google_maps_integration_desc": "Connect your Google Maps account to get high-quality location search results and recommendations." diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index 858c7c8..62c293d 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -669,7 +669,15 @@ "api_key_placeholder": "Ingrese su clave de API IMICH", "enable_integration": "Habilitar la integración", "immich_integration_desc": "Conecte su servidor de administración de fotos de Immich", - "need_help": "¿Necesita ayuda para configurar esto? \nMira el" + "need_help": "¿Necesita ayuda para configurar esto? \nMira el", + "connection_error": "Error conectarse al servidor Immich", + "copy_locally": "Copiar imágenes localmente", + "copy_locally_desc": "Copie imágenes al servidor para obtener acceso fuera de línea. \nUtiliza más espacio en disco.", + "error_saving_image": "Imagen de ahorro de errores", + "integration_already_exists": "Ya existe una integración IMICH. \nSolo puedes tener una integración a la vez.", + "integration_not_found": "Integración IMACH no encontrada. \nPor favor cree una nueva integración.", + "network_error": "Error de red mientras se conecta al servidor Immich. \nVerifique su conexión y vuelva a intentarlo.", + "validation_error": "Se produjo un error al validar la integración de Immich. \nVerifique la URL y la tecla API de su servidor." }, "recomendations": { "address": "DIRECCIÓN", @@ -712,5 +720,8 @@ "villa": "Villa", "edit_lodging": "Editar alojamiento", "current_timezone": "Zona horaria" + }, + "google_maps": { + "google_maps_integration_desc": "Conecte su cuenta de Google Maps para obtener resultados y recomendaciones de búsqueda de ubicación de alta calidad." } } diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index 54c4f73..57cecab 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -669,7 +669,15 @@ "api_key_placeholder": "Entrez votre clé API Immich", "enable_integration": "Activer l'intégration", "immich_integration_desc": "Connectez votre serveur de gestion de photos Immich", - "need_help": "Besoin d'aide pour la configurer? \nDécouvrez le" + "need_help": "Besoin d'aide pour la configurer? \nDécouvrez le", + "connection_error": "Erreur de connexion à Immich Server", + "copy_locally": "Copier les images localement", + "copy_locally_desc": "Copiez des images sur le serveur pour un accès hors ligne. \nUtilise plus d'espace disque.", + "error_saving_image": "Image d'enregistrement d'erreur", + "integration_already_exists": "Une intégration Immich existe déjà. \nVous ne pouvez avoir qu'une seule intégration à la fois.", + "integration_not_found": "L'intégration d'immich n'est pas trouvée. \nVeuillez créer une nouvelle intégration.", + "network_error": "Erreur réseau lors de la connexion au serveur Immich. \nVeuillez vérifier votre connexion et réessayer.", + "validation_error": "Une erreur s'est produite lors de la validation de l'intégration d'Immich. \nVeuillez vérifier l'URL et la clé API de votre serveur." }, "recomendations": { "address": "Adresse", @@ -712,5 +720,8 @@ "type": "Type", "villa": "Villa", "current_timezone": "Fuseau horaire actuel" + }, + "google_maps": { + "google_maps_integration_desc": "Connectez votre compte Google Maps pour obtenir des résultats de recherche et recommandations de recherche de haute qualité." } } diff --git a/frontend/src/locales/it.json b/frontend/src/locales/it.json index 0da8696..f894b81 100644 --- a/frontend/src/locales/it.json +++ b/frontend/src/locales/it.json @@ -669,7 +669,15 @@ "api_key_placeholder": "Inserisci la tua chiave API immich", "enable_integration": "Abilita l'integrazione", "immich_integration_desc": "Collega il tuo server di gestione delle foto immich", - "need_help": "Hai bisogno di aiuto per impostare questo? \nDai un'occhiata al" + "need_help": "Hai bisogno di aiuto per impostare questo? \nDai un'occhiata al", + "connection_error": "Errore che si collega al server immich", + "copy_locally": "Copia immagini localmente", + "error_saving_image": "Errore salvare l'immagine", + "integration_already_exists": "Esiste già un'integrazione immich. \nPuoi avere solo un'integrazione alla volta.", + "integration_not_found": "Integrazione immich non trovata. \nSi prega di creare una nuova integrazione.", + "network_error": "Errore di rete durante la connessione al server immich. \nControlla la tua connessione e riprova.", + "validation_error": "Si è verificato un errore durante la convalida dell'integrazione immich. \nControlla l'URL e la chiave API del server.", + "copy_locally_desc": "Copia le immagini sul server per l'accesso offline. \nUtilizza più spazio su disco." }, "recomendations": { "address": "Indirizzo", @@ -712,5 +720,8 @@ "lodging_type": "Tipo di alloggio", "motel": "Motel", "current_timezone": "Fuso orario attuale" + }, + "google_maps": { + "google_maps_integration_desc": "Collega il tuo account Google Maps per ottenere risultati e consigli di ricerca sulla posizione di alta qualità." } } diff --git a/frontend/src/locales/ko.json b/frontend/src/locales/ko.json index 206bc88..6da6fd1 100644 --- a/frontend/src/locales/ko.json +++ b/frontend/src/locales/ko.json @@ -387,7 +387,15 @@ "api_key_placeholder": "Immich API 키를 입력하십시오", "enable_integration": "통합을 활성화합니다", "immich_integration_desc": "Immich Photo Management Server를 연결하십시오", - "need_help": "이것을 설정하는 데 도움이 필요하십니까? \n확인하십시오" + "need_help": "이것을 설정하는 데 도움이 필요하십니까? \n확인하십시오", + "connection_error": "Immich 서버에 연결하는 오류", + "copy_locally": "로컬에서 이미지를 복사하십시오", + "copy_locally_desc": "오프라인 액세스를 위해 이미지를 서버에 복사하십시오. \n더 많은 디스크 공간을 사용합니다.", + "error_saving_image": "오류 저장 이미지", + "integration_already_exists": "면역 통합이 이미 존재합니다. \n한 번에 하나만 통합 할 수 있습니다.", + "integration_not_found": "Immich 통합을 찾을 수 없습니다. \n새로운 통합을 작성하십시오.", + "network_error": "Immich 서버에 연결하는 동안 네트워크 오류. \n연결을 확인하고 다시 시도하십시오.", + "validation_error": "면역 통합을 검증하는 동안 오류가 발생했습니다. \n서버 URL 및 API 키를 확인하십시오." }, "map": { "add_adventure": "새로운 모험 추가", @@ -711,5 +719,8 @@ "type": "유형", "villa": "별장", "check_out": "체크 아웃" + }, + "google_maps": { + "google_maps_integration_desc": "Google지도 계정을 연결하여 고품질 위치 검색 결과 및 권장 사항을 얻으십시오." } } diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index ec167bf..7c5ff5d 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -669,7 +669,15 @@ "api_key_placeholder": "Voer uw Immich API -sleutel in", "enable_integration": "Integratie inschakelen", "immich_integration_desc": "Verbind uw Immich Photo Management Server", - "need_help": "Hulp nodig bij het opzetten van dit? \nBekijk de" + "need_help": "Hulp nodig bij het opzetten van dit? \nBekijk de", + "connection_error": "Error verbinding maken met Immich Server", + "copy_locally": "Kopieer afbeeldingen lokaal", + "copy_locally_desc": "Kopieer afbeeldingen naar de server voor offline toegang. \nGebruikt meer schijfruimte.", + "error_saving_image": "Foutopslagafbeelding", + "integration_already_exists": "Er bestaat al een Immich -integratie. \nU kunt maar één integratie tegelijk hebben.", + "integration_not_found": "Immich -integratie niet gevonden. \nMaak een nieuwe integratie.", + "network_error": "Netwerkfout terwijl u verbinding maakt met de Immich -server. \nControleer uw verbinding en probeer het opnieuw.", + "validation_error": "Er is een fout opgetreden bij het valideren van de Immich -integratie. \nControleer uw server -URL en API -toets." }, "recomendations": { "address": "Adres", @@ -712,5 +720,8 @@ "type": "Type", "villa": "Villa", "current_timezone": "Huidige tijdzone" + }, + "google_maps": { + "google_maps_integration_desc": "Sluit uw Google Maps-account aan om zoekresultaten en aanbevelingen van hoge kwaliteit te krijgen." } } diff --git a/frontend/src/locales/no.json b/frontend/src/locales/no.json index 29f760f..8d8de76 100644 --- a/frontend/src/locales/no.json +++ b/frontend/src/locales/no.json @@ -699,7 +699,15 @@ "api_key_placeholder": "Skriv inn Immich API -tasten", "enable_integration": "Aktiver integrasjon", "immich_integration_desc": "Koble til Immich Photo Management Server", - "need_help": "Trenger du hjelp til å sette opp dette? \nSjekk ut" + "need_help": "Trenger du hjelp til å sette opp dette? \nSjekk ut", + "connection_error": "Feil tilkobling til Immich Server", + "copy_locally": "Kopier bilder lokalt", + "copy_locally_desc": "Kopier bilder til serveren for offline tilgang. \nBruker mer diskplass.", + "error_saving_image": "Feil å lagre bilde", + "integration_already_exists": "En Immich -integrasjon eksisterer allerede. \nDu kan bare ha en integrasjon om gangen.", + "integration_not_found": "Immich -integrasjon ikke funnet. \nOpprett en ny integrasjon.", + "network_error": "Nettverksfeil mens du kobler til Immich -serveren. \nVennligst sjekk tilkoblingen din og prøv igjen.", + "validation_error": "Det oppstod en feil under validering av Immich -integrasjonen. \nVennligst sjekk server -URL -en og API -tasten." }, "recomendations": { "address": "Adresse", @@ -712,5 +720,8 @@ "food": "Mat", "miles": "Miles", "tourism": "Turisme" + }, + "google_maps": { + "google_maps_integration_desc": "Koble til Google Maps-kontoen din for å få søkeresultater og anbefalinger av høy kvalitet." } } diff --git a/frontend/src/locales/pl.json b/frontend/src/locales/pl.json index e3551e3..772ed09 100644 --- a/frontend/src/locales/pl.json +++ b/frontend/src/locales/pl.json @@ -669,7 +669,15 @@ "api_key_placeholder": "Wprowadź swój klucz API IMMICH", "enable_integration": "Włącz integrację", "immich_integration_desc": "Połącz swój serwer zarządzania zdjęciami Immich", - "need_help": "Potrzebujesz pomocy w konfiguracji? \nSprawdź" + "need_help": "Potrzebujesz pomocy w konfiguracji? \nSprawdź", + "connection_error": "Błąd łączący się z serwerem Immich", + "copy_locally": "Kopiuj obrazy lokalnie", + "copy_locally_desc": "Skopiuj obrazy na serwer, aby uzyskać dostęp offline. \nWykorzystuje więcej miejsca na dysku.", + "error_saving_image": "Obraz zapisujący błąd", + "integration_already_exists": "Immichu jest już integracja i immich. \nMożesz mieć tylko jedną integrację na raz.", + "integration_not_found": "Nie znaleziono integracji imich. \nUtwórz nową integrację.", + "network_error": "Błąd sieci podczas łączenia się z serwerem IMMICH. \nSprawdź połączenie i spróbuj ponownie.", + "validation_error": "Wystąpił błąd podczas walidacji integracji immicha. \nSprawdź swój adres URL serwera i klawisz API." }, "recomendations": { "address": "Adres", @@ -712,5 +720,8 @@ "reservation_number": "Numer rezerwacji", "resort": "Uciec", "current_timezone": "Obecna strefa czasowa" + }, + "google_maps": { + "google_maps_integration_desc": "Połącz swoje konto Google Maps, aby uzyskać wysokiej jakości wyniki wyszukiwania i zalecenia dotyczące lokalizacji." } } diff --git a/frontend/src/locales/sv.json b/frontend/src/locales/sv.json index fd39824..aa98ec9 100644 --- a/frontend/src/locales/sv.json +++ b/frontend/src/locales/sv.json @@ -669,7 +669,15 @@ "api_key_placeholder": "Ange din immich API -nyckel", "enable_integration": "Aktivera integration", "immich_integration_desc": "Anslut din immich fotohanteringsserver", - "need_help": "Behöver du hjälp med att ställa in detta? \nKolla in" + "need_help": "Behöver du hjälp med att ställa in detta? \nKolla in", + "connection_error": "Fel som ansluter till Imchich Server", + "copy_locally": "Kopiera bilder lokalt", + "copy_locally_desc": "Kopiera bilder till servern för offlineåtkomst. \nAnvänder mer diskutrymme.", + "error_saving_image": "Felbesparande bild", + "integration_already_exists": "En immich integration finns redan. \nDu kan bara ha en integration åt gången.", + "integration_not_found": "Imkik integration hittades inte. \nSkapa en ny integration.", + "network_error": "Nätverksfel vid anslutning till den immich servern. \nKontrollera din anslutning och försök igen.", + "validation_error": "Ett fel inträffade vid validering av den immich integrationen. \nKontrollera din server -URL- och API -nyckel." }, "recomendations": { "address": "Adress", @@ -712,5 +720,8 @@ "edit": "Redigera", "edit_lodging": "Redigera logi", "current_timezone": "Nuvarande tidszon" + }, + "google_maps": { + "google_maps_integration_desc": "Anslut ditt Google Maps-konto för att få sökresultat och rekommendationer av hög kvalitet." } } diff --git a/frontend/src/locales/zh.json b/frontend/src/locales/zh.json index fbee109..48fbb2b 100644 --- a/frontend/src/locales/zh.json +++ b/frontend/src/locales/zh.json @@ -669,7 +669,15 @@ "api_key_placeholder": "输入您的Immich API密钥", "enable_integration": "启用集成", "immich_integration_desc": "连接您的Immich照片管理服务器", - "need_help": "需要帮助设置吗?\n查看" + "need_help": "需要帮助设置吗?\n查看", + "connection_error": "连接到Immich服务器的错误", + "copy_locally": "在本地复制图像", + "copy_locally_desc": "将图像复制到服务器以进行离线访问。\n使用更多的磁盘空间。", + "error_saving_image": "保存错误的图像", + "integration_already_exists": "Immich整合已经存在。\n您一次只能进行一个集成。", + "integration_not_found": "没有找到Immich整合。\n请创建一个新的集成。", + "network_error": "连接到Immich服务器时的网络错误。\n请检查您的连接,然后重试。", + "validation_error": "在验证IMMICH集成时发生了错误。\n请检查您的服务器URL和API键。" }, "recomendations": { "address": "地址", @@ -712,5 +720,8 @@ "reservation_number": "预订号", "resort": "度假村", "current_timezone": "当前时区" + }, + "google_maps": { + "google_maps_integration_desc": "连接您的Google Maps帐户以获取高质量的位置搜索结果和建议。" } } diff --git a/frontend/src/routes/settings/+page.svelte b/frontend/src/routes/settings/+page.svelte index 06a2903..c07ee36 100644 --- a/frontend/src/routes/settings/+page.svelte +++ b/frontend/src/routes/settings/+page.svelte @@ -187,37 +187,57 @@ } } - async function enableImmichIntegration() { - if (!immichIntegration?.id) { - let res = await fetch('/api/integrations/immich/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(newImmichIntegration) - }); - let data = await res.json(); - if (res.ok) { - addToast('success', $t('immich.immich_enabled')); - immichIntegration = data; - } else { - addToast('error', $t('immich.immich_error')); - } + function handleImmichError(data: { + code: string; + details: any; + message: any; + error: any; + server_url: any[]; + api_key: any[]; + }) { + if (data.code === 'immich.connection_failed') { + return `${$t('immich.connection_error')}: ${data.details || data.message}`; + } else if (data.code === 'immich.integration_exists') { + return $t('immich.integration_already_exists'); + } else if (data.code === 'immich.integration_not_found') { + return $t('immich.integration_not_found'); + } else if (data.error && data.message) { + return data.message; } else { - let res = await fetch(`/api/integrations/immich/${immichIntegration.id}/`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json' - }, + // Handle validation errors + const errors = []; + if (data.server_url) errors.push(`Server URL: ${data.server_url.join(', ')}`); + if (data.api_key) errors.push(`API Key: ${data.api_key.join(', ')}`); + return errors.length > 0 + ? `${$t('immich.validation_error')}: ${errors.join('; ')}` + : $t('immich.immich_error'); + } + } + + async function enableImmichIntegration() { + const isUpdate = !!immichIntegration?.id; + const url = isUpdate + ? `/api/integrations/immich/${immichIntegration?.id ?? ''}/` + : '/api/integrations/immich/'; + const method = isUpdate ? 'PUT' : 'POST'; + + try { + const res = await fetch(url, { + method, + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newImmichIntegration) }); - let data = await res.json(); + + const data = await res.json(); + if (res.ok) { - addToast('success', $t('immich.immich_updated')); + addToast('success', $t(isUpdate ? 'immich.immich_updated' : 'immich.immich_enabled')); immichIntegration = data; } else { - addToast('error', $t('immich.immich_error')); + addToast('error', handleImmichError(data)); } + } catch (error) { + addToast('error', $t('immich.network_error')); } }