diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 11408b6..b33c316 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -138,10 +138,9 @@ export class AuthController { this.logger.warn(`Ozonetel token refresh on login failed: ${err.message}`); }); - const ozAgentPassword = this.telephony.getConfig().ozonetel.agentPassword || 'Test123$'; this.ozonetelAgent.loginAgent({ agentId: agentConfig.ozonetelAgentId, - password: ozAgentPassword, + password: agentConfig.sipPassword, phoneNumber: agentConfig.sipExtension, mode: 'blended', }).catch(err => { @@ -250,9 +249,14 @@ export class AuthController { await this.sessionService.unlockSession(agentConfig.ozonetelAgentId); this.logger.log(`Session unlocked for ${agentConfig.ozonetelAgentId}`); - this.ozonetelAgent.logoutAgent({ + // Await the Ozonetel logout so it completes before the + // HTTP response returns. Without this, a fast re-login + // (e.g. "remember me" auto-fill) races the logout and + // the agent lands in "Telephony Unavailable" because + // Ozonetel receives login while still processing logout. + await this.ozonetelAgent.logoutAgent({ agentId: agentConfig.ozonetelAgentId, - password: this.telephony.getConfig().ozonetel.agentPassword || 'Test123$', + password: agentConfig.sipPassword, }).catch(err => this.logger.warn(`Ozonetel logout failed: ${err.message}`)); this.agentConfigService.clearCache(memberId); diff --git a/src/maint/maint.controller.ts b/src/maint/maint.controller.ts index 4c9c90e..1553d45 100644 --- a/src/maint/maint.controller.ts +++ b/src/maint/maint.controller.ts @@ -31,13 +31,26 @@ export class MaintController { async forceReady(@Body() body: { agentId: string }) { if (!body?.agentId) throw new HttpException('agentId required', 400); const agentId = body.agentId; - const oz = this.telephony.getConfig().ozonetel; - const password = oz.agentPassword; - if (!password) throw new HttpException('agent password not configured', 400); - const sipId = oz.sipId; - if (!sipId) throw new HttpException('SIP ID not configured', 400); - this.logger.log(`[MAINT] Force ready: agent=${agentId}`); + // Look up the Agent entity to get sipPassword + sipExtension. + // Password comes from the Agent record, not an env var — each + // agent owns their own Ozonetel credential. + const agentData = await this.platform.query( + `{ agents(first: 1, filter: { ozonetelAgentId: { eq: "${agentId}" } }) { edges { node { + id sipExtension sipPassword + } } } }`, + ).catch(() => null); + + const agent = agentData?.agents?.edges?.[0]?.node; + if (!agent) throw new HttpException(`Agent ${agentId} not found in platform`, 404); + + const password = agent.sipPassword ?? agent.sipExtension; + if (!password) throw new HttpException(`Agent ${agentId} has no sipPassword configured`, 400); + + const sipId = agent.sipExtension; + if (!sipId) throw new HttpException(`Agent ${agentId} has no sipExtension configured`, 400); + + this.logger.log(`[MAINT] Force ready: agent=${agentId} ext=${sipId}`); try { await this.ozonetel.logoutAgent({ agentId, password }); diff --git a/src/worklist/worklist.service.ts b/src/worklist/worklist.service.ts index e5a1663..fc57c59 100644 --- a/src/worklist/worklist.service.ts +++ b/src/worklist/worklist.service.ts @@ -177,6 +177,7 @@ export class WorklistService { startedAt endedAt durationSec disposition leadId leadName callbackStatus callSourceNumber missedCallCount callbackAttemptedAt + campaign { id campaignName } } } pageInfo { hasNextPage endCursor } } }`, 'calls', authHeader,