loadMissing('credential'); $credential = $connection->credential; $payload = $credential instanceof ProviderCredential && is_array($credential->payload) ? $credential->payload : []; $previousClientId = trim((string) ($payload['client_id'] ?? '')); $needsConsentReset = $connection->connection_type !== ProviderConnectionType::Dedicated || $previousClientId === '' || $previousClientId !== $clientId; $consentStatus = $needsConsentReset ? ProviderConsentStatus::Required : $this->normalizeConsentStatus($connection->consent_status); $verificationStatus = ProviderVerificationStatus::Unknown; $updates = $this->projectConnectionState( connection: $connection, connectionType: ProviderConnectionType::Dedicated, consentStatus: $consentStatus, verificationStatus: $verificationStatus, ); $connection->forceFill(array_merge($updates, [ 'connection_type' => ProviderConnectionType::Dedicated->value, 'last_health_check_at' => null, 'last_error_reason_code' => $needsConsentReset ? ProviderReasonCodes::ProviderConsentMissing : null, 'last_error_message' => null, 'scopes_granted' => $needsConsentReset ? [] : ($connection->scopes_granted ?? []), 'consent_granted_at' => $needsConsentReset ? null : $connection->consent_granted_at, 'consent_last_checked_at' => $needsConsentReset ? null : $connection->consent_last_checked_at, 'consent_error_code' => $needsConsentReset ? null : $connection->consent_error_code, 'consent_error_message' => $needsConsentReset ? null : $connection->consent_error_message, ]))->save(); $this->credentials->upsertClientSecretCredential( connection: $connection->fresh(), clientId: $clientId, clientSecret: $clientSecret, ); return $connection->fresh(['credential']); }); } public function revertToPlatform(ProviderConnection $connection): ProviderConnection { return DB::transaction(function () use ($connection): ProviderConnection { $connection->loadMissing('credential'); if ($connection->credential instanceof ProviderCredential) { $connection->credential->delete(); } $updates = $this->projectConnectionState( connection: $connection, connectionType: ProviderConnectionType::Platform, consentStatus: ProviderConsentStatus::Required, verificationStatus: ProviderVerificationStatus::Unknown, ); $connection->forceFill(array_merge($updates, [ 'connection_type' => ProviderConnectionType::Platform->value, 'consent_granted_at' => null, 'consent_last_checked_at' => null, 'consent_error_code' => null, 'consent_error_message' => null, 'verification_status' => ProviderVerificationStatus::Unknown->value, 'last_health_check_at' => null, 'last_error_reason_code' => ProviderReasonCodes::ProviderConsentMissing, 'last_error_message' => null, 'scopes_granted' => [], ]))->save(); return $connection->fresh(['credential']); }); } public function deleteDedicatedCredential(ProviderConnection $connection): ProviderConnection { return DB::transaction(function () use ($connection): ProviderConnection { $connection->loadMissing('credential'); if ($connection->credential instanceof ProviderCredential) { $connection->credential->delete(); } $consentStatus = $this->normalizeConsentStatus($connection->consent_status); $verificationStatus = ProviderVerificationStatus::Blocked; $updates = $this->projectConnectionState( connection: $connection, connectionType: ProviderConnectionType::Dedicated, consentStatus: $consentStatus, verificationStatus: $verificationStatus, ); $connection->forceFill(array_merge($updates, [ 'connection_type' => ProviderConnectionType::Dedicated->value, 'consent_status' => $consentStatus->value, 'verification_status' => $verificationStatus->value, 'last_health_check_at' => null, 'last_error_reason_code' => ProviderReasonCodes::DedicatedCredentialMissing, 'last_error_message' => 'Dedicated credential is missing.', ]))->save(); return $connection->fresh(['credential']); }); } private function projectConnectionState( ProviderConnection $connection, ProviderConnectionType $connectionType, ProviderConsentStatus $consentStatus, ProviderVerificationStatus $verificationStatus, ): array { $projected = $this->stateProjector->project( connectionType: $connectionType, consentStatus: $consentStatus, verificationStatus: $verificationStatus, currentStatus: is_string($connection->status) ? $connection->status : null, ); return [ 'consent_status' => $consentStatus->value, 'verification_status' => $verificationStatus->value, 'status' => $projected['status'], 'health_status' => $projected['health_status'], ]; } private function normalizeConsentStatus( ProviderConsentStatus|string|null $consentStatus, ): ProviderConsentStatus { if ($consentStatus instanceof ProviderConsentStatus) { return $consentStatus; } if (is_string($consentStatus)) { return ProviderConsentStatus::tryFrom(trim($consentStatus)) ?? ProviderConsentStatus::Required; } return ProviderConsentStatus::Required; } }