Skip to content

Commit

Permalink
feat (DEVEXP-148): Support Callouts (Custom)
Browse files Browse the repository at this point in the history
  • Loading branch information
JPPortier committed Dec 15, 2023
1 parent 6272eb9 commit 4c319a3
Show file tree
Hide file tree
Showing 15 changed files with 387 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* SMS API related models
*
* @since 1.0
*/
package com.sinch.sdk.domains.sms.models;
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import com.sinch.sdk.domains.voice.models.dto.v1.CalloutRequestDto.MethodEnum;
import com.sinch.sdk.domains.voice.models.dto.v1.ConferenceCalloutRequestConferenceDtmfOptionsDto;
import com.sinch.sdk.domains.voice.models.dto.v1.ConferenceCalloutRequestDto;
import com.sinch.sdk.domains.voice.models.dto.v1.CustomCalloutRequestDto;
import com.sinch.sdk.domains.voice.models.dto.v1.DestinationDto;
import com.sinch.sdk.domains.voice.models.dto.v1.DestinationDto.TypeEnum;
import com.sinch.sdk.domains.voice.models.dto.v1.GetCalloutResponseObjDto;
import com.sinch.sdk.domains.voice.models.dto.v1.TtsCalloutRequestDto;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParameters;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersConference;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersCustom;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersTTS;
import com.sinch.sdk.domains.voice.models.requests.ConferenceDtfmOptions;
import com.sinch.sdk.domains.voice.models.requests.Destination;
Expand All @@ -26,6 +28,9 @@ public static CalloutRequestDto convert(CalloutRequestParameters client) {
} else if (client instanceof CalloutRequestParametersTTS) {
CalloutRequestParametersTTS parameters = (CalloutRequestParametersTTS) client;
return convert(parameters);
} else if (client instanceof CalloutRequestParametersCustom) {
CalloutRequestParametersCustom parameters = (CalloutRequestParametersCustom) client;
return convert(parameters);
}
return null;
}
Expand Down Expand Up @@ -82,6 +87,23 @@ private static CalloutRequestDto convert(CalloutRequestParametersTTS client) {
return new CalloutRequestDto().method(MethodEnum.TTSCALLOUT.getValue()).ttsCallout(dto);
}

private static CalloutRequestDto convert(CalloutRequestParametersCustom client) {

CustomCalloutRequestDto dto =
new CustomCalloutRequestDto().destination(convert(client.getDestination()));

client.getCli().ifPresent(f -> dto.setCli(f.stringValue()));
client.getDtfm().ifPresent(dto::setDtmf);
client.getCustom().ifPresent(dto::setCustom);

client.getMaxDuration().ifPresent(dto::setMaxDuration);
client.getIce().ifPresent(dto::setIce);
client.getAce().ifPresent(dto::setAce);
client.getPie().ifPresent(dto::setPie);

return new CalloutRequestDto().method(MethodEnum.CUSTOMCALLOUT.getValue()).customCallout(dto);
}

private static DestinationDto convert(Destination client) {
DestinationDto dto = new DestinationDto();
if (client instanceof DestinationNumber) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Voice API related models
*
* @since 1.0
*/
package com.sinch.sdk.domains.voice.models;
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ public Optional<ConferenceDtfmOptions> getDtfmOptions() {
}

/**
* @return Max duration
* The maximum amount of time in seconds that the call will last.
*
* @return Max duration value
*/
public Optional<Integer> getMaxDuration() {
return Optional.ofNullable(maxDuration);
Expand Down Expand Up @@ -140,6 +142,36 @@ public Optional<DomainType> getDomain() {
return Optional.ofNullable(domain);
}

@Override
public String toString() {
return "CalloutRequestParametersConference{"
+ "conferenceId='"
+ conferenceId
+ '\''
+ ", dtfmOptions="
+ dtfmOptions
+ ", maxDuration="
+ maxDuration
+ ", enableAce="
+ enableAce
+ ", enableDice="
+ enableDice
+ ", enablePie="
+ enablePie
+ ", locale='"
+ locale
+ '\''
+ ", greeting='"
+ greeting
+ '\''
+ ", mohClass="
+ mohClass
+ ", domain="
+ domain
+ "} "
+ super.toString();
}

public static Builder builder() {
return new Builder();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package com.sinch.sdk.domains.voice.models.requests;

import com.sinch.sdk.domains.voice.models.CalloutMethodType;
import com.sinch.sdk.models.E164PhoneNumber;
import java.util.Optional;

/**
* The custom callout, the server initiates a call from the servers that can be controlled by
* specifying how the call should progress at each call event.
*/
public class CalloutRequestParametersCustom extends CalloutRequestParameters {

private final Integer maxDuration;
private final String ice;
private final String ace;
private final String pie;

public CalloutRequestParametersCustom(
Destination destination,
E164PhoneNumber cli,
String dtfm,
String custom,
Integer maxDuration,
String ice,
String ace,
String pie) {
super(CalloutMethodType.CUSTOM_CALLOUT, destination, cli, dtfm, custom);

this.maxDuration = maxDuration;
this.ice = ice;
this.ace = ace;
this.pie = pie;
}

/**
* The maximum amount of time in seconds that the call will last.
*
* @return Max duration value
*/
public Optional<Integer> getMaxDuration() {
return Optional.ofNullable(maxDuration);
}

/**
* You can use inline <a
* href="https://developers.sinch.com/docs/voice/api-reference/svaml/">SVAML</a> to replace a
* callback URL when using custom callouts.
*
* <p>Ensure that the JSON object is escaped correctly
*
* <p>If inline ICE SVAML is passed, exclude cli and destination properties from the customCallout
* request body. <b>Example:</b> <code>
* "{\"action\": {\"name\": \"RunMenu\",\"locale\": \"en-US\",\"menus\": [{\"id\": \"main\",\"mainPrompt\": \"#tts[ Welcome to the main menu. Press 1 for a callback or 2 for a cancel&lt;\/speak&gt;]\",\"timeoutMills\": 5000,\"options\": [ {\"dtmf\": \"1\",\"action\": \"return(callback)\"}, {\"dtmf\": \"2\",\"action\": \"return(cancel)\"}]}]}}""
* </code>
*
* @return The Incoming Call Event value
*/
public Optional<String> getIce() {
return Optional.ofNullable(ice);
}

/**
* You can use inline <a
* href="https://developers.sinch.com/docs/voice/api-reference/svaml/">SVAML</a> to replace a
* callback URL when using custom callouts.
*
* <p>Ensure that the JSON object is escaped correctly <b>Example:</b> <code>
* "{\"action\":{\"name\":\"connectPstn\",\"number\":\"46000000001\",\"maxDuration\":90}}"</code>
*
* @return The Answered Call Event value
*/
public Optional<String> getAce() {
return Optional.ofNullable(ace);
}

/**
* <b>Note:</b> PIE callbacks are not available for DATA Calls; only PSTN and SIP calls.
*
* <p>You can use inline <a
* href="https://developers.sinch.com/docs/voice/api-reference/svaml/">SVAML</a> to replace a
* callback URL when using custom callouts.
*
* <p>Ensure that the JSON object is escaped correctly. A PIE event will contain a value chosen
* from an IVR choice. Usually a PIE event wil contain a URL to a callback sever that will receive
* the choice and be able to parse it. This could result in further SVAML or some other
* application logic function.
*
* @return Prompt Input Event value
*/
public Optional<String> getPie() {
return Optional.ofNullable(pie);
}

@Override
public String toString() {
return "CalloutRequestParametersCustom{"
+ "maxDuration="
+ maxDuration
+ ", ice='"
+ ice
+ '\''
+ ", ace='"
+ ace
+ '\''
+ ", pie='"
+ pie
+ '\''
+ "} "
+ super.toString();
}

public static Builder builder() {
return new Builder();
}

public static class Builder extends CalloutRequestParameters.Builder<Builder> {

Integer maxDuration;
String ice;
String ace;
String pie;

public Builder() {
super();
}

public Builder setMaxDuration(Integer maxDuration) {
this.maxDuration = maxDuration;
return self();
}

public Builder setIce(String ice) {
this.ice = ice;
return self();
}

public Builder setAce(String ace) {
this.ace = ace;
return self();
}

public Builder setPie(String pie) {
this.pie = pie;
return self();
}

public CalloutRequestParametersCustom build() {
return new CalloutRequestParametersCustom(
destination, cli, dtfm, custom, maxDuration, ice, ace, pie);
}

@Override
protected Builder self() {
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,30 @@ public Optional<String> getPrompts() {
return Optional.ofNullable(prompts);
}

@Override
public String toString() {
return "CalloutRequestParametersTTS{"
+ "enableAce="
+ enableAce
+ ", enableDice="
+ enableDice
+ ", enablePie="
+ enablePie
+ ", locale='"
+ locale
+ '\''
+ ", text='"
+ text
+ '\''
+ ", prompts='"
+ prompts
+ '\''
+ ", domain="
+ domain
+ "} "
+ super.toString();
}

public static Builder builder() {
return new Builder();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.Arrays;
import java.util.stream.Stream;

/** Determines what DTMF mode the participant will use in the call. */
public class DtfmModeType extends EnumDynamic<String, DtfmModeType> {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Voice API requests related models
*
* @since 1.0
*/
package com.sinch.sdk.domains.voice.models.requests;
2 changes: 1 addition & 1 deletion client/src/main/com/sinch/sdk/http/HttpClientApache.java
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ private void addAuth(
.forEachRemaining(f -> requestBuilder.setHeader(f.getLeft(), f.getRight()));
return;
} else {
LOGGER.info("Ignore unknown authentication value: '" + entry + "'");
LOGGER.finest("Ignore unknown authentication value: '" + entry + "'");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.sinch.sdk.domains.voice.models.dto.v1.CalloutRequestDtoTest;
import com.sinch.sdk.domains.voice.models.dto.v1.CalloutResponseDtoTest;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersConferenceTest;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersCustomTest;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersTTSTest;
import com.sinch.sdk.models.Configuration;
import java.util.Map;
Expand Down Expand Up @@ -62,4 +63,16 @@ void callTTS() throws ApiException {
Assertions.assertThat(response)
.isEqualTo(CalloutResponseDtoTest.expectedCalloutResponseDto.getCallId());
}

@Test
void callCustom() throws ApiException {

when(api.callouts(eq(CalloutRequestDtoTest.customRequestDto)))
.thenReturn(CalloutResponseDtoTest.expectedCalloutResponseDto);

String response = service.call(CalloutRequestParametersCustomTest.customRequestParameters);

Assertions.assertThat(response)
.isEqualTo(CalloutResponseDtoTest.expectedCalloutResponseDto.getCallId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.sinch.sdk.BaseTest;
import com.sinch.sdk.domains.voice.models.dto.v1.CalloutRequestDtoTest;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersConferenceTest;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersCustomTest;
import com.sinch.sdk.domains.voice.models.requests.CalloutRequestParametersTTSTest;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -31,7 +32,17 @@ void convertTTSCallRequest() {
}

@Test
void convertConferenceCallResponse() {
void convertCustomCallRequest() {

Assertions.assertThat(
CalloutsDtoConverter.convert(
CalloutRequestParametersCustomTest.customRequestParameters))
.usingRecursiveComparison()
.isEqualTo(CalloutRequestDtoTest.customRequestDto);
}

@Test
void convertCallResponse() {

Assertions.assertThat(
CalloutsDtoConverter.convert(
Expand Down
Loading

0 comments on commit 4c319a3

Please sign in to comment.