From cf740a09f2136430b81adcc46a35bc2958059243 Mon Sep 17 00:00:00 2001 From: Juntu Chen <95723208+juntuchen-msft@users.noreply.github.com> Date: Tue, 12 Nov 2024 19:31:26 -0500 Subject: [PATCH] Juntuchen/ops outgoing call (#31567) ### Packages impacted by this PR ### Issues associated with this PR ### Describe the problem that is addressed by this PR ### What are the possible designs available to address the problem? If there are more than one possible design, why was the one in this PR chosen? ### Are there test cases added in this PR? _(If not, why?)_ ### Provide a list of related PRs _(if any)_ ### Command used to generate this PR:**_(Applicable only to SDK release request PRs)_ ### Checklists - [ ] Added impacted package name to the issue description - [ ] Does this PR needs any fixes in the SDK Generator?** _(If so, create an Issue in the [Autorest/typescript](https://github.com/Azure/autorest.typescript) repository and link it here)_ - [ ] Added a changelog (if necessary) --- .../communication-call-automation.api.md | 1 + .../src/callAutomationClient.ts | 12 ++++ .../src/generated/src/models/index.ts | 7 ++- .../src/generated/src/models/mappers.ts | 14 +++++ .../generated/src/operations/callDialog.ts | 5 +- .../src/operationsInterfaces/callDialog.ts | 5 +- .../src/utli/converters.ts | 23 +++++++ .../swagger/README.md | 2 +- .../test/callAutomationClient.spec.ts | 63 +++++++++++++++++++ 9 files changed, 123 insertions(+), 9 deletions(-) diff --git a/sdk/communication/communication-call-automation/review/communication-call-automation.api.md b/sdk/communication/communication-call-automation/review/communication-call-automation.api.md index 0e9d28d0adb7..a366dac240bd 100644 --- a/sdk/communication/communication-call-automation/review/communication-call-automation.api.md +++ b/sdk/communication/communication-call-automation/review/communication-call-automation.api.md @@ -113,6 +113,7 @@ export class CallAutomationClient { // @public export interface CallAutomationClientOptions extends CommonClientOptions { + opsSourceIdentity?: MicrosoftTeamsAppIdentifier; sourceIdentity?: CommunicationUserIdentifier; } diff --git a/sdk/communication/communication-call-automation/src/callAutomationClient.ts b/sdk/communication/communication-call-automation/src/callAutomationClient.ts index 71b43e879940..a5cfb3ff7849 100644 --- a/sdk/communication/communication-call-automation/src/callAutomationClient.ts +++ b/sdk/communication/communication-call-automation/src/callAutomationClient.ts @@ -7,6 +7,7 @@ import type { InternalPipelineOptions } from "@azure/core-rest-pipeline"; import type { CommunicationIdentifier, CommunicationUserIdentifier, + MicrosoftTeamsAppIdentifier, } from "@azure/communication-common"; import { parseClientArguments, isKeyCredential } from "@azure/communication-common"; import { logger } from "./models/logger"; @@ -14,6 +15,7 @@ import type { AnswerCallRequest, CallAutomationApiClient, CommunicationUserIdentifierModel, + MicrosoftTeamsAppIdentifierModel, CreateCallRequest, RedirectCallRequest, RejectCallRequest, @@ -34,6 +36,7 @@ import { communicationIdentifierModelConverter, communicationUserIdentifierConverter, communicationUserIdentifierModelConverter, + microsoftTeamsAppIdentifierModelConverter, phoneNumberIdentifierConverter, PhoneNumberIdentifierModelConverter, } from "./utli/converters"; @@ -49,6 +52,11 @@ export interface CallAutomationClientOptions extends CommonClientOptions { * The identifier of the source of the call for call creating/answering/inviting operation. */ sourceIdentity?: CommunicationUserIdentifier; + /** + * The identifier of the One Phone System bot for call creating operation. + * Should be mutually exclusive with sourceIdentity. + */ + opsSourceIdentity?: MicrosoftTeamsAppIdentifier; } /** @@ -65,6 +73,7 @@ const isCallAutomationClientOptions = (options: any): options is CallAutomationC export class CallAutomationClient { private readonly callAutomationApiClient: CallAutomationApiClient; private readonly sourceIdentity?: CommunicationUserIdentifierModel; + private readonly opsSourceIdentity?: MicrosoftTeamsAppIdentifierModel; private readonly credential: TokenCredential | KeyCredential; private readonly internalPipelineOptions: InternalPipelineOptions; private readonly callAutomationEventProcessor: CallAutomationEventProcessor; @@ -127,6 +136,7 @@ export class CallAutomationClient { ); this.sourceIdentity = communicationUserIdentifierModelConverter(options.sourceIdentity); + this.opsSourceIdentity = microsoftTeamsAppIdentifierModelConverter(options.opsSourceIdentity); } /** @@ -245,6 +255,7 @@ export class CallAutomationClient { ): Promise { const request: CreateCallRequest = { source: this.sourceIdentity, + opsSource: this.opsSourceIdentity, targets: [communicationIdentifierModelConverter(targetParticipant.targetParticipant)], callbackUri: callbackUrl, operationContext: options.operationContext, @@ -277,6 +288,7 @@ export class CallAutomationClient { ): Promise { const request: CreateCallRequest = { source: this.sourceIdentity, + opsSource: this.opsSourceIdentity, targets: targetParticipants.map((target) => communicationIdentifierModelConverter(target)), callbackUri: callbackUrl, operationContext: options.operationContext, diff --git a/sdk/communication/communication-call-automation/src/generated/src/models/index.ts b/sdk/communication/communication-call-automation/src/generated/src/models/index.ts index 8033a147ae4d..ecc485f622b0 100644 --- a/sdk/communication/communication-call-automation/src/generated/src/models/index.ts +++ b/sdk/communication/communication-call-automation/src/generated/src/models/index.ts @@ -27,6 +27,8 @@ export interface CreateCallRequest { sourceDisplayName?: string; /** The identifier of the source of the call */ source?: CommunicationUserIdentifierModel; + /** The identifier of the source in an OPS call */ + opsSource?: MicrosoftTeamsAppIdentifierModel; /** A customer set value used to track the answering of a call. */ operationContext?: string; /** The callback URI. */ @@ -194,6 +196,8 @@ export interface AnswerCallRequest { incomingCallContext: string; /** The callback uri. */ callbackUri: string; + /** Used by customer to send custom calling context to targets when answering On-Behalf-Of call */ + customCallingContext?: CustomCallingContextInternal; /** A customer set value used to track the answering of a call. */ operationContext?: string; /** Media Streaming Configuration. */ @@ -711,7 +715,7 @@ export interface StartCallRecordingRequest { pauseOnStart?: boolean; } -/** The locator used for joining or taking action on a call. */ +/** The locator used for joining or taking action on a call */ export interface CallLocator { /** The group call id */ groupCallId?: string; @@ -3064,7 +3068,6 @@ export type CallDialogStartDialogResponse = DialogStateResponse; /** Optional parameters. */ export interface CallDialogStopDialogOptionalParams extends coreClient.OperationOptions { - /** Operation callback URI. */ operationCallbackUri?: string; } diff --git a/sdk/communication/communication-call-automation/src/generated/src/models/mappers.ts b/sdk/communication/communication-call-automation/src/generated/src/models/mappers.ts index 0e121e804a3f..d5b306a6efc6 100644 --- a/sdk/communication/communication-call-automation/src/generated/src/models/mappers.ts +++ b/sdk/communication/communication-call-automation/src/generated/src/models/mappers.ts @@ -46,6 +46,13 @@ export const CreateCallRequest: coreClient.CompositeMapper = { className: "CommunicationUserIdentifierModel", }, }, + opsSource: { + serializedName: "opsSource", + type: { + name: "Composite", + className: "MicrosoftTeamsAppIdentifierModel", + }, + }, operationContext: { serializedName: "operationContext", type: { @@ -522,6 +529,13 @@ export const AnswerCallRequest: coreClient.CompositeMapper = { name: "String", }, }, + customCallingContext: { + serializedName: "customCallingContext", + type: { + name: "Composite", + className: "CustomCallingContextInternal", + }, + }, operationContext: { serializedName: "operationContext", type: { diff --git a/sdk/communication/communication-call-automation/src/generated/src/operations/callDialog.ts b/sdk/communication/communication-call-automation/src/generated/src/operations/callDialog.ts index ed2a0cf76d98..02330c389d27 100644 --- a/sdk/communication/communication-call-automation/src/generated/src/operations/callDialog.ts +++ b/sdk/communication/communication-call-automation/src/generated/src/operations/callDialog.ts @@ -52,9 +52,8 @@ export class CallDialogImpl implements CallDialog { } /** - * Stop a dialog. - * @param callConnectionId The call connection id - * @param dialogId The dialog id + * @param callConnectionId + * @param dialogId * @param options The options parameters. */ stopDialog( diff --git a/sdk/communication/communication-call-automation/src/generated/src/operationsInterfaces/callDialog.ts b/sdk/communication/communication-call-automation/src/generated/src/operationsInterfaces/callDialog.ts index 731b8415380f..4fccc524812b 100644 --- a/sdk/communication/communication-call-automation/src/generated/src/operationsInterfaces/callDialog.ts +++ b/sdk/communication/communication-call-automation/src/generated/src/operationsInterfaces/callDialog.ts @@ -31,9 +31,8 @@ export interface CallDialog { options?: CallDialogStartDialogOptionalParams, ): Promise; /** - * Stop a dialog. - * @param callConnectionId The call connection id - * @param dialogId The dialog id + * @param callConnectionId + * @param dialogId * @param options The options parameters. */ stopDialog( diff --git a/sdk/communication/communication-call-automation/src/utli/converters.ts b/sdk/communication/communication-call-automation/src/utli/converters.ts index 7cc3187111df..e24a15b791e8 100644 --- a/sdk/communication/communication-call-automation/src/utli/converters.ts +++ b/sdk/communication/communication-call-automation/src/utli/converters.ts @@ -26,6 +26,7 @@ import type { KnownCommunicationCloudEnvironmentModel, PhoneNumberIdentifierModel, CommunicationUserIdentifierModel, + MicrosoftTeamsAppIdentifierModel, } from "../generated/src"; import { KnownCommunicationIdentifierModelKind } from "../generated/src"; import type { CallParticipant } from "../models/models"; @@ -221,3 +222,25 @@ export function communicationUserIdentifierConverter( return { communicationUserId: identifier.id }; } + +/** Convert MicrosoftTeamsAppIdentifier to MicrosoftTeamsAppIdentifierModel (Internal usage class) */ +export function microsoftTeamsAppIdentifierModelConverter( + identifier: MicrosoftTeamsAppIdentifier | undefined, +): MicrosoftTeamsAppIdentifierModel | undefined { + if (!identifier || !identifier.teamsAppId) { + return undefined; + } + + return { appId: identifier.teamsAppId }; +} + +/** Convert MicrosoftTeamsAppIdentifierModel to MicrosoftTeamsAppIdentifier (Public usage class) */ +export function microsoftTeamsAppIdentifierConverter( + identifier: MicrosoftTeamsAppIdentifierModel | undefined, +): MicrosoftTeamsAppIdentifier | undefined { + if (!identifier || !identifier.appId) { + return undefined; + } + + return { teamsAppId: identifier.appId }; +} diff --git a/sdk/communication/communication-call-automation/swagger/README.md b/sdk/communication/communication-call-automation/swagger/README.md index 951fc4ae04f0..8323c607fa9f 100644 --- a/sdk/communication/communication-call-automation/swagger/README.md +++ b/sdk/communication/communication-call-automation/swagger/README.md @@ -13,7 +13,7 @@ license-header: MICROSOFT_MIT_NO_VERSION output-folder: ../src/generated tag: package-2023-10-03-preview require: - - https://github.com/Azure/azure-rest-api-specs/blob/156ff363e44f764ddd8a0a6adcd371610240ba15/specification/communication/data-plane/CallAutomation/readme.md + - https://github.com/Azure/azure-rest-api-specs/blob/be2a0fa68829fcb15c4e6b47aa6bc4bdd566c1cf/specification/communication/data-plane/CallAutomation/readme.md package-version: 1.3.0-beta.1 model-date-time-as-string: false optional-response-headers: true diff --git a/sdk/communication/communication-call-automation/test/callAutomationClient.spec.ts b/sdk/communication/communication-call-automation/test/callAutomationClient.spec.ts index cb1f5db2fd64..dee7538a6561 100644 --- a/sdk/communication/communication-call-automation/test/callAutomationClient.spec.ts +++ b/sdk/communication/communication-call-automation/test/callAutomationClient.spec.ts @@ -15,6 +15,7 @@ import { import type { CommunicationIdentifier, CommunicationUserIdentifier, + MicrosoftTeamsAppIdentifier, } from "@azure/communication-common"; import { assert } from "chai"; import type { Context } from "mocha"; @@ -39,6 +40,17 @@ import type { CreateCallEventResult, } from "../src/eventprocessor/eventResponses"; import { randomUUID } from "@azure/core-util"; +import { KnownCommunicationCloudEnvironmentModel } from "../src/generated/src"; + +function createOPSCallAutomationClient( + oPSSourceIdentity: MicrosoftTeamsAppIdentifier, +): CallAutomationClient { + const connectionString = "endpoint=https://redacted.communication.azure.com/;accesskey=redacted"; + + return new CallAutomationClient(connectionString, { + opsSourceIdentity: oPSSourceIdentity, + }); +} describe("Call Automation Client Unit Tests", () => { let targets: CommunicationIdentifier[]; @@ -132,6 +144,57 @@ describe("Call Automation Client Unit Tests", () => { .catch((error) => console.error(error)); }); + it("CreateOPSCall", async () => { + // defined dummy variables + const appId = "28:acs:redacted"; + const appCloud = KnownCommunicationCloudEnvironmentModel.Public; + const oPSSouceStub = { + teamsAppId: appId, + cloud: appCloud, + }; + + // stub an OPS CallAutomationClient + const createOPSClientStub = Sinon.stub().callsFake(() => + createOPSCallAutomationClient(oPSSouceStub), + ); + + // Use the stubbed factory function to create the client + const oPSClient: SinonStubbedInstance & CallAutomationClient = + createOPSClientStub(); + + // Explicitly stub the createCall method + oPSClient.createCall = Sinon.stub(); + + // mocks + const createCallResultMock: CreateCallResult = { + callConnectionProperties: { + source: { + rawId: appId, + teamsAppId: appId, + cloud: appCloud, + } as MicrosoftTeamsAppIdentifier, + } as CallConnectionProperties, + callConnection: {} as CallConnection, + waitForEventProcessor: async () => { + return {} as CreateCallEventResult; + }, + }; + + (oPSClient.createCall as Sinon.SinonStub).returns(Promise.resolve(createCallResultMock)); + + const promiseResult = oPSClient.createCall(target, CALL_CALLBACK_URL); + + // asserts + promiseResult + .then((result: CreateCallResult) => { + assert.isNotNull(result); + assert.isTrue(oPSClient.createCall.calledWith(target, CALL_CALLBACK_URL)); + assert.equal(result, createCallResultMock); + return; + }) + .catch((error) => console.error(error)); + }); + it("AnswerCall", async () => { // mocks const answerCallResultMock: AnswerCallResult = {