Introduce per-tenant override for helpdesk BC connection config. New table helpdesk_tenant_settings stores tenant-specific credentials with encrypted secrets (AES-256-GCM). EffectiveHelpdeskSettingsService resolves global vs tenant config per request. Settings UI extended with tenant override tab, toggle, and dual editing mode. All runtime consumers (OData, SOAP, OAuth) read through the new resolver. Token cache flushed on any config change. Default behavior unchanged — tenants use global config until override explicitly enabled. Also includes risk radar UI refinements: Stripe-style card redesign with accent borders and score pills, removal of redundant KPI tiles and search, and filtering of zero-score entries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
200 lines
6.2 KiB
PHP
200 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace MintyPHP\Module\Helpdesk\Service;
|
|
|
|
use MintyPHP\Http\SessionStoreInterface;
|
|
|
|
/**
|
|
* Resolves the effective helpdesk BC config for the current request.
|
|
*
|
|
* Resolution rule:
|
|
* - If the current tenant has an active override (override_enabled=1): tenant config.
|
|
* - Otherwise: global config from the settings table.
|
|
*
|
|
* All runtime consumers (OData, SOAP, OAuth) should read through this service
|
|
* instead of accessing HelpdeskSettingsGateway directly.
|
|
*/
|
|
class EffectiveHelpdeskSettingsService
|
|
{
|
|
public function __construct(
|
|
private readonly HelpdeskSettingsGateway $globalGateway,
|
|
private readonly HelpdeskTenantSettingsGateway $tenantGateway,
|
|
private readonly SessionStoreInterface $sessionStore
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Resolve the effective settings for the given tenant.
|
|
*/
|
|
public function resolveForTenant(int $tenantId): EffectiveHelpdeskSettings
|
|
{
|
|
if ($tenantId > 0 && $this->tenantGateway->isOverrideEnabled($tenantId)) {
|
|
return $this->buildFromTenant($tenantId);
|
|
}
|
|
|
|
return $this->buildFromGlobal();
|
|
}
|
|
|
|
/**
|
|
* Resolve for the current session tenant.
|
|
*/
|
|
public function resolveForCurrentTenant(): EffectiveHelpdeskSettings
|
|
{
|
|
$tenantId = $this->resolveCurrentTenantId();
|
|
|
|
return $this->resolveForTenant($tenantId);
|
|
}
|
|
|
|
// --- Proxy methods for gateway compatibility ---
|
|
// These allow consumers to swap HelpdeskSettingsGateway → EffectiveHelpdeskSettingsService
|
|
// with minimal code changes.
|
|
|
|
public function getAuthMode(): string
|
|
{
|
|
return $this->resolveForCurrentTenant()->authMode;
|
|
}
|
|
|
|
public function getODataBaseUrl(): string
|
|
{
|
|
return $this->resolveForCurrentTenant()->odataBaseUrl;
|
|
}
|
|
|
|
public function getCompanyName(): string
|
|
{
|
|
return $this->resolveForCurrentTenant()->companyName;
|
|
}
|
|
|
|
public function getBasicUser(): ?string
|
|
{
|
|
return $this->resolveForCurrentTenant()->basicUser;
|
|
}
|
|
|
|
public function getBasicPassword(): ?string
|
|
{
|
|
return $this->resolveForCurrentTenant()->basicPassword;
|
|
}
|
|
|
|
public function getOAuthTenantId(): ?string
|
|
{
|
|
return $this->resolveForCurrentTenant()->oauthTenantId;
|
|
}
|
|
|
|
public function getOAuthClientId(): ?string
|
|
{
|
|
return $this->resolveForCurrentTenant()->oauthClientId;
|
|
}
|
|
|
|
public function getOAuthClientSecret(): ?string
|
|
{
|
|
return $this->resolveForCurrentTenant()->oauthClientSecret;
|
|
}
|
|
|
|
public function getOAuthTokenEndpoint(): ?string
|
|
{
|
|
return $this->resolveForCurrentTenant()->oauthTokenEndpoint;
|
|
}
|
|
|
|
public function buildEntityUrl(string $entitySet): string
|
|
{
|
|
return $this->resolveForCurrentTenant()->buildEntityUrl($entitySet);
|
|
}
|
|
|
|
/**
|
|
* @return array<string>
|
|
*/
|
|
public function validateConfiguration(): array
|
|
{
|
|
return $this->resolveForCurrentTenant()->validateConfiguration();
|
|
}
|
|
|
|
public function isConfigured(): bool
|
|
{
|
|
return $this->resolveForCurrentTenant()->isConfigured();
|
|
}
|
|
|
|
/**
|
|
* @return array{
|
|
* config: array<string, mixed>,
|
|
* source: 'default'|'settings'|'fallback_invalid_json'
|
|
* }
|
|
*/
|
|
public function getSystemRecommendationsConfigEnvelope(): array
|
|
{
|
|
return $this->globalGateway->getSystemRecommendationsConfigEnvelope();
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function getSystemRecommendationsConfig(): array
|
|
{
|
|
return $this->globalGateway->getSystemRecommendationsConfig();
|
|
}
|
|
|
|
/**
|
|
* @return array{
|
|
* config: array<string, mixed>,
|
|
* source: 'default'|'settings'|'fallback_invalid_json'
|
|
* }
|
|
*/
|
|
public function getControllingRiskConfigEnvelope(): array
|
|
{
|
|
return $this->globalGateway->getControllingRiskConfigEnvelope();
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function getControllingRiskConfig(): array
|
|
{
|
|
return $this->globalGateway->getControllingRiskConfig();
|
|
}
|
|
|
|
private function buildFromGlobal(): EffectiveHelpdeskSettings
|
|
{
|
|
return new EffectiveHelpdeskSettings(
|
|
source: 'global',
|
|
authMode: $this->globalGateway->getAuthMode(),
|
|
odataBaseUrl: $this->globalGateway->getODataBaseUrl(),
|
|
companyName: $this->globalGateway->getCompanyName(),
|
|
basicUser: $this->globalGateway->getBasicUser(),
|
|
basicPassword: $this->globalGateway->getBasicPassword(),
|
|
oauthTenantId: $this->globalGateway->getOAuthTenantId(),
|
|
oauthClientId: $this->globalGateway->getOAuthClientId(),
|
|
oauthClientSecret: $this->globalGateway->getOAuthClientSecret(),
|
|
oauthTokenEndpoint: $this->globalGateway->getOAuthTokenEndpoint(),
|
|
systemRecommendationsConfigRaw: null,
|
|
controllingRiskConfigRaw: null,
|
|
);
|
|
}
|
|
|
|
private function buildFromTenant(int $tenantId): EffectiveHelpdeskSettings
|
|
{
|
|
return new EffectiveHelpdeskSettings(
|
|
source: 'tenant',
|
|
authMode: $this->tenantGateway->getAuthMode($tenantId),
|
|
odataBaseUrl: $this->tenantGateway->getODataBaseUrl($tenantId),
|
|
companyName: $this->tenantGateway->getCompanyName($tenantId),
|
|
basicUser: $this->tenantGateway->getBasicUser($tenantId),
|
|
basicPassword: $this->tenantGateway->getBasicPassword($tenantId),
|
|
oauthTenantId: $this->tenantGateway->getOAuthTenantId($tenantId),
|
|
oauthClientId: $this->tenantGateway->getOAuthClientId($tenantId),
|
|
oauthClientSecret: $this->tenantGateway->getOAuthClientSecret($tenantId),
|
|
oauthTokenEndpoint: $this->tenantGateway->getOAuthTokenEndpoint($tenantId),
|
|
systemRecommendationsConfigRaw: $this->tenantGateway->getSystemRecommendationsConfig($tenantId),
|
|
controllingRiskConfigRaw: $this->tenantGateway->getControllingRiskConfig($tenantId),
|
|
);
|
|
}
|
|
|
|
private function resolveCurrentTenantId(): int
|
|
{
|
|
$session = $this->sessionStore->all();
|
|
$tenant = $session['current_tenant'] ?? null;
|
|
if (!is_array($tenant)) {
|
|
return 0;
|
|
}
|
|
|
|
return (int) ($tenant['id'] ?? 0);
|
|
}
|
|
}
|