Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sms delivery reports #6

Merged
merged 10 commits into from
Nov 10, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
*
* @since 1.0
*/
public final class Capability extends EnumDynamic<Capability> {
public final class Capability extends EnumDynamic<String, Capability> {
/** The SMS product can use the number. */
public static final Capability SMS = new Capability("SMS");

/** The Voice product can use the number. */
public static final Capability VOICE = new Capability("VOICE");

private static final EnumSupportDynamic<Capability> ENUM_SUPPORT =
private static final EnumSupportDynamic<String, Capability> ENUM_SUPPORT =
new EnumSupportDynamic<>(Capability.class, Capability::new, Arrays.asList(SMS, VOICE));

private Capability(String value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* @since 1.0
*/
public final class NumberType extends EnumDynamic<NumberType> {
public final class NumberType extends EnumDynamic<String, NumberType> {

/** Numbers that belong to a specific range. */
public static final NumberType MOBILE = new NumberType("MOBILE");
Expand All @@ -20,7 +20,7 @@ public final class NumberType extends EnumDynamic<NumberType> {
/** Numbers that are free of charge for the calling party but billed for all arriving calls. */
public static final NumberType TOLL_FREE = new NumberType("TOLL_FREE");

private static final EnumSupportDynamic<NumberType> ENUM_SUPPORT =
private static final EnumSupportDynamic<String, NumberType> ENUM_SUPPORT =
new EnumSupportDynamic<>(
NumberType.class, NumberType::new, Arrays.asList(MOBILE, LOCAL, TOLL_FREE));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
*
* @since 1.0
*/
public final class OrderBy extends EnumDynamic<OrderBy> {
public final class OrderBy extends EnumDynamic<String, OrderBy> {
/** Ordering by phoneNumber */
public static final OrderBy PHONE_NUMBER = new OrderBy("phoneNumber");
/** Ordering by displayName */
public static final OrderBy DISPLAY_NAME = new OrderBy("displayName");

private static final EnumSupportDynamic<OrderBy> ENUM_SUPPORT =
private static final EnumSupportDynamic<String, OrderBy> ENUM_SUPPORT =
new EnumSupportDynamic<>(
OrderBy.class, OrderBy::new, Arrays.asList(PHONE_NUMBER, DISPLAY_NAME));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* href="https://developers.sinch.com/docs/numbers/api-reference/error-codes/provisioning-errors/">https://developers.sinch.com/docs/numbers/api-reference/error-codes/provisioning-errors/</a>
* @since 1.0
*/
public final class ProvisioningStatus extends EnumDynamic<ProvisioningStatus> {
public final class ProvisioningStatus extends EnumDynamic<String, ProvisioningStatus> {

public static final ProvisioningStatus PROVISIONING_STATUS_UNSPECIFIED =
new ProvisioningStatus("PROVISIONING_STATUS_UNSPECIFIED");
Expand All @@ -22,7 +22,7 @@ public final class ProvisioningStatus extends EnumDynamic<ProvisioningStatus> {
public static final ProvisioningStatus UNKNOWN_DEFAULT_OPEN_API =
new ProvisioningStatus("UNKNOWN_DEFAULT_OPEN_API");

private static final EnumSupportDynamic<ProvisioningStatus> ENUM_SUPPORT =
private static final EnumSupportDynamic<String, ProvisioningStatus> ENUM_SUPPORT =
new EnumSupportDynamic<>(
ProvisioningStatus.class,
ProvisioningStatus::new,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*
* @since 1.0
*/
public final class SearchPattern extends EnumDynamic<SearchPattern> {
public final class SearchPattern extends EnumDynamic<String, SearchPattern> {
/**
* Numbers that begin with the @see NumberPattern.getPattern entered.
*
Expand All @@ -26,7 +26,7 @@ public final class SearchPattern extends EnumDynamic<SearchPattern> {
/** The number ends with the number pattern entered. */
public static final SearchPattern END = new SearchPattern("END");

private static final EnumSupportDynamic<SearchPattern> ENUM_SUPPORT =
private static final EnumSupportDynamic<String, SearchPattern> ENUM_SUPPORT =
new EnumSupportDynamic<>(
SearchPattern.class, SearchPattern::new, Arrays.asList(START, CONTAINS, END));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* href="https://developers.sinch.com/docs/numbers/api-reference/error-codes/provisioning-errors/">https://developers.sinch.com/docs/numbers/api-reference/error-codes/provisioning-errors/</a>
* @since 1.0
*/
public final class SmsErrorCode extends EnumDynamic<SmsErrorCode> {
public final class SmsErrorCode extends EnumDynamic<String, SmsErrorCode> {
public static final SmsErrorCode ERROR_CODE_UNSPECIFIED =
new SmsErrorCode("ERROR_CODE_UNSPECIFIED");
public static final SmsErrorCode INTERNAL_ERROR = new SmsErrorCode("INTERNAL_ERROR");
Expand Down Expand Up @@ -42,7 +42,7 @@ public final class SmsErrorCode extends EnumDynamic<SmsErrorCode> {
public static final SmsErrorCode UNKNOWN_DEFAULT_OPEN_API =
new SmsErrorCode("UNKNOWN_DEFAULT_OPEN_API");

private static final EnumSupportDynamic<SmsErrorCode> ENUM_SUPPORT =
private static final EnumSupportDynamic<String, SmsErrorCode> ENUM_SUPPORT =
new EnumSupportDynamic<>(
SmsErrorCode.class,
SmsErrorCode::new,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.sinch.sdk.domains.sms;

import com.sinch.sdk.core.exceptions.ApiException;
import com.sinch.sdk.domains.sms.models.DeliveryReportBatch;
import com.sinch.sdk.domains.sms.models.DeliveryReportRecipient;
import com.sinch.sdk.domains.sms.models.requests.DeliveryReportBatchGetRequestParameters;
import com.sinch.sdk.domains.sms.models.requests.DeliveryReportListRequestParameters;
import com.sinch.sdk.domains.sms.models.responses.DeliveryReportsListResponse;

/**
* Delivery reports Service
*
* <p>The REST API uses message statuses and error codes in delivery reports, which refer to the
* state of the batch and can be present in either <a
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports/#tag/Delivery-reports/operation/GetDeliveryReportByBatchId">Retrieve
* a delivery report</a> or sent as a callback.
*
* @see <a
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports">https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports</a>
* @since 1.0
*/
public interface DeliveryReportsService {

/**
* Retrieve a batch delivery report <br>
* Delivery reports can be retrieved even if no callback was requested. The difference between a
* summary and a full report is only that the full report contains the phone numbers in <a
* href="https://community.sinch.com/t5/Glossary/E-164/ta-p/7537">E.164</a> format for each status
* code.
*
* @param batchId The batch ID you received from sending a message param type param status param
* code
* @param parameters Filtering parameters
* @return Delivery report related to batchId according to filters
* @see <a
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports/#tag/Delivery-reports/operation/GetDeliveryReportByBatchId">https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports/#tag/Delivery-reports/operation/GetDeliveryReportByBatchId</a>
* @since 1.0
*/
DeliveryReportBatch get(String batchId, DeliveryReportBatchGetRequestParameters parameters)
throws ApiException;

/**
* Retrieve a recipient delivery report <br>
* A recipient delivery report contains the message status for a single recipient phone number.
*
* @param batchId The batch ID you received from sending a message param type param status param
* code
* @param recipient Phone number for which you to want to search
* @return Delivery report related to batchId according to filters
* @see <a
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports/#tag/Delivery-reports/operation/GetDeliveryReportByPhoneNumber">https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports/#tag/Delivery-reports/operation/GetDeliveryReportByPhoneNumber</a>
* @since 1.0
*/
DeliveryReportRecipient getForNumber(String batchId, String recipient) throws ApiException;

/**
* Get a list of finished delivery reports.<br>
* This operation supports pagination.
*
* @param parameters Filtering parameters
* @return Delivery report related to batchId according to filters
* @see <a
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports/#tag/Delivery-reports/operation/getDeliveryReports">https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports/#tag/Delivery-reports/operation/getDeliveryReports</a>
* @since 1.0
*/
DeliveryReportsListResponse list(DeliveryReportListRequestParameters parameters)
throws ApiException;
}
8 changes: 8 additions & 0 deletions client/src/main/com/sinch/sdk/domains/sms/SMSService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ public interface SMSService {
* @since 1.0
*/
WebHooksService webHooks();

/**
* Delivery Reports Service instance
*
* @return service instance for project
* @since 1.0
*/
DeliveryReportsService deliveryReports();
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.sinch.sdk.domains.sms;

import com.sinch.sdk.core.exceptions.ApiMappingException;
import com.sinch.sdk.domains.sms.models.webhooks.BaseDeliveryReport;
import com.sinch.sdk.domains.sms.models.BaseDeliveryReport;
import com.sinch.sdk.domains.sms.models.webhooks.BaseIncomingSMS;

/**
Expand Down Expand Up @@ -81,7 +81,7 @@ public interface WebHooksService {
* <ul>
* <li>The <code>delivery_report_sms</code> and <code>delivery_report_mms</code> types are
* documented under <b>Delivery report</b>. These are reports containing <a
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Batches/#tag/Batches/operation/SendSMS!path=0/delivery_report&t=request">either
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Batches/#tag/Batches/operation/SendSMS!path=0/delivery_report&amp;t=request">either
* a full report or summary report</a>, depending on your selection at the time the batch
* was sent.
* <li>The <code>recipient_delivery_report_sms</code> and <code>recipient_delivery_report_mms
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.sinch.sdk.domains.sms.adapters;

import com.sinch.sdk.core.exceptions.ApiException;
import com.sinch.sdk.core.http.HttpClient;
import com.sinch.sdk.core.http.HttpMapper;
import com.sinch.sdk.core.models.pagination.Page;
import com.sinch.sdk.core.models.pagination.PageToken;
import com.sinch.sdk.core.utils.EnumDynamic;
import com.sinch.sdk.core.utils.Pair;
import com.sinch.sdk.domains.sms.adapters.api.v1.DeliveryReportsApi;
import com.sinch.sdk.domains.sms.adapters.converters.DeliveryReportDtoConverter;
import com.sinch.sdk.domains.sms.models.DeliveryReportBatch;
import com.sinch.sdk.domains.sms.models.DeliveryReportRecipient;
import com.sinch.sdk.domains.sms.models.DeliveryReportType;
import com.sinch.sdk.domains.sms.models.dto.v1.DeliveryReportListDto;
import com.sinch.sdk.domains.sms.models.requests.DeliveryReportBatchGetRequestParameters;
import com.sinch.sdk.domains.sms.models.requests.DeliveryReportListRequestParameters;
import com.sinch.sdk.domains.sms.models.responses.DeliveryReportsListResponse;
import com.sinch.sdk.models.Configuration;
import java.time.Instant;
import java.util.Collection;
import java.util.stream.Collectors;

/**
* Delivery reports Service
*
* <p>The REST API uses message statuses and error codes in delivery reports, which refer to the
* state of the batch and can be present in either <a
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports/#tag/Delivery-reports/operation/GetDeliveryReportByBatchId">Retrieve
* a delivery report</a> or sent as a callback.
*
* @see <a
* href="https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports">https://developers.sinch.com/docs/sms/api-reference/sms/tag/Delivery-reports</a>
* @since 1.0
*/
public class DeliveryReportsService implements com.sinch.sdk.domains.sms.DeliveryReportsService {

private Configuration configuration;
private DeliveryReportsApi api;
Comment on lines +38 to +39
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final allows to set the variable only once anywhere, be it constructor, or another method. Does it makes sense to mark this variables as final in this context?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should yes.
But I'm facing an issue (not yet finalized) due to unit testing and mocking library: when set to final mocking lib is not able to set variables and test execution are facing null pointer.
I'll have to take time to fix this...


public DeliveryReportsService() {}

private DeliveryReportsApi getApi() {
return this.api;
}

public DeliveryReportsService(Configuration configuration, HttpClient httpClient) {
this.configuration = configuration;
this.api = new DeliveryReportsApi(httpClient, configuration.getSmsServer(), new HttpMapper());
}

public DeliveryReportBatch get(String batchId, DeliveryReportBatchGetRequestParameters parameters)
throws ApiException {

DeliveryReportBatchGetRequestParameters guardParameters =
null != parameters ? parameters : DeliveryReportBatchGetRequestParameters.builder().build();

return DeliveryReportDtoConverter.convert(
getApi()
.getDeliveryReportByBatchId(
configuration.getProjectId(),
batchId,
guardParameters.getType().map(DeliveryReportType::value).orElse(null),
guardParameters
.geStatues()
.map(f -> f.stream().map(EnumDynamic::value).collect(Collectors.joining(",")))
.orElse(null),
guardParameters
.getCodes()
.map(f -> f.stream().map(Object::toString).collect(Collectors.joining(",")))
.orElse(null)));
}

public DeliveryReportRecipient getForNumber(String batchId, String recipient)
throws ApiException {
return DeliveryReportDtoConverter.convert(
getApi().getDeliveryReportByPhoneNumber(configuration.getProjectId(), batchId, recipient));
}

public DeliveryReportsListResponse list(DeliveryReportListRequestParameters parameters)
throws ApiException {
DeliveryReportListRequestParameters guardParameters =
null != parameters ? parameters : DeliveryReportListRequestParameters.builder().build();

DeliveryReportListDto response =
getApi()
.getDeliveryReports(
configuration.getProjectId(),
guardParameters.getPage().orElse(null),
guardParameters.getPageSize().orElse(null),
guardParameters.getStartDate().map(Instant::toString).orElse(null),
guardParameters.getEndDate().map(Instant::toString).orElse(null),
guardParameters
.getStatuses()
.map(f -> f.stream().map(EnumDynamic::value).collect(Collectors.joining(",")))
.orElse(null),
guardParameters
.getCodes()
.map(f -> f.stream().map(Object::toString).collect(Collectors.joining(",")))
.orElse(null),
guardParameters.getClientReference().orElse(null));

Pair<Collection<DeliveryReportRecipient>, PageToken<Integer>> content =
DeliveryReportDtoConverter.convert(response);

return new DeliveryReportsListResponse(
this, new Page<>(guardParameters, content.getLeft(), content.getRight()));
}
}
11 changes: 11 additions & 0 deletions client/src/main/com/sinch/sdk/domains/sms/adapters/SMSService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.sinch.sdk.core.http.HttpClient;
import com.sinch.sdk.domains.sms.BatchesService;
import com.sinch.sdk.domains.sms.DeliveryReportsService;
import com.sinch.sdk.domains.sms.WebHooksService;
import com.sinch.sdk.models.Configuration;

Expand All @@ -11,6 +12,7 @@ public class SMSService implements com.sinch.sdk.domains.sms.SMSService {
private final HttpClient httpClient;
private BatchesService batches;
private WebHooksService webHooks;
private DeliveryReportsService deliveryReports;

public SMSService(Configuration configuration, HttpClient httpClient) {
this.configuration = configuration;
Expand All @@ -33,4 +35,13 @@ public WebHooksService webHooks() {
}
return this.webHooks;
}

@Override
public DeliveryReportsService deliveryReports() {
if (null == this.deliveryReports) {
this.deliveryReports =
new com.sinch.sdk.domains.sms.adapters.DeliveryReportsService(configuration, httpClient);
}
return this.deliveryReports;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
import com.sinch.sdk.core.exceptions.ApiMappingException;
import com.sinch.sdk.core.utils.StringUtil;
import com.sinch.sdk.core.utils.databind.Mapper;
import com.sinch.sdk.domains.sms.models.webhooks.BaseDeliveryReport;
import com.sinch.sdk.domains.sms.adapters.converters.DeliveryReportDtoConverter;
import com.sinch.sdk.domains.sms.models.BaseDeliveryReport;
import com.sinch.sdk.domains.sms.models.dto.v1.DeliveryReportDto;
import com.sinch.sdk.domains.sms.models.dto.v1.DeliveryReportDto.TypeEnum;
import com.sinch.sdk.domains.sms.models.dto.v1.RecipientDeliveryReportDto;
import com.sinch.sdk.domains.sms.models.webhooks.BaseIncomingSMS;
import java.util.Objects;

public class WebHooksService implements com.sinch.sdk.domains.sms.WebHooksService {

Expand All @@ -26,12 +31,27 @@ public BaseIncomingSMS<?> incomingSMS(String jsonPayload) throws ApiMappingExcep
@Override
public BaseDeliveryReport deliveryReport(String jsonPayload) throws ApiMappingException {
try {
BaseDeliveryReport generic =
Mapper.getInstance().readValue(jsonPayload, BaseDeliveryReport.class);
if (null == generic && !StringUtil.isEmpty(jsonPayload)) {
throw new ApiMappingException(jsonPayload, null);
// Can we convert payload to Recipient DeliveryReport or Batch Delivery Report ?
RecipientDeliveryReportDto recipient =
Mapper.getInstance().readValue(jsonPayload, RecipientDeliveryReportDto.class);
if (null != recipient
&& (Objects.equals(
recipient.getType(), RecipientDeliveryReportDto.TypeEnum.MMS.getValue())
|| Objects.equals(
recipient.getType(), RecipientDeliveryReportDto.TypeEnum.SMS.getValue()))) {
return DeliveryReportDtoConverter.convert(recipient);
}
return generic;

DeliveryReportDto batch =
Mapper.getInstance().readValue(jsonPayload, DeliveryReportDto.class);
if (null != batch
&& (Objects.equals(batch.getType(), TypeEnum.MMS.getValue())
|| Objects.equals(batch.getType(), TypeEnum.SMS.getValue()))) {
return DeliveryReportDtoConverter.convert(batch);
}

throw new ApiMappingException(jsonPayload, null);

} catch (JsonProcessingException e) {
throw new ApiMappingException(jsonPayload, e);
}
Expand Down
Loading