From fb1b83da95fc18918aac82cc024ad6a855a95533 Mon Sep 17 00:00:00 2001 From: Tournier Quentin Date: Thu, 5 Jun 2025 02:32:13 +0200 Subject: [PATCH 1/3] feat(SMS-102): add otp service and models --- .../java/dev/resms/core/net/HttpMethod.java | 1 + src/main/java/dev/resms/services/otp/Otp.java | 94 +++++++++++++++++++ .../services/otp/model/CreateOtpOptions.java | 17 ++++ .../services/otp/model/CreateOtpResponse.java | 14 +++ .../services/otp/model/DeleteOtpResponse.java | 10 ++ .../dev/resms/services/otp/model/OtpCode.java | 6 ++ .../services/otp/model/VerifyOtpOptions.java | 13 +++ .../services/otp/model/VerifyOtpResponse.java | 15 +++ 8 files changed, 170 insertions(+) create mode 100644 src/main/java/dev/resms/services/otp/Otp.java create mode 100644 src/main/java/dev/resms/services/otp/model/CreateOtpOptions.java create mode 100644 src/main/java/dev/resms/services/otp/model/CreateOtpResponse.java create mode 100644 src/main/java/dev/resms/services/otp/model/DeleteOtpResponse.java create mode 100644 src/main/java/dev/resms/services/otp/model/OtpCode.java create mode 100644 src/main/java/dev/resms/services/otp/model/VerifyOtpOptions.java create mode 100644 src/main/java/dev/resms/services/otp/model/VerifyOtpResponse.java diff --git a/src/main/java/dev/resms/core/net/HttpMethod.java b/src/main/java/dev/resms/core/net/HttpMethod.java index fd75db3..7a7f9a9 100644 --- a/src/main/java/dev/resms/core/net/HttpMethod.java +++ b/src/main/java/dev/resms/core/net/HttpMethod.java @@ -4,4 +4,5 @@ public enum HttpMethod { GET, POST, + DELETE, } diff --git a/src/main/java/dev/resms/services/otp/Otp.java b/src/main/java/dev/resms/services/otp/Otp.java new file mode 100644 index 0000000..4a0f20b --- /dev/null +++ b/src/main/java/dev/resms/services/otp/Otp.java @@ -0,0 +1,94 @@ +package dev.resms.services.otp; + +import dev.resms.core.exception.ReSMSException; +import dev.resms.core.net.AbstractHttpResponse; +import dev.resms.core.net.HttpMethod; +import dev.resms.core.service.BaseService; +import dev.resms.services.otp.model.CreateOtpResponse; +import dev.resms.services.otp.model.DeleteOtpResponse; +import dev.resms.services.otp.model.VerifyOtpOptions; +import dev.resms.services.otp.model.VerifyOtpResponse; + +public class Otp extends BaseService { + private static final String CREATE_OTP_PATH = "/otp"; + private static final String VERIFY_OTP_PATH = "/otp/verify"; + private static final String DELETE_OTP_PATH = "/otp"; + + /** + * Constructs an instance of the {@code Otp} class. + * + * @param apiKey The apiKey used for authentication. + */ + public Otp(final String apiKey) { + super(apiKey); + } + + /** + * Create an OTP based on the provided OTP request + * + * @param createOtpResponse The request containing OTP details. + * @return The response indicating the status of the OTP creation. + * @throws ReSMSException If an error occurs while creating the OTP. + */ + public CreateOtpResponse create(CreateOtpResponse createOtpResponse) throws ReSMSException { + String payload = super.reSMSMapper.toJson(createOtpResponse); + + AbstractHttpResponse response = + super.httpClient.perform(CREATE_OTP_PATH, apiKey, HttpMethod.POST, payload); + + if (!response.isSuccessful()) { + throw new ReSMSException( + "Failed to create otp: " + response.getCode() + " " + response.getBody()); + } + + String responseBody = response.getBody(); + + return reSMSMapper.fromJson(responseBody, CreateOtpResponse.class); + } + + /** + * Verify an OTP based on the provided OTP verify request + * + * @param verifyOtpOptions The request containing OTP verify details. + * @return The response indicating the status of the OTP verification. + * @throws ReSMSException If an error occurs while verifying the OTP. + */ + public VerifyOtpResponse verify(VerifyOtpOptions verifyOtpOptions) throws ReSMSException { + String payload = super.reSMSMapper.toJson(verifyOtpOptions); + + AbstractHttpResponse response = + super.httpClient.perform(VERIFY_OTP_PATH, apiKey, HttpMethod.POST, payload); + + if (!response.isSuccessful()) { + throw new ReSMSException( + "Failed to create otp: " + response.getCode() + " " + response.getBody()); + } + + String responseBody = response.getBody(); + + return reSMSMapper.fromJson(responseBody, VerifyOtpResponse.class); + } + + /** + * Delete an OTP based on its id + * + * @param otpId The id of the OTP to delete. + * @return The response indicating the status of the OTP deletion. + * @throws ReSMSException If an error occurs while deleting the OTP. + */ + public DeleteOtpResponse delete(String otpId) throws ReSMSException { + String payload = "{\"otpId\": \"" + otpId + "\"}"; + + AbstractHttpResponse response = + super.httpClient.perform(DELETE_OTP_PATH, apiKey, HttpMethod.DELETE, payload); + + if (!response.isSuccessful()) { + throw new ReSMSException( + "Failed to create otp: " + response.getCode() + " " + response.getBody()); + } + + String responseBody = response.getBody(); + + return reSMSMapper.fromJson(responseBody, DeleteOtpResponse.class); + } +} diff --git a/src/main/java/dev/resms/services/otp/model/CreateOtpOptions.java b/src/main/java/dev/resms/services/otp/model/CreateOtpOptions.java new file mode 100644 index 0000000..9887476 --- /dev/null +++ b/src/main/java/dev/resms/services/otp/model/CreateOtpOptions.java @@ -0,0 +1,17 @@ +package dev.resms.services.otp.model; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class CreateOtpOptions { + private String to; + private String message; + private String senderId; + private OtpCode codeType; + private int codeLength; + private int validityMinutes; +} diff --git a/src/main/java/dev/resms/services/otp/model/CreateOtpResponse.java b/src/main/java/dev/resms/services/otp/model/CreateOtpResponse.java new file mode 100644 index 0000000..34467ad --- /dev/null +++ b/src/main/java/dev/resms/services/otp/model/CreateOtpResponse.java @@ -0,0 +1,14 @@ +package dev.resms.services.otp.model; + +import lombok.Getter; + +@Getter +public class CreateOtpResponse { + private CreateOtpResponseData data; + + @Getter + public static class CreateOtpResponseData { + private String phoneNumber; + private String expiresAt; + } +} diff --git a/src/main/java/dev/resms/services/otp/model/DeleteOtpResponse.java b/src/main/java/dev/resms/services/otp/model/DeleteOtpResponse.java new file mode 100644 index 0000000..5d5d8ce --- /dev/null +++ b/src/main/java/dev/resms/services/otp/model/DeleteOtpResponse.java @@ -0,0 +1,10 @@ +package dev.resms.services.otp.model; + +import lombok.Getter; + +@Getter +public class DeleteOtpResponse { + private String otpId; + private String phoneNumber; + private String revokedAt; +} diff --git a/src/main/java/dev/resms/services/otp/model/OtpCode.java b/src/main/java/dev/resms/services/otp/model/OtpCode.java new file mode 100644 index 0000000..c33b369 --- /dev/null +++ b/src/main/java/dev/resms/services/otp/model/OtpCode.java @@ -0,0 +1,6 @@ +package dev.resms.services.otp.model; + +public enum OtpCode { + NUMERIC, + ALPHA, +} diff --git a/src/main/java/dev/resms/services/otp/model/VerifyOtpOptions.java b/src/main/java/dev/resms/services/otp/model/VerifyOtpOptions.java new file mode 100644 index 0000000..9b92fa8 --- /dev/null +++ b/src/main/java/dev/resms/services/otp/model/VerifyOtpOptions.java @@ -0,0 +1,13 @@ +package dev.resms.services.otp.model; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class VerifyOtpOptions { + private String to; + private String code; +} diff --git a/src/main/java/dev/resms/services/otp/model/VerifyOtpResponse.java b/src/main/java/dev/resms/services/otp/model/VerifyOtpResponse.java new file mode 100644 index 0000000..2b7a391 --- /dev/null +++ b/src/main/java/dev/resms/services/otp/model/VerifyOtpResponse.java @@ -0,0 +1,15 @@ +package dev.resms.services.otp.model; + +import lombok.Getter; + +@Getter +public class VerifyOtpResponse { + private VerifyOtpResponseData data; + + @Getter + public static class VerifyOtpResponseData { + private String otpId; + private String phoneNumber; + private String verifiedAt; + } +} From d83c295e4022bbfc9a8d224755c932c650db9b91 Mon Sep 17 00:00:00 2001 From: Tournier Quentin Date: Thu, 5 Jun 2025 09:32:23 +0200 Subject: [PATCH 2/3] fix: otpResponse type --- src/main/java/dev/resms/services/otp/Otp.java | 19 +++++++------------ .../services/otp/model/CreateOtpResponse.java | 3 ++- .../services/otp/model/DeleteOtpResponse.java | 3 ++- .../services/otp/model/VerifyOtpResponse.java | 3 ++- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main/java/dev/resms/services/otp/Otp.java b/src/main/java/dev/resms/services/otp/Otp.java index 4a0f20b..e807087 100644 --- a/src/main/java/dev/resms/services/otp/Otp.java +++ b/src/main/java/dev/resms/services/otp/Otp.java @@ -4,6 +4,7 @@ import dev.resms.core.net.AbstractHttpResponse; import dev.resms.core.net.HttpMethod; import dev.resms.core.service.BaseService; +import dev.resms.services.otp.model.CreateOtpOptions; import dev.resms.services.otp.model.CreateOtpResponse; import dev.resms.services.otp.model.DeleteOtpResponse; import dev.resms.services.otp.model.VerifyOtpOptions; @@ -26,12 +27,12 @@ public Otp(final String apiKey) { /** * Create an OTP based on the provided OTP request * - * @param createOtpResponse The request containing OTP details. + * @param createOtpOptions The request containing OTP details. * @return The response indicating the status of the OTP creation. * @throws ReSMSException If an error occurs while creating the OTP. */ - public CreateOtpResponse create(CreateOtpResponse createOtpResponse) throws ReSMSException { - String payload = super.reSMSMapper.toJson(createOtpResponse); + public CreateOtpResponse create(CreateOtpOptions createOtpOptions) throws ReSMSException { + String payload = super.reSMSMapper.toJson(createOtpOptions); AbstractHttpResponse response = super.httpClient.perform(CREATE_OTP_PATH, apiKey, HttpMethod.POST, payload); @@ -41,9 +42,7 @@ public CreateOtpResponse create(CreateOtpResponse createOtpResponse) throws ReSM "Failed to create otp: " + response.getCode() + " " + response.getBody()); } - String responseBody = response.getBody(); - - return reSMSMapper.fromJson(responseBody, CreateOtpResponse.class); + return reSMSMapper.fromJson(response.getBody(), CreateOtpResponse.class); } /** @@ -64,9 +63,7 @@ public VerifyOtpResponse verify(VerifyOtpOptions verifyOtpOptions) throws ReSMSE "Failed to create otp: " + response.getCode() + " " + response.getBody()); } - String responseBody = response.getBody(); - - return reSMSMapper.fromJson(responseBody, VerifyOtpResponse.class); + return reSMSMapper.fromJson(response.getBody(), VerifyOtpResponse.class); } /** @@ -87,8 +84,6 @@ public DeleteOtpResponse delete(String otpId) throws ReSMSException { "Failed to create otp: " + response.getCode() + " " + response.getBody()); } - String responseBody = response.getBody(); - - return reSMSMapper.fromJson(responseBody, DeleteOtpResponse.class); + return reSMSMapper.fromJson(response.getBody(), DeleteOtpResponse.class); } } diff --git a/src/main/java/dev/resms/services/otp/model/CreateOtpResponse.java b/src/main/java/dev/resms/services/otp/model/CreateOtpResponse.java index 34467ad..45b3c81 100644 --- a/src/main/java/dev/resms/services/otp/model/CreateOtpResponse.java +++ b/src/main/java/dev/resms/services/otp/model/CreateOtpResponse.java @@ -1,9 +1,10 @@ package dev.resms.services.otp.model; +import dev.resms.core.model.Response; import lombok.Getter; @Getter -public class CreateOtpResponse { +public class CreateOtpResponse extends Response { private CreateOtpResponseData data; @Getter diff --git a/src/main/java/dev/resms/services/otp/model/DeleteOtpResponse.java b/src/main/java/dev/resms/services/otp/model/DeleteOtpResponse.java index 5d5d8ce..34ffe54 100644 --- a/src/main/java/dev/resms/services/otp/model/DeleteOtpResponse.java +++ b/src/main/java/dev/resms/services/otp/model/DeleteOtpResponse.java @@ -1,9 +1,10 @@ package dev.resms.services.otp.model; +import dev.resms.core.model.Response; import lombok.Getter; @Getter -public class DeleteOtpResponse { +public class DeleteOtpResponse extends Response { private String otpId; private String phoneNumber; private String revokedAt; diff --git a/src/main/java/dev/resms/services/otp/model/VerifyOtpResponse.java b/src/main/java/dev/resms/services/otp/model/VerifyOtpResponse.java index 2b7a391..e0fe935 100644 --- a/src/main/java/dev/resms/services/otp/model/VerifyOtpResponse.java +++ b/src/main/java/dev/resms/services/otp/model/VerifyOtpResponse.java @@ -1,9 +1,10 @@ package dev.resms.services.otp.model; +import dev.resms.core.model.Response; import lombok.Getter; @Getter -public class VerifyOtpResponse { +public class VerifyOtpResponse extends Response { private VerifyOtpResponseData data; @Getter From cabb3ad791142cf7209d224dde57d1aabc51423f Mon Sep 17 00:00:00 2001 From: Tournier Quentin Date: Thu, 5 Jun 2025 09:56:16 +0200 Subject: [PATCH 3/3] feat(SMS-102): add otp service to ReSMS top class --- src/main/java/dev/resms/ReSMS.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/dev/resms/ReSMS.java b/src/main/java/dev/resms/ReSMS.java index 8430d14..846c458 100644 --- a/src/main/java/dev/resms/ReSMS.java +++ b/src/main/java/dev/resms/ReSMS.java @@ -1,5 +1,6 @@ package dev.resms; +import dev.resms.services.otp.Otp; import dev.resms.services.sms.Sms; import lombok.RequiredArgsConstructor; @@ -17,4 +18,13 @@ public class ReSMS { public Sms sms() { return new Sms(apiKey); } + + /** + * Returns an Otp object that can be used to interact with the Otp service. + * + * @return An Otp object. + */ + public Otp otp() { + return new Otp(apiKey); + } }