diff --git a/backend/services/memberTransferService.js b/backend/services/memberTransferService.js index 5c192e9..d84a127 100644 --- a/backend/services/memberTransferService.js +++ b/backend/services/memberTransferService.js @@ -72,14 +72,44 @@ class MemberTransferService { loginEndpointUrl = savedConfig.server.replace(/\/$/, '') + '/' + config.loginEndpoint.replace(/^\//, ''); // Login-Credentials aus gespeicherter Konfiguration laden, falls vorhanden - if (!loginCredentials && savedConfig.loginEndpoint === config.loginEndpoint) { - loginCredentials = savedConfig.getLoginCredentials(); + // WICHTIG: Nur wenn keine Credentials übergeben wurden ODER wenn übergebene Credentials leer sind + if (!loginCredentials || Object.keys(loginCredentials).length === 0) { + if (savedConfig.loginEndpoint === config.loginEndpoint) { + const savedCredentials = savedConfig.getLoginCredentials(); + if (savedCredentials && Object.keys(savedCredentials).length > 0) { + loginCredentials = savedCredentials; + } + } } } } - if (config.transferEndpoint && !config.transferEndpoint.startsWith('http') && savedConfig) { - if (savedConfig.server) { + // Auch wenn vollständige URLs verwendet werden, gespeicherte Credentials verwenden falls keine übergeben + if (config.loginEndpoint && config.loginEndpoint.startsWith('http')) { + if (!loginCredentials || Object.keys(loginCredentials).length === 0) { + // Versuche gespeicherte Konfiguration zu finden (falls noch nicht geladen) + if (!savedConfig) { + savedConfig = await MemberTransferConfig.findOne({ + where: { clubId } + }); + } + if (savedConfig && savedConfig.loginEndpoint === config.loginEndpoint) { + const savedCredentials = savedConfig.getLoginCredentials(); + if (savedCredentials && Object.keys(savedCredentials).length > 0) { + loginCredentials = savedCredentials; + } + } + } + } + + if (config.transferEndpoint && !config.transferEndpoint.startsWith('http')) { + // Versuche gespeicherte Konfiguration zu finden (falls noch nicht geladen) + if (!savedConfig) { + savedConfig = await MemberTransferConfig.findOne({ + where: { clubId } + }); + } + if (savedConfig && savedConfig.server) { // Server + relativen Pfad kombinieren transferEndpointUrl = savedConfig.server.replace(/\/$/, '') + '/' + config.transferEndpoint.replace(/^\//, ''); } @@ -90,7 +120,21 @@ class MemberTransferService { config.bulkWrapperTemplate = savedConfig.bulkWrapperTemplate; } - if (loginEndpointUrl && loginCredentials) { + // Prüfe ob Login-Credentials vorhanden sind und nicht leer + // Filtere leere Strings/Leerzeichen heraus + if (loginCredentials && Object.keys(loginCredentials).length > 0) { + // Prüfe ob alle Werte nicht-leer sind (nach Trimmen) + const hasValidCredentials = Object.values(loginCredentials).some( + value => value && typeof value === 'string' && value.trim().length > 0 + ); + + if (!hasValidCredentials) { + devLog('[transferMembers] Login-Credentials enthalten nur leere Werte'); + loginCredentials = null; + } + } + + if (loginEndpointUrl && loginCredentials && Object.keys(loginCredentials).length > 0) { try { const loginResult = await this.performLogin( loginEndpointUrl, @@ -99,11 +143,13 @@ class MemberTransferService { ); if (!loginResult.success) { + // WICHTIG: Verwende 400 statt 401, damit der Benutzer nicht ausgeloggt wird + // 401 wird vom Frontend als "nicht autorisiert" interpretiert und führt zu automatischem Logout return { - status: 401, + status: 400, response: { success: false, - message: 'Login fehlgeschlagen', + message: 'Login am externen System fehlgeschlagen', error: loginResult.error, transferred: 0, errors: [] @@ -115,11 +161,12 @@ class MemberTransferService { sessionCookie = loginResult.cookie; } catch (loginError) { devLog('[transferMembers] Login error:', loginError); + // WICHTIG: Verwende 400 statt 401, damit der Benutzer nicht ausgeloggt wird return { - status: 401, + status: 400, response: { success: false, - message: 'Login fehlgeschlagen: ' + loginError.message, + message: 'Login am externen System fehlgeschlagen: ' + loginError.message, transferred: 0, errors: [] } @@ -394,9 +441,30 @@ class MemberTransferService { }; } catch (error) { devLog('[performLogin] Error:', error); + + // Extrahiere detaillierte Fehlerinformationen + let errorMessage = 'Login fehlgeschlagen'; + let statusCode = error.response?.status; + + if (error.response?.data) { + // Versuche verschiedene Felder für die Fehlermeldung + errorMessage = error.response.data.message || + error.response.data.error || + error.response.data.errorMessage || + (typeof error.response.data === 'string' ? error.response.data : errorMessage); + } else if (error.message) { + errorMessage = error.message; + } + + // Logge den Status-Code für Debugging + if (statusCode) { + devLog(`[performLogin] Externer Endpoint Status: ${statusCode}`); + } + return { success: false, - error: error.response?.data?.message || error.message || 'Login fehlgeschlagen' + error: errorMessage, + statusCode: statusCode }; } } diff --git a/frontend/src/components/MemberTransferDialog.vue b/frontend/src/components/MemberTransferDialog.vue index 0ac0b62..0dad70e 100644 --- a/frontend/src/components/MemberTransferDialog.vue +++ b/frontend/src/components/MemberTransferDialog.vue @@ -179,9 +179,24 @@ export default { methods: { async loadSavedConfig() { if (!this.currentClub) { + // Login-Credentials leeren, auch wenn kein Club vorhanden + this.loginCredentials = { + username: '', + password: '', + additionalField1: '', + additionalField2: '' + }; return; } + // WICHTIG: Login-Credentials sofort leeren, damit sie nicht vorausgefüllt werden + this.loginCredentials = { + username: '', + password: '', + additionalField1: '', + additionalField2: '' + }; + this.loadingConfig = true; try { const response = await apiClient.get(`/member-transfer-config/${this.currentClub}`); @@ -200,13 +215,8 @@ export default { this.config.useBulkMode = savedConfig.useBulkMode || false; this.config.bulkWrapperTemplate = savedConfig.bulkWrapperTemplate || ''; - // Login-Credentials zurücksetzen (werden nur verwendet, wenn im Dialog eingegeben) - this.loginCredentials = { - username: '', - password: '', - additionalField1: '', - additionalField2: '' - }; + // Login-Credentials bleiben leer (werden nur verwendet, wenn im Dialog eingegeben) + // Gespeicherte Credentials werden vom Backend verwendet, wenn keine eingegeben werden } } catch (error) { // Keine Konfiguration vorhanden - das ist OK, Dialog bleibt leer @@ -214,6 +224,13 @@ export default { console.error('Fehler beim Laden der gespeicherten Konfiguration:', error); } } finally { + // Sicherstellen, dass Login-Credentials leer sind + this.loginCredentials = { + username: '', + password: '', + additionalField1: '', + additionalField2: '' + }; this.loadingConfig = false; } }, @@ -252,28 +269,37 @@ export default { try { // Login-Credentials zusammenstellen + // WICHTIG: Nur nicht-leere Werte hinzufügen (nach Trimmen) + // Leere Strings würden die gespeicherten Credentials überschreiben const loginCredentials = {}; - if (this.loginCredentials.username) { - loginCredentials.username = this.loginCredentials.username; + const trimmedUsername = this.loginCredentials.username?.trim(); + const trimmedPassword = this.loginCredentials.password?.trim(); + + if (trimmedUsername) { + loginCredentials.username = trimmedUsername; } - if (this.loginCredentials.password) { - loginCredentials.password = this.loginCredentials.password; + if (trimmedPassword) { + loginCredentials.password = trimmedPassword; } - // Zusätzliche Felder verarbeiten - if (this.loginCredentials.additionalField1) { - const parts1 = this.loginCredentials.additionalField1.split(':').map(s => s.trim()); - if (parts1.length === 2) { + // Zusätzliche Felder verarbeiten (nur wenn nicht leer) + const trimmedAdditional1 = this.loginCredentials.additionalField1?.trim(); + if (trimmedAdditional1) { + const parts1 = trimmedAdditional1.split(':').map(s => s.trim()); + if (parts1.length === 2 && parts1[0] && parts1[1]) { loginCredentials[parts1[0]] = parts1[1]; - } else { + } else if (parts1.length === 1 && parts1[0]) { + // Falls kein Doppelpunkt, verwende den gesamten Wert als Feldname loginCredentials[parts1[0]] = parts1[0]; } } - if (this.loginCredentials.additionalField2) { - const parts2 = this.loginCredentials.additionalField2.split(':').map(s => s.trim()); - if (parts2.length === 2) { + + const trimmedAdditional2 = this.loginCredentials.additionalField2?.trim(); + if (trimmedAdditional2) { + const parts2 = trimmedAdditional2.split(':').map(s => s.trim()); + if (parts2.length === 2 && parts2[0] && parts2[1]) { loginCredentials[parts2[0]] = parts2[1]; - } else { + } else if (parts2.length === 1 && parts2[0]) { loginCredentials[parts2[0]] = parts2[0]; } }