From 4e41c0c5b5a931b06cf1e448c4ed00d2f9d69dd0 Mon Sep 17 00:00:00 2001 From: Aivis Olsteins Date: Wed, 23 Nov 2022 13:31:54 +0000 Subject: [PATCH 01/99] Voice call flow optional maxDuration --- .../com/messagebird/objects/voicecalls/VoiceCallFlow.java | 8 ++++++++ api/src/test/java/com/messagebird/TestUtil.java | 1 + examples/src/main/java/ExampleSendVoiceCall.java | 1 + 3 files changed, 10 insertions(+) diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlow.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlow.java index 9554ac58..53130c77 100644 --- a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlow.java +++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCallFlow.java @@ -23,6 +23,9 @@ public class VoiceCallFlow implements Serializable { @JsonProperty("default") private boolean defaultCall; + @JsonProperty("maxDuration") + private Integer maxDuration; + private Date createdAt; private Date updatedAt; @@ -71,6 +74,10 @@ public void setDefaultCall(boolean defaultCall) { this.defaultCall = defaultCall; } + public Integer getMaxDuration() { return maxDuration; } + + public void setMaxDuration(Integer maxDuration) { this.maxDuration = maxDuration; } + public Date getCreatedAt() { return createdAt; } @@ -103,6 +110,7 @@ public String toString() { ", record=" + record + ", steps=" + steps + ", default=" + defaultCall + + ", maxDuration=" + maxDuration + ", createdAt=" + createdAt + ", updatedAt=" + updatedAt + '}'; diff --git a/api/src/test/java/com/messagebird/TestUtil.java b/api/src/test/java/com/messagebird/TestUtil.java index e3852308..1c3f5c07 100644 --- a/api/src/test/java/com/messagebird/TestUtil.java +++ b/api/src/test/java/com/messagebird/TestUtil.java @@ -30,6 +30,7 @@ static VoiceCall createVoiceCall(String destination) { final VoiceCallFlow voiceCallFlow = new VoiceCallFlow(); VoiceStep voiceStep = new VoiceStep(); voiceStep.setAction("say"); + voiceCallFlow.setMaxDuration(28800); final VoiceStepOption voiceStepOption = new VoiceStepOption(); voiceStepOption.setPayload("This is a journey into sound. Good bye!"); diff --git a/examples/src/main/java/ExampleSendVoiceCall.java b/examples/src/main/java/ExampleSendVoiceCall.java index c61fddd0..13381ca9 100644 --- a/examples/src/main/java/ExampleSendVoiceCall.java +++ b/examples/src/main/java/ExampleSendVoiceCall.java @@ -46,6 +46,7 @@ public static void main(String[] args) { voiceStep.setOptions(voiceStepOption); voiceCallFlow.setSteps(Collections.singletonList(voiceStep)); + voiceCallFlow.setMaxDuration(28800); voiceCall.setCallFlow(voiceCallFlow); //Sending request to client final VoiceCallResponse response = messageBirdClient.sendVoiceCall(voiceCall); From b616084bf5b9f4ea0489df42f42dd64c8b59b3ab Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 24 Nov 2022 11:37:20 +0100 Subject: [PATCH 02/99] new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 2208a7c9..afb138cf 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.1.1 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 56314ab8..ab7fb34c 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "5.1.1"; + private final String clientVersion = "5.1.2"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 91323182..5081bea0 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 5.1.1 + 5.1.2 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 5.1.1 + 5.1.2 compile From ae6ac2ee7e6325ad95d4968dc7892493dc9664ce Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 24 Nov 2022 11:38:29 +0100 Subject: [PATCH 03/99] [maven-release-plugin] prepare release v5.1.2 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index afb138cf..8a61cbd9 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.1.2-SNAPSHOT @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v5.1.2 From 7bc982aed171c4aa84cdb7c554ab9aa54952830c Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 24 Nov 2022 11:38:33 +0100 Subject: [PATCH 04/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 8a61cbd9..37752bf5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.1.2 @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v5.1.2 + HEAD From b01905e52ae257ff29a481f1814938a39ec6fc68 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 24 Nov 2022 22:23:25 +0100 Subject: [PATCH 05/99] new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 37752bf5..574f1379 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.1.3-SNAPSHOT From 507d49af680570aae7d3f96778a21d4f3f961e9c Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 2 Dec 2022 10:44:15 +0100 Subject: [PATCH 06/99] removed objectmapper serialization feature and updated Language enum class --- .../com/messagebird/MessageBirdServiceImpl.java | 1 - .../java/com/messagebird/objects/Language.java | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index ab7fb34c..2ee65699 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -590,7 +590,6 @@ public

HttpURLConnection getConnection(final String serviceUrl, final P body connection.setRequestProperty("Content-Type", "application/json"); ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(Include.NON_NULL); - mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); // Specifically set the date format for POST requests so scheduled // messages and other things relying on specific date formats don't // fail when sending. diff --git a/api/src/main/java/com/messagebird/objects/Language.java b/api/src/main/java/com/messagebird/objects/Language.java index 9fedb2f2..ccb63351 100644 --- a/api/src/main/java/com/messagebird/objects/Language.java +++ b/api/src/main/java/com/messagebird/objects/Language.java @@ -1,5 +1,7 @@ package com.messagebird.objects; +import com.fasterxml.jackson.annotation.JsonValue; + /** * Created by faizan on 09/12/15. */ @@ -25,13 +27,21 @@ public enum Language { PT_BR("pt-br"), RO_RO("ro-ro"); - private String code; + final String code; Language(String code) { this.code = code; } + @JsonValue + public String getCode() { + return code; + } + + @Override public String toString() { - return this.code; + return "Language{" + + "code='" + code + '\'' + + '}'; } } From bd91eb76e5621def75e60da2db9ae51a5706aef3 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 2 Dec 2022 10:59:10 +0100 Subject: [PATCH 07/99] new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 574f1379..6759f94f 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.1.2 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 2ee65699..c15a2e3e 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "5.1.2"; + private final String clientVersion = "5.3.0"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 5081bea0..e656f597 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 5.1.2 + 5.3.0 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 5.1.2 + 5.3.0 compile From 76556c8d89edb473efffdf47246c7e14fc0a0f29 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 2 Dec 2022 11:00:32 +0100 Subject: [PATCH 08/99] [maven-release-plugin] prepare release v5.3.0 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 6759f94f..1da18cf1 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.0-SNAPSHOT @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v5.3.0 From 881064e8baf9426802bfd0d74d653bddd050d47e Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 2 Dec 2022 11:00:37 +0100 Subject: [PATCH 09/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 1da18cf1..c3102b86 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.0 @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v5.3.0 + HEAD From eee5ef8922d705861284a0ffee72df5d61b32463 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 2 Dec 2022 17:05:58 +0100 Subject: [PATCH 10/99] new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index c3102b86..6de456fb 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.1-SNAPSHOT From 6cfe2e7351ed3bc33ece92fbab046c4e9f707a65 Mon Sep 17 00:00:00 2001 From: Daniel Morales Date: Fri, 9 Dec 2022 11:43:33 +0000 Subject: [PATCH 11/99] Added the two new template status DISABLED and PAUSED --- .../java/com/messagebird/objects/integrations/HSMStatus.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMStatus.java b/api/src/main/java/com/messagebird/objects/integrations/HSMStatus.java index fa179b0f..1b1980f1 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMStatus.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMStatus.java @@ -16,7 +16,9 @@ public enum HSMStatus { PENDING("PENDING"), REJECTED("REJECTED"), PENDING_DELETION("PENDING_DELETION"), - DELETED("DELETED"); + DELETED("DELETED"), + DISABLED("DISABLED"), + PAUSED("PAUSED"); private final String status; From f8599d46c6c4a4a87a9be152afe7a936b59b075c Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 9 Dec 2022 13:36:32 +0100 Subject: [PATCH 12/99] new release with HSM template changes --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 6de456fb..c3102b86 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.0 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index c15a2e3e..13b4bc95 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "5.3.0"; + private final String clientVersion = "5.3.1"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index e656f597..a78c2f6e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 5.3.0 + 5.3.1 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 5.3.0 + 5.3.1 compile From bcc8653fc3bcd416b20fc61c5cd14a1473334717 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 9 Dec 2022 13:38:00 +0100 Subject: [PATCH 13/99] [maven-release-plugin] prepare release v5.3.1 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index c3102b86..6afbfd2a 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.1-SNAPSHOT @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v5.3.1 From 5449d58da8a5e83bfb0e1c47daf729779418fac0 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 9 Dec 2022 13:38:04 +0100 Subject: [PATCH 14/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 6afbfd2a..1c0e436e 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.1 @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v5.3.1 + HEAD From 5b00aa09a5a931dd1eb1cf01e5134041dcb0b681 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 12 Dec 2022 09:25:58 +0100 Subject: [PATCH 15/99] new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 1c0e436e..650fa9ca 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.2-SNAPSHOT From 29461f076061302effabc7b6a6975d212d612608 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 16 Mar 2023 15:38:21 +0100 Subject: [PATCH 16/99] added json ignore to disable setting webhook --- .../java/com/messagebird/objects/voicecalls/VoiceCall.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java index 8ece36ec..816e1f12 100644 --- a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java +++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java @@ -63,10 +63,12 @@ public Webhook getWebhook() { return webhook; } + @JsonIgnore public void setWebhook(String url) { this.setWebhook(url, null); } + @JsonIgnore public void setWebhook(String url, String token) { this.webhook.setUrl(url); this.webhook.setToken(token); @@ -102,7 +104,6 @@ public String toString() { "source='" + source + '\'' + ", destination='" + destination + '\'' + ", callFlow=" + callFlow + - ", webhook=" + webhook + '}'; } } From 6a7d304511e0d6c4cea6fca1b375994db00d0d2b Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 17 Mar 2023 10:41:54 +0100 Subject: [PATCH 17/99] updated --- .../main/java/com/messagebird/objects/voicecalls/VoiceCall.java | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java index 816e1f12..573b42be 100644 --- a/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java +++ b/api/src/main/java/com/messagebird/objects/voicecalls/VoiceCall.java @@ -104,6 +104,7 @@ public String toString() { "source='" + source + '\'' + ", destination='" + destination + '\'' + ", callFlow=" + callFlow + + ", webhook=" + webhook + '}'; } } From df495e98e30966403e4500694f53234084a5a63d Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 17 Mar 2023 10:48:16 +0100 Subject: [PATCH 18/99] new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 650fa9ca..1c0e436e 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.1 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 13b4bc95..13ecc56e 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "5.3.1"; + private final String clientVersion = "5.3.2"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index a78c2f6e..24c63c7a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 5.3.1 + 5.3.2 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 5.3.1 + 5.3.2 compile From 4c73809b81b0f1651ba1beb659d8a26cf7835c91 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 17 Mar 2023 10:51:04 +0100 Subject: [PATCH 19/99] [maven-release-plugin] prepare release v5.3.2 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 1c0e436e..bc74d0bd 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.2-SNAPSHOT @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v5.3.2 From 6b2bdfa8af6d5e459899ecdd5d4dcac9e4aeac38 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 17 Mar 2023 10:51:09 +0100 Subject: [PATCH 20/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index bc74d0bd..a07eb2e7 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.2 @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v5.3.2 + HEAD From 52c02b198aa4ed8d20c499bc34221f385b48bd3f Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 17 Mar 2023 11:31:41 +0100 Subject: [PATCH 21/99] updated --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index a07eb2e7..92f912fb 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.3-SNAPSHOT From d9854473ab885a932dd0349b19150383a0b5ed59 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Tue, 21 Mar 2023 12:16:11 -0400 Subject: [PATCH 22/99] Make `MessageBirdClient#getVerifyObject` public --- api/src/main/java/com/messagebird/MessageBirdClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/messagebird/MessageBirdClient.java b/api/src/main/java/com/messagebird/MessageBirdClient.java index 276ba3c8..be7a8fa5 100644 --- a/api/src/main/java/com/messagebird/MessageBirdClient.java +++ b/api/src/main/java/com/messagebird/MessageBirdClient.java @@ -470,7 +470,7 @@ public Verify verifyToken(String id, String token) throws NotFoundException, Gen * @throws UnauthorizedException if client is unauthorized * @throws GeneralException general exception */ - Verify getVerifyObject(String id) throws NotFoundException, GeneralException, UnauthorizedException { + public Verify getVerifyObject(String id) throws NotFoundException, GeneralException, UnauthorizedException { if (id == null || id.isEmpty()) { throw new IllegalArgumentException("ID cannot be empty for verify"); } From da083253d51a05d00b08916b164d32b023131408 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 27 Mar 2023 18:17:35 +0200 Subject: [PATCH 23/99] new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 92f912fb..a07eb2e7 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.2 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 13ecc56e..85d169fb 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "5.3.2"; + private final String clientVersion = "5.3.3"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 24c63c7a..8ca96bbb 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 5.3.2 + 5.3.3 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 5.3.2 + 5.3.3 compile From c8ab481596f757a4160be0f0f63bb416ac8253af Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 27 Mar 2023 18:20:28 +0200 Subject: [PATCH 24/99] [maven-release-plugin] prepare release v5.3.3 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index a07eb2e7..922f2822 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.3-SNAPSHOT @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v5.3.3 From 8e4287fbfd920bcc7a9b2bbc1705a964b31e5865 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 27 Mar 2023 18:20:32 +0200 Subject: [PATCH 25/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 922f2822..5bcc495f 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.3 @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v5.3.3 + HEAD From 6ea1fe172e853bc648587cfe166cd9654f617efc Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 28 Mar 2023 09:19:24 +0200 Subject: [PATCH 26/99] new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 5bcc495f..0d2ab9f2 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.4-SNAPSHOT From ff3460343ec2dad52d9201ed49f11754b2a332ec Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Wed, 5 Apr 2023 10:43:52 -0400 Subject: [PATCH 27/99] Represent prices as `BigDecimal` --- .../main/java/com/messagebird/objects/MessageResponse.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/messagebird/objects/MessageResponse.java b/api/src/main/java/com/messagebird/objects/MessageResponse.java index 91d4d6da..aa104e52 100644 --- a/api/src/main/java/com/messagebird/objects/MessageResponse.java +++ b/api/src/main/java/com/messagebird/objects/MessageResponse.java @@ -3,6 +3,7 @@ import org.jetbrains.annotations.Nullable; import java.io.Serializable; +import java.math.BigDecimal; import java.math.BigInteger; import java.util.Date; import java.util.List; @@ -382,7 +383,7 @@ static public class Price implements Serializable { private static final long serialVersionUID = -4104837036540050532L; - private float amount; + private BigDecimal amount; private String currency; public Price() { @@ -397,6 +398,10 @@ public String toString() { } public float getAmount() { + return amount.floatValue(); + } + + public BigDecimal getAmountDecimal() { return amount; } From 73609399c9679a2dc2db878d3241fcceadd98ad2 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 7 Apr 2023 16:46:35 +0200 Subject: [PATCH 28/99] preparation of a new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 0d2ab9f2..5bcc495f 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.3 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 85d169fb..45e0548d 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "5.3.3"; + private final String clientVersion = "5.3.4"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 8ca96bbb..b5c54efa 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 5.3.3 + 5.3.4 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 5.3.3 + 5.3.4 compile From d685f52ab28c2fa12cb77694e022fc94946c6d1a Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 7 Apr 2023 16:48:31 +0200 Subject: [PATCH 29/99] [maven-release-plugin] prepare release v5.3.4 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 5bcc495f..338bc5d6 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.4-SNAPSHOT @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v5.3.4 From b4c87886675afdedb03fc511b920006697830869 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 7 Apr 2023 16:48:35 +0200 Subject: [PATCH 30/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 338bc5d6..871c4840 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.4 @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v5.3.4 + HEAD From 420d72cb2cf31b0bbd2dabb363b29e250c6d9a4f Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 7 Apr 2023 17:27:43 +0200 Subject: [PATCH 31/99] updated --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 871c4840..081e6601 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.5-SNAPSHOT From 9b5503c8c62f1b4387bcb79724aa522771987d65 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 8 May 2023 16:17:14 +0200 Subject: [PATCH 32/99] HSM Category Updated --- .../com/messagebird/objects/integrations/HSMCategory.java | 4 ++-- api/src/test/java/com/messagebird/TestUtil.java | 4 ++-- examples/src/main/java/ExampleCreateTemplate.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMCategory.java b/api/src/main/java/com/messagebird/objects/integrations/HSMCategory.java index c88d974b..3edb1db9 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMCategory.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMCategory.java @@ -11,8 +11,8 @@ */ public enum HSMCategory { - OTP("OTP"), - TRANSACTIONAL("TRANSACTIONAL"), + AUTHENTICATION("AUTHENTICATION"), + UTILITY("UTILITY"), MARKETING("MARKETING"); private final String category; diff --git a/api/src/test/java/com/messagebird/TestUtil.java b/api/src/test/java/com/messagebird/TestUtil.java index 1c3f5c07..29744ba5 100644 --- a/api/src/test/java/com/messagebird/TestUtil.java +++ b/api/src/test/java/com/messagebird/TestUtil.java @@ -305,7 +305,7 @@ public static TemplateResponse createWhatsAppTemplateResponse(final String templ final TemplateResponse templateResponse = new TemplateResponse(); templateResponse.setName(templateName); templateResponse.setLanguage(language); - templateResponse.setCategory(HSMCategory.OTP); + templateResponse.setCategory(HSMCategory.AUTHENTICATION); templateResponse.setStatus(HSMStatus.NEW); templateResponse.setCreatedAt(new Date()); templateResponse.setUpdatedAt(new Date()); @@ -327,7 +327,7 @@ public static Template createWhatsAppTemplate(final String templateName, final S final Template template = new Template(); template.setName(templateName); template.setLanguage(language); - template.setCategory(HSMCategory.OTP); + template.setCategory(HSMCategory.AUTHENTICATION); final List components = new ArrayList<>(); components.add(createHSMComponentHeader()); diff --git a/examples/src/main/java/ExampleCreateTemplate.java b/examples/src/main/java/ExampleCreateTemplate.java index 9e8a1e96..336340a6 100644 --- a/examples/src/main/java/ExampleCreateTemplate.java +++ b/examples/src/main/java/ExampleCreateTemplate.java @@ -86,7 +86,7 @@ public static void main(String[] args) { template.setLanguage("en_US"); template.setWABAID(args[2]); template.setComponents(components); - template.setCategory(HSMCategory.OTP); + template.setCategory(HSMCategory.AUTHENTICATION); try { TemplateResponse response = messageBirdClient.createWhatsAppTemplate(template); From c78199f8b9e5c0ba5983881787bc01226f3e5ed5 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 8 May 2023 16:22:01 +0200 Subject: [PATCH 33/99] new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 081e6601..d13082e0 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 5.3.4 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 45e0548d..6d8e69c7 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "5.3.4"; + private final String clientVersion = "6.0.0"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index b5c54efa..7416aedc 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 5.3.4 + 6.0.0 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 5.3.4 + 6.0.0 compile From 7dcae2d371c61505fdac751d57c97446e1c01a08 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 8 May 2023 16:24:09 +0200 Subject: [PATCH 34/99] [maven-release-plugin] prepare release v6.0.0 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index d13082e0..99b27149 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.0.0-SNAPSHOT @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v6.0.0 From 53c79541a5a126deb86aec0c2d0e6ae45a5169d5 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 8 May 2023 16:24:14 +0200 Subject: [PATCH 35/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 99b27149..05cfe86e 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.0.0 @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v6.0.0 + HEAD From 22c39cdaff814ce02fbcfbb624d9c939a63abf1a Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 8 May 2023 17:35:15 +0200 Subject: [PATCH 36/99] new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 05cfe86e..6ace8cc1 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.0.1-SNAPSHOT From 99bf12976404544e9b2b65056bcb956074a33919 Mon Sep 17 00:00:00 2001 From: "Daniel A. Morales" Date: Tue, 13 Jun 2023 21:00:12 +0100 Subject: [PATCH 37/99] Added support to create and read the OTP authentification template --- .../objects/integrations/HSMComponent.java | 23 ++- .../integrations/HSMComponentButton.java | 192 +++++++++++------- .../integrations/HSMComponentButtonType.java | 3 +- .../integrations/HSMOTPButtonType.java | 38 ++++ .../main/java/ExampleCreateAuthTemplate.java | 69 +++++++ 5 files changed, 248 insertions(+), 77 deletions(-) create mode 100644 api/src/main/java/com/messagebird/objects/integrations/HSMOTPButtonType.java create mode 100644 examples/src/main/java/ExampleCreateAuthTemplate.java diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java index 51b7efba..ccda2075 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java @@ -1,5 +1,7 @@ package com.messagebird.objects.integrations; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; /** @@ -13,7 +15,11 @@ public class HSMComponent { private HSMComponentType type; private HSMComponentFormat format; private String text; - private List buttons; + @JsonProperty("add_security_recommendation") + private Boolean addSecurityRecommendation; + @JsonProperty("code_expiration_minutes") + private Integer codeExpirationMinutes; + private List buttons; private HSMExample example; public HSMComponentType getType() { @@ -56,6 +62,21 @@ public void setExample(HSMExample example) { this.example = example; } + public Boolean getAddSecurityRecommendation() { + return addSecurityRecommendation; + } + + public void setAddSecurityRecommendation(Boolean addSecurityRecommendation) { + this.addSecurityRecommendation = addSecurityRecommendation; + } + + public Integer getCodeExpirationMinutes() { + return codeExpirationMinutes; + } + + public void setCodeExpirationMinutes(Integer codeExpirationMinutes) { + this.codeExpirationMinutes = codeExpirationMinutes; + } @Override public String toString() { return "HSMComponent{" + diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java index 6438f79e..9bb4ffb1 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java @@ -1,5 +1,7 @@ package com.messagebird.objects.integrations; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; /** @@ -10,79 +12,119 @@ */ public class HSMComponentButton { - private HSMComponentButtonType type; - private String text; - private String url; - private String phone_number; - private List example; - - public HSMComponentButtonType getType() { - return type; - } - - public void setType(HSMComponentButtonType type) { - this.type = type; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getPhone_number() { - return phone_number; - } - - public void setPhone_number(String phone_number) { - this.phone_number = phone_number; - } - - public List getExample() { - return example; - } - - public void setExample(List example) { - this.example = example; - } - - @Override - public String toString() { - return "HSMComponentButton{" + - "type=" + type + - ", text='" + text + '\'' + - ", url='" + url + '\'' + - ", phone_number='" + phone_number + '\'' + - ", example=" + example + - '}'; - } - - /** - * Check if example field is able to use. - * - * @throws IllegalArgumentException Occurs if button type is not {@code URL} or {@code QUICK_REPLY}. - */ - public void validateButtonExample() throws IllegalArgumentException { - final boolean isExampleEmpty = this.example == null || this.example.isEmpty(); - final boolean isNotProperType = !(this.type.equals(HSMComponentButtonType.URL) - || this.type.equals(HSMComponentButtonType.QUICK_REPLY)); - - if (isExampleEmpty) { - return; - } - - if (isNotProperType) { - throw new IllegalArgumentException("An example field in HSMComponentButton is available for only URL or QUICK_REPLY button types."); - } - } + private HSMComponentButtonType type; + private String text; + private String url; + private String phone_number; + private List example; + + //fields used by the authentification template + @JsonProperty("otp_type") + private HSMOTPButtonType otpType; + @JsonProperty("autofill_text") + private String autofillText; + @JsonProperty("package_name") + private String packageName; + @JsonProperty("signature_hash") + private String signatureHash; + + public HSMComponentButtonType getType() { + return type; + } + + public void setType(HSMComponentButtonType type) { + this.type = type; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getPhone_number() { + return phone_number; + } + + public void setPhone_number(String phone_number) { + this.phone_number = phone_number; + } + + public List getExample() { + return example; + } + + public void setExample(List example) { + this.example = example; + } + public HSMOTPButtonType getOtpType() { + return otpType; + } + + public void setOtpType(HSMOTPButtonType otpType) { + this.otpType = otpType; + } + + public String getAutofillText() { + return autofillText; + } + + public void setAutofillText(String autofillText) { + this.autofillText = autofillText; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getSignatureHash() { + return signatureHash; + } + + public void setSignatureHash(String signatureHash) { + this.signatureHash = signatureHash; + } + @Override + public String toString() { + return "HSMComponentButton{" + + "type=" + type + + ", text='" + text + '\'' + + ", url='" + url + '\'' + + ", phone_number='" + phone_number + '\'' + + ", example=" + example + + '}'; + } + + /** + * Check if example field is able to use. + * + * @throws IllegalArgumentException Occurs if button type is not {@code URL} or {@code QUICK_REPLY}. + */ + public void validateButtonExample() throws IllegalArgumentException { + final boolean isExampleEmpty = this.example == null || this.example.isEmpty(); + final boolean isNotProperType = !(this.type.equals(HSMComponentButtonType.URL) + || this.type.equals(HSMComponentButtonType.QUICK_REPLY)); + + if (isExampleEmpty) { + return; + } + + if (isNotProperType) { + throw new IllegalArgumentException("An example field in HSMComponentButton is available for only URL or QUICK_REPLY button types."); + } + } } diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java index 937f6baf..5029fc73 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java @@ -13,7 +13,8 @@ public enum HSMComponentButtonType { PHONE_NUMBER("PHONE_NUMBER"), URL("URL"), - QUICK_REPLY("QUICK_REPLY"); + QUICK_REPLY("QUICK_REPLY"), + OTP("OTP"); private final String type; diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMOTPButtonType.java b/api/src/main/java/com/messagebird/objects/integrations/HSMOTPButtonType.java new file mode 100644 index 00000000..499ef1f3 --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMOTPButtonType.java @@ -0,0 +1,38 @@ +package com.messagebird.objects.integrations; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum HSMOTPButtonType { + ONE_TAP("ONE_TAP"), + COPY_CODE("COPY_CODE"); + + private final String type; + + HSMOTPButtonType(String type) { + this.type = type; + } + @JsonCreator + public static HSMOTPButtonType forValue(String value) { + for (HSMOTPButtonType OTPButtonType : HSMOTPButtonType.values()) { + if (OTPButtonType.getType().equals(value)) { + return OTPButtonType; + } + } + return null; + } + + @JsonValue + public String toJson() { + return getType(); + } + + public String getType() { + return type; + } + + @Override + public String toString() { + return getType(); + } +} diff --git a/examples/src/main/java/ExampleCreateAuthTemplate.java b/examples/src/main/java/ExampleCreateAuthTemplate.java new file mode 100644 index 00000000..31b5f415 --- /dev/null +++ b/examples/src/main/java/ExampleCreateAuthTemplate.java @@ -0,0 +1,69 @@ +import com.messagebird.MessageBirdClient; +import com.messagebird.MessageBirdService; +import com.messagebird.MessageBirdServiceImpl; +import com.messagebird.exceptions.GeneralException; +import com.messagebird.exceptions.UnauthorizedException; +import com.messagebird.objects.integrations.*; + +import java.util.ArrayList; +import java.util.List; + +public class ExampleCreateAuthTemplate { + public static void main(String[] args) { + + if (args.length < 3) { + System.out.println("Please specify your access key and a template name and WABA ID example : java -jar test_accesskey \"My template name\" \"WABA ID\""); + return; + } + + // First create your service object + MessageBirdService wsr = new MessageBirdServiceImpl(args[0]); + + // Add the service to the client + MessageBirdClient messageBirdClient = new MessageBirdClient(wsr); + + /* body */ + HSMComponent bodyComponent = new HSMComponent(); + bodyComponent.setType(HSMComponentType.BODY); + bodyComponent.setAddSecurityRecommendation(true); + + /* footer */ + HSMComponent footerComponent = new HSMComponent(); + footerComponent.setType(HSMComponentType.FOOTER); + footerComponent.setCodeExpirationMinutes(8); + + /* button */ + HSMComponent buttonComponent = new HSMComponent(); + List buttons = new ArrayList<>(); + HSMComponentButton otpButton = new HSMComponentButton(); + otpButton.setOtpType(HSMOTPButtonType.ONE_TAP); + otpButton.setText("Copy code"); + otpButton.setAutofillText("Autofill"); + otpButton.setPackageName("com.example.luckyshrub"); + otpButton.setSignatureHash("K8a%2FAINcGX7"); + + buttons.add(otpButton); + buttonComponent.setType(HSMComponentType.BUTTONS); + buttonComponent.setButtons(buttons); + + /* set components */ + Template template = new Template(); + List components = new ArrayList<>(); + components.add(bodyComponent); + components.add(footerComponent); + components.add(buttonComponent); + + template.setName(args[1]); + template.setLanguage("en_US"); + template.setWABAID(args[2]); + template.setComponents(components); + template.setCategory(HSMCategory.AUTHENTICATION); + + try { + TemplateResponse response = messageBirdClient.createWhatsAppTemplate(template); + System.out.println(response.toString()); + } catch (GeneralException | UnauthorizedException | IllegalArgumentException exception) { + exception.printStackTrace(); + } + } +} \ No newline at end of file From e5e5b6350f85bccfd4d89c189787f67b849485c1 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 15 Jun 2023 11:50:17 +0200 Subject: [PATCH 38/99] preperation for the new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 6ace8cc1..04c132c1 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.0.0 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 6d8e69c7..719c0cfd 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.0.0"; + private final String clientVersion = "6.1.0"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 7416aedc..e05d8c0e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.0.0 + 6.1.0 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.0.0 + 6.1.0 compile From 19ef745550213650cb3072ca56fd0cb33f406a73 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 15 Jun 2023 11:51:46 +0200 Subject: [PATCH 39/99] [maven-release-plugin] prepare release v6.1.0 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 04c132c1..74a71df9 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.0-SNAPSHOT @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v6.1.0 From 13c8625bde5971b5c7c3b7be817389d484c6a17c Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 15 Jun 2023 11:51:51 +0200 Subject: [PATCH 40/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 74a71df9..7d432ca5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.0 @@ -42,7 +42,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v6.1.0 + HEAD From b2858670c4e38c83d58da1de59a667402aa3d6fb Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 15 Jun 2023 13:28:02 +0200 Subject: [PATCH 41/99] preperation for the new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 7d432ca5..e29537ee 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.1-SNAPSHOT From c3086196a1e25eae1164157c5f6cd33a708b6980 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Wed, 16 Aug 2023 10:45:07 -0400 Subject: [PATCH 42/99] Add SMS pricing model objects --- .../messagebird/objects/OutboundSmsPrice.java | 60 +++++++++++++++++++ .../objects/OutboundSmsPriceResponse.java | 36 +++++++++++ 2 files changed, 96 insertions(+) create mode 100644 api/src/main/java/com/messagebird/objects/OutboundSmsPrice.java create mode 100644 api/src/main/java/com/messagebird/objects/OutboundSmsPriceResponse.java diff --git a/api/src/main/java/com/messagebird/objects/OutboundSmsPrice.java b/api/src/main/java/com/messagebird/objects/OutboundSmsPrice.java new file mode 100644 index 00000000..3733cf69 --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/OutboundSmsPrice.java @@ -0,0 +1,60 @@ +package com.messagebird.objects; + +import java.math.BigDecimal; + +public class OutboundSmsPrice { + private BigDecimal price; + private String currencyCode; + private String mccmnc; + private String mcc; + private String mnc; + private String countryName; + private String countryIsoCode; + private String operatorName; + + public BigDecimal getPrice() { + return price; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public String getMccmnc() { + return mccmnc; + } + + public String getMcc() { + return mcc; + } + + public String getMnc() { + return mnc; + } + + public String getCountryName() { + return countryName; + } + + public String getCountryIsoCode() { + return countryIsoCode; + } + + public String getOperatorName() { + return operatorName; + } + + @Override + public String toString() { + return "OutboundSmsPrice{" + + "price=" + price + + ", currencyCode='" + currencyCode + '\'' + + ", mccmnc='" + mccmnc + '\'' + + ", mcc='" + mcc + '\'' + + ", mnc='" + mnc + '\'' + + ", countryName='" + countryName + '\'' + + ", countryIsoCode='" + countryIsoCode + '\'' + + ", operatorName='" + operatorName + '\'' + + '}'; + } +} diff --git a/api/src/main/java/com/messagebird/objects/OutboundSmsPriceResponse.java b/api/src/main/java/com/messagebird/objects/OutboundSmsPriceResponse.java new file mode 100644 index 00000000..6d036882 --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/OutboundSmsPriceResponse.java @@ -0,0 +1,36 @@ +package com.messagebird.objects; + +import java.util.List; + +public class OutboundSmsPriceResponse { + private int gateway; + private String currencyCode; + private int totalCount; + private List prices; + + public int getGateway() { + return gateway; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public int getTotalCount() { + return totalCount; + } + + public List getPrices() { + return prices; + } + + @Override + public String toString() { + return "OutboundSmsPriceResponse{" + + "gateway=" + gateway + + ", currencyCode='" + currencyCode + '\'' + + ", totalCount=" + totalCount + + ", prices=" + prices + + '}'; + } +} From 20a811d549b72d7943991859d454286a15160922 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Wed, 16 Aug 2023 11:16:55 -0400 Subject: [PATCH 43/99] Add client methods for getting outbound SMS prices --- .../com/messagebird/MessageBirdClient.java | 35 +++++++++ .../messagebird/OutboundSmsPricesTest.java | 77 +++++++++++++++++++ .../fixtures/outbound_sms_prices.json | 37 +++++++++ 3 files changed, 149 insertions(+) create mode 100644 api/src/test/java/com/messagebird/OutboundSmsPricesTest.java create mode 100644 api/src/test/resources/fixtures/outbound_sms_prices.json diff --git a/api/src/main/java/com/messagebird/MessageBirdClient.java b/api/src/main/java/com/messagebird/MessageBirdClient.java index be7a8fa5..6e216fe7 100644 --- a/api/src/main/java/com/messagebird/MessageBirdClient.java +++ b/api/src/main/java/com/messagebird/MessageBirdClient.java @@ -105,6 +105,8 @@ public class MessageBirdClient { private static final String VOICELEGS_SUFFIX_PATH = "/legs"; static final String FILES_PATH = "/files"; static final String TEMPLATES_PATH = "/templates"; + static final String OUTBOUND_SMS_PRICING_PATH = "/pricing/sms/outbound"; + static final String OUTBOUND_SMS_PRICING_SMPP_PATH = "/pricing/sms/outbound/smpp/%s"; static final String RECORDING_DOWNLOAD_FORMAT = ".wav"; @@ -2202,4 +2204,37 @@ public void deleteChildAccount(final String id) throws UnauthorizedException, Ge System.out.println("url: " + url); messageBirdService.deleteByID(url, id); } + + /** + * Returns outbound pricing for the default SMS configuration for the authenticated account. + * + * @return outbound pricing for the default SMS configuration for the authenticated account + * + * @throws UnauthorizedException if client is unauthorized + * @throws GeneralException general exception + * @throws NotFoundException if pricing information could not be found + * + * @see Pricing API + */ + public OutboundSmsPriceResponse getOutboundSmsPrices() throws GeneralException, UnauthorizedException, NotFoundException { + return messageBirdService.request(OUTBOUND_SMS_PRICING_PATH, OutboundSmsPriceResponse.class); + } + + /** + * Returns outbound SMS pricing for a specific SMPP username. + * + * @param smppUsername the SMPP SystemID provided by MessageBird + * + * @return outbound SMS pricing for the given SMPP username + * + * @throws UnauthorizedException if client is unauthorized + * @throws GeneralException general exception + * @throws NotFoundException if pricing information could not be found for the given SMPP username + * + * @see Pricing API + */ + public OutboundSmsPriceResponse getOutboundSmsPrices(final String smppUsername) throws GeneralException, UnauthorizedException, NotFoundException { + final String url = String.format(OUTBOUND_SMS_PRICING_SMPP_PATH, smppUsername); + return messageBirdService.request(url, OutboundSmsPriceResponse.class); + } } diff --git a/api/src/test/java/com/messagebird/OutboundSmsPricesTest.java b/api/src/test/java/com/messagebird/OutboundSmsPricesTest.java new file mode 100644 index 00000000..60d6b466 --- /dev/null +++ b/api/src/test/java/com/messagebird/OutboundSmsPricesTest.java @@ -0,0 +1,77 @@ +package com.messagebird; + +import com.messagebird.exceptions.GeneralException; +import com.messagebird.exceptions.NotFoundException; +import com.messagebird.exceptions.UnauthorizedException; +import com.messagebird.objects.OutboundSmsPriceResponse; +import com.messagebird.util.Resources; +import org.junit.Test; + +import java.math.BigDecimal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class OutboundSmsPricesTest { + + @Test + public void testGetOutboundSmsPrices() throws GeneralException, UnauthorizedException, NotFoundException { + String responseFixture = Resources.readResourceText("/fixtures/outbound_sms_prices.json"); + + MessageBirdService messageBirdService = SpyService + .expects("GET", "pricing/sms/outbound") + .withRestAPIBaseURL() + .andReturns(new APIResponse(responseFixture, 200)); + MessageBirdClient messageBirdClient = new MessageBirdClient(messageBirdService); + + assertReceivedExpectedResponse(messageBirdClient.getOutboundSmsPrices()); + } + + @Test + public void testGetOutboundSmsPricesSmppUsername() throws GeneralException, UnauthorizedException, NotFoundException { + String responseFixture = Resources.readResourceText("/fixtures/outbound_sms_prices.json"); + + MessageBirdService messageBirdService = SpyService + .expects("GET", "pricing/sms/outbound/smpp/test-smpp-user") + .withRestAPIBaseURL() + .andReturns(new APIResponse(responseFixture, 200)); + MessageBirdClient messageBirdClient = new MessageBirdClient(messageBirdService); + + assertReceivedExpectedResponse(messageBirdClient.getOutboundSmsPrices("test-smpp-user")); + } + + private static void assertReceivedExpectedResponse(OutboundSmsPriceResponse outboundSmsPriceResponse) { + assertEquals(10, outboundSmsPriceResponse.getGateway()); + assertEquals("EUR", outboundSmsPriceResponse.getCurrencyCode()); + assertEquals(3, outboundSmsPriceResponse.getTotalCount()); + + assertEquals(3, outboundSmsPriceResponse.getPrices().size()); + + assertEquals(new BigDecimal("0.060000"), outboundSmsPriceResponse.getPrices().get(0).getPrice()); + assertEquals("EUR", outboundSmsPriceResponse.getPrices().get(0).getCurrencyCode()); + assertEquals("0", outboundSmsPriceResponse.getPrices().get(0).getMccmnc()); + assertEquals("0", outboundSmsPriceResponse.getPrices().get(0).getMcc()); + assertNull(outboundSmsPriceResponse.getPrices().get(0).getMnc()); + assertEquals("Default Rate", outboundSmsPriceResponse.getPrices().get(0).getCountryName()); + assertEquals("XX", outboundSmsPriceResponse.getPrices().get(0).getCountryIsoCode()); + assertEquals("Default Rate", outboundSmsPriceResponse.getPrices().get(0).getOperatorName()); + + assertEquals(new BigDecimal("0.047000"), outboundSmsPriceResponse.getPrices().get(1).getPrice()); + assertEquals("EUR", outboundSmsPriceResponse.getPrices().get(1).getCurrencyCode()); + assertEquals("202", outboundSmsPriceResponse.getPrices().get(1).getMccmnc()); + assertEquals("202", outboundSmsPriceResponse.getPrices().get(1).getMcc()); + assertNull(outboundSmsPriceResponse.getPrices().get(1).getMnc()); + assertEquals("Greece", outboundSmsPriceResponse.getPrices().get(1).getCountryName()); + assertEquals("GR", outboundSmsPriceResponse.getPrices().get(1).getCountryIsoCode()); + assertNull(outboundSmsPriceResponse.getPrices().get(1).getOperatorName()); + + assertEquals(new BigDecimal("0.045000"), outboundSmsPriceResponse.getPrices().get(2).getPrice()); + assertEquals("EUR", outboundSmsPriceResponse.getPrices().get(2).getCurrencyCode()); + assertEquals("20205", outboundSmsPriceResponse.getPrices().get(2).getMccmnc()); + assertEquals("202", outboundSmsPriceResponse.getPrices().get(2).getMcc()); + assertEquals("05", outboundSmsPriceResponse.getPrices().get(2).getMnc()); + assertEquals("Greece", outboundSmsPriceResponse.getPrices().get(2).getCountryName()); + assertEquals("GR", outboundSmsPriceResponse.getPrices().get(2).getCountryIsoCode()); + assertEquals("Vodafone", outboundSmsPriceResponse.getPrices().get(2).getOperatorName()); + } +} diff --git a/api/src/test/resources/fixtures/outbound_sms_prices.json b/api/src/test/resources/fixtures/outbound_sms_prices.json new file mode 100644 index 00000000..261401d3 --- /dev/null +++ b/api/src/test/resources/fixtures/outbound_sms_prices.json @@ -0,0 +1,37 @@ +{ + "gateway": 10, + "currencyCode": "EUR", + "totalCount": 3, + "prices": [ + { + "price": "0.060000", + "currencyCode": "EUR", + "mccmnc": "0", + "mcc": "0", + "mnc": null, + "countryName": "Default Rate", + "countryIsoCode": "XX", + "operatorName": "Default Rate" + }, + { + "price": "0.047000", + "currencyCode": "EUR", + "mccmnc": "202", + "mcc": "202", + "mnc": null, + "countryName": "Greece", + "countryIsoCode": "GR", + "operatorName": null + }, + { + "price": "0.045000", + "currencyCode": "EUR", + "mccmnc": "20205", + "mcc": "202", + "mnc": "05", + "countryName": "Greece", + "countryIsoCode": "GR", + "operatorName": "Vodafone" + } + ] +} From b6a4f909aab9f7c92064fd76940e3d12b3db2eec Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Thu, 17 Aug 2023 09:40:51 -0400 Subject: [PATCH 44/99] Guard against `null` `smppUsername` arguments --- api/src/main/java/com/messagebird/MessageBirdClient.java | 4 ++++ .../test/java/com/messagebird/OutboundSmsPricesTest.java | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/api/src/main/java/com/messagebird/MessageBirdClient.java b/api/src/main/java/com/messagebird/MessageBirdClient.java index 6e216fe7..322b1247 100644 --- a/api/src/main/java/com/messagebird/MessageBirdClient.java +++ b/api/src/main/java/com/messagebird/MessageBirdClient.java @@ -2234,6 +2234,10 @@ public OutboundSmsPriceResponse getOutboundSmsPrices() throws GeneralException, * @see Pricing API */ public OutboundSmsPriceResponse getOutboundSmsPrices(final String smppUsername) throws GeneralException, UnauthorizedException, NotFoundException { + if (smppUsername == null) { + throw new IllegalArgumentException("SMPP username must be specified."); + } + final String url = String.format(OUTBOUND_SMS_PRICING_SMPP_PATH, smppUsername); return messageBirdService.request(url, OutboundSmsPriceResponse.class); } diff --git a/api/src/test/java/com/messagebird/OutboundSmsPricesTest.java b/api/src/test/java/com/messagebird/OutboundSmsPricesTest.java index 60d6b466..665dba71 100644 --- a/api/src/test/java/com/messagebird/OutboundSmsPricesTest.java +++ b/api/src/test/java/com/messagebird/OutboundSmsPricesTest.java @@ -11,6 +11,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; public class OutboundSmsPricesTest { @@ -40,6 +41,11 @@ public void testGetOutboundSmsPricesSmppUsername() throws GeneralException, Unau assertReceivedExpectedResponse(messageBirdClient.getOutboundSmsPrices("test-smpp-user")); } + @Test(expected = IllegalArgumentException.class) + public void testGetOutboundSmsPricesSmppUsernameNull() throws GeneralException, UnauthorizedException, NotFoundException { + new MessageBirdClient(mock(MessageBirdService.class)).getOutboundSmsPrices(null); + } + private static void assertReceivedExpectedResponse(OutboundSmsPriceResponse outboundSmsPriceResponse) { assertEquals(10, outboundSmsPriceResponse.getGateway()); assertEquals("EUR", outboundSmsPriceResponse.getCurrencyCode()); From 1ccb707792abba5cbbbd362c6be473a900f847d1 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Thu, 17 Aug 2023 09:49:00 -0400 Subject: [PATCH 45/99] Add an example of fetching outbound SMS prices --- .../java/ExampleGetOutboundSmsPrices.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 examples/src/main/java/ExampleGetOutboundSmsPrices.java diff --git a/examples/src/main/java/ExampleGetOutboundSmsPrices.java b/examples/src/main/java/ExampleGetOutboundSmsPrices.java new file mode 100644 index 00000000..e90d5151 --- /dev/null +++ b/examples/src/main/java/ExampleGetOutboundSmsPrices.java @@ -0,0 +1,33 @@ +import com.messagebird.MessageBirdClient; +import com.messagebird.MessageBirdServiceImpl; +import com.messagebird.exceptions.MessageBirdException; +import com.messagebird.objects.OutboundSmsPriceResponse; + +public class ExampleGetOutboundSmsPrices { + + public static void main(String[] args) { + if (args.length != 1 && args.length != 2) { + System.out.println("Please specify your access key and (optionally) SMPP username"); + return; + } + + final MessageBirdClient messageBirdClient = new MessageBirdClient(new MessageBirdServiceImpl(args[0])); + + try { + System.out.println("Get a list of outbound SMS prices"); + + final OutboundSmsPriceResponse outboundSmsPriceResponse; + + if (args.length == 2) { + final String smppUsername = args[1]; + outboundSmsPriceResponse = messageBirdClient.getOutboundSmsPrices(smppUsername); + } else { + outboundSmsPriceResponse = messageBirdClient.getOutboundSmsPrices(); + } + + System.out.println("response: " + outboundSmsPriceResponse); + } catch (MessageBirdException e) { + e.printStackTrace(); + } + } +} From 5b28fb722584fbbc1d7acf00519ebd930f77fa98 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Thu, 17 Aug 2023 09:59:28 -0400 Subject: [PATCH 46/99] Replace `Base64.java` with the JDK-provided `Base64` decoder --- api/pom.xml | 5 +- api/src/main/java/com/messagebird/Base64.java | 512 ------------------ .../java/com/messagebird/RequestSigner.java | 8 +- 3 files changed, 5 insertions(+), 520 deletions(-) delete mode 100644 api/src/main/java/com/messagebird/Base64.java diff --git a/api/pom.xml b/api/pom.xml index e29537ee..1d6f8b2d 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,10 +4,7 @@ com.messagebird messagebird-api - 6.1.0 + 6.1.0 jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/Base64.java b/api/src/main/java/com/messagebird/Base64.java deleted file mode 100644 index f96ef9fa..00000000 --- a/api/src/main/java/com/messagebird/Base64.java +++ /dev/null @@ -1,512 +0,0 @@ -package com.messagebird; - -/** - * Cutted version of iharder's base64 implementation - * - * @author Robert Harder - * @author rob@iharder.net - * @version 2.3.7 - * @todo replace with actual library on next major bump - * - *

Encodes and decodes to and from Base64 notation.

- *

Homepage: http://iharder.net/base64.

- * - *

- * I am placing this code in the Public Domain. Do with it as you will. - * This software comes with no guarantees or warranties but with - * plenty of well-wishing instead! - * Please visit http://iharder.net/base64 - * periodically to check for updates or to contribute improvements. - *

- * @deprecated This class is being deprecated together with {@link RequestSigner} - */ -@Deprecated -class Base64 { - - /* ******** P U B L I C F I E L D S ******** */ - - - /** - * No options specified. Value is zero. - */ - public final static int NO_OPTIONS = 0; - - /** - * Specify that gzipped data should not be automatically gunzipped. - */ - public final static int DONT_GUNZIP = 4; - - /** - * Encode using Base64-like encoding that is URL- and Filename-safe as described - * in Section 4 of RFC3548: - * http://www.faqs.org/rfcs/rfc3548.html. - * It is important to note that data encoded this way is not officially valid Base64, - * or at the very least should not be called Base64 without also specifying that is - * was encoded using the URL- and Filename-safe dialect. - */ - public final static int URL_SAFE = 16; - - - /** - * Encode using the special "ordered" dialect of Base64 described here: - * http://www.faqs.org/qa/rfcc-1940.html. - */ - public final static int ORDERED = 32; - - - /* ******** P R I V A T E F I E L D S ******** */ - - - /** - * The equals sign (=) as a byte. - */ - private final static byte EQUALS_SIGN = (byte) '='; - - - /** - * Preferred encoding. - */ - private final static String PREFERRED_ENCODING = "US-ASCII"; - - - private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding - private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding - - - /* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */ - - /** - * Translates a Base64 value to either its 6-bit reconstruction value - * or a negative number indicating some other meaning. - **/ - private final static byte[] _STANDARD_DECODABET = { - -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9, -9, -9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255 - }; - - - /* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */ - - /** - * Used in decoding URL- and Filename-safe dialects of Base64. - */ - private final static byte[] _URL_SAFE_DECODABET = { - -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - -9, // Plus sign at decimal 43 - -9, // Decimal 44 - 62, // Minus sign at decimal 45 - -9, // Decimal 46 - -9, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, // Decimal 91 - 94 - 63, // Underscore at decimal 95 - -9, // Decimal 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255 - }; - - - - /* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */ - - /** - * Used in decoding the "ordered" dialect of Base64. - */ - private final static byte[] _ORDERED_DECODABET = { - -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - -9, // Plus sign at decimal 43 - -9, // Decimal 44 - 0, // Minus sign at decimal 45 - -9, // Decimal 46 - -9, // Slash at decimal 47 - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A' through 'M' - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N' through 'Z' - -9, -9, -9, -9, // Decimal 91 - 94 - 37, // Underscore at decimal 95 - -9, // Decimal 96 - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a' through 'm' - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255 - }; - - - /* ******** D E T E R M I N E W H I C H A L H A B E T ******** */ - - /** - * Returns one of the _SOMETHING_DECODABET byte arrays depending on - * the options specified. - * It's possible, though silly, to specify ORDERED and URL_SAFE - * in which case one of them will be picked, though there is - * no guarantee as to which one will be picked. - */ - private final static byte[] getDecodabet(int options) { - if ((options & URL_SAFE) == URL_SAFE) { - return _URL_SAFE_DECODABET; - } else if ((options & ORDERED) == ORDERED) { - return _ORDERED_DECODABET; - } else { - return _STANDARD_DECODABET; - } - } // end getAlphabet - - - /** - * Defeats instantiation. - */ - private Base64() { - } - - - - /* ******** D E C O D I N G M E T H O D S ******** */ - - - /** - * Decodes four bytes from array source - * and writes the resulting bytes (up to three of them) - * to destination. - * The source and destination arrays can be manipulated - * anywhere along their length by specifying - * srcOffset and destOffset. - * This method does not check to make sure your arrays - * are large enough to accomodate srcOffset + 4 for - * the source array or destOffset + 3 for - * the destination array. - * This method returns the actual number of bytes that - * were converted from the Base64 encoding. - *

This is the lowest level of the decoding methods with - * all possible parameters.

- * - * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param options alphabet type is pulled from this (standard, url-safe, ordered) - * @return the number of decoded bytes converted - * @throws NullPointerException if source or destination arrays are null - * @throws IllegalArgumentException if srcOffset or destOffset are invalid - * or there is not enough room in the array. - * @since 1.3 - */ - private static int decode4to3( - byte[] source, int srcOffset, - byte[] destination, int destOffset, int options) { - - // Lots of error checking and exception throwing - if (source == null) { - throw new NullPointerException("Source array was null."); - } // end if - if (destination == null) { - throw new NullPointerException("Destination array was null."); - } // end if - if (srcOffset < 0 || srcOffset + 3 >= source.length) { - throw new IllegalArgumentException(String.format( - "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset)); - } // end if - if (destOffset < 0 || destOffset + 2 >= destination.length) { - throw new IllegalArgumentException(String.format( - "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset)); - } // end if - - - byte[] DECODABET = getDecodabet(options); - - // Example: Dk== - if (source[srcOffset + 2] == EQUALS_SIGN) { - // Two ways to do the same thing. Don't know which way I like best. - //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12); - - destination[destOffset] = (byte) (outBuff >>> 16); - return 1; - } - - // Example: DkL= - else if (source[srcOffset + 3] == EQUALS_SIGN) { - // Two ways to do the same thing. Don't know which way I like best. - //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) - // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) - | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6); - - destination[destOffset] = (byte) (outBuff >>> 16); - destination[destOffset + 1] = (byte) (outBuff >>> 8); - return 2; - } - - // Example: DkLE - else { - // Two ways to do the same thing. Don't know which way I like best. - //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) - // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) - // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) - | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) - | ((DECODABET[source[srcOffset + 3]] & 0xFF)); - - - destination[destOffset] = (byte) (outBuff >> 16); - destination[destOffset + 1] = (byte) (outBuff >> 8); - destination[destOffset + 2] = (byte) (outBuff); - - return 3; - } - } // end decodeToBytes - - - /** - * Low-level access to decoding ASCII characters in - * the form of a byte array. Ignores GUNZIP option, if - * it's set. This is not generally a recommended method, - * although it is used internally as part of the decoding process. - * Special case: if len = 0, an empty array is returned. Still, - * if you need more speed and reduced memory footprint (and aren't - * gzipping), consider this method. - * - * @param source The Base64 encoded data - * @param off The offset of where to begin decoding - * @param len The length of characters to decode - * @param options Can specify options such as alphabet type to use - * @return decoded data - * @throws java.io.IOException If bogus characters exist in source data - * @since 1.3 - */ - public static byte[] decode(byte[] source, int off, int len, int options) - throws java.io.IOException { - - // Lots of error checking and exception throwing - if (source == null) { - throw new NullPointerException("Cannot decode null source array."); - } // end if - if (off < 0 || off + len > source.length) { - throw new IllegalArgumentException(String.format( - "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len)); - } // end if - - if (len == 0) { - return new byte[0]; - } else if (len < 4) { - throw new IllegalArgumentException( - "Base64-encoded string must have at least four characters, but length specified was " + len); - } // end if - - byte[] DECODABET = getDecodabet(options); - - int len34 = len * 3 / 4; // Estimate on array size - byte[] outBuff = new byte[len34]; // Upper limit on size of output - int outBuffPosn = 0; // Keep track of where we're writing - - byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space - int b4Posn = 0; // Keep track of four byte input buffer - int i = 0; // Source array counter - byte sbiDecode = 0; // Special value from DECODABET - - for (i = off; i < off + len; i++) { // Loop through source - - sbiDecode = DECODABET[source[i] & 0xFF]; - - // White space, Equals sign, or legit Base64 character - // Note the values such as -5 and -9 in the - // DECODABETs at the top of the file. - if (sbiDecode >= WHITE_SPACE_ENC) { - if (sbiDecode >= EQUALS_SIGN_ENC) { - b4[b4Posn++] = source[i]; // Save non-whitespace - if (b4Posn > 3) { // Time to decode? - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, options); - b4Posn = 0; - - // If that was the equals sign, break out of 'for' loop - if (source[i] == EQUALS_SIGN) { - break; - } // end if: equals sign - } // end if: quartet built - } // end if: equals sign or better - } // end if: white space, equals sign or better - else { - // There's a bad input character in the Base64 stream. - throw new java.io.IOException(String.format( - "Bad Base64 input character decimal %d in array position %d", ((int) source[i]) & 0xFF, i)); - } // end else: - } // each input character - - byte[] out = new byte[outBuffPosn]; - System.arraycopy(outBuff, 0, out, 0, outBuffPosn); - return out; - } // end decode - - - /** - * Decodes data from Base64 notation, automatically - * detecting gzip-compressed data and decompressing it. - * - * @param s the string to decode - * @return the decoded data - * @throws java.io.IOException If there is a problem - * @since 1.4 - */ - public static byte[] decode(String s) throws java.io.IOException { - return decode(s, NO_OPTIONS); - } - - - /** - * Decodes data from Base64 notation, automatically - * detecting gzip-compressed data and decompressing it. - * - * @param s the string to decode - * @param options encode options such as URL_SAFE - * @return the decoded data - * @throws java.io.IOException if there is an error - * @throws NullPointerException if s is null - * @since 1.4 - */ - public static byte[] decode(String s, int options) throws java.io.IOException { - - if (s == null) { - throw new NullPointerException("Input string was null."); - } // end if - - byte[] bytes; - try { - bytes = s.getBytes(PREFERRED_ENCODING); - } // end try - catch (java.io.UnsupportedEncodingException uee) { - bytes = s.getBytes(); - } // end catch - // - - // Decode - bytes = decode(bytes, 0, bytes.length, options); - - // Check to see if it's gzip-compressed - // GZIP Magic Two-Byte Number: 0x8b1f (35615) - boolean dontGunzip = (options & DONT_GUNZIP) != 0; - if ((bytes != null) && (bytes.length >= 4) && (!dontGunzip)) { - - int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); - if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) { - java.io.ByteArrayInputStream bais = null; - java.util.zip.GZIPInputStream gzis = null; - java.io.ByteArrayOutputStream baos = null; - byte[] buffer = new byte[2048]; - int length = 0; - - try { - baos = new java.io.ByteArrayOutputStream(); - bais = new java.io.ByteArrayInputStream(bytes); - gzis = new java.util.zip.GZIPInputStream(bais); - - while ((length = gzis.read(buffer)) >= 0) { - baos.write(buffer, 0, length); - } // end while: reading input - - // No error? Get new bytes. - bytes = baos.toByteArray(); - - } // end try - catch (java.io.IOException e) { - e.printStackTrace(); - // Just return originally-decoded bytes - } // end catch - finally { - try { - baos.close(); - } catch (Exception e) { - } - try { - gzis.close(); - } catch (Exception e) { - } - try { - bais.close(); - } catch (Exception e) { - } - } // end finally - - } // end if: gzipped - } // end if: bytes.length >= 2 - - return bytes; - } // end decode - - -} // end class Base64 diff --git a/api/src/main/java/com/messagebird/RequestSigner.java b/api/src/main/java/com/messagebird/RequestSigner.java index 32c257a2..d79e464c 100644 --- a/api/src/main/java/com/messagebird/RequestSigner.java +++ b/api/src/main/java/com/messagebird/RequestSigner.java @@ -4,13 +4,13 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Base64; /** * RequestSigner is used to verify HTTP requests and is an implementation of: @@ -27,7 +27,7 @@ public class RequestSigner { private static final String ALGORITHM_HMAC_SHA256 = "HmacSHA256"; private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8; - private SecretKeySpec secret; + private final SecretKeySpec secret; /** * Constructs a new RequestSigner instance. @@ -55,8 +55,8 @@ public RequestSigner(byte[] key) { @Deprecated public boolean isMatch(String expectedSignature, Request request) { try { - return isMatch(Base64.decode(expectedSignature), request); - } catch (IOException e) { + return isMatch(Base64.getDecoder().decode(expectedSignature), request); + } catch (IllegalArgumentException e) { throw new RequestSigningException(e); } } From d442f9d5330443b2bc2946f590c0f390037a2e52 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 17 Aug 2023 17:11:33 +0200 Subject: [PATCH 47/99] new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 1d6f8b2d..5b748aa1 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.0 + 6.1.1-SNAPSHOT jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 719c0cfd..72665c7e 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.1.0"; + private final String clientVersion = "6.1.1"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index e05d8c0e..240cdfac 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.1.0 + 6.1.1 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.1.0 + 6.1.1 compile From 0236ce4d071d553c58d3d866e6a7d3eafd5ed613 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 17 Aug 2023 17:13:28 +0200 Subject: [PATCH 48/99] [maven-release-plugin] prepare release v6.1.1 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 5b748aa1..50479b1c 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.1-SNAPSHOT + 6.1.1 jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v6.1.1 From 35b91d9f08c7a9fa6e1fc3dbdbef9851ad543c78 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 17 Aug 2023 17:13:33 +0200 Subject: [PATCH 49/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 50479b1c..ffc04d29 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.1 + 6.1.2-SNAPSHOT jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v6.1.1 + HEAD From e2bb604476a83a26918e9a460dbed6fb7e64e84e Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 17 Aug 2023 17:54:59 +0200 Subject: [PATCH 50/99] updated --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index ffc04d29..7b141482 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.2-SNAPSHOT + 6.1.1 jar ${project.groupId}:${project.artifactId} From 989b09047c82141d78a93ff486ce5aa8e999f89a Mon Sep 17 00:00:00 2001 From: "Daniel A. Morales" Date: Thu, 14 Dec 2023 22:07:19 +0000 Subject: [PATCH 51/99] Added support for updating whatsapp template --- .../com/messagebird/MessageBirdClient.java | 25 ++++++++++++ .../messagebird/MessageBirdClientTest.java | 38 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/api/src/main/java/com/messagebird/MessageBirdClient.java b/api/src/main/java/com/messagebird/MessageBirdClient.java index 322b1247..7011ab10 100644 --- a/api/src/main/java/com/messagebird/MessageBirdClient.java +++ b/api/src/main/java/com/messagebird/MessageBirdClient.java @@ -1876,6 +1876,31 @@ public TemplateResponse createWhatsAppTemplate(final Template template) return messageBirdService.sendPayLoad(url, template, TemplateResponse.class); } + /** + * Update a WhatsApp message template through MessageBird. + * + * @param template {@link Template} object to be created + * @param templateName A name as returned by getWhatsAppTemplateBy in the name variable + * @param language A language code as returned by getWhatsAppTemplateBy in the language variable + * @return {@link TemplateResponse} response object + * @throws UnauthorizedException if client is unauthorized + * @throws GeneralException general exception + * @throws IllegalArgumentException invalid template format + */ + public TemplateResponse updateWhatsAppTemplate(final Template template, final String templateName, final String language) + throws UnauthorizedException, GeneralException, IllegalArgumentException { + template.validate(); + + String url = String.format( + "%s%s%s/%s/%s", + INTEGRATIONS_BASE_URL_V2, + INTEGRATIONS_WHATSAPP_PATH, + TEMPLATES_PATH, + templateName, + language); + + return messageBirdService.sendPayLoad("PUT",url, template, TemplateResponse.class); + } /** * Gets a WhatsAppTemplate listing with specified pagination options. * diff --git a/api/src/test/java/com/messagebird/MessageBirdClientTest.java b/api/src/test/java/com/messagebird/MessageBirdClientTest.java index 50459497..9c462e9e 100644 --- a/api/src/test/java/com/messagebird/MessageBirdClientTest.java +++ b/api/src/test/java/com/messagebird/MessageBirdClientTest.java @@ -1077,6 +1077,44 @@ public void testCreateWhatsAppTemplate() throws UnauthorizedException, GeneralEx assertEquals(response.getComponents().get(i).getText(), templateResponse.getComponents().get(i).getText()); } } + @Test + public void testUpdateWhatsAppTemplate() throws UnauthorizedException, GeneralException { + final TemplateResponse templateResponse = TestUtil.createWhatsAppTemplateResponse("sample_template_name", "ko"); + final Template template = TestUtil.createWhatsAppTemplate("sample_template_name", "ko"); + + MessageBirdService messageBirdServiceMock = mock(MessageBirdService.class); + MessageBirdClient messageBirdClientInjectMock = new MessageBirdClient(messageBirdServiceMock); + + String url = String.format( + "%s%s%s/%s/%s", + INTEGRATIONS_BASE_URL_V2, + INTEGRATIONS_WHATSAPP_PATH, + TEMPLATES_PATH, + "sample_template_name", + "ko" + ); + + when(messageBirdServiceMock.sendPayLoad("PUT",url, template, TemplateResponse.class)) + .thenReturn(templateResponse); + + final TemplateResponse response = messageBirdClientInjectMock.updateWhatsAppTemplate(template,"sample_template_name","ko"); + verify(messageBirdServiceMock, times(1)).sendPayLoad("PUT",url, template, TemplateResponse.class); + assertNotNull(response); + assertEquals(response.getName(), templateResponse.getName()); + assertEquals(response.getLanguage(), templateResponse.getLanguage()); + assertEquals(response.getCategory(), templateResponse.getCategory()); + assertEquals(response.getStatus(), templateResponse.getStatus()); + assertEquals(response.getWabaID(), templateResponse.getWabaID()); + assertEquals(response.getCreatedAt(), templateResponse.getCreatedAt()); + assertEquals(response.getUpdatedAt(), templateResponse.getUpdatedAt()); + + /* verify components */ + for (int i = 0; i < response.getComponents().size(); i++) { + assertEquals(response.getComponents().get(i).getType(), templateResponse.getComponents().get(i).getType()); + assertEquals(response.getComponents().get(i).getFormat(), templateResponse.getComponents().get(i).getFormat()); + assertEquals(response.getComponents().get(i).getText(), templateResponse.getComponents().get(i).getText()); + } + } @Test public void testListWhatsAppTemplates() throws UnauthorizedException, GeneralException { From edd6fbbcfea18821919d613ca4719e13a68a2619 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 15 Dec 2023 09:49:06 +0100 Subject: [PATCH 52/99] preparing for a new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 7b141482..ffc04d29 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.1 + 6.1.2-SNAPSHOT jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 72665c7e..8b638bff 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.1.1"; + private final String clientVersion = "6.1.2"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 240cdfac..c5a6daf5 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.1.1 + 6.1.2 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.1.1 + 6.1.2 compile From 9efcce21eff4c5365b5dd48d7f8552acf75f44b3 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 15 Dec 2023 09:51:03 +0100 Subject: [PATCH 53/99] [maven-release-plugin] prepare release v6.1.2 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index ffc04d29..aca0d7ad 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.2-SNAPSHOT + 6.1.2 jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v6.1.2 From 28e396cb387040f6a95c70bd741353638bacfdaf Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 15 Dec 2023 09:51:08 +0100 Subject: [PATCH 54/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index aca0d7ad..247fa805 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.2 + 6.1.3-SNAPSHOT jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v6.1.2 + HEAD From d73d1c343a0e056784676064d0e754ecad590e75 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Fri, 15 Dec 2023 10:25:49 +0100 Subject: [PATCH 55/99] new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 247fa805..511ade81 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.3-SNAPSHOT + 6.1.2 jar ${project.groupId}:${project.artifactId} From 31f90a4c31ed57f5d056c9b1dbc13ce963719f93 Mon Sep 17 00:00:00 2001 From: Alexander Levintsev <44775486+AlexL-mb@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:48:38 +0100 Subject: [PATCH 56/99] Added support for Carousel and Coupon code WhatsApp template messages. --- .../objects/integrations/HSMComponent.java | 11 ++ .../integrations/HSMComponentButton.java | 4 +- .../integrations/HSMComponentButtonType.java | 3 +- .../integrations/HSMComponentCard.java | 21 ++++ .../integrations/HSMComponentType.java | 3 +- .../messagebird/MessageBirdClientTest.java | 38 ++++++ .../test/java/com/messagebird/TestUtil.java | 56 +++++++++ .../java/ExampleCreateCarouselTemplate.java | 113 ++++++++++++++++++ .../java/ExampleCreateCouponTemplate.java | 80 +++++++++++++ 9 files changed, 326 insertions(+), 3 deletions(-) create mode 100644 api/src/main/java/com/messagebird/objects/integrations/HSMComponentCard.java create mode 100644 examples/src/main/java/ExampleCreateCarouselTemplate.java create mode 100644 examples/src/main/java/ExampleCreateCouponTemplate.java diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java index ccda2075..c13f2761 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java @@ -20,6 +20,9 @@ public class HSMComponent { @JsonProperty("code_expiration_minutes") private Integer codeExpirationMinutes; private List buttons; + + private List cards; + private HSMExample example; public HSMComponentType getType() { @@ -54,6 +57,14 @@ public void setButtons(List buttons) { this.buttons = buttons; } + public List getCards() { + return cards; + } + + public void setCards(List cards) { + this.cards = cards; + } + public HSMExample getExample() { return example; } diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java index 9bb4ffb1..75204df0 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButton.java @@ -117,7 +117,9 @@ public String toString() { public void validateButtonExample() throws IllegalArgumentException { final boolean isExampleEmpty = this.example == null || this.example.isEmpty(); final boolean isNotProperType = !(this.type.equals(HSMComponentButtonType.URL) - || this.type.equals(HSMComponentButtonType.QUICK_REPLY)); + || this.type.equals(HSMComponentButtonType.QUICK_REPLY) + || this.type.equals(HSMComponentButtonType.COPY_CODE) + ); if (isExampleEmpty) { return; diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java index 5029fc73..06e6eb91 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentButtonType.java @@ -14,7 +14,8 @@ public enum HSMComponentButtonType { PHONE_NUMBER("PHONE_NUMBER"), URL("URL"), QUICK_REPLY("QUICK_REPLY"), - OTP("OTP"); + OTP("OTP"), + COPY_CODE("COPY_CODE"); private final String type; diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentCard.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentCard.java new file mode 100644 index 00000000..23411941 --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentCard.java @@ -0,0 +1,21 @@ +package com.messagebird.objects.integrations; + +import java.util.List; + +/** + * HSMComponentCard + * + * @author AlexL-mb + * @see HSMComponentCard + */ +public class HSMComponentCard { + private List components; + + public List getComponents() { + return components; + } + + public void setComponents(List components) { + this.components = components; + } +} \ No newline at end of file diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java index 0acda414..eff331dc 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java @@ -12,7 +12,8 @@ public enum HSMComponentType { BODY("BODY"), HEADER("HEADER"), FOOTER("FOOTER"), - BUTTONS("BUTTONS"); + BUTTONS("BUTTONS"), + CAROUSEL("CAROUSEL"); private final String type; diff --git a/api/src/test/java/com/messagebird/MessageBirdClientTest.java b/api/src/test/java/com/messagebird/MessageBirdClientTest.java index 9c462e9e..f1902b5f 100644 --- a/api/src/test/java/com/messagebird/MessageBirdClientTest.java +++ b/api/src/test/java/com/messagebird/MessageBirdClientTest.java @@ -1077,6 +1077,44 @@ public void testCreateWhatsAppTemplate() throws UnauthorizedException, GeneralEx assertEquals(response.getComponents().get(i).getText(), templateResponse.getComponents().get(i).getText()); } } + @Test + public void testCreateWhatsAppCarouselTemplate() throws UnauthorizedException, GeneralException { + final TemplateResponse templateResponse = TestUtil.createWhatsAppCarouselTemplateResponse("sample_template_name", "ko"); + final Template template = TestUtil.createWhatsAppCarouselTemplate("sample_template_name", "ko"); + + MessageBirdService messageBirdServiceMock = mock(MessageBirdService.class); + MessageBirdClient messageBirdClientInjectMock = new MessageBirdClient(messageBirdServiceMock); + + String url = String.format( + "%s%s%s", + INTEGRATIONS_BASE_URL_V2, + INTEGRATIONS_WHATSAPP_PATH, + TEMPLATES_PATH + ); + + when(messageBirdServiceMock.sendPayLoad(url, template, TemplateResponse.class)) + .thenReturn(templateResponse); + + final TemplateResponse response = messageBirdClientInjectMock.createWhatsAppTemplate(template); + + verify(messageBirdServiceMock, times(1)).sendPayLoad(url, template, TemplateResponse.class); + assertNotNull(response); + assertEquals(response.getName(), templateResponse.getName()); + assertEquals(response.getLanguage(), templateResponse.getLanguage()); + assertEquals(response.getCategory(), templateResponse.getCategory()); + assertEquals(response.getStatus(), templateResponse.getStatus()); + assertEquals(response.getWabaID(), templateResponse.getWabaID()); + assertEquals(response.getCreatedAt(), templateResponse.getCreatedAt()); + assertEquals(response.getUpdatedAt(), templateResponse.getUpdatedAt()); + + /* verify components */ + for (int i = 0; i < response.getComponents().size(); i++) { + assertEquals(response.getComponents().get(i).getType(), templateResponse.getComponents().get(i).getType()); + assertEquals(response.getComponents().get(i).getFormat(), templateResponse.getComponents().get(i).getFormat()); + assertEquals(response.getComponents().get(i).getText(), templateResponse.getComponents().get(i).getText()); + } + } + @Test public void testUpdateWhatsAppTemplate() throws UnauthorizedException, GeneralException { final TemplateResponse templateResponse = TestUtil.createWhatsAppTemplateResponse("sample_template_name", "ko"); diff --git a/api/src/test/java/com/messagebird/TestUtil.java b/api/src/test/java/com/messagebird/TestUtil.java index 29744ba5..09883ed3 100644 --- a/api/src/test/java/com/messagebird/TestUtil.java +++ b/api/src/test/java/com/messagebird/TestUtil.java @@ -6,6 +6,7 @@ import com.messagebird.objects.integrations.HSMComponent; import com.messagebird.objects.integrations.HSMComponentButton; import com.messagebird.objects.integrations.HSMComponentButtonType; +import com.messagebird.objects.integrations.HSMComponentCard; import com.messagebird.objects.integrations.HSMComponentFormat; import com.messagebird.objects.integrations.HSMComponentType; import com.messagebird.objects.integrations.HSMExample; @@ -301,6 +302,24 @@ private static HSMComponent createHSMComponentButton() { return buttonComponent; } + private static HSMComponent createHSMComponentCarousel() { + final HSMComponent carouselComponent = new HSMComponent(); + carouselComponent.setType(HSMComponentType.CAROUSEL); + + final List cards = new ArrayList<>(); + final HSMComponentCard card = new HSMComponentCard(); + final List cardComponents = new ArrayList<>(); + cardComponents.add(createHSMComponentHeader()); + cardComponents.add(createHSMComponentBody()); + cardComponents.add(createHSMComponentButton()); + card.setComponents(cardComponents); + cards.add(card); + + carouselComponent.setCards(cards); + + return carouselComponent; + } + public static TemplateResponse createWhatsAppTemplateResponse(final String templateName, final String language) { final TemplateResponse templateResponse = new TemplateResponse(); templateResponse.setName(templateName); @@ -341,6 +360,43 @@ public static Template createWhatsAppTemplate(final String templateName, final S return template; } + public static TemplateResponse createWhatsAppCarouselTemplateResponse(final String templateName, final String language) { + final TemplateResponse templateResponse = new TemplateResponse(); + templateResponse.setName(templateName); + templateResponse.setLanguage(language); + templateResponse.setCategory(HSMCategory.MARKETING); + templateResponse.setStatus(HSMStatus.NEW); + templateResponse.setCreatedAt(new Date()); + templateResponse.setUpdatedAt(new Date()); + + final List components = new ArrayList<>(); + components.add(createHSMComponentBody()); + components.add(createHSMComponentCarousel()); + templateResponse.setComponents(components); + + templateResponse.setWabaID("testWABAID"); + templateResponse.setNamespace("testNamespace"); + + return templateResponse; + } + + public static Template createWhatsAppCarouselTemplate(final String templateName, final String language) { + final Template template = new Template(); + template.setName(templateName); + template.setLanguage(language); + template.setCategory(HSMCategory.MARKETING); + + final List components = new ArrayList<>(); + components.add(createHSMComponentBody()); + components.add(createHSMComponentCarousel()); + template.setComponents(components); + + template.setWABAID("testWABAID"); + + return template; + } + + public static TemplateList createWhatsAppTemplateList(final String templateName) { final TemplateResponse template1 = TestUtil.createWhatsAppTemplateResponse(templateName, "en_US"); final TemplateResponse template2 = TestUtil.createWhatsAppTemplateResponse(templateName, "ko"); diff --git a/examples/src/main/java/ExampleCreateCarouselTemplate.java b/examples/src/main/java/ExampleCreateCarouselTemplate.java new file mode 100644 index 00000000..54bea0dd --- /dev/null +++ b/examples/src/main/java/ExampleCreateCarouselTemplate.java @@ -0,0 +1,113 @@ +import com.messagebird.MessageBirdClient; +import com.messagebird.MessageBirdService; +import com.messagebird.MessageBirdServiceImpl; +import com.messagebird.exceptions.GeneralException; +import com.messagebird.exceptions.UnauthorizedException; +import com.messagebird.objects.integrations.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Create template. + * + * @see Doc - Create template + * @author AlexL-mb + */ +public class ExampleCreateCarouselTemplate { + + public static void main(String[] args) { + if (args.length < 3) { + System.out.println("Please specify your access key and a template name and WABA ID example : java -jar test_accesskey \"My template name\" \"WABA ID\""); + return; + } + + // First create your service object + MessageBirdService wsr = new MessageBirdServiceImpl(args[0]); + + // Add the service to the client + MessageBirdClient messageBirdClient = new MessageBirdClient(wsr); + + /* body */ + HSMComponent bodyComponent = new HSMComponent(); + final HSMExample bodyExample = new HSMExample(); + final List> bodyText = new ArrayList<>(); + bodyText.add(Arrays.asList("John")); + bodyExample.setBody_text(bodyText); + bodyComponent.setType(HSMComponentType.BODY); + bodyComponent.setText("Hey {{1}}! This is a sample template from Java."); + bodyComponent.setExample(bodyExample); + + /* carousel */ + final HSMComponent carouselComponent = new HSMComponent(); + carouselComponent.setType(HSMComponentType.CAROUSEL); + + /* cards */ + final List cards = new ArrayList<>(); + /* card 0 */ + final HSMComponentCard card = new HSMComponentCard(); + final List cardComponents = new ArrayList<>(); + + /* card header */ + final HSMComponent headerComponent = new HSMComponent(); + final HSMExample headerExample = new HSMExample(); + headerExample.setHeader_url(Arrays.asList("https://images.freeimages.com/images/small-previews/c5a/colourful-paper-rip-1-1195879.jpg")); + + headerComponent.setType(HSMComponentType.HEADER); + headerComponent.setFormat(HSMComponentFormat.IMAGE); + headerComponent.setExample(headerExample); + cardComponents.add(headerComponent); + + /* card body */ + final HSMComponent cardBodyComponent = new HSMComponent(); + final HSMExample cardBodyExample = new HSMExample(); + final List> cardBodyText = new ArrayList<>(); + cardBodyText.add(Arrays.asList("John")); + cardBodyExample.setBody_text(cardBodyText); + + cardBodyComponent.setType(HSMComponentType.BODY); + cardBodyComponent.setText("Hey {{1}}! This is a sample template from Java."); + cardBodyComponent.setExample(cardBodyExample); + cardComponents.add(cardBodyComponent); + + /* card buttons */ + final HSMComponent buttonComponent = new HSMComponent(); + final List buttons = new ArrayList<>(); + final HSMComponentButton button = new HSMComponentButton(); + button.setType(HSMComponentButtonType.URL); + button.setText("Touch it"); + button.setUrl("https://www.messagebird.com"); + button.setExample(Arrays.asList("https://developers.messagebird.com")); + buttons.add(button); + buttonComponent.setType(HSMComponentType.BUTTONS); + buttonComponent.setButtons(buttons); + cardComponents.add(buttonComponent); + + card.setComponents(cardComponents); + + cards.add(card); + + carouselComponent.setCards(cards); + + /* set components */ + Template template = new Template(); + List components = new ArrayList<>(); + components.add(bodyComponent); + components.add(carouselComponent); + + template.setName(args[1]); + template.setLanguage("en_US"); + template.setWABAID(args[2]); + template.setComponents(components); + template.setCategory(HSMCategory.MARKETING); + + try { + TemplateResponse response = messageBirdClient.createWhatsAppTemplate(template); + System.out.println(response.toString()); + } catch (GeneralException | UnauthorizedException | IllegalArgumentException exception) { + exception.printStackTrace(); + } + + } +} diff --git a/examples/src/main/java/ExampleCreateCouponTemplate.java b/examples/src/main/java/ExampleCreateCouponTemplate.java new file mode 100644 index 00000000..649f7a4c --- /dev/null +++ b/examples/src/main/java/ExampleCreateCouponTemplate.java @@ -0,0 +1,80 @@ +import com.messagebird.MessageBirdClient; +import com.messagebird.MessageBirdService; +import com.messagebird.MessageBirdServiceImpl; +import com.messagebird.exceptions.GeneralException; +import com.messagebird.exceptions.UnauthorizedException; +import com.messagebird.objects.integrations.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Create template. + * + * @see Doc - Create template + * @author AlexL-mb + */ +public class ExampleCreateCouponTemplate { + + public static void main(String[] args) { + if (args.length < 3) { + System.out.println("Please specify your access key and a template name and WABA ID example : java -jar test_accesskey \"My template name\" \"WABA ID\""); + return; + } + + // First create your service object + final MessageBirdService wsr = new MessageBirdServiceImpl(args[0]); + + // Add the service to the client + final MessageBirdClient messageBirdClient = new MessageBirdClient(wsr); + + /* header */ + final HSMComponent headerComponent = new HSMComponent(); + headerComponent.setType(HSMComponentType.HEADER); + headerComponent.setFormat(HSMComponentFormat.TEXT); + headerComponent.setText("Our Fall Sale is on!"); + + /* body */ + final HSMComponent bodyComponent = new HSMComponent(); + final HSMExample bodyExample = new HSMExample(); + final List> bodyText = new ArrayList<>(); + bodyText.add(Arrays.asList("25OFF", "25%")); + bodyExample.setBody_text(bodyText); + + bodyComponent.setType(HSMComponentType.BODY); + bodyComponent.setText("Shop now through November and use code {{1}} to get {{2}} off of all merchandise!"); + bodyComponent.setExample(bodyExample); + + + /* button */ + final HSMComponent buttonComponent = new HSMComponent(); + final List buttons = new ArrayList<>(); + final HSMComponentButton button = new HSMComponentButton(); + button.setType(HSMComponentButtonType.COPY_CODE); + button.setExample(Arrays.asList("CODE25")); + buttons.add(button); + buttonComponent.setType(HSMComponentType.BUTTONS); + buttonComponent.setButtons(buttons); + + /* set components */ + final Template template = new Template(); + final List components = new ArrayList<>(); + components.add(headerComponent); + components.add(bodyComponent); + components.add(buttonComponent); + + template.setName(args[1]); + template.setLanguage("en_US"); + template.setWABAID(args[2]); + template.setComponents(components); + template.setCategory(HSMCategory.MARKETING); + + try { + TemplateResponse response = messageBirdClient.createWhatsAppTemplate(template); + System.out.println(response.toString()); + } catch (GeneralException | UnauthorizedException | IllegalArgumentException exception) { + exception.printStackTrace(); + } + } +} From 948b772c9c321466775ae27e79761554ceb15100 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 9 Jan 2024 17:34:05 +0100 Subject: [PATCH 57/99] preparing for a new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 511ade81..247fa805 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.2 + 6.1.3-SNAPSHOT jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 8b638bff..b4bd19b8 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.1.2"; + private final String clientVersion = "6.1.3"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index c5a6daf5..b9a88404 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.1.2 + 6.1.3 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.1.2 + 6.1.3 compile From ac768b90b75c53f8aeef264b6cfed7d1cf8fa241 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 9 Jan 2024 17:36:32 +0100 Subject: [PATCH 58/99] [maven-release-plugin] prepare release v6.1.3 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 247fa805..70599c83 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.3-SNAPSHOT + 6.1.3 jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v6.1.3 From 83622f5004dfa136faa61aaa6891de931359e7dd Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 9 Jan 2024 17:36:37 +0100 Subject: [PATCH 59/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 70599c83..16954df4 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.3 + 6.1.4-SNAPSHOT jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v6.1.3 + HEAD From b7221c953babfa4f795d82cb6537fa92302d5cac Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 9 Jan 2024 18:20:22 +0100 Subject: [PATCH 60/99] preparing for a new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 16954df4..3ba0045a 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.4-SNAPSHOT + 6.1.3 jar ${project.groupId}:${project.artifactId} From 46489bb26f4a44ab5c5a2c04c88601f6ea49b334 Mon Sep 17 00:00:00 2001 From: Alexander Levintsev <44775486+AlexL-mb@users.noreply.github.com> Date: Sat, 27 Jan 2024 15:42:27 +0100 Subject: [PATCH 61/99] Added support for CTAURLLinkTrackingOptedOut and QualityScore in WhatsApp templates. --- .../objects/integrations/HSMQualityScore.java | 42 +++++++++++++++++++ .../objects/integrations/Template.java | 14 ++++++- .../integrations/TemplateResponse.java | 24 +++++++++++ .../test/java/com/messagebird/TestUtil.java | 1 + .../java/ExampleCreateCouponTemplate.java | 1 + 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 api/src/main/java/com/messagebird/objects/integrations/HSMQualityScore.java diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMQualityScore.java b/api/src/main/java/com/messagebird/objects/integrations/HSMQualityScore.java new file mode 100644 index 00000000..112492fd --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMQualityScore.java @@ -0,0 +1,42 @@ +package com.messagebird.objects.integrations; + +import java.util.List; + +public class HSMQualityScore { + private String score; + private long date; + private List reasons; + + public String getScore() { + return score; + } + + public void setScore(String score) { + this.score = score; + } + + public long getDate() { + return date; + } + + public void setDate(long date) { + this.date = date; + } + + public List getReasons() { + return reasons; + } + + public void setReasons(List reasons) { + this.reasons = reasons; + } + + @Override + public String toString() { + return "HSMQualityScore{" + + "score='" + score + '\'' + + ", date=" + date + + ", reasons=" + reasons + + '}'; + } +} diff --git a/api/src/main/java/com/messagebird/objects/integrations/Template.java b/api/src/main/java/com/messagebird/objects/integrations/Template.java index a61741f5..f6a83e93 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/Template.java +++ b/api/src/main/java/com/messagebird/objects/integrations/Template.java @@ -15,17 +15,20 @@ public class Template { private String wabaID; private List components; private HSMCategory category; + private boolean ctaURLLinkTrackingOptedOut; public Template() { } + public Template(String name, String language, String wabaID, - List components, HSMCategory category) { + List components, HSMCategory category, boolean ctaURLLinkTrackingOptedOut) { this.name = name; this.language = language; this.wabaID = wabaID; this.components = components; this.category = category; + this.ctaURLLinkTrackingOptedOut = ctaURLLinkTrackingOptedOut; } public String getName() { @@ -68,6 +71,14 @@ public void setCategory(HSMCategory category) { this.category = category; } + public void setCtaURLLinkTrackingOptedOut (boolean ctaURLLinkTrackingOptedOut) { + this.ctaURLLinkTrackingOptedOut = ctaURLLinkTrackingOptedOut; + } + + public boolean getCtaURLLinkTrackingOptedOut () { + return ctaURLLinkTrackingOptedOut; + } + @Override public String toString() { return "WhatsAppTemplate{" + @@ -76,6 +87,7 @@ public String toString() { ", wabaID='" + wabaID + '\'' + ", components=" + components + ", category='" + category + '\'' + + ", ctaURLLinkTrackingOptedOut='" + ctaURLLinkTrackingOptedOut + '\'' + '}'; } diff --git a/api/src/main/java/com/messagebird/objects/integrations/TemplateResponse.java b/api/src/main/java/com/messagebird/objects/integrations/TemplateResponse.java index 426ae64a..3c75fabe 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/TemplateResponse.java +++ b/api/src/main/java/com/messagebird/objects/integrations/TemplateResponse.java @@ -20,6 +20,11 @@ public class TemplateResponse implements Serializable { private String rejectedReason; private String wabaID; private String namespace; + + private boolean ctaURLLinkTrackingOptedOut; + + private HSMQualityScore qualityScore; + private Date createdAt; private Date updatedAt; @@ -107,6 +112,22 @@ public void setUpdatedAt(Date updatedAt) { this.updatedAt = updatedAt; } + public boolean isCtaURLLinkTrackingOptedOut() { + return ctaURLLinkTrackingOptedOut; + } + + public void setCtaURLLinkTrackingOptedOut(boolean ctaURLLinkTrackingOptedOut) { + this.ctaURLLinkTrackingOptedOut = ctaURLLinkTrackingOptedOut; + } + + public HSMQualityScore getQualityScore() { + return qualityScore; + } + + public void setQualityScore(HSMQualityScore qualityScore) { + this.qualityScore = qualityScore; + } + @Override public String toString() { return "WhatsAppTemplateResponse{" + @@ -118,8 +139,11 @@ public String toString() { ", rejectedReason='" + rejectedReason + '\'' + ", wabaID='" + wabaID + '\'' + ", namespace='" + namespace + '\'' + + ", ctaURLLinkTrackingOptedOut='" + ctaURLLinkTrackingOptedOut + '\'' + + ", qualityScore='" + qualityScore + '\'' + ", createdAt=" + createdAt + ", updatedAt=" + updatedAt + '}'; } + } diff --git a/api/src/test/java/com/messagebird/TestUtil.java b/api/src/test/java/com/messagebird/TestUtil.java index 09883ed3..3e9c5a33 100644 --- a/api/src/test/java/com/messagebird/TestUtil.java +++ b/api/src/test/java/com/messagebird/TestUtil.java @@ -326,6 +326,7 @@ public static TemplateResponse createWhatsAppTemplateResponse(final String templ templateResponse.setLanguage(language); templateResponse.setCategory(HSMCategory.AUTHENTICATION); templateResponse.setStatus(HSMStatus.NEW); + templateResponse.setCtaURLLinkTrackingOptedOut(true); templateResponse.setCreatedAt(new Date()); templateResponse.setUpdatedAt(new Date()); diff --git a/examples/src/main/java/ExampleCreateCouponTemplate.java b/examples/src/main/java/ExampleCreateCouponTemplate.java index 649f7a4c..f5480434 100644 --- a/examples/src/main/java/ExampleCreateCouponTemplate.java +++ b/examples/src/main/java/ExampleCreateCouponTemplate.java @@ -69,6 +69,7 @@ public static void main(String[] args) { template.setWABAID(args[2]); template.setComponents(components); template.setCategory(HSMCategory.MARKETING); + template.setCtaURLLinkTrackingOptedOut(true); try { TemplateResponse response = messageBirdClient.createWhatsAppTemplate(template); From ba96d005f62992d904e393a0e6260b9da1213406 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 30 Jan 2024 15:39:04 +0100 Subject: [PATCH 62/99] new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 3ba0045a..16954df4 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.3 + 6.1.4-SNAPSHOT jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index b4bd19b8..35b2a705 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.1.3"; + private final String clientVersion = "6.1.4"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index b9a88404..7c103dc4 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.1.3 + 6.1.4 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.1.3 + 6.1.4 compile From 9262fc34ff84b58518383417a6e03670df88a734 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 30 Jan 2024 15:40:33 +0100 Subject: [PATCH 63/99] [maven-release-plugin] prepare release v6.1.4 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 16954df4..6298ecfe 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.4-SNAPSHOT + 6.1.4 jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v6.1.4 From c9129c62fcc1c2335b07f08ca7109dc9cbe5f4f1 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 30 Jan 2024 15:40:38 +0100 Subject: [PATCH 64/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 6298ecfe..eec90102 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.4 + 6.1.5-SNAPSHOT jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v6.1.4 + HEAD From 37e2545ce96afdb9fe73d5979060a74cf04c66dc Mon Sep 17 00:00:00 2001 From: denizkilic Date: Tue, 30 Jan 2024 15:59:12 +0100 Subject: [PATCH 65/99] updated --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index eec90102..123cbaad 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.5-SNAPSHOT + 6.1.4 jar ${project.groupId}:${project.artifactId} From 350009d6890fbc6218deec2a394851aa9c47c51e Mon Sep 17 00:00:00 2001 From: Alexander Levintsev <44775486+AlexL-mb@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:45:13 +0100 Subject: [PATCH 66/99] Added support for sending Carousel messages --- .../conversations/MessageComponent.java | 39 ++++++++++++++++++- .../conversations/MessageComponentType.java | 4 +- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java b/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java index 9dd25b3a..6bb9ca79 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java +++ b/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java @@ -8,6 +8,10 @@ public class MessageComponent { private String sub_type; private int index; private List parameters; + private int card_index; + private List cards; + private MessageComponent card; + private List components; public void setType(MessageComponentType type) { this.type = type; @@ -41,13 +45,46 @@ public void setParameters(List parameters) { this.parameters = parameters; } + public void setCards(List cards) { + this.cards = cards; + } + + public List getCards() { + return cards; + } + + public int getCard_index() { + return card_index; + } + + public void setCard_index(int card_index) { + this.card_index = card_index; + } + + public MessageComponent getCard() { + return card; + } + + public void setCard(MessageComponent card) { + this.card = card; + } + + public List getComponents() { + return components; + } + + public void setComponents(List components) { + this.components = components; + } + @Override public String toString() { return "MessageComponent{" + "type='" + type + '\'' + ", sub_type='" + sub_type + '\'' + ", index=" + index + - ", parameters=" + parameters + + ", parameters=" + parameters + '\'' + + ", cards=" + cards + '}'; } } diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java b/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java index 327525fd..c2be69bf 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java +++ b/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java @@ -8,7 +8,9 @@ public enum MessageComponentType { HEADER("header"), BODY("body"), FOOTER("footer"), - BUTTON("button"); + BUTTON("button"), + CARD("card"), + CAROUSEL("carousel"); private final String type; From 7eb58cae36872263c5b7a14ecc6e62a09287d4f9 Mon Sep 17 00:00:00 2001 From: Alexander Levintsev <44775486+AlexL-mb@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:46:00 +0100 Subject: [PATCH 67/99] added sending carousel messages example --- ...ampleConversationSendCarouselTemplate.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 examples/src/main/java/ExampleConversationSendCarouselTemplate.java diff --git a/examples/src/main/java/ExampleConversationSendCarouselTemplate.java b/examples/src/main/java/ExampleConversationSendCarouselTemplate.java new file mode 100644 index 00000000..f386917d --- /dev/null +++ b/examples/src/main/java/ExampleConversationSendCarouselTemplate.java @@ -0,0 +1,116 @@ +import com.messagebird.MessageBirdClient; +import com.messagebird.MessageBirdService; +import com.messagebird.MessageBirdServiceImpl; +import com.messagebird.exceptions.GeneralException; +import com.messagebird.exceptions.UnauthorizedException; +import com.messagebird.objects.conversations.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ExampleConversationSendCarouselTemplate { + + public static void main(String[] args) { + + if (args.length < 3) { + System.out.println("Please at least specify your access key, the channel id and destination address.\n" + + "Usage : java -jar test_accesskey(Required) channel_id(Required) to(Required)"); + return; + } + + //First create your service object + final MessageBirdService wsr = new MessageBirdServiceImpl(args[0]); + //Add the service to the client + final MessageBirdClient messageBirdClient = new MessageBirdClient(wsr); + + ConversationContent conversationContent = new ConversationContent(); + ConversationContentHsm conversationContentHsm = new ConversationContentHsm(); + conversationContentHsm.setNamespace("c663a566_a4de_492f_86b2_028cbf612345"); + conversationContentHsm.setTemplateName("carousel_template_test_hello"); + ConversationHsmLanguage language = new ConversationHsmLanguage(); + language.setCode("en_US"); + conversationContentHsm.setLanguage(language); + + + +// card0 components + List card0Components = new ArrayList<>(); +// card0 header + MessageComponent card0HeaderComponent = new MessageComponent(); + card0HeaderComponent.setType(MessageComponentType.HEADER); + MessageParam imageParam = new MessageParam(); + imageParam.setType(TemplateMediaType.IMAGE); + Media media = new Media(); + media.setUrl("https://upload.wikimedia.org/wikipedia/commons/f/f9/Phoenicopterus_ruber_in_S%C3%A3o_Paulo_Zoo.jpg"); + imageParam.setImage(media); + card0HeaderComponent.setParameters(Collections.singletonList(imageParam)); + card0Components.add(card0HeaderComponent); +// card0 body + MessageComponent card0BodyComponent = new MessageComponent(); + card0BodyComponent.setType(MessageComponentType.BODY); + MessageParam textParam = new MessageParam(); + textParam.setType(TemplateMediaType.TEXT); + textParam.setText("dummy text"); + card0BodyComponent.setParameters(Collections.singletonList(textParam)); + card0Components.add(card0BodyComponent); +// card0 button + MessageComponent card0ButtonComponent = new MessageComponent(); + card0ButtonComponent.setType(MessageComponentType.BUTTON); + card0ButtonComponent.setSub_type("quick_reply"); + card0ButtonComponent.setIndex(0); + MessageParam buttonParam = new MessageParam(); + buttonParam.setType(TemplateMediaType.PAYLOAD); + buttonParam.setPayload("dummy button"); + card0ButtonComponent.setParameters(Collections.singletonList(buttonParam)); + card0Components.add(card0ButtonComponent); + +// card0 + MessageComponent card0 = new MessageComponent(); + card0.setType(MessageComponentType.CARD); + card0.setCard_index(0); + card0.setComponents(card0Components); + + +// cards list + List cards = new ArrayList<>(); + cards.add(card0); + +// carousel component + MessageComponent carousel = new MessageComponent(); + carousel.setType(MessageComponentType.CAROUSEL); + carousel.setCards(cards); +// body component + MessageComponent body = new MessageComponent(); + body.setType(MessageComponentType.BODY); + MessageParam bodyParam = new MessageParam(); + bodyParam.setType(TemplateMediaType.TEXT); + bodyParam.setText("Jackson"); + body.setParameters(Collections.singletonList(bodyParam)); + +// set components to message + List messageComponents = new ArrayList<>(); + messageComponents.add(body); + messageComponents.add(carousel); + conversationContentHsm.setComponents(messageComponents); + + conversationContent.setHsm(conversationContentHsm); + ConversationSendRequest request = new ConversationSendRequest( + args[2], + ConversationContentType.HSM, + conversationContent, + args[1], + "", + null, + null, + null); + + try { + ConversationSendResponse sendResponse = messageBirdClient.sendMessage(request); + System.out.println(sendResponse.toString()); + + } catch (GeneralException | UnauthorizedException exception) { + exception.printStackTrace(); + } + } +} From 90e1840c8a3413c1a85ad3a96ec238bb5f3bbbae Mon Sep 17 00:00:00 2001 From: Alexander Levintsev <44775486+AlexL-mb@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:08:01 +0100 Subject: [PATCH 68/99] removed unused private field card from MessageComponent --- .../objects/conversations/MessageComponent.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java b/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java index 6bb9ca79..d3a7c20b 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java +++ b/api/src/main/java/com/messagebird/objects/conversations/MessageComponent.java @@ -10,7 +10,6 @@ public class MessageComponent { private List parameters; private int card_index; private List cards; - private MessageComponent card; private List components; public void setType(MessageComponentType type) { @@ -61,14 +60,6 @@ public void setCard_index(int card_index) { this.card_index = card_index; } - public MessageComponent getCard() { - return card; - } - - public void setCard(MessageComponent card) { - this.card = card; - } - public List getComponents() { return components; } @@ -82,8 +73,9 @@ public String toString() { return "MessageComponent{" + "type='" + type + '\'' + ", sub_type='" + sub_type + '\'' + - ", index=" + index + + ", index=" + index + '\'' + ", parameters=" + parameters + '\'' + + ", components=" + components + '\'' + ", cards=" + cards + '}'; } From e7f9a5b0570081979f03995508b868d883ee06a2 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 7 Mar 2024 13:53:50 +0100 Subject: [PATCH 69/99] new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 123cbaad..eec90102 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.4 + 6.1.5-SNAPSHOT jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 35b2a705..ca9651fb 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -71,7 +71,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.1.4"; + private final String clientVersion = "6.1.5"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 7c103dc4..1f130fb0 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.1.4 + 6.1.5 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.1.4 + 6.1.5 compile From 2295a5ad2aec69f3e5843d5a9545121561275ac1 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 7 Mar 2024 13:55:18 +0100 Subject: [PATCH 70/99] [maven-release-plugin] prepare release v6.1.5 --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index eec90102..b56694bd 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.5-SNAPSHOT + 6.1.5 jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - HEAD + v6.1.5 From bc9b0ffd8bab145bb383b773d0150f5dba5b2f53 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 7 Mar 2024 13:55:23 +0100 Subject: [PATCH 71/99] [maven-release-plugin] prepare for next development iteration --- api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index b56694bd..8934ab77 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.5 + 6.1.6-SNAPSHOT jar ${project.groupId}:${project.artifactId} @@ -39,7 +39,7 @@ scm:git:git@github.com:messagebird/java-rest-api.git scm:git:git@github.com:messagebird/java-rest-api.git git@github.com:messagebird/java-rest-api.git - v6.1.5 + HEAD From c1b872a10bd470b0b2aa2b0ef548722f1bcb0bf9 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Thu, 7 Mar 2024 14:15:22 +0100 Subject: [PATCH 72/99] new release --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 8934ab77..6f1ceec6 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.6-SNAPSHOT + 6.1.5 jar ${project.groupId}:${project.artifactId} From 905a11215646a0505c2de1bfba7bb5fc50b726bc Mon Sep 17 00:00:00 2001 From: Elkhan Eminov Date: Sun, 14 Apr 2024 21:12:49 +0200 Subject: [PATCH 73/99] fix java version parsing --- api/pom.xml | 5 ++ .../messagebird/MessageBirdServiceImpl.java | 54 +++++++------------ 2 files changed, 23 insertions(+), 36 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 6f1ceec6..54cddd64 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -92,6 +92,11 @@ java-jwt 3.17.0 + + org.apache.maven + maven-artifact + 3.9.6 + junit junit diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index ca9651fb..ac84617b 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -8,6 +8,8 @@ import com.messagebird.exceptions.UnauthorizedException; import com.messagebird.objects.ErrorReport; import com.messagebird.objects.PagedPaging; +import org.apache.maven.artifact.versioning.ComparableVersion; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -60,8 +62,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private static final String[] PROTOCOL_LISTS = new String[]{"http://", "https://"}; private static final List PROTOCOLS = Arrays.asList(PROTOCOL_LISTS); - // Used when the actual version can not be parsed. - private static final double DEFAULT_JAVA_VERSION = 0.0; + private static final ComparableVersion JAVA_VERSION = getJavaVersion(); // Indicates whether we've overridden HttpURLConnection's behaviour to // allow PATCH requests yet. Also see docs on allowPatchRequestsIfNeeded(). @@ -88,15 +89,17 @@ public MessageBirdServiceImpl(final String accessKey, final String serviceUrl) { } - private String determineUserAgentString() { - double javaVersion = DEFAULT_JAVA_VERSION; + private static ComparableVersion getJavaVersion() { try { - javaVersion = getVersion(); - } catch (GeneralException e) { - // Do nothing: leave the version at its default. + String version = System.getProperty("java.version"); + return new ComparableVersion(version); + } catch (IllegalArgumentException e) { + return new ComparableVersion("0.0"); } + } - return String.format("MessageBird Java/%s ApiClient/%s", javaVersion, clientVersion); + private String determineUserAgentString() { + return String.format("MessageBird Java/%s ApiClient/%s", JAVA_VERSION, clientVersion); } /** @@ -360,7 +363,7 @@ private void handleHttpFailStatuses(final int status, String body) throws Unauth

APIResponse doRequest(final String method, final String url, final Map headers, final P payload) throws GeneralException { HttpURLConnection connection = null; InputStream inputStream = null; - + if (METHOD_PATCH.equalsIgnoreCase(method)) { // It'd perhaps be cleaner to call this in the constructor, but // we'd then need to throw GeneralExceptions from there. This means @@ -473,13 +476,13 @@ private synchronized static void allowPatchRequestsIfNeeded() throws GeneralExce Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL); - + Object noInstanceBecauseStaticField = null; - + // Determine what methods should be allowed. String[] existingMethods = (String[]) methodsField.get(noInstanceBecauseStaticField); String[] allowedMethods = getAllowedMethods(existingMethods); - + // Override the actual field to allow PATCH. methodsField.set(noInstanceBecauseStaticField, allowedMethods); @@ -631,34 +634,13 @@ private void setAdditionalHeaders(HttpURLConnection connection, Map 1.6) { + ComparableVersion java6 = new ComparableVersion("1.6"); + if (JAVA_VERSION.compareTo(java6) > 0) { return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); } return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZ"); } - private double getVersion() throws GeneralException { - String version = System.getProperty("java.version"); - - try { - int pos = version.indexOf('.'); - pos = version.indexOf('.', pos + 1); - - return Double.parseDouble(version.substring(0, pos)); - } catch (RuntimeException e) { - // Thrown if the index is out of bounds, or when we can't parse a - // double for some reason. - throw new GeneralException(e); - } - } - /** * Get the MessageBird error report data. * @@ -802,7 +784,7 @@ private String getPathVariables(final Map map) { // the value is returned from the next() call bpath.append(encodeKeyValuePair(param.getKey(), iterator.next())); count++; - } + } } else { // If the value is not a collection, create the querystring value directly. bpath.append(encodeKeyValuePair(param.getKey(), param.getValue())); From 45aaecccdbb40082c07c2bb64287189a7e8752f0 Mon Sep 17 00:00:00 2001 From: denizkilic Date: Mon, 15 Apr 2024 18:22:36 +0200 Subject: [PATCH 74/99] maxAttempts param in VerifyRequest --- .../main/java/com/messagebird/objects/VerifyRequest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/src/main/java/com/messagebird/objects/VerifyRequest.java b/api/src/main/java/com/messagebird/objects/VerifyRequest.java index 70de2591..bee684e9 100644 --- a/api/src/main/java/com/messagebird/objects/VerifyRequest.java +++ b/api/src/main/java/com/messagebird/objects/VerifyRequest.java @@ -15,6 +15,7 @@ public class VerifyRequest implements Serializable { private String template; private Integer timeout; private Integer tokenLength; + private Integer maxAttempts; private Gender voice; private Language language; private String subject; @@ -124,4 +125,12 @@ public void setSubject(String subject) { public String getSubject() { return subject; } + + public Integer getMaxAttempts() { + return maxAttempts; + } + + public void setMaxAttempts(Integer maxAttempts) { + this.maxAttempts = maxAttempts; + } } From 61fc3f2857310f8f82e9f0e2fd2b48d72e316821 Mon Sep 17 00:00:00 2001 From: Deniz Kilic Date: Mon, 15 Apr 2024 19:36:24 +0200 Subject: [PATCH 75/99] Cut 6.1.6 (#255) *release v6.1.6 --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 54cddd64..2f375fdf 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.5 + 6.1.6 jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index ac84617b..7e11ee5a 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.1.5"; + private final String clientVersion = "6.1.6"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 1f130fb0..68637ec2 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.1.5 + 6.1.6 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.1.5 + 6.1.6 compile From d9af92705c8421be1bdf8821f468010f2417ab2f Mon Sep 17 00:00:00 2001 From: Daniel AM Date: Tue, 28 May 2024 12:03:09 +0100 Subject: [PATCH 76/99] =?UTF-8?q?Issue-256:=20Updated=20the=20checkHeader?= =?UTF-8?q?=20to=20allow=20header=5Furl=20in=20both=20video=20and=20image?= =?UTF-8?q?=20a=E2=80=A6=20(#257)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * updated the checkHeader to allow header_url in both video and image as it is supported * added document format --------- Co-authored-by: denizkilic --- .../com/messagebird/objects/integrations/HSMComponent.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java index c13f2761..4e3fe648 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java @@ -166,10 +166,9 @@ private void checkHeaderText() throws IllegalArgumentException { * @throws IllegalArgumentException Occurs when type is not {@code HEADER} and format is not {@code IMAGE}. */ private void checkHeaderUrl() throws IllegalArgumentException { - if (!(type.equals(HSMComponentType.HEADER) - && format.equals(HSMComponentFormat.IMAGE)) - ) { - throw new IllegalArgumentException("\"header_url\" is available for only HEADER type and IMAGE format."); + if (!(type.equals(HSMComponentType.HEADER) && + (format.equals(HSMComponentFormat.IMAGE) || format.equals(HSMComponentFormat.VIDEO) || format.equals(HSMComponentFormat.DOCUMENT)))) { + throw new IllegalArgumentException("\"header_url\" is available for only HEADER type and IMAGE, VIDEO and DOCUMENT format."); } } } From 39145c43883a716e77e01a78ce6b7909a3924f4b Mon Sep 17 00:00:00 2001 From: Deniz Kilic Date: Tue, 28 May 2024 13:32:24 +0200 Subject: [PATCH 77/99] Release 6.1.7 (#258) * new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 2f375fdf..c6bc186b 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.6 + 6.1.7 jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 7e11ee5a..f8e30a86 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.1.6"; + private final String clientVersion = "6.1.7"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 68637ec2..37e71aa6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.1.6 + 6.1.7 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.1.6 + 6.1.7 compile From b742d17839a79ad0859215ed517ac22b40cc300c Mon Sep 17 00:00:00 2001 From: Chris Eager <79161849+eager-signal@users.noreply.github.com> Date: Mon, 23 Sep 2024 04:36:14 -0500 Subject: [PATCH 78/99] Update com.auth0:java-jwt to 4.4.0 (#259) --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/RequestValidator.java | 6 ++++-- .../test/java/com/messagebird/RequestValidatorTest.java | 9 ++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index c6bc186b..a4d2e90a 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -90,7 +90,7 @@ com.auth0 java-jwt - 3.17.0 + 4.4.0 org.apache.maven diff --git a/api/src/main/java/com/messagebird/RequestValidator.java b/api/src/main/java/com/messagebird/RequestValidator.java index f2a4613b..24ae6343 100644 --- a/api/src/main/java/com/messagebird/RequestValidator.java +++ b/api/src/main/java/com/messagebird/RequestValidator.java @@ -5,13 +5,14 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.Clock; +import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.JWTVerifier; import com.messagebird.exceptions.RequestValidationException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.time.Clock; /** * RequestValidator validates request signature signed by MessageBird services. @@ -128,7 +129,8 @@ public DecodedJWT validateSignature(Clock clock, String signature, String url, b if (!skipURLValidation) builder.withClaim("url_hash", calculateSha256(url.getBytes())); - boolean payloadHashClaimExist = !jwt.getClaim("payload_hash").isNull(); + Claim payloadHashClaim = jwt.getClaim("payload_hash"); + boolean payloadHashClaimExist = !(payloadHashClaim.isNull() || payloadHashClaim.isMissing()); if (requestBody != null && requestBody.length > 0) { if (!payloadHashClaimExist) { throw new RequestValidationException("The Claim 'payload_hash' is not set but payload is present."); diff --git a/api/src/test/java/com/messagebird/RequestValidatorTest.java b/api/src/test/java/com/messagebird/RequestValidatorTest.java index a8d38132..23c64ef0 100644 --- a/api/src/test/java/com/messagebird/RequestValidatorTest.java +++ b/api/src/test/java/com/messagebird/RequestValidatorTest.java @@ -1,6 +1,5 @@ package com.messagebird; -import com.auth0.jwt.interfaces.Clock; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.messagebird.exceptions.RequestValidationException; @@ -13,7 +12,10 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.Clock; +import java.time.Instant; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.util.*; import java.util.stream.Collectors; @@ -64,10 +66,7 @@ public static Collection data() throws IOException { public void testWebhookSignature() throws Throwable { RequestValidator validator = new RequestValidator(testCase.secret != null ? testCase.secret : ""); - Clock clock = mock(Clock.class); - Date clockDate = spy(Date.from(OffsetDateTime.parse(testCase.timestamp).toInstant())); - when(clock.getToday()).thenReturn(clockDate); - + Clock clock = Clock.fixed(OffsetDateTime.parse(testCase.timestamp).toInstant(), ZoneId.systemDefault()); ThrowingRunnable runnable = () -> validator.validateSignature(clock, testCase.token, testCase.url, (testCase.payload == null) ? null : testCase.payload.getBytes(StandardCharsets.UTF_8)); From aa7ab0b512e336021ec94593b42dba0c84a51f8d Mon Sep 17 00:00:00 2001 From: Alyona Akulshyn <165909017+alyona007@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:38:48 +0200 Subject: [PATCH 79/99] Add support for LTO templates (#262) Add unpause method support --- .../conversations/MessageComponentType.java | 23 +++-- .../objects/conversations/MessageParam.java | 44 +++++++-- .../conversations/TemplateMediaType.java | 26 +++-- .../objects/integrations/HSMComponent.java | 52 +++++++--- .../integrations/HSMComponentType.java | 27 ++++-- .../MessageComponentTypeTest.java | 28 ++++++ .../conversations/MessageParamTest.java | 30 ++++++ .../conversations/TemplateMediaTypeTest.java | 27 ++++++ .../integrations/HSMComponentTest.java | 26 +++++ .../integrations/HSMComponentTypeTest.java | 23 +++++ ...sationSendHSMLimitedTimeOfferTemplate.java | 90 ++++++++++++++++++ ...ExampleCreateLimitedTimeOfferTemplate.java | 95 +++++++++++++++++++ 12 files changed, 443 insertions(+), 48 deletions(-) create mode 100644 api/src/test/java/com/messagebird/objects/conversations/MessageComponentTypeTest.java create mode 100644 api/src/test/java/com/messagebird/objects/conversations/MessageParamTest.java create mode 100644 api/src/test/java/com/messagebird/objects/conversations/TemplateMediaTypeTest.java create mode 100644 api/src/test/java/com/messagebird/objects/integrations/HSMComponentTest.java create mode 100644 api/src/test/java/com/messagebird/objects/integrations/HSMComponentTypeTest.java create mode 100644 examples/src/main/java/ExampleConversationSendHSMLimitedTimeOfferTemplate.java create mode 100644 examples/src/main/java/ExampleCreateLimitedTimeOfferTemplate.java diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java b/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java index c2be69bf..cdb695cd 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java +++ b/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import java.util.*; + public enum MessageComponentType { HEADER("header"), @@ -10,8 +12,18 @@ public enum MessageComponentType { FOOTER("footer"), BUTTON("button"), CARD("card"), - CAROUSEL("carousel"); + CAROUSEL("carousel"), + LIMITED_TIME_OFFER("limited_time_offer"); + + private static final Map TYPE_MAP; + static { + Map map = new HashMap<>(); + for (MessageComponentType componentType : MessageComponentType.values()) { + map.put(componentType.getType().toLowerCase(), componentType); + } + TYPE_MAP = Collections.unmodifiableMap(map); + } private final String type; @@ -21,13 +33,8 @@ public enum MessageComponentType { @JsonCreator public static MessageComponentType forValue(String value) { - for (MessageComponentType componentType: MessageComponentType.values()) { - if (componentType.getType().equals(value)) { - return componentType; - } - } - - return null; + Objects.requireNonNull(value, "Value cannot be null"); + return TYPE_MAP.get(value.toLowerCase(Locale.ROOT)); } @JsonValue diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java b/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java index 069c3f62..38ae18f6 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java +++ b/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java @@ -1,5 +1,8 @@ package com.messagebird.objects.conversations; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.StringUtils; + public class MessageParam { private TemplateMediaType type; @@ -10,6 +13,8 @@ public class MessageParam { private Media document; private Media image; private Media video; + @JsonProperty("expiration_time") + private String expirationTime; public TemplateMediaType getType() { return type; @@ -24,6 +29,9 @@ public String getText() { } public void setText(String text) { + if (StringUtils.isBlank(text)) { + throw new IllegalArgumentException("Text cannot be null or empty"); + } this.text = text; } @@ -48,6 +56,9 @@ public String getDateTime() { } public void setDateTime(String dateTime) { + if (StringUtils.isBlank(dateTime)) { + throw new IllegalArgumentException("dateTime cannot be null or empty"); + } this.dateTime = dateTime; } @@ -71,17 +82,30 @@ public void setImage(Media image) { public void setVideo(Media video) { this.video = video; } + public String getExpirationTime() { + return expirationTime; + } + + public void setExpirationTime(String expirationTime) { + if (StringUtils.isBlank(expirationTime)) { + throw new IllegalArgumentException("expirationTime cannot be null or empty"); + } + this.expirationTime = expirationTime; + } + @Override public String toString() { - return "MessageParam{" + - "type=" + type + '\'' + - ", text='" + text + '\'' + - ", payload='" + payload + '\'' + - ", currency=" + currency + '\'' + - ", dateTime='" + dateTime + '\'' + - ", document=" + document + '\'' + - ", image=" + image + '\'' + - ", video=" + video + - '}'; + StringBuilder sb = new StringBuilder("MessageParam{"); + sb.append("type=").append(type) + .append(", text='").append(text).append('\'') + .append(", payload='").append(payload).append('\'') + .append(", currency=").append(currency) + .append(", dateTime='").append(dateTime).append('\'') + .append(", document=").append(document) + .append(", image=").append(image) + .append(", video=").append(video) + .append(", expirationTime='").append(expirationTime).append('\'') + .append('}'); + return sb.toString(); } } diff --git a/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java b/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java index fe5494fd..fd600ab2 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java +++ b/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java @@ -2,6 +2,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Map; +import java.util.HashMap; +import java.util.Collections; public enum TemplateMediaType { @@ -11,7 +14,19 @@ public enum TemplateMediaType { TEXT("text"), CURRENCY("currency"), DATETIME("date_time"), - PAYLOAD("payload"); + PAYLOAD("payload"), + EXPIRATION_TIME("expiration_time"); + + private static final Map TYPE_MAP; + + static { + Map map = new HashMap<>(); + for (TemplateMediaType templateMediaType : TemplateMediaType.values()) { + map.put(templateMediaType.getType().toLowerCase(), templateMediaType); + } + TYPE_MAP = Collections.unmodifiableMap(map); + } + private final String type; @@ -21,13 +36,10 @@ public enum TemplateMediaType { @JsonCreator public static TemplateMediaType forValue(String value) { - for (TemplateMediaType templateMediaType: TemplateMediaType.values()) { - if (templateMediaType.getType().equals(value)) { - return templateMediaType; - } + if (value == null) { + throw new IllegalArgumentException("Value cannot be null"); } - - return null; + return TYPE_MAP.get(value.toLowerCase()); } @JsonValue diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java index 4e3fe648..ed93847f 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponent.java @@ -1,6 +1,7 @@ package com.messagebird.objects.integrations; import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.StringUtils; import java.util.List; @@ -20,6 +21,8 @@ public class HSMComponent { @JsonProperty("code_expiration_minutes") private Integer codeExpirationMinutes; private List buttons; + @JsonProperty("has_expiration") + private Boolean hasExpiration; private List cards; @@ -46,6 +49,9 @@ public String getText() { } public void setText(String text) { + if (StringUtils.isBlank(text)) { + throw new IllegalArgumentException("Text cannot be null or empty"); + } this.text = text; } @@ -88,15 +94,29 @@ public Integer getCodeExpirationMinutes() { public void setCodeExpirationMinutes(Integer codeExpirationMinutes) { this.codeExpirationMinutes = codeExpirationMinutes; } + + public Boolean getHasExpiration() { + return hasExpiration; + } + + public void setHasExpiration(Boolean hasExpiration) { + this.hasExpiration = hasExpiration; + } + @Override public String toString() { - return "HSMComponent{" + - "type='" + type + '\'' + - ", format='" + format + '\'' + - ", text='" + text + '\'' + - ", buttons=" + buttons + - ", example=" + example + - '}'; + StringBuilder sb = new StringBuilder("HSMComponent{"); + sb.append("type=").append(type) + .append(", format=").append(format) + .append(", text='").append(text).append('\'') + .append(", addSecurityRecommendation=").append(addSecurityRecommendation) + .append(", codeExpirationMinutes=").append(codeExpirationMinutes) + .append(", buttons=").append(buttons) + .append(", hasExpiration=").append(hasExpiration) + .append(", cards=").append(cards) + .append(", example=").append(example) + .append('}'); + return sb.toString(); } /** @@ -105,8 +125,12 @@ public String toString() { * @throws IllegalArgumentException Occurs when validation is not passed. */ public void validateComponent() throws IllegalArgumentException { - this.validateButtons(); - this.validateComponentExample(); + try { + this.validateButtons(); + this.validateComponentExample(); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Component validation failed: " + e.getMessage(), e); + } } /** @@ -153,9 +177,7 @@ private void validateComponentExample() throws IllegalArgumentException { * @throws IllegalArgumentException Occurs when type is not {@code HEADER} and format is not {@code TEXT}. */ private void checkHeaderText() throws IllegalArgumentException { - if (!(type.equals(HSMComponentType.HEADER) - && format.equals(HSMComponentFormat.TEXT)) - ) { + if (!(HSMComponentType.HEADER.equals(type) && HSMComponentFormat.TEXT.equals(format))) { throw new IllegalArgumentException("\"header_text\" is available for only HEADER type and TEXT format."); } } @@ -166,9 +188,9 @@ private void checkHeaderText() throws IllegalArgumentException { * @throws IllegalArgumentException Occurs when type is not {@code HEADER} and format is not {@code IMAGE}. */ private void checkHeaderUrl() throws IllegalArgumentException { - if (!(type.equals(HSMComponentType.HEADER) && - (format.equals(HSMComponentFormat.IMAGE) || format.equals(HSMComponentFormat.VIDEO) || format.equals(HSMComponentFormat.DOCUMENT)))) { - throw new IllegalArgumentException("\"header_url\" is available for only HEADER type and IMAGE, VIDEO and DOCUMENT format."); + if (!(HSMComponentType.HEADER.equals(type) && + (HSMComponentFormat.IMAGE.equals(format) || HSMComponentFormat.VIDEO.equals(format) || HSMComponentFormat.DOCUMENT.equals(format)))) { + throw new IllegalArgumentException("\"header_url\" is available for only HEADER type and IMAGE, VIDEO, or DOCUMENT formats."); } } } diff --git a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java index eff331dc..8610146a 100644 --- a/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java +++ b/api/src/main/java/com/messagebird/objects/integrations/HSMComponentType.java @@ -2,6 +2,11 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Map; +import java.util.HashMap; +import java.util.Collections; +import java.util.Locale; +import java.util.Objects; /** * An enum for HSMComponentType @@ -13,7 +18,18 @@ public enum HSMComponentType { HEADER("HEADER"), FOOTER("FOOTER"), BUTTONS("BUTTONS"), - CAROUSEL("CAROUSEL"); + CAROUSEL("CAROUSEL"), + LIMITED_TIME_OFFER("LIMITED_TIME_OFFER"); + + private static final Map TYPE_MAP; + + static { + Map map = new HashMap<>(); + for (HSMComponentType hsmComponentType : HSMComponentType.values()) { + map.put(hsmComponentType.getType().toLowerCase(), hsmComponentType); + } + TYPE_MAP = Collections.unmodifiableMap(map); + } private final String type; @@ -23,13 +39,8 @@ public enum HSMComponentType { @JsonCreator public static HSMComponentType forValue(String value) { - for (HSMComponentType hsmComponentType : HSMComponentType.values()) { - if (hsmComponentType.getType().equals(value)) { - return hsmComponentType; - } - } - - return null; + Objects.requireNonNull(value, "Value cannot be null"); + return TYPE_MAP.get(value.toLowerCase(Locale.ROOT)); } @JsonValue diff --git a/api/src/test/java/com/messagebird/objects/conversations/MessageComponentTypeTest.java b/api/src/test/java/com/messagebird/objects/conversations/MessageComponentTypeTest.java new file mode 100644 index 00000000..385b1652 --- /dev/null +++ b/api/src/test/java/com/messagebird/objects/conversations/MessageComponentTypeTest.java @@ -0,0 +1,28 @@ +package com.messagebird.objects.conversations; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class MessageComponentTypeTest { + @Test + public void testMessageComponentTypeForValueValid() { + assertEquals(MessageComponentType.HEADER, MessageComponentType.forValue("header")); + assertEquals(MessageComponentType.BUTTON, MessageComponentType.forValue("button")); + } + + @Test(expected = NullPointerException.class) + public void testMessageComponentTypeForValueNull() { + MessageComponentType.forValue(null); + } + + @Test + public void testMessageComponentTypeForValueInvalid() { + assertNull(MessageComponentType.forValue("invalid_type")); + } + + @Test + public void testMessageComponentTypeToString() { + assertEquals("header", MessageComponentType.HEADER.toString()); + } +} diff --git a/api/src/test/java/com/messagebird/objects/conversations/MessageParamTest.java b/api/src/test/java/com/messagebird/objects/conversations/MessageParamTest.java new file mode 100644 index 00000000..6ddabad7 --- /dev/null +++ b/api/src/test/java/com/messagebird/objects/conversations/MessageParamTest.java @@ -0,0 +1,30 @@ +package com.messagebird.objects.conversations; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +public class MessageParamTest { + @Test + public void testMessageParamToString() { + MessageParam param = new MessageParam(); + param.setType(TemplateMediaType.IMAGE); + param.setText("Sample text"); + param.setPayload("Sample payload"); + + String expected = "MessageParam{type=image, text='Sample text', payload='Sample payload', currency=null, dateTime='null', document=null, image=null, video=null, expirationTime='null'}"; + assertEquals(expected, param.toString()); + } + + @Test(expected = IllegalArgumentException.class) + public void testMessageParamSetTextInvalid() { + MessageParam param = new MessageParam(); + param.setText(""); + } + + @Test + public void testMessageParamSetTextValid() { + MessageParam param = new MessageParam(); + param.setText("Valid text"); + assertEquals("Valid text", param.getText()); + } +} diff --git a/api/src/test/java/com/messagebird/objects/conversations/TemplateMediaTypeTest.java b/api/src/test/java/com/messagebird/objects/conversations/TemplateMediaTypeTest.java new file mode 100644 index 00000000..d30bde28 --- /dev/null +++ b/api/src/test/java/com/messagebird/objects/conversations/TemplateMediaTypeTest.java @@ -0,0 +1,27 @@ +package com.messagebird.objects.conversations; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class TemplateMediaTypeTest { + @Test + public void testTemplateMediaTypeForValueValid() { + assertEquals(TemplateMediaType.VIDEO, TemplateMediaType.forValue("video")); + } + + @Test(expected = IllegalArgumentException.class) + public void testTemplateMediaTypeForValueNull() { + TemplateMediaType.forValue(null); + } + + @Test + public void testTemplateMediaTypeForValueInvalid() { + assertNull(TemplateMediaType.forValue("non_existing_value")); + } + + @Test + public void testTemplateMediaTypeToString() { + assertEquals("video", TemplateMediaType.VIDEO.toString()); + } +} diff --git a/api/src/test/java/com/messagebird/objects/integrations/HSMComponentTest.java b/api/src/test/java/com/messagebird/objects/integrations/HSMComponentTest.java new file mode 100644 index 00000000..9af4bb64 --- /dev/null +++ b/api/src/test/java/com/messagebird/objects/integrations/HSMComponentTest.java @@ -0,0 +1,26 @@ +package com.messagebird.objects.integrations; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +public class HSMComponentTest { + @Test + public void testToString() { + HSMComponent component = new HSMComponent(); + component.setType(HSMComponentType.BODY); + component.setFormat(HSMComponentFormat.TEXT); + component.setText("Test text"); + component.setAddSecurityRecommendation(true); + component.setCodeExpirationMinutes(10); + component.setHasExpiration(true); + + String expected = "HSMComponent{type=BODY, format=TEXT, text='Test text', addSecurityRecommendation=true, codeExpirationMinutes=10, buttons=null, hasExpiration=true, cards=null, example=null}"; + assertEquals(expected, component.toString()); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetTextInvalid() { + HSMComponent component = new HSMComponent(); + component.setText(""); + } +} diff --git a/api/src/test/java/com/messagebird/objects/integrations/HSMComponentTypeTest.java b/api/src/test/java/com/messagebird/objects/integrations/HSMComponentTypeTest.java new file mode 100644 index 00000000..47053509 --- /dev/null +++ b/api/src/test/java/com/messagebird/objects/integrations/HSMComponentTypeTest.java @@ -0,0 +1,23 @@ +package com.messagebird.objects.integrations; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class HSMComponentTypeTest { + @Test + public void testForValueValid() { + assertEquals(HSMComponentType.BODY, HSMComponentType.forValue("BODY")); + assertEquals(HSMComponentType.BODY, HSMComponentType.forValue("body")); + } + + @Test(expected = NullPointerException.class) + public void testForValueNull() { + HSMComponentType.forValue(null); + } + + @Test + public void testForValueInvalid() { + assertNull(HSMComponentType.forValue("INVALID")); + } +} diff --git a/examples/src/main/java/ExampleConversationSendHSMLimitedTimeOfferTemplate.java b/examples/src/main/java/ExampleConversationSendHSMLimitedTimeOfferTemplate.java new file mode 100644 index 00000000..65b959a8 --- /dev/null +++ b/examples/src/main/java/ExampleConversationSendHSMLimitedTimeOfferTemplate.java @@ -0,0 +1,90 @@ +import com.messagebird.MessageBirdClient; +import com.messagebird.MessageBirdService; +import com.messagebird.MessageBirdServiceImpl; +import com.messagebird.exceptions.GeneralException; +import com.messagebird.exceptions.UnauthorizedException; +import com.messagebird.objects.conversations.*; + +import java.util.ArrayList; +import java.util.List; + +public class ExampleConversationSendHSMLimitedTimeOfferTemplate { + + public static void main(String[] args) { + if (args.length < 6) { + System.out.println("Please at least specify your access key, the channel id and destination address.\n" + + "Usage : java -jar test_accesskey(Required) channel_id(Required) from(Required) destination(Required) templateName(Required) namespace(Required) expirationTimeInput(Required)"); + return; + } + + final String accessKey = args[0]; + final String from = args[1]; + final String destination = args[2]; + final String templateName = args[3]; + final String namespace = args[4]; + final String expirationTimeInput = args[5]; + + //First create your service object + final MessageBirdService wsr = new MessageBirdServiceImpl(accessKey); + //Add the service to the client + final MessageBirdClient messageBirdClient = new MessageBirdClient(wsr); + + ConversationContent conversationContent = new ConversationContent(); + ConversationContentHsm conversationContentHsm = new ConversationContentHsm(); + conversationContentHsm.setNamespace(namespace); + conversationContentHsm.setTemplateName(templateName); + ConversationHsmLanguage language = new ConversationHsmLanguage(); + language.setCode("en"); + conversationContentHsm.setLanguage(language); + List messageComponents = new ArrayList<>(); + + // Add LTO component + MessageComponent messageLTOComponent = new MessageComponent(); + messageLTOComponent.setType(MessageComponentType.LIMITED_TIME_OFFER); + List messageLTOParams = new ArrayList<>(); + + MessageParam expirationTime = new MessageParam(); + expirationTime.setType(TemplateMediaType.EXPIRATION_TIME); + expirationTime.setExpirationTime(expirationTimeInput); + messageLTOParams.add(expirationTime); + + messageLTOComponent.setParameters(messageLTOParams); + + // Add body component + MessageComponent messageBodyComponent = new MessageComponent(); + messageBodyComponent.setType(MessageComponentType.BODY); + List messageBodyParams = new ArrayList<>(); + + MessageParam text = new MessageParam(); + text.setType(TemplateMediaType.TEXT); + text.setText("Bob"); + messageBodyParams.add(text); + + messageBodyComponent.setParameters(messageBodyParams); + + messageComponents.add(messageLTOComponent); + messageComponents.add(messageBodyComponent); + conversationContentHsm.setComponents(messageComponents); + conversationContent.setHsm(conversationContentHsm); + ConversationSendRequest request = new ConversationSendRequest( + destination, + ConversationContentType.HSM, + conversationContent, + from, + "", + null, + null, + null); + + try { + ConversationSendResponse sendResponse = messageBirdClient.sendMessage(request); + System.out.println(sendResponse.toString()); + + } catch (UnauthorizedException e) { + System.err.println("Authorization failed. Please check your access key: " + e.getMessage()); + } catch (GeneralException e) { + System.err.println("An error occurred while sending the message: " + e.getMessage()); + } + } + +} diff --git a/examples/src/main/java/ExampleCreateLimitedTimeOfferTemplate.java b/examples/src/main/java/ExampleCreateLimitedTimeOfferTemplate.java new file mode 100644 index 00000000..dc721f9f --- /dev/null +++ b/examples/src/main/java/ExampleCreateLimitedTimeOfferTemplate.java @@ -0,0 +1,95 @@ +import com.messagebird.MessageBirdClient; +import com.messagebird.MessageBirdService; +import com.messagebird.MessageBirdServiceImpl; +import com.messagebird.exceptions.GeneralException; +import com.messagebird.exceptions.UnauthorizedException; +import com.messagebird.objects.integrations.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ExampleCreateLimitedTimeOfferTemplate { + + public static void main(String[] args) { + if (args.length < 4) { + System.out.println("Please specify your access key and a template name and WABA ID example : java -jar test_accesskey(Required) templateName(Required) wabaID(required)"); + return; + } + + final String accessKey = args[0]; + final String templateName = args[1]; + final String wabaID = args[2]; + + // First create your service object + final MessageBirdService wsr = new MessageBirdServiceImpl(accessKey); + + // Add the service to the client + final MessageBirdClient messageBirdClient = new MessageBirdClient(wsr); + + // header + final HSMComponent headerComponent = new HSMComponent(); + final HSMExample headerExample = new HSMExample(); + headerExample.setHeader_url(Arrays.asList("https://images.freeimages.com/images/small-previews/c5a/colourful-paper-rip-1-1195879.jpg")); + + headerComponent.setType(HSMComponentType.HEADER); + headerComponent.setFormat(HSMComponentFormat.IMAGE); + headerComponent.setExample(headerExample); + + // limited time offer + final HSMComponent ltoComponent = new HSMComponent(); + ltoComponent.setType(HSMComponentType.LIMITED_TIME_OFFER); + ltoComponent.setText("Expiring offer!"); + ltoComponent.setHasExpiration(true); + + // body + final HSMComponent bodyComponent = new HSMComponent(); + final HSMExample bodyExample = new HSMExample(); + final List> bodyText = new ArrayList<>(); + bodyText.add(Arrays.asList("John", "CARIBE25")); + bodyExample.setBody_text(bodyText); + + bodyComponent.setType(HSMComponentType.BODY); + bodyComponent.setText("Good news, {{1}}! Use code {{2}} to get 0% off all packages!"); + bodyComponent.setExample(bodyExample); + + // buttons + final HSMComponent buttonComponent = new HSMComponent(); + final List buttons = new ArrayList<>(); + + final HSMComponentButton buttonCopyCode = new HSMComponentButton(); + buttonCopyCode.setType(HSMComponentButtonType.COPY_CODE); + buttonCopyCode.setExample(Arrays.asList("CARIBE25")); + + final HSMComponentButton buttonBookNow = new HSMComponentButton(); + buttonBookNow.setType(HSMComponentButtonType.URL); + buttonBookNow.setText("Book now!"); + buttonBookNow.setUrl("https://www.bird.com?code={{1}}"); + buttonBookNow.setExample(Arrays.asList("https://www.bird.com?code=CARIBE25")); + + buttons.addAll(Arrays.asList(buttonCopyCode, buttonBookNow)); + buttonComponent.setType(HSMComponentType.BUTTONS); + buttonComponent.setButtons(buttons); + + // set components + final Template template = new Template(); + final List components = new ArrayList<>(); + components.addAll(Arrays.asList(headerComponent, ltoComponent, bodyComponent, buttonComponent)); + + template.setName(templateName); + template.setLanguage("en_US"); + template.setWABAID(wabaID); + template.setComponents(components); + template.setCategory(HSMCategory.MARKETING); + + try { + TemplateResponse response = messageBirdClient.createWhatsAppTemplate(template); + System.out.println(response.toString()); + } catch (UnauthorizedException e) { + System.err.println("Authorization failed. Please check your access key: " + e.getMessage()); + } catch (GeneralException e) { + System.err.println("An error occurred while sending the message: " + e.getMessage()); + } + } + +} From 0418288b73b21139279e3cc5b2f29fa172f3ba4c Mon Sep 17 00:00:00 2001 From: Deniz Kilic Date: Wed, 25 Sep 2024 11:29:08 +0200 Subject: [PATCH 80/99] Cut 6.2.1 (#263) * new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index a4d2e90a..4f732bad 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.1.7 + 6.2.1 jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index f8e30a86..03d52bea 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.1.7"; + private final String clientVersion = "6.2.1"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 37e71aa6..9d56a89f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.1.7 + 6.2.1 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.1.7 + 6.2.1 compile From 5a34cd2011cb48d97df23f3bc1516b1324da3ef9 Mon Sep 17 00:00:00 2001 From: Alyona Akulshyn <165909017+alyona007@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:25:45 +0100 Subject: [PATCH 81/99] Add unpause method support (#261) * Add unpause method support --- .../com/messagebird/MessageBirdClient.java | 18 +++++++++++++++ .../messagebird/MessageBirdServiceImpl.java | 3 +++ .../messagebird/MessageBirdClientTest.java | 22 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/messagebird/MessageBirdClient.java b/api/src/main/java/com/messagebird/MessageBirdClient.java index 7011ab10..583dcb40 100644 --- a/api/src/main/java/com/messagebird/MessageBirdClient.java +++ b/api/src/main/java/com/messagebird/MessageBirdClient.java @@ -105,6 +105,7 @@ public class MessageBirdClient { private static final String VOICELEGS_SUFFIX_PATH = "/legs"; static final String FILES_PATH = "/files"; static final String TEMPLATES_PATH = "/templates"; + static final String UNPAUSE_TEMAPLATE_PATH = "/unpause"; static final String OUTBOUND_SMS_PRICING_PATH = "/pricing/sms/outbound"; static final String OUTBOUND_SMS_PRICING_SMPP_PATH = "/pricing/sms/outbound/smpp/%s"; @@ -2145,6 +2146,23 @@ public void deleteTemplatesBy(final String templateName) messageBirdService.delete(url, null); } + public void unpauseTemplatesByTemplateName(final String templateName) + throws UnauthorizedException, GeneralException { + if (templateName == null) { + throw new IllegalArgumentException("Template name must be specified."); + } + + String url = String.format( + "%s%s%s%s/%s", + INTEGRATIONS_BASE_URL_V2, + INTEGRATIONS_WHATSAPP_PATH, + TEMPLATES_PATH, + UNPAUSE_TEMAPLATE_PATH, + templateName + ); + messageBirdService.sendPayLoad("POST", url, "", null); + } + /** * Function to create a child account * diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 03d52bea..a16019ef 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -382,6 +382,9 @@

APIResponse doRequest(final String method, final String url, final Map Date: Thu, 14 Nov 2024 13:40:07 +0100 Subject: [PATCH 82/99] Cut 6.2.2 (#264) * new release --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 4f732bad..2d99afc2 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.2.1 + 6.2.2 jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index a16019ef..a5e897dd 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.2.1"; + private final String clientVersion = "6.2.2"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 9d56a89f..4a98866a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.2.1 + 6.2.2 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.2.1 + 6.2.2 compile From be42898afb15ff8e6e29a46b7f15125c328e716b Mon Sep 17 00:00:00 2001 From: Venkateswaran S Date: Wed, 9 Apr 2025 10:31:09 +0200 Subject: [PATCH 83/99] support for copy code --- .../conversations/MessageComponentType.java | 3 +- .../objects/conversations/MessageParam.java | 9 ++ .../conversations/TemplateMediaType.java | 3 +- ...leConversationSendHSMCopyCodeTemplate.java | 92 +++++++++++++++++++ 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 examples/src/main/java/ExampleConversationSendHSMCopyCodeTemplate.java diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java b/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java index cdb695cd..9f9290cf 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java +++ b/api/src/main/java/com/messagebird/objects/conversations/MessageComponentType.java @@ -13,7 +13,8 @@ public enum MessageComponentType { BUTTON("button"), CARD("card"), CAROUSEL("carousel"), - LIMITED_TIME_OFFER("limited_time_offer"); + LIMITED_TIME_OFFER("limited_time_offer"), + COPY_CODE("copy_code"); private static final Map TYPE_MAP; diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java b/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java index 38ae18f6..7772d2cd 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java +++ b/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java @@ -15,6 +15,8 @@ public class MessageParam { private Media video; @JsonProperty("expiration_time") private String expirationTime; + @JsonProperty("coupon_code") + private String couponCode; public TemplateMediaType getType() { return type; @@ -93,6 +95,13 @@ public void setExpirationTime(String expirationTime) { this.expirationTime = expirationTime; } + public void setCouponCode(String couponCode) { + if (StringUtils.isBlank(couponCode)) { + throw new IllegalArgumentException("couponCode cannot be null or empty"); + } + this.couponCode = couponCode; + } + @Override public String toString() { StringBuilder sb = new StringBuilder("MessageParam{"); diff --git a/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java b/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java index fd600ab2..580dcc97 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java +++ b/api/src/main/java/com/messagebird/objects/conversations/TemplateMediaType.java @@ -15,7 +15,8 @@ public enum TemplateMediaType { CURRENCY("currency"), DATETIME("date_time"), PAYLOAD("payload"), - EXPIRATION_TIME("expiration_time"); + EXPIRATION_TIME("expiration_time"), + COUPON_CODE("coupon_code"); private static final Map TYPE_MAP; diff --git a/examples/src/main/java/ExampleConversationSendHSMCopyCodeTemplate.java b/examples/src/main/java/ExampleConversationSendHSMCopyCodeTemplate.java new file mode 100644 index 00000000..44f482bb --- /dev/null +++ b/examples/src/main/java/ExampleConversationSendHSMCopyCodeTemplate.java @@ -0,0 +1,92 @@ +import com.messagebird.MessageBirdClient; +import com.messagebird.MessageBirdService; +import com.messagebird.MessageBirdServiceImpl; +import com.messagebird.exceptions.GeneralException; +import com.messagebird.exceptions.UnauthorizedException; +import com.messagebird.objects.conversations.*; + +import java.util.ArrayList; +import java.util.List; + +public class ExampleConversationSendHSMCopyCodeTemplate { + + public static void main(String[] args) { + if (args.length < 6) { + System.out.println("Please at least specify your access key, the channel id and destination address.\n" + + "Usage : java -jar test_accesskey(Required) channel_id(Required) from(Required) destination(Required) templateName(Required) namespace(Required) expirationTimeInput(Required)"); + return; + } + + final String accessKey = args[0]; + final String from = args[1]; + final String destination = args[2]; + final String templateName = args[3]; + final String namespace = args[4]; + final String couponCodeInput = args[5]; + + //First create your service object + final MessageBirdService wsr = new MessageBirdServiceImpl(accessKey); + //Add the service to the client + final MessageBirdClient messageBirdClient = new MessageBirdClient(wsr); + + ConversationContent conversationContent = new ConversationContent(); + ConversationContentHsm conversationContentHsm = new ConversationContentHsm(); + conversationContentHsm.setNamespace(namespace); + conversationContentHsm.setTemplateName(templateName); + ConversationHsmLanguage language = new ConversationHsmLanguage(); + language.setCode("en"); + conversationContentHsm.setLanguage(language); + List messageComponents = new ArrayList<>(); + + // Add LTO component + MessageComponent messageCopyCodeComponent = new MessageComponent(); + messageCopyCodeComponent.setType(MessageComponentType.BUTTON); + messageCopyCodeComponent.setSub_type(MessageComponentType.COPY_CODE.toString()); + List messageCCParams = new ArrayList<>(); + + MessageParam couponCodeParam = new MessageParam(); + couponCodeParam.setType(TemplateMediaType.COUPON_CODE); + couponCodeParam.setCouponCode(couponCodeInput); + messageCCParams.add(couponCodeParam); + + messageCopyCodeComponent.setParameters(messageCCParams); + + // Add body component + MessageComponent messageBodyComponent = new MessageComponent(); + messageBodyComponent.setType(MessageComponentType.BODY); + List messageBodyParams = new ArrayList<>(); + + MessageParam text = new MessageParam(); + text.setType(TemplateMediaType.TEXT); + text.setText("Bob"); + messageBodyParams.add(text); + + messageBodyComponent.setParameters(messageBodyParams); + + messageComponents.add(messageCopyCodeComponent); + messageComponents.add(messageBodyComponent); + conversationContentHsm.setComponents(messageComponents); + conversationContent.setHsm(conversationContentHsm); + ConversationSendRequest request = new ConversationSendRequest( + destination, + ConversationContentType.HSM, + conversationContent, + from, + "", + null, + null, + null); + + try { + System.out.println(request.toString()); + ConversationSendResponse sendResponse = messageBirdClient.sendMessage(request); + System.out.println(sendResponse.toString()); + + } catch (UnauthorizedException e) { + System.err.println("Authorization failed. Please check your access key: " + e.getMessage()); + } catch (GeneralException e) { + System.err.println("An error occurred while sending the message: " + e.getMessage()); + } + } + +} From 41052be1a88176e6ea0ce1bb2453baaf7ad5c390 Mon Sep 17 00:00:00 2001 From: Venkat Sankaran Date: Wed, 9 Apr 2025 13:23:02 +0200 Subject: [PATCH 84/99] Update to version 6.2.3 --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 2d99afc2..fd0dbced 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.2.2 + 6.2.3 jar ${project.groupId}:${project.artifactId} From edf16851ea6d5c8f6f45fc09dda3cce8778380f1 Mon Sep 17 00:00:00 2001 From: Venkat Sankaran Date: Wed, 9 Apr 2025 13:24:40 +0200 Subject: [PATCH 85/99] Update examples --- examples/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 4a98866a..ba4ab890 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.2.2 + 6.2.3 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.2.2 + 6.2.3 compile From 94e0aee94e3e63d9e247db43d791a75cf53a49fd Mon Sep 17 00:00:00 2001 From: Venkat Sankaran Date: Wed, 9 Apr 2025 13:25:15 +0200 Subject: [PATCH 86/99] Update client version string --- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index a5e897dd..33f6f8e6 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.2.2"; + private final String clientVersion = "6.2.3"; private final String userAgentString; private Proxy proxy = null; From 2abd1cdad7b32cf5d10f6cef8cdeaa04320c6822 Mon Sep 17 00:00:00 2001 From: Venkateswaran S Date: Wed, 9 Apr 2025 16:38:43 +0200 Subject: [PATCH 87/99] update to version v6.2.4 --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index fd0dbced..cdfd9969 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.2.3 + 6.2.4 jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 33f6f8e6..b36427fc 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.2.3"; + private final String clientVersion = "6.2.4"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index ba4ab890..4b56224c 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.2.3 + 6.2.4 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.2.3 + 6.2.4 compile From 51dcd3911fd0855a2f5f8ecc038a442e8fefc0d6 Mon Sep 17 00:00:00 2001 From: Venkateswaran S Date: Thu, 10 Apr 2025 10:53:28 +0200 Subject: [PATCH 88/99] adding venkat to devs --- api/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/pom.xml b/api/pom.xml index cdfd9969..d060594d 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -27,6 +27,12 @@ MessageBird https://www.messagebird.com + + Venkateswaran S + venkat.sankaran@bird.com + MessageBird + https://www.messagebird.com + Sam Wierema sam@messagebird.com From 24b8bdb05553977c5437b903f3ab8b02a2fb4a04 Mon Sep 17 00:00:00 2001 From: Venkateswaran S Date: Fri, 11 Apr 2025 12:17:36 +0200 Subject: [PATCH 89/99] adding helper method to get copyCode --- .../com/messagebird/objects/conversations/MessageParam.java | 5 +++++ .../messagebird/objects/conversations/MessageParamTest.java | 2 +- .../java/ExampleConversationSendHSMCopyCodeTemplate.java | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java b/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java index 7772d2cd..6432369f 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java +++ b/api/src/main/java/com/messagebird/objects/conversations/MessageParam.java @@ -95,6 +95,10 @@ public void setExpirationTime(String expirationTime) { this.expirationTime = expirationTime; } + public String getCouponCode() { + return couponCode; + } + public void setCouponCode(String couponCode) { if (StringUtils.isBlank(couponCode)) { throw new IllegalArgumentException("couponCode cannot be null or empty"); @@ -114,6 +118,7 @@ public String toString() { .append(", image=").append(image) .append(", video=").append(video) .append(", expirationTime='").append(expirationTime).append('\'') + .append(", couponCode='").append(couponCode).append('\'') .append('}'); return sb.toString(); } diff --git a/api/src/test/java/com/messagebird/objects/conversations/MessageParamTest.java b/api/src/test/java/com/messagebird/objects/conversations/MessageParamTest.java index 6ddabad7..f1147d2f 100644 --- a/api/src/test/java/com/messagebird/objects/conversations/MessageParamTest.java +++ b/api/src/test/java/com/messagebird/objects/conversations/MessageParamTest.java @@ -11,7 +11,7 @@ public void testMessageParamToString() { param.setText("Sample text"); param.setPayload("Sample payload"); - String expected = "MessageParam{type=image, text='Sample text', payload='Sample payload', currency=null, dateTime='null', document=null, image=null, video=null, expirationTime='null'}"; + String expected = "MessageParam{type=image, text='Sample text', payload='Sample payload', currency=null, dateTime='null', document=null, image=null, video=null, expirationTime='null', couponCode='null'}"; assertEquals(expected, param.toString()); } diff --git a/examples/src/main/java/ExampleConversationSendHSMCopyCodeTemplate.java b/examples/src/main/java/ExampleConversationSendHSMCopyCodeTemplate.java index 44f482bb..4d5dcd3f 100644 --- a/examples/src/main/java/ExampleConversationSendHSMCopyCodeTemplate.java +++ b/examples/src/main/java/ExampleConversationSendHSMCopyCodeTemplate.java @@ -13,7 +13,7 @@ public class ExampleConversationSendHSMCopyCodeTemplate { public static void main(String[] args) { if (args.length < 6) { System.out.println("Please at least specify your access key, the channel id and destination address.\n" + - "Usage : java -jar test_accesskey(Required) channel_id(Required) from(Required) destination(Required) templateName(Required) namespace(Required) expirationTimeInput(Required)"); + "Usage : java -jar test_accesskey(Required) channel_id(Required) from(Required) destination(Required) templateName(Required) namespace(Required) couponCodeInput(Required)"); return; } From 5746f75677b0e0fd81cf966428bb5b28ad451db4 Mon Sep 17 00:00:00 2001 From: Venkateswaran S Date: Fri, 11 Apr 2025 12:28:38 +0200 Subject: [PATCH 90/99] update version 6.2.5 --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- examples/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index d060594d..e17d2358 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.2.4 + 6.2.5 jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index b36427fc..3cc1f25e 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.2.4"; + private final String clientVersion = "6.2.5"; private final String userAgentString; private Proxy proxy = null; diff --git a/examples/pom.xml b/examples/pom.xml index 4b56224c..a0089732 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.2.4 + 6.2.5 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.2.4 + 6.2.5 compile From 8ec864ea95ae45c6b00150d46c442136fa4832fb Mon Sep 17 00:00:00 2001 From: Chris Casey Date: Thu, 21 May 2026 10:44:53 +0100 Subject: [PATCH 91/99] feat: add WhatsApp BSUID support and split test/integration profiles - Add ConversationMessageMetadata, ConversationSenderMetadata, and ConversationStatusMessageMetadata to model BSUID webhook payloads - Add metadata field to ConversationMessage - Split Maven test/integration profiles so unit tests run without credentials - Fix ContactTest and MessageBirdClientTest to skip gracefully via assumeNotNull - Bump version to 6.3.0 Co-Authored-By: Claude Sonnet 4.6 --- api/pom.xml | 38 ++++++++- .../messagebird/MessageBirdServiceImpl.java | 2 +- .../conversations/ConversationMessage.java | 10 +++ .../ConversationMessageMetadata.java | 39 +++++++++ .../ConversationSenderMetadata.java | 47 +++++++++++ .../ConversationStatusMessageMetadata.java | 79 +++++++++++++++++++ .../java/com/messagebird/ContactTest.java | 2 + .../com/messagebird/ConversationsTest.java | 1 + .../messagebird/MessageBirdClientTest.java | 6 +- 9 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java create mode 100644 api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java create mode 100644 api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java diff --git a/api/pom.xml b/api/pom.xml index e17d2358..fb65b2b0 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.2.5 + 6.3.0 jar ${project.groupId}:${project.artifactId} @@ -62,19 +62,51 @@ + test false + + + UTF-8 + + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + **/ContactTest.java + **/MessageBirdClientTest.java + + + + + + + + + integration + + false + UTF-8 + disable-doclint - [8,11,) + [1.8,11) none - true UTF-8 diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index 3cc1f25e..ce3c10e7 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.2.5"; + private final String clientVersion = "6.3.0"; private final String userAgentString; private Proxy proxy = null; diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessage.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessage.java index 2be027be..1dea8280 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessage.java +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessage.java @@ -22,6 +22,7 @@ public class ConversationMessage { private Date updatedDatetime; private Map source; private ConversationMessageTag tag; + private ConversationMessageMetadata metadata; /** * See: {@link ConversationPlatformConstants} */ @@ -115,6 +116,14 @@ public void setTag(ConversationMessageTag tag) { this.tag = tag; } + public ConversationMessageMetadata getMetadata() { + return metadata; + } + + public void setMetadata(ConversationMessageMetadata metadata) { + this.metadata = metadata; + } + public String getPlatform() { return platform; } @@ -146,6 +155,7 @@ public String toString() { ", updatedDatetime=" + updatedDatetime + ", source=" + source + ", tag=" + tag + + ", metadata=" + metadata + ", platform='" + platform + '\'' + '}'; } diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java new file mode 100644 index 00000000..7d908e6a --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java @@ -0,0 +1,39 @@ +package com.messagebird.objects.conversations; + +import java.util.Date; + +/** + * Inner metadata attached to a conversation message. Present on both incoming + * messages and status webhook payloads. {@code sender.userId} always contains + * the BSUID when Meta provides one. When both identifiers exist, the phone + * number appears in the parent {@code from} field, not in this object. + */ +public class ConversationMessageMetadata { + + private ConversationSenderMetadata sender; + private Date receivedAt; + + public ConversationSenderMetadata getSender() { + return sender; + } + + public void setSender(ConversationSenderMetadata sender) { + this.sender = sender; + } + + public Date getReceivedAt() { + return receivedAt; + } + + public void setReceivedAt(Date receivedAt) { + this.receivedAt = receivedAt; + } + + @Override + public String toString() { + return "ConversationMessageMetadata{" + + "sender=" + sender + + ", receivedAt=" + receivedAt + + '}'; + } +} diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java new file mode 100644 index 00000000..33d7e225 --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java @@ -0,0 +1,47 @@ +package com.messagebird.objects.conversations; + +/** + * Metadata about the sender of a WhatsApp message. {@code userId} always + * contains the BSUID (e.g. "US.13491208655302741918") when Meta supplies one. + * When both a phone number and a BSUID are available, the phone number appears + * in the parent message's {@code from} field — not here. + */ +public class ConversationSenderMetadata { + + private String userId; + private String username; + private String displayName; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + @Override + public String toString() { + return "ConversationSenderMetadata{" + + "userId='" + userId + '\'' + + ", username='" + username + '\'' + + ", displayName='" + displayName + '\'' + + '}'; + } +} diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java new file mode 100644 index 00000000..ce5635ae --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java @@ -0,0 +1,79 @@ +package com.messagebird.objects.conversations; + +/** + * The {@code messageMetadata} block delivered in status webhook events (e.g. + * {@code statusSent}). Reflects the original message that triggered the status. + * + *

Both {@code from} and {@code to} accept either a phone number or a + * WhatsApp Business-Scoped User ID (BSUID, e.g. "US.13491208655302741918"). + * The BSUID is also available via {@code metadata.sender.userId}. + */ +public class ConversationStatusMessageMetadata { + + private String id; + private String from; + private String to; + private String type; + private ConversationContent content; + private ConversationMessageMetadata metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public ConversationContent getContent() { + return content; + } + + public void setContent(ConversationContent content) { + this.content = content; + } + + public ConversationMessageMetadata getMetadata() { + return metadata; + } + + public void setMetadata(ConversationMessageMetadata metadata) { + this.metadata = metadata; + } + + @Override + public String toString() { + return "ConversationStatusMessageMetadata{" + + "id='" + id + '\'' + + ", from='" + from + '\'' + + ", to='" + to + '\'' + + ", type='" + type + '\'' + + ", content=" + content + + ", metadata=" + metadata + + '}'; + } +} diff --git a/api/src/test/java/com/messagebird/ContactTest.java b/api/src/test/java/com/messagebird/ContactTest.java index 2377733d..5dfdea38 100644 --- a/api/src/test/java/com/messagebird/ContactTest.java +++ b/api/src/test/java/com/messagebird/ContactTest.java @@ -8,6 +8,7 @@ import org.mockito.Mockito; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import static org.junit.Assume.assumeNotNull; import static org.unitils.reflectionassert.ReflectionAssert.assertReflectionEquals; /** @@ -30,6 +31,7 @@ public class ContactTest { @BeforeClass public static void setUpClass() throws UnauthorizedException, GeneralException { String accessKey = System.getProperty("messageBirdAccessKey"); + assumeNotNull("Integration test skipped: set -DmessageBirdAccessKey to run", accessKey); msisdn = generateMsisdn(); diff --git a/api/src/test/java/com/messagebird/ConversationsTest.java b/api/src/test/java/com/messagebird/ConversationsTest.java index 4e7624e8..e08f0175 100644 --- a/api/src/test/java/com/messagebird/ConversationsTest.java +++ b/api/src/test/java/com/messagebird/ConversationsTest.java @@ -17,6 +17,7 @@ public class ConversationsTest { private static final String JSON_CONVERSATION = "{\"id\": \"convid\",\"contactId\": \"contid\",\"contact\": {\"id\": \"contid\",\"href\": \"https://chat.messagebird.com/1/contacts/contid\",\"msisdn\": 31612345678,\"firstName\": \"Foo\",\"lastName\": \"Bar\",\"customDetails\": {\"avatar\": \"https://example.com/assets/image.jpg\",\"firstName\": \"Foo\",\"lastName\": \"Bar\",\"userId\": 12345678 },\"createdDatetime\": \"2018-08-22T15:47:32Z\",\"updatedDatetime\": null},\"channels\": [{\"id\": \"chid\",\"name\": \"chname\",\"platformId\": \"telegram\",\"status\": \"active\",\"createdDatetime\": \"2018-08-22T15:18:11Z\",\"updatedDatetime\": \"2018-08-22T15:18:13Z\"}],\"status\": \"active\",\"createdDatetime\": \"2018-08-22T15:47:34Z\",\"updatedDatetime\": \"2018-08-22T16:05:15Z\",\"lastReceivedDatetime\": \"2018-08-22T15:47:34Z\",\"lastUsedChannelId\": \"chid\",\"messages\": {\"totalCount\": 1,\"href\": \"https://conversations.messagebird.com/v1/conversations/convid/messages\"}}"; private static final String JSON_CONVERSATION_LIST = "{\"offset\": 20,\"limit\": 10,\"count\": 1,\"totalCount\": 1,\"items\": [{\"id\": \"convid\",\"contactId\": \"contid\",\"contact\": {\"id\": \"contid\",\"href\": \"https://chat.messagebird.com/1/contacts/contid\",\"msisdn\": 31612345678,\"firstName\": \"Foo\",\"lastName\": \"Bar\",\"customDetails\": {\"avatar\": \"https://s3-eu-west-1.amazonaws.com/messagebird-chat/telegram/0d1dae7t5b7d7eb4531c14n04328336/6de655at5b7d859309f821n60607065/d0b705dt5b7d859309f987n05372263.jpg\",\"firstName\": \"Foo\",\"lastName\": \"Bar\",\"userId\": 12345678},\"createdDatetime\": \"2018-08-22T15:47:32Z\",\"updatedDatetime\": null},\"channels\": [{\"id\": \"chid\",\"name\": \"TestChannel\",\"platformId\": \"telegram\",\"status\": \"active\",\"createdDatetime\": \"2018-08-22T15:18:11Z\",\"updatedDatetime\": \"2018-08-22T15:18:13Z\"}],\"status\": \"active\",\"createdDatetime\": \"2018-08-22T15:47:34Z\",\"updatedDatetime\": \"2018-08-24T09:49:01Z\",\"lastReceivedDatetime\": \"2018-08-24T09:49:01Z\",\"lastUsedChannelId\": \"chid\",\"messages\": {\"totalCount\": 3,\"href\": \"https://conversations.messagebird.com/v1/conversations/convid/messages\"}}]}"; private static final String JSON_UNAUTHORIZED_ERROR = "{\"errors\": [{\"code\": 2,\"description\": \"Request was not authenticated\"}]}"; + // Status-update payload where Meta supplies both a phone number and a BSUID on the contact. @Test(expected = UnauthorizedException.class) public void testItThrowsErrors() throws GeneralException, UnauthorizedException { diff --git a/api/src/test/java/com/messagebird/MessageBirdClientTest.java b/api/src/test/java/com/messagebird/MessageBirdClientTest.java index ee2dc890..b11c2f54 100644 --- a/api/src/test/java/com/messagebird/MessageBirdClientTest.java +++ b/api/src/test/java/com/messagebird/MessageBirdClientTest.java @@ -16,6 +16,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mockito; +import static org.junit.Assume.assumeNotNull; import java.math.BigInteger; import java.util.Collections; @@ -44,7 +45,10 @@ public class MessageBirdClientTest { @BeforeClass public static void setUpClass() { messageBirdAccessKey = System.getProperty("messageBirdAccessKey"); - messageBirdMSISDN = new BigInteger(System.getProperty("messageBirdMSISDN")); + String msisdn = System.getProperty("messageBirdMSISDN"); + assumeNotNull("Integration test skipped: set -DmessageBirdAccessKey and -DmessageBirdMSISDN to run", + messageBirdAccessKey, msisdn); + messageBirdMSISDN = new BigInteger(msisdn); } @Before From fa2a89860e0647accd1c4653a429ab99915dfa3b Mon Sep 17 00:00:00 2001 From: Chris Casey Date: Thu, 21 May 2026 12:18:24 +0100 Subject: [PATCH 92/99] test: add deserialization tests for BSUID metadata; refine status metadata javadoc - Add JSON round-trip tests covering ConversationMessage.metadata and ConversationStatusMessageMetadata so the new types are exercised. - Clarify in javadoc that ConversationStatusMessageMetadata is a standalone POJO for consumers parsing incoming webhook payloads (not produced by any SDK request). - Remove dangling code comment in ConversationsTest. Co-Authored-By: Claude Sonnet 4.6 --- .../ConversationStatusMessageMetadata.java | 9 ++++- .../messagebird/ConversationMessagesTest.java | 39 +++++++++++++++++++ .../com/messagebird/ConversationsTest.java | 1 - 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java index ce5635ae..df7feebf 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java @@ -1,8 +1,13 @@ package com.messagebird.objects.conversations; /** - * The {@code messageMetadata} block delivered in status webhook events (e.g. - * {@code statusSent}). Reflects the original message that triggered the status. + * The {@code messageMetadata} block delivered inside status webhook payloads + * (e.g. {@code statusSent}, {@code statusDelivered}). Reflects the original + * message that triggered the status update. + * + *

This class is not produced by any SDK request — it is a standalone POJO + * intended for consumers who deserialize incoming webhook payloads in their + * own HTTP handlers. Use it via {@code ObjectMapper.readValue(body, ...)}. * *

Both {@code from} and {@code to} accept either a phone number or a * WhatsApp Business-Scoped User ID (BSUID, e.g. "US.13491208655302741918"). diff --git a/api/src/test/java/com/messagebird/ConversationMessagesTest.java b/api/src/test/java/com/messagebird/ConversationMessagesTest.java index 81357f88..5bd0a5c5 100644 --- a/api/src/test/java/com/messagebird/ConversationMessagesTest.java +++ b/api/src/test/java/com/messagebird/ConversationMessagesTest.java @@ -1,5 +1,7 @@ package com.messagebird; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import com.messagebird.exceptions.GeneralException; import com.messagebird.exceptions.NotFoundException; import com.messagebird.exceptions.UnauthorizedException; @@ -23,6 +25,8 @@ public class ConversationMessagesTest { private static final String JSON_CONVERSATION_MESSAGE_TEXT = "{\"id\": \"mesid\",\"conversationId\": \"convid\",\"channelId\": \"chanid\",\"status\": \"received\",\"type\": \"text\",\"direction\": \"received\",\"content\": {\"text\": \"Hello\"},\"createdDatetime\": \"2018-08-29T11:49:16Z\",\"updatedDatetime\": \"2018-08-29T11:49:16Z\"}"; private static final String JSON_CONVERSATION_MESSAGE_VIDEO = "{\"id\": \"mesid\",\"conversationId\": \"convid\",\"channelId\": \"chanid\",\"status\": \"received\",\"type\": \"video\",\"direction\": \"received\",\"content\": {\"video\": { \"url\": \"https://example.com/video.mp4\" } },\"createdDatetime\": \"2018-08-29T11:49:16Z\",\"updatedDatetime\": \"2018-08-29T11:49:16Z\"}"; private static final String JSON_CONVERSATION_SEND_MESSAGE_RESPONSE = "{\"id\":\"mesid\",\"status\":\"accepted\",\"fallback\":{\"id\":\"mesid\"}}"; + private static final String JSON_CONVERSATION_MESSAGE_BSUID = "{\"id\": \"mesid\",\"conversationId\": \"convid\",\"channelId\": \"chanid\",\"status\": \"received\",\"type\": \"text\",\"direction\": \"received\",\"content\": {\"text\": \"Hello\"},\"metadata\": {\"sender\": {\"displayName\": \"Alice\",\"username\": \"alice_shop\",\"userId\": \"US.13491208655302741918\"},\"receivedAt\": \"2025-04-15T16:00:00Z\"},\"createdDatetime\": \"2025-04-15T16:00:00Z\",\"updatedDatetime\": \"2025-04-15T16:00:00Z\"}"; + private static final String JSON_STATUS_MESSAGE_METADATA = "{\"id\": \"e5f6a7b8-c9d0-1234-ef01-23456789abcd\",\"from\": \"15551234567\",\"to\": \"US.13491208655302741918\",\"type\": \"text\",\"content\": {\"text\": \"Hello! Your order has been shipped.\"},\"metadata\": {\"sender\": {\"userId\": \"US.13491208655302741918\"},\"receivedAt\": \"0001-01-01T00:00:00Z\"}}"; /** * Epsilon to use when checking two latitudes or longitudes for equality. @@ -183,6 +187,41 @@ public void testViewConversationMessageLocation() throws GeneralException, NotFo assertEquals(4.911627, location.getLongitude(), EPSILON_LOCATION_EQUALITY); } + @Test + public void testViewConversationMessageWithBsuidMetadata() throws GeneralException, NotFoundException, UnauthorizedException { + MessageBirdService messageBirdService = SpyService + .expects("GET", "messages/mesid") + .withConversationsAPIBaseURL() + .andReturns(new APIResponse(JSON_CONVERSATION_MESSAGE_BSUID)); + MessageBirdClient messageBirdClient = new MessageBirdClient(messageBirdService); + + ConversationMessage message = messageBirdClient.viewConversationMessage("mesid"); + + ConversationMessageMetadata metadata = message.getMetadata(); + assertNotNull(metadata); + assertNotNull(metadata.getReceivedAt()); + ConversationSenderMetadata sender = metadata.getSender(); + assertEquals("Alice", sender.getDisplayName()); + assertEquals("alice_shop", sender.getUsername()); + assertEquals("US.13491208655302741918", sender.getUserId()); + } + + @Test + public void testStatusMessageMetadataDeserializes() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + + ConversationStatusMessageMetadata md = mapper.readValue( + JSON_STATUS_MESSAGE_METADATA, ConversationStatusMessageMetadata.class); + + assertEquals("e5f6a7b8-c9d0-1234-ef01-23456789abcd", md.getId()); + assertEquals("15551234567", md.getFrom()); + assertEquals("US.13491208655302741918", md.getTo()); + assertEquals("text", md.getType()); + assertEquals("Hello! Your order has been shipped.", md.getContent().getText()); + assertEquals("US.13491208655302741918", md.getMetadata().getSender().getUserId()); + } + @Test public void testViewConversationMessageText() throws GeneralException, NotFoundException, UnauthorizedException { MessageBirdService messageBirdService = SpyService diff --git a/api/src/test/java/com/messagebird/ConversationsTest.java b/api/src/test/java/com/messagebird/ConversationsTest.java index e08f0175..4e7624e8 100644 --- a/api/src/test/java/com/messagebird/ConversationsTest.java +++ b/api/src/test/java/com/messagebird/ConversationsTest.java @@ -17,7 +17,6 @@ public class ConversationsTest { private static final String JSON_CONVERSATION = "{\"id\": \"convid\",\"contactId\": \"contid\",\"contact\": {\"id\": \"contid\",\"href\": \"https://chat.messagebird.com/1/contacts/contid\",\"msisdn\": 31612345678,\"firstName\": \"Foo\",\"lastName\": \"Bar\",\"customDetails\": {\"avatar\": \"https://example.com/assets/image.jpg\",\"firstName\": \"Foo\",\"lastName\": \"Bar\",\"userId\": 12345678 },\"createdDatetime\": \"2018-08-22T15:47:32Z\",\"updatedDatetime\": null},\"channels\": [{\"id\": \"chid\",\"name\": \"chname\",\"platformId\": \"telegram\",\"status\": \"active\",\"createdDatetime\": \"2018-08-22T15:18:11Z\",\"updatedDatetime\": \"2018-08-22T15:18:13Z\"}],\"status\": \"active\",\"createdDatetime\": \"2018-08-22T15:47:34Z\",\"updatedDatetime\": \"2018-08-22T16:05:15Z\",\"lastReceivedDatetime\": \"2018-08-22T15:47:34Z\",\"lastUsedChannelId\": \"chid\",\"messages\": {\"totalCount\": 1,\"href\": \"https://conversations.messagebird.com/v1/conversations/convid/messages\"}}"; private static final String JSON_CONVERSATION_LIST = "{\"offset\": 20,\"limit\": 10,\"count\": 1,\"totalCount\": 1,\"items\": [{\"id\": \"convid\",\"contactId\": \"contid\",\"contact\": {\"id\": \"contid\",\"href\": \"https://chat.messagebird.com/1/contacts/contid\",\"msisdn\": 31612345678,\"firstName\": \"Foo\",\"lastName\": \"Bar\",\"customDetails\": {\"avatar\": \"https://s3-eu-west-1.amazonaws.com/messagebird-chat/telegram/0d1dae7t5b7d7eb4531c14n04328336/6de655at5b7d859309f821n60607065/d0b705dt5b7d859309f987n05372263.jpg\",\"firstName\": \"Foo\",\"lastName\": \"Bar\",\"userId\": 12345678},\"createdDatetime\": \"2018-08-22T15:47:32Z\",\"updatedDatetime\": null},\"channels\": [{\"id\": \"chid\",\"name\": \"TestChannel\",\"platformId\": \"telegram\",\"status\": \"active\",\"createdDatetime\": \"2018-08-22T15:18:11Z\",\"updatedDatetime\": \"2018-08-22T15:18:13Z\"}],\"status\": \"active\",\"createdDatetime\": \"2018-08-22T15:47:34Z\",\"updatedDatetime\": \"2018-08-24T09:49:01Z\",\"lastReceivedDatetime\": \"2018-08-24T09:49:01Z\",\"lastUsedChannelId\": \"chid\",\"messages\": {\"totalCount\": 3,\"href\": \"https://conversations.messagebird.com/v1/conversations/convid/messages\"}}]}"; private static final String JSON_UNAUTHORIZED_ERROR = "{\"errors\": [{\"code\": 2,\"description\": \"Request was not authenticated\"}]}"; - // Status-update payload where Meta supplies both a phone number and a BSUID on the contact. @Test(expected = UnauthorizedException.class) public void testItThrowsErrors() throws GeneralException, UnauthorizedException { From 805aa5af470ab14924e389648c6383e4d449bb94 Mon Sep 17 00:00:00 2001 From: Chris Casey Date: Thu, 28 May 2026 16:37:05 +0100 Subject: [PATCH 93/99] chore: migrate deploy plugin from OSSRH to Sonatype Central Portal OSSRH (oss.sonatype.org) was sunset in March 2025. Replace nexus-staging-maven-plugin with central-publishing-maven-plugin and drop the now-unused snapshotRepository distributionManagement block. autoPublish=false keeps the manual review/release behaviour the old config had via autoReleaseAfterClose=false. Co-Authored-By: Claude Sonnet 4.6 --- api/pom.xml | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index fb65b2b0..37e4f157 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -161,13 +161,6 @@ - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - @@ -262,14 +255,22 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 + + org.sonatype.central + central-publishing-maven-plugin + 0.7.0 true - ossrh - https://oss.sonatype.org/ - false + central + false + validated From 365e12ffcc27b1ae7aef325506f0d5a54241b1f3 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 20 Jul 2026 11:24:04 +0200 Subject: [PATCH 94/99] fix(deps): pin plexus-utils to 3.6.1 to resolve CVE-2025-67030 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit maven-artifact:3.9.6 (used only for ComparableVersion) transitively pulls plexus-utils:3.5.1, which is affected by CVE-2025-67030 — a directory traversal / Zip Slip in org.codehaus.plexus.util.Expand.extractFile (CVSS 8.8). The vulnerable code is not reachable from this client, but the jar is flagged by SCA scanners. Add a dependencyManagement pin forcing the patched plexus-utils 3.6.1. Staying on the 3.x line avoids the plexus-xml package split introduced in 4.x. dependency:tree confirms plexus-utils now resolves to 3.6.1 and the build/tests are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- api/pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/api/pom.xml b/api/pom.xml index 37e4f157..bb736110 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -114,6 +114,17 @@ + + + + + org.codehaus.plexus + plexus-utils + 3.6.1 + + + + com.fasterxml.jackson.core From d330cbfc725ef50eb55a2e1b8af817ddeafb4c8f Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 20 Jul 2026 12:53:44 +0200 Subject: [PATCH 95/99] chore(release): bump version to 6.3.1 Release the CVE-2025-67030 plexus-utils fix as a patch. Bumps the Maven artifact version and the hardcoded clientVersion used in the User-Agent header to keep them in sync. Co-Authored-By: Claude Opus 4.8 (1M context) --- api/pom.xml | 2 +- api/src/main/java/com/messagebird/MessageBirdServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index bb736110..d9c1f273 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.3.0 + 6.3.1 jar ${project.groupId}:${project.artifactId} diff --git a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java index ce3c10e7..ef179b45 100644 --- a/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java +++ b/api/src/main/java/com/messagebird/MessageBirdServiceImpl.java @@ -72,7 +72,7 @@ public class MessageBirdServiceImpl implements MessageBirdService { private final String accessKey; private final String serviceUrl; - private final String clientVersion = "6.3.0"; + private final String clientVersion = "6.3.1"; private final String userAgentString; private Proxy proxy = null; From 6b39ec409ce9c5d0e17d80b27a02d57ac54e6303 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 20 Jul 2026 13:02:52 +0200 Subject: [PATCH 96/99] chore(release): bump examples module to 6.3.1 The examples module was left at 6.2.5 (missed in the 6.3.0 release). Bring its own version and its messagebird-api dependency in line with the 6.3.1 release, matching the convention in #275. Co-Authored-By: Claude Opus 4.8 (1M context) --- examples/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index a0089732..9ffe9f18 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.2.5 + 6.3.1 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.2.5 + 6.3.1 compile From c53da1787dca061d66c9d3c4bd6d2022991b017d Mon Sep 17 00:00:00 2001 From: Chris Casey Date: Fri, 31 Jul 2026 12:08:06 +0100 Subject: [PATCH 97/99] feat: model recipient BSUIDs on WhatsApp status webhooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meta's parent business-scoped user ID rollout adds two identifiers our webhooks now forward, neither of which the SDK could express. - ConversationSenderMetadata gains parentUserId, the sender's parent BSUID (from Meta's messages[].from_parent_user_id). - ConversationRecipientMetadata is new, modelling status.metadata.recipient.{userId,parentUserId}. Status payloads did not carry the recipient's own identity before — messageMetadata.to is only an echo of the address the customer addressed — so this is the first way to learn a contact's BSUID from a status webhook. - ConversationStatusMetadata is new, modelling the enclosing status.metadata block. pricing and conversation stay raw maps: they are near-verbatim passthroughs of Meta's objects and keep their snake_case keys, while recipient is ours and is camelCase. Unmodelled keys (e.g. biz_opaque_callback_data) are collected rather than dropped. Both new types parse under a plain ObjectMapper, so consumers need not disable FAIL_ON_UNKNOWN_PROPERTIES. recipient is absent from payloads for accounts that receive no BSUIDs, and deserialises to null there. Co-Authored-By: Claude Opus 5 --- .../ConversationRecipientMetadata.java | 50 +++++++++++ .../ConversationSenderMetadata.java | 16 ++++ .../ConversationStatusMessageMetadata.java | 5 ++ .../ConversationStatusMetadata.java | 85 +++++++++++++++++++ .../messagebird/ConversationMessagesTest.java | 50 ++++++++++- 5 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 api/src/main/java/com/messagebird/objects/conversations/ConversationRecipientMetadata.java create mode 100644 api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMetadata.java diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationRecipientMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationRecipientMetadata.java new file mode 100644 index 00000000..7537da85 --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationRecipientMetadata.java @@ -0,0 +1,50 @@ +package com.messagebird.objects.conversations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Identifies the recipient of an outbound WhatsApp message, as reported back on + * status webhook payloads under {@code status.metadata.recipient}. Mirrors + * {@link ConversationSenderMetadata} on the inbound side. + * + *

{@code userId} is the recipient's BSUID (e.g. "US.13491208655302741918"); + * {@code parentUserId} is the parent business-scoped user ID of the enterprise + * that owns the business portfolio it was scoped against (e.g. + * "US.ENT.11815799212886844830"). + * + *

Either field may be {@code null}: Meta only supplies them for accounts + * enrolled in the BSUID rollout, and the enclosing {@code recipient} object is + * omitted entirely when neither is present. This is the only place a status + * payload carries the recipient's own identity — {@code messageMetadata.to} is + * an echo of the address the message was addressed to. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ConversationRecipientMetadata { + + private String userId; + private String parentUserId; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getParentUserId() { + return parentUserId; + } + + public void setParentUserId(String parentUserId) { + this.parentUserId = parentUserId; + } + + @Override + public String toString() { + return "ConversationRecipientMetadata{" + + "userId='" + userId + '\'' + + ", parentUserId='" + parentUserId + '\'' + + '}'; + } +} diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java index 33d7e225..d7f60b9f 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java @@ -5,10 +5,17 @@ * contains the BSUID (e.g. "US.13491208655302741918") when Meta supplies one. * When both a phone number and a BSUID are available, the phone number appears * in the parent message's {@code from} field — not here. + * + *

{@code parentUserId} carries the sender's parent business-scoped user ID + * (e.g. "US.ENT.11815799212886844830"), which identifies the enterprise that + * owns the business portfolio the {@code userId} was scoped against. It is only + * present for accounts enrolled in Meta's parent-BSUID rollout; for everyone + * else it stays {@code null}. */ public class ConversationSenderMetadata { private String userId; + private String parentUserId; private String username; private String displayName; @@ -20,6 +27,14 @@ public void setUserId(String userId) { this.userId = userId; } + public String getParentUserId() { + return parentUserId; + } + + public void setParentUserId(String parentUserId) { + this.parentUserId = parentUserId; + } + public String getUsername() { return username; } @@ -40,6 +55,7 @@ public void setDisplayName(String displayName) { public String toString() { return "ConversationSenderMetadata{" + "userId='" + userId + '\'' + + ", parentUserId='" + parentUserId + '\'' + ", username='" + username + '\'' + ", displayName='" + displayName + '\'' + '}'; diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java index df7feebf..537ad7bb 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java @@ -12,6 +12,11 @@ *

Both {@code from} and {@code to} accept either a phone number or a * WhatsApp Business-Scoped User ID (BSUID, e.g. "US.13491208655302741918"). * The BSUID is also available via {@code metadata.sender.userId}. + * + *

{@code to} echoes back the address the message was originally addressed + * to, so it is not a reliable source of the recipient's BSUID. That identity + * lives alongside this block, under {@code status.metadata.recipient} — see + * {@link ConversationStatusMetadata}. */ public class ConversationStatusMessageMetadata { diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMetadata.java new file mode 100644 index 00000000..0b4d5f7f --- /dev/null +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMetadata.java @@ -0,0 +1,85 @@ +package com.messagebird.objects.conversations; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * The {@code status.metadata} block delivered inside status webhook payloads + * (e.g. {@code statusSent}, {@code statusDelivered}). + * + *

This class is not produced by any SDK request — it is a standalone POJO + * intended for consumers who deserialize incoming webhook payloads in their own + * HTTP handlers. Use it via {@code ObjectMapper.readValue(body, ...)}. + * + *

Note the mixed casing of this object. {@code pricing} and + * {@code conversation} are near-verbatim passthroughs of Meta's own objects and + * so keep their snake_case keys ({@code pricing_model}, {@code category}, …); + * they are exposed here as raw maps rather than modelled types, because their + * contents track Meta's schema rather than ours. {@code recipient} is ours and + * follows the camelCase convention used everywhere else in the API. Any other + * key present on the payload — for example {@code biz_opaque_callback_data} — + * is collected into {@link #getAdditionalProperties()} rather than dropped. + * + *

{@code recipient} is absent from payloads for accounts that never receive + * BSUIDs, in which case {@link #getRecipient()} returns {@code null}. + */ +public class ConversationStatusMetadata { + + private Map pricing; + private Map conversation; + private ConversationRecipientMetadata recipient; + private final Map additionalProperties = new LinkedHashMap<>(); + + public Map getPricing() { + return pricing; + } + + public void setPricing(Map pricing) { + this.pricing = pricing; + } + + public Map getConversation() { + return conversation; + } + + public void setConversation(Map conversation) { + this.conversation = conversation; + } + + public ConversationRecipientMetadata getRecipient() { + return recipient; + } + + public void setRecipient(ConversationRecipientMetadata recipient) { + this.recipient = recipient; + } + + /** + * Every key on the payload that has no dedicated accessor above, in the + * order it was encountered. Empty when the payload holds nothing else. + * + * @return the unmodelled remainder of the metadata object + */ + @JsonAnyGetter + public Map getAdditionalProperties() { + return additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } + + @Override + public String toString() { + return "ConversationStatusMetadata{" + + "pricing=" + pricing + + ", conversation=" + conversation + + ", recipient=" + recipient + + ", additionalProperties=" + additionalProperties + + '}'; + } +} diff --git a/api/src/test/java/com/messagebird/ConversationMessagesTest.java b/api/src/test/java/com/messagebird/ConversationMessagesTest.java index 5bd0a5c5..da670fca 100644 --- a/api/src/test/java/com/messagebird/ConversationMessagesTest.java +++ b/api/src/test/java/com/messagebird/ConversationMessagesTest.java @@ -25,9 +25,13 @@ public class ConversationMessagesTest { private static final String JSON_CONVERSATION_MESSAGE_TEXT = "{\"id\": \"mesid\",\"conversationId\": \"convid\",\"channelId\": \"chanid\",\"status\": \"received\",\"type\": \"text\",\"direction\": \"received\",\"content\": {\"text\": \"Hello\"},\"createdDatetime\": \"2018-08-29T11:49:16Z\",\"updatedDatetime\": \"2018-08-29T11:49:16Z\"}"; private static final String JSON_CONVERSATION_MESSAGE_VIDEO = "{\"id\": \"mesid\",\"conversationId\": \"convid\",\"channelId\": \"chanid\",\"status\": \"received\",\"type\": \"video\",\"direction\": \"received\",\"content\": {\"video\": { \"url\": \"https://example.com/video.mp4\" } },\"createdDatetime\": \"2018-08-29T11:49:16Z\",\"updatedDatetime\": \"2018-08-29T11:49:16Z\"}"; private static final String JSON_CONVERSATION_SEND_MESSAGE_RESPONSE = "{\"id\":\"mesid\",\"status\":\"accepted\",\"fallback\":{\"id\":\"mesid\"}}"; - private static final String JSON_CONVERSATION_MESSAGE_BSUID = "{\"id\": \"mesid\",\"conversationId\": \"convid\",\"channelId\": \"chanid\",\"status\": \"received\",\"type\": \"text\",\"direction\": \"received\",\"content\": {\"text\": \"Hello\"},\"metadata\": {\"sender\": {\"displayName\": \"Alice\",\"username\": \"alice_shop\",\"userId\": \"US.13491208655302741918\"},\"receivedAt\": \"2025-04-15T16:00:00Z\"},\"createdDatetime\": \"2025-04-15T16:00:00Z\",\"updatedDatetime\": \"2025-04-15T16:00:00Z\"}"; + private static final String JSON_CONVERSATION_MESSAGE_BSUID = "{\"id\": \"mesid\",\"conversationId\": \"convid\",\"channelId\": \"chanid\",\"status\": \"received\",\"type\": \"text\",\"direction\": \"received\",\"content\": {\"text\": \"Hello\"},\"metadata\": {\"sender\": {\"displayName\": \"Alice\",\"username\": \"alice_shop\",\"userId\": \"US.13491208655302741918\",\"parentUserId\": \"US.ENT.11815799212886844830\"},\"receivedAt\": \"2025-04-15T16:00:00Z\"},\"createdDatetime\": \"2025-04-15T16:00:00Z\",\"updatedDatetime\": \"2025-04-15T16:00:00Z\"}"; private static final String JSON_STATUS_MESSAGE_METADATA = "{\"id\": \"e5f6a7b8-c9d0-1234-ef01-23456789abcd\",\"from\": \"15551234567\",\"to\": \"US.13491208655302741918\",\"type\": \"text\",\"content\": {\"text\": \"Hello! Your order has been shipped.\"},\"metadata\": {\"sender\": {\"userId\": \"US.13491208655302741918\"},\"receivedAt\": \"0001-01-01T00:00:00Z\"}}"; + private static final String JSON_STATUS_METADATA_WITH_RECIPIENT = "{\"pricing\": {\"billable\": true,\"pricing_model\": \"CBP\",\"category\": \"utility\"},\"conversation\": {\"id\": \"a1b2c3d4\",\"origin\": {\"type\": \"utility\"}},\"biz_opaque_callback_data\": \"order-1234\",\"recipient\": {\"userId\": \"US.13491208655302741918\",\"parentUserId\": \"US.ENT.11815799212886844830\"}}"; + private static final String JSON_STATUS_METADATA_WITHOUT_RECIPIENT = "{\"pricing\": {\"billable\": true,\"pricing_model\": \"CBP\",\"category\": \"utility\"},\"conversation\": {\"id\": \"a1b2c3d4\",\"origin\": {\"type\": \"utility\"}}}"; + private static final String JSON_STATUS_METADATA_PARENT_ONLY = "{\"recipient\": {\"parentUserId\": \"US.ENT.11815799212886844830\"}}"; + /** * Epsilon to use when checking two latitudes or longitudes for equality. */ @@ -204,6 +208,50 @@ public void testViewConversationMessageWithBsuidMetadata() throws GeneralExcepti assertEquals("Alice", sender.getDisplayName()); assertEquals("alice_shop", sender.getUsername()); assertEquals("US.13491208655302741918", sender.getUserId()); + assertEquals("US.ENT.11815799212886844830", sender.getParentUserId()); + } + + @Test + public void testStatusMetadataDeserializesRecipient() throws Exception { + // A plain mapper: these payload POJOs must not require the caller to + // disable FAIL_ON_UNKNOWN_PROPERTIES. + ConversationStatusMetadata metadata = new ObjectMapper().readValue( + JSON_STATUS_METADATA_WITH_RECIPIENT, ConversationStatusMetadata.class); + + ConversationRecipientMetadata recipient = metadata.getRecipient(); + assertNotNull(recipient); + assertEquals("US.13491208655302741918", recipient.getUserId()); + assertEquals("US.ENT.11815799212886844830", recipient.getParentUserId()); + + // Meta's own objects pass through untouched, snake_case keys and all. + assertEquals("CBP", metadata.getPricing().get("pricing_model")); + assertEquals("a1b2c3d4", metadata.getConversation().get("id")); + + // Anything else on the payload is kept rather than dropped. + assertEquals("order-1234", metadata.getAdditionalProperties().get("biz_opaque_callback_data")); + } + + @Test + public void testStatusMetadataWithoutRecipientIsNull() throws Exception { + ConversationStatusMetadata metadata = new ObjectMapper().readValue( + JSON_STATUS_METADATA_WITHOUT_RECIPIENT, ConversationStatusMetadata.class); + + // Accounts that never receive BSUIDs get payloads with no recipient key + // at all — the rest of the metadata must still parse. + assertNull(metadata.getRecipient()); + assertEquals("CBP", metadata.getPricing().get("pricing_model")); + assertTrue(metadata.getAdditionalProperties().isEmpty()); + } + + @Test + public void testStatusMetadataRecipientWithParentOnly() throws Exception { + ConversationStatusMetadata metadata = new ObjectMapper().readValue( + JSON_STATUS_METADATA_PARENT_ONLY, ConversationStatusMetadata.class); + + ConversationRecipientMetadata recipient = metadata.getRecipient(); + assertNotNull(recipient); + assertNull(recipient.getUserId()); + assertEquals("US.ENT.11815799212886844830", recipient.getParentUserId()); } @Test From 59d1fc22f6b35a82ccb914648af5f50b917b7572 Mon Sep 17 00:00:00 2001 From: Chris Casey Date: Fri, 31 Jul 2026 12:24:32 +0100 Subject: [PATCH 98/99] fix: tolerate unknown fields on webhook payload POJOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The payload types added in 6.3.0 are meant to be deserialized by consumers in their own HTTP handlers, but only parsed under a mapper with FAIL_ON_UNKNOWN_PROPERTIES disabled — which the SDK's internal mapper does and a plain ObjectMapper does not. A consumer following the javadoc got an UnrecognizedPropertyException, and would get one again every time the platform adds a field to a payload they already parse. Adds @JsonIgnoreProperties(ignoreUnknown = true) to the four types on the status payload path: ConversationStatusMessageMetadata, ConversationMessageMetadata, ConversationSenderMetadata and ConversationContent. This matches the new types added alongside it and makes the webhook-parsing story uniform. Deserialization only loosens, so nothing that parsed before stops parsing; serialization is untouched, which the existing send-request tests cover. The 6.3.0 test no longer needs to disable the feature by hand, and a new test parses a payload carrying unknown keys at every nesting level under a plain mapper. Co-Authored-By: Claude Opus 5 --- .../conversations/ConversationContent.java | 7 +++++ .../ConversationMessageMetadata.java | 3 +++ .../ConversationSenderMetadata.java | 3 +++ .../ConversationStatusMessageMetadata.java | 3 +++ .../messagebird/ConversationMessagesTest.java | 27 +++++++++++++++---- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationContent.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationContent.java index 9ba82bd8..8b4fe164 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/ConversationContent.java +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationContent.java @@ -1,9 +1,16 @@ package com.messagebird.objects.conversations; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * ConversationContent wraps actual content. The field that should be set here * is indicated by ConversationContentType. + * + *

Unknown keys are ignored on deserialization so that consumers parsing + * webhook payloads in their own handlers are not broken by content fields added + * after their SDK version. Serialization is unaffected. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class ConversationContent { private ConversationContentMedia audio; diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java index 7d908e6a..c41e814b 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationMessageMetadata.java @@ -1,5 +1,7 @@ package com.messagebird.objects.conversations; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import java.util.Date; /** @@ -8,6 +10,7 @@ * the BSUID when Meta provides one. When both identifiers exist, the phone * number appears in the parent {@code from} field, not in this object. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class ConversationMessageMetadata { private ConversationSenderMetadata sender; diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java index d7f60b9f..b7fdcbb0 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationSenderMetadata.java @@ -1,5 +1,7 @@ package com.messagebird.objects.conversations; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * Metadata about the sender of a WhatsApp message. {@code userId} always * contains the BSUID (e.g. "US.13491208655302741918") when Meta supplies one. @@ -12,6 +14,7 @@ * present for accounts enrolled in Meta's parent-BSUID rollout; for everyone * else it stays {@code null}. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class ConversationSenderMetadata { private String userId; diff --git a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java index 537ad7bb..47a4a8d1 100644 --- a/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java +++ b/api/src/main/java/com/messagebird/objects/conversations/ConversationStatusMessageMetadata.java @@ -1,5 +1,7 @@ package com.messagebird.objects.conversations; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * The {@code messageMetadata} block delivered inside status webhook payloads * (e.g. {@code statusSent}, {@code statusDelivered}). Reflects the original @@ -18,6 +20,7 @@ * lives alongside this block, under {@code status.metadata.recipient} — see * {@link ConversationStatusMetadata}. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class ConversationStatusMessageMetadata { private String id; diff --git a/api/src/test/java/com/messagebird/ConversationMessagesTest.java b/api/src/test/java/com/messagebird/ConversationMessagesTest.java index da670fca..beac543a 100644 --- a/api/src/test/java/com/messagebird/ConversationMessagesTest.java +++ b/api/src/test/java/com/messagebird/ConversationMessagesTest.java @@ -1,6 +1,5 @@ package com.messagebird; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.messagebird.exceptions.GeneralException; import com.messagebird.exceptions.NotFoundException; @@ -32,6 +31,13 @@ public class ConversationMessagesTest { private static final String JSON_STATUS_METADATA_WITHOUT_RECIPIENT = "{\"pricing\": {\"billable\": true,\"pricing_model\": \"CBP\",\"category\": \"utility\"},\"conversation\": {\"id\": \"a1b2c3d4\",\"origin\": {\"type\": \"utility\"}}}"; private static final String JSON_STATUS_METADATA_PARENT_ONLY = "{\"recipient\": {\"parentUserId\": \"US.ENT.11815799212886844830\"}}"; + /** + * The same payload as JSON_STATUS_MESSAGE_METADATA with an unrecognised key + * added at every nesting level, standing in for fields the platform adds + * after this SDK version ships. + */ + private static final String JSON_STATUS_MESSAGE_METADATA_UNKNOWN_FIELDS = "{\"id\": \"e5f6a7b8-c9d0-1234-ef01-23456789abcd\",\"from\": \"15551234567\",\"to\": \"US.13491208655302741918\",\"type\": \"text\",\"futureTopLevelField\": \"ignored\",\"content\": {\"text\": \"Hello! Your order has been shipped.\",\"futureContentField\": \"ignored\"},\"metadata\": {\"sender\": {\"userId\": \"US.13491208655302741918\",\"futureSenderField\": \"ignored\"},\"receivedAt\": \"0001-01-01T00:00:00Z\",\"futureMetadataField\": \"ignored\"}}"; + /** * Epsilon to use when checking two latitudes or longitudes for equality. */ @@ -211,6 +217,20 @@ public void testViewConversationMessageWithBsuidMetadata() throws GeneralExcepti assertEquals("US.ENT.11815799212886844830", sender.getParentUserId()); } + @Test + public void testStatusMessageMetadataToleratesUnknownFields() throws Exception { + // A plain mapper, and unknown keys at every level: webhook payload POJOs + // must not force consumers to disable FAIL_ON_UNKNOWN_PROPERTIES, and + // must survive fields the platform adds after this version ships. + ConversationStatusMessageMetadata md = new ObjectMapper().readValue( + JSON_STATUS_MESSAGE_METADATA_UNKNOWN_FIELDS, ConversationStatusMessageMetadata.class); + + assertEquals("e5f6a7b8-c9d0-1234-ef01-23456789abcd", md.getId()); + assertEquals("Hello! Your order has been shipped.", md.getContent().getText()); + assertEquals("US.13491208655302741918", md.getMetadata().getSender().getUserId()); + assertNotNull(md.getMetadata().getReceivedAt()); + } + @Test public void testStatusMetadataDeserializesRecipient() throws Exception { // A plain mapper: these payload POJOs must not require the caller to @@ -256,10 +276,7 @@ public void testStatusMetadataRecipientWithParentOnly() throws Exception { @Test public void testStatusMessageMetadataDeserializes() throws Exception { - ObjectMapper mapper = new ObjectMapper(); - mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - - ConversationStatusMessageMetadata md = mapper.readValue( + ConversationStatusMessageMetadata md = new ObjectMapper().readValue( JSON_STATUS_MESSAGE_METADATA, ConversationStatusMessageMetadata.class); assertEquals("e5f6a7b8-c9d0-1234-ef01-23456789abcd", md.getId()); From 4f1152db6a4a2c267a8e06b4f5c2a78cfdf36b49 Mon Sep 17 00:00:00 2001 From: Chris Casey Date: Fri, 31 Jul 2026 12:08:06 +0100 Subject: [PATCH 99/99] chore(release): bump version to 6.4.0 Co-Authored-By: Claude Opus 5 --- api/pom.xml | 2 +- examples/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index d9c1f273..b64ee8b0 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ com.messagebird messagebird-api - 6.3.1 + 6.4.0 jar ${project.groupId}:${project.artifactId} diff --git a/examples/pom.xml b/examples/pom.xml index 9ffe9f18..cb9b7489 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ com.messagebird examples - 6.3.1 + 6.4.0 @@ -20,7 +20,7 @@ com.messagebird messagebird-api - 6.3.1 + 6.4.0 compile