Skip to content

[Ming] Support the whatsapp send Media Carousel Template message #223

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
45 changes: 45 additions & 0 deletions src/main/java/com/whatsapp/api/domain/messages/CarouselCard.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.whatsapp.api.domain.messages;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.ArrayList;
import java.util.List;

/**
* The carousel card
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CarouselCard {

@JsonProperty("card_index")
private Integer cardIndex;

@JsonProperty("components")
private List<Component<?>> components;

public CarouselCard(Integer cardIndex) {
this.cardIndex = cardIndex;
}

public CarouselCard addComponent(Component<?> component) {
if (this.components == null) {
this.components = new ArrayList<>();
}
this.components.add(component);
return this;
}

public CarouselCard setComponents(List<Component<?>> components) {
this.components = components;
return this;
}

public Integer getCardIndex() {
return cardIndex;
}

public List<Component<?>> getComponents() {
return components;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.whatsapp.api.domain.messages;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.whatsapp.api.domain.messages.type.ComponentType;

import java.util.ArrayList;
import java.util.List;


/**
* The type Carousel component, to send template messages
* @see <a href="https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-message-templates/media-card-carousel-templates">Api reference</a>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CarouselComponent extends Component<CarouselComponent> {

@JsonProperty("cards")
public List<CarouselCard> cards;

/**
* Instantiates a new Carousel component, to send template messages
*/
public CarouselComponent() {
super(ComponentType.CAROUSEL);
}

public CarouselComponent setCards(List<CarouselCard> cards) {
this.cards = cards;
return this;
}

public CarouselComponent addCard(CarouselCard card) {
if (this.cards == null) {
this.cards = new ArrayList<>();
}
this.cards.add(card);
return this;
}

public List<CarouselCard> getCards() {
return cards;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = ButtonComponent.class, name = "button"), //
@JsonSubTypes.Type(value = HeaderComponent.class, name = "header"), //
@JsonSubTypes.Type(value = BodyComponent.class, name = "body")})//
@JsonSubTypes.Type(value = BodyComponent.class, name = "body"),
@JsonSubTypes.Type(value = CarouselComponent.class, name = "carousel")})//
public abstract class Component<T extends Component<T>> {
@JsonProperty("type")
private final ComponentType type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ public enum ComponentType {
/**
* Button component type.
*/
BUTTON("button");
BUTTON("button"),

/**
* Carousel component type.
*/
CAROUSEL("carousel");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ public enum EventType {
/**
* Pin changed event type.
*/
PIN_CHANGED
PIN_CHANGED,

/**
* Template pending deletion event type.
*/
PENDING_DELETION
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ public enum FieldType {
* Notifies you when the quality-related status of a phone number has an update.
*/
PHONE_NUMBER_QUALITY_UPDATE("phone_number_quality_update"),
/**
* Notifies you when changes to a template's components, like a change in title or body, or an addition of a button.
*/
MESSAGE_TEMPLATE_COMPONENTS_UPDATE("message_template_components_update"),
/**
* Notifies you when the message template quality update, like
*/
MESSAGE_TEMPLATE_QUALITY_UPDATE("message_template_quality_update"),
/**
* Notifies you when a WABA has been upgraded from unverified trial experience to a verified account, or if a WABA has been banned.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.whatsapp.api.domain.messages;

import com.whatsapp.api.domain.messages.type.ButtonSubType;
import com.whatsapp.api.domain.templates.type.LanguageType;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

public class CarouselCardTest {

@Test
public void testMessageBuilderWIthCarousel() {
CarouselCard firstCard = composeCarouselCard(0, "image_media_123", "Tokyo", "product_1", "SKU_1.html");
CarouselCard secondCard = composeCarouselCard(1, "image_media_456", "China", "product_2", "SKU_2.html");

TemplateMessage templateMessage = new TemplateMessage();
templateMessage.setName("carousel_card_2");
templateMessage.setLanguage(new Language(LanguageType.EN));
templateMessage.addComponent(new CarouselComponent().setCards(List.of(firstCard, secondCard)));

Message message = Message.MessageBuilder.builder().buildTemplateMessage(templateMessage);

assertEquals(1, message.getTemplateMessage().getComponents().size());
assertInstanceOf(CarouselComponent.class, message.getTemplateMessage().getComponents().get(0));

CarouselComponent carouselComponent = (CarouselComponent) message.getTemplateMessage().getComponents().get(0);
assertEquals(2, carouselComponent.getCards().size());
assertEquals(firstCard, carouselComponent.getCards().get(0));
assertEquals(secondCard, carouselComponent.getCards().get(1));
}

private static CarouselCard composeCarouselCard(int cardIndex, String imageMediaId, String bodyParam, String productId, String productUrlPath) {
CarouselCard card = new CarouselCard(cardIndex);

HeaderComponent headerComponent = new HeaderComponent();
headerComponent.addParameter(new ImageParameter().setImage(new Image().setId(imageMediaId)));
card.addComponent(headerComponent);

BodyComponent bodyComponent = new BodyComponent();
bodyComponent.addParameter(new TextParameter(bodyParam));
card.addComponent(bodyComponent);

ButtonComponent replyBtnComponent = new ButtonComponent()
.setIndex(0)
.setSubType(ButtonSubType.QUICK_REPLY);
replyBtnComponent.addParameter(new ButtonPayloadParameter(productId));
card.addComponent(replyBtnComponent);

ButtonComponent urlBtnComponent = new ButtonComponent()
.setIndex(1)
.setSubType(ButtonSubType.URL);
replyBtnComponent.addParameter(new ButtonPayloadParameter(productUrlPath));
card.addComponent(urlBtnComponent);

return card;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.whatsapp.api.examples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.whatsapp.api.TestConstants;
import com.whatsapp.api.WhatsappApiFactory;
import com.whatsapp.api.domain.messages.*;
import com.whatsapp.api.domain.messages.Message.MessageBuilder;
import com.whatsapp.api.domain.messages.type.ButtonSubType;
import com.whatsapp.api.domain.templates.type.LanguageType;
import com.whatsapp.api.impl.WhatsappBusinessCloudApi;

import static com.whatsapp.api.TestConstants.PHONE_NUMBER_1;
import static com.whatsapp.api.TestConstants.PHONE_NUMBER_ID;

public class SendCarouselTemplateMessageExample {
public static void main(String[] args) throws JsonProcessingException {
WhatsappApiFactory factory = WhatsappApiFactory.newInstance(TestConstants.TOKEN);

WhatsappBusinessCloudApi whatsappBusinessCloudApi = factory.newBusinessCloudApi();

var message = MessageBuilder.builder()//
.setTo(PHONE_NUMBER_1)//
.buildTemplateMessage(//
new TemplateMessage()//
.setLanguage(new Language(LanguageType.EN))//
.setName("carousel3_tour_1")//
.addComponent(new CarouselComponent()
.addCard(new CarouselCard(0)
.addComponent(
new HeaderComponent().addParameter(
new ImageParameter().setImage(new Image().setLink("https://ik.imgkit.net/3vlqs5axxjf/TW-Asia/ik-seo/uploadedImages/Industry/Destinations(1)/AdobeStock_302223688_Editorial_Use_Only/Hear-Singapore-roar-with-its-2023-tourism-performa.jpeg"))
))
.addComponent(
new BodyComponent().addParameter(new TextParameter("Tokyo"))
)
.addComponent(
new ButtonComponent().setIndex(0).setSubType(ButtonSubType.QUICK_REPLY).addParameter(new ButtonPayloadParameter("product_123"))
)
.addComponent(
new ButtonComponent().setIndex(1).setSubType(ButtonSubType.URL).addParameter(new TextParameter("url_123"))
)
)
.addCard(new CarouselCard(1)
.addComponent(
new HeaderComponent().addParameter(
new ImageParameter().setImage(new Image().setLink("https://ik.imgkit.net/3vlqs5axxjf/TW-Asia/ik-seo/uploadedImages/Industry/Destinations(1)/AdobeStock_302223688_Editorial_Use_Only/Hear-Singapore-roar-with-its-2023-tourism-performa.jpeg"))
))
.addComponent(
new BodyComponent().addParameter(new TextParameter("China"))
)
.addComponent(
new ButtonComponent().setIndex(0).setSubType(ButtonSubType.QUICK_REPLY).addParameter(new ButtonPayloadParameter("product_234"))
)
.addComponent(
new ButtonComponent().setIndex(1).setSubType(ButtonSubType.URL).addParameter(new TextParameter("url_234"))
)
)
.addCard(new CarouselCard(2)
.addComponent(
new HeaderComponent().addParameter(
new ImageParameter().setImage(new Image().setLink("https://ik.imgkit.net/3vlqs5axxjf/TW-Asia/ik-seo/uploadedImages/Industry/Destinations(1)/AdobeStock_302223688_Editorial_Use_Only/Hear-Singapore-roar-with-its-2023-tourism-performa.jpeg"))
))
.addComponent(
new BodyComponent().addParameter(new TextParameter("Australia"))
)
.addComponent(
new ButtonComponent().setIndex(0).setSubType(ButtonSubType.QUICK_REPLY).addParameter(new ButtonPayloadParameter("product_456"))
)
.addComponent(
new ButtonComponent().setIndex(1).setSubType(ButtonSubType.URL).addParameter(new TextParameter("url_456"))
)
)
)
);
System.out.println(new ObjectMapper().writeValueAsString(message));

whatsappBusinessCloudApi.sendMessage(PHONE_NUMBER_ID, message);
}
}