Skip to content

2040- brevo add trigger #2373

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

Merged
merged 4 commits into from
Apr 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion docs/src/content/docs/reference/components/brevo.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: "Brevo is an email marketing platform that offers a cloud-based mar
Brevo is an email marketing platform that offers a cloud-based marketing communication software suite with transactional email, marketing automation, customer-relationship management and more.


Categories: marketing-automation
Categories: Marketing Automation


Type: brevo/v1
Expand Down Expand Up @@ -187,3 +187,30 @@ Type: OBJECT



## Triggers


### Transactional Email Opened
Name: transactionalEmailOpened

Triggers when transactional email is opened.

Type: DYNAMIC_WEBHOOK


#### Output

The output for this action is dynamic and may vary depending on the input parameters. To determine the exact structure of the output, you need to execute the action.

#### JSON Example
```json
{
"label" : "Transactional Email Opened",
"name" : "transactionalEmailOpened",
"type" : "brevo/v1/transactionalEmailOpened"
}
```


<hr />

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.bytechef.component.brevo.action.BrevoSendTransactionalEmailAction;
import com.bytechef.component.brevo.action.BrevoUpdateContactAction;
import com.bytechef.component.brevo.connection.BrevoConnection;
import com.bytechef.component.brevo.trigger.BrevoTransactionalEmailOpenedTrigger;
import com.bytechef.component.definition.ComponentCategory;
import com.bytechef.component.definition.ComponentDefinition;
import com.google.auto.service.AutoService;
Expand All @@ -46,6 +47,8 @@ public class BrevoComponentHandler implements ComponentHandler {
BrevoCreateContactAction.ACTION_DEFINITION,
BrevoUpdateContactAction.ACTION_DEFINITION,
BrevoSendTransactionalEmailAction.ACTION_DEFINITION)
.triggers(
BrevoTransactionalEmailOpenedTrigger.TRIGGER_DEFINITION)
.clusterElements(
tool(BrevoCreateContactAction.ACTION_DEFINITION),
tool(BrevoUpdateContactAction.ACTION_DEFINITION),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ public class BrevoConstants {
public static final String CONTENT_TYPE = "contentType";
public static final String EMAIL = "email";
public static final String FIRST_NAME = "FIRSTNAME";
public static final String ID = "id";
public static final String LAST_NAME = "LASTNAME";
public static final String NAME = "name";
public static final String RECIPIENT_EMAIL = "recipientEmail";
public static final String SENDER_EMAIL = "senderEmail";
public static final String SUBJECT = "subject";
public static final String TO = "to";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright 2023-present ByteChef Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.bytechef.component.brevo.trigger;

import static com.bytechef.component.brevo.constant.BrevoConstants.ID;
import static com.bytechef.component.definition.ComponentDsl.trigger;

import com.bytechef.component.definition.ComponentDsl.ModifiableTriggerDefinition;
import com.bytechef.component.definition.Context.Http;
import com.bytechef.component.definition.Parameters;
import com.bytechef.component.definition.TriggerContext;
import com.bytechef.component.definition.TriggerDefinition.HttpHeaders;
import com.bytechef.component.definition.TriggerDefinition.HttpParameters;
import com.bytechef.component.definition.TriggerDefinition.TriggerType;
import com.bytechef.component.definition.TriggerDefinition.WebhookBody;
import com.bytechef.component.definition.TriggerDefinition.WebhookEnableOutput;
import com.bytechef.component.definition.TriggerDefinition.WebhookMethod;
import com.bytechef.component.definition.TypeReference;
import java.util.List;
import java.util.Map;

/**
* @author Marija Horvat
*/
public class BrevoTransactionalEmailOpenedTrigger {

public static final ModifiableTriggerDefinition TRIGGER_DEFINITION = trigger("transactionalEmailOpened")
.title("Transactional Email Opened")
.description("Triggers when transactional email is opened.")
.type(TriggerType.DYNAMIC_WEBHOOK)
.output()
.webhookEnable(BrevoTransactionalEmailOpenedTrigger::webhookEnable)
.webhookDisable(BrevoTransactionalEmailOpenedTrigger::webhookDisable)
.webhookRequest(BrevoTransactionalEmailOpenedTrigger::webhookRequest);

private BrevoTransactionalEmailOpenedTrigger() {
}

protected static WebhookEnableOutput webhookEnable(
Parameters inputParameters, Parameters connectionParameters, String webhookUrl,
String workflowExecutionId, TriggerContext context) {

Map<String, ?> body = context.http(http -> http.post("/webhooks"))
.body(Http.Body.of("url", webhookUrl, "events", List.of("opened")))
.configuration(Http.responseType(Http.ResponseType.JSON))
.execute()
.getBody(new TypeReference<>() {});

return new WebhookEnableOutput(Map.of(ID, body.get(ID)), null);
}

protected static void webhookDisable(
Parameters inputParameters, Parameters connectionParameters, Parameters outputParameters,
String workflowExecutionId, TriggerContext context) {

context.http(http -> http.delete("/webhooks/" + outputParameters.getRequiredInteger(ID)))
.execute();
}

protected static Object webhookRequest(
Parameters inputParameters, Parameters connectionParameters, HttpHeaders headers, HttpParameters parameters,
WebhookBody body, WebhookMethod method, WebhookEnableOutput output, TriggerContext context) {

return body.getContent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ public static List<Option<String>> getContactsOptions(
Parameters inputParameters, Parameters connectionParameters, Map<String, String> dependencyPaths,
String searchText, Context context) {

Map<String, Object> body = context
.http(http -> http.get("/contacts"))
Map<String, Object> body = context.http(http -> http.get("/contacts"))
.configuration(responseType(Http.ResponseType.JSON))
.execute()
.getBody(new TypeReference<>() {});
Expand All @@ -66,8 +65,7 @@ public static List<Option<String>> getSendersOptions(
Parameters inputParameters, Parameters connectionParameters, Map<String, String> dependencyPaths,
String searchText, Context context) {

Map<String, List<Map<String, Object>>> body = context
.http(http -> http.get("/senders"))
Map<String, List<Map<String, Object>>> body = context.http(http -> http.get("/senders"))
.configuration(responseType(Http.ResponseType.JSON))
.execute()
.getBody(new TypeReference<>() {});
Expand All @@ -82,5 +80,4 @@ public static List<Option<String>> getSendersOptions(

return options;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2023-present ByteChef Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.bytechef.component.brevo.trigger;

import static com.bytechef.component.brevo.constant.BrevoConstants.ID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.bytechef.component.definition.Context.Http;
import com.bytechef.component.definition.Parameters;
import com.bytechef.component.definition.TriggerContext;
import com.bytechef.component.definition.TriggerDefinition.HttpHeaders;
import com.bytechef.component.definition.TriggerDefinition.HttpParameters;
import com.bytechef.component.definition.TriggerDefinition.WebhookBody;
import com.bytechef.component.definition.TriggerDefinition.WebhookEnableOutput;
import com.bytechef.component.definition.TriggerDefinition.WebhookMethod;
import com.bytechef.component.definition.TypeReference;
import com.bytechef.component.test.definition.MockParametersFactory;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

/**
* @author Marija Horvat
*/
class BrevoTransactionalEmailOpenedTriggerTest {

private final WebhookEnableOutput mockedWebhookEnableOutput = mock(WebhookEnableOutput.class);
private final ArgumentCaptor<Http.Body> bodyArgumentCaptor = ArgumentCaptor.forClass(Http.Body.class);
private final WebhookBody mockedWebhookBody = mock(WebhookBody.class);
private final HttpHeaders mockedHttpHeaders = mock(HttpHeaders.class);
private final HttpParameters mockedHttpParameters = mock(HttpParameters.class);
private final WebhookMethod mockedWebhookMethod = mock(WebhookMethod.class);
private final Parameters mockedParameters = MockParametersFactory.create(Map.of(ID, "id"));
private final TriggerContext mockedTriggerContext = mock(TriggerContext.class);
private final Object mockedObject = mock(Object.class);
private final Http.Executor mockedExecutor = mock(Http.Executor.class);
private final Http.Response mockedResponse = mock(Http.Response.class);

@Test
void testWebhookEnable() {
String webhookUrl = "testWebhookUrl";
String workflowExecutionId = "testWorkflowExecutionId";

when(mockedTriggerContext.http(any()))
.thenReturn(mockedExecutor);
when(mockedExecutor.body(bodyArgumentCaptor.capture()))
.thenReturn(mockedExecutor);
when(mockedExecutor.configuration(any()))
.thenReturn(mockedExecutor);
when(mockedExecutor.execute())
.thenReturn(mockedResponse);
when(mockedResponse.getBody(any(TypeReference.class)))
.thenReturn(Map.of(ID, "123"));

WebhookEnableOutput webhookEnableOutput = BrevoTransactionalEmailOpenedTrigger.webhookEnable(
mockedParameters, mockedParameters, webhookUrl, workflowExecutionId, mockedTriggerContext);

WebhookEnableOutput expectedWebhookEnableOutput = new WebhookEnableOutput(Map.of(ID, "123"), null);

assertEquals(expectedWebhookEnableOutput, webhookEnableOutput);

Http.Body body = bodyArgumentCaptor.getValue();

assertEquals(Map.of("url", webhookUrl, "events", List.of("opened")), body.getContent());
}

@Test
void testWebhookRequest() {
when(mockedWebhookBody.getContent())
.thenReturn(mockedObject);

Object result = BrevoTransactionalEmailOpenedTrigger.webhookRequest(
mockedParameters, mockedParameters, mockedHttpHeaders, mockedHttpParameters, mockedWebhookBody,
mockedWebhookMethod, mockedWebhookEnableOutput, mockedTriggerContext);

assertEquals(mockedObject, result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.mockito.Mockito.when;

import com.bytechef.component.definition.Context;
import com.bytechef.component.definition.Context.Http;
import com.bytechef.component.definition.Option;
import com.bytechef.component.definition.Parameters;
import com.bytechef.component.definition.TypeReference;
Expand All @@ -41,9 +42,9 @@ class BrevoUtilsTest {
option("[email protected]", "[email protected]"),
option("[email protected]", "[email protected]"));
private final Context mockedContext = mock(Context.class);
private final Context.Http.Executor mockedExecutor = mock(Context.Http.Executor.class);
private final Http.Executor mockedExecutor = mock(Http.Executor.class);
private final Parameters mockedParameters = mock(Parameters.class);
private final Context.Http.Response mockedResponse = mock(Context.Http.Response.class);
private final Http.Response mockedResponse = mock(Http.Response.class);

@BeforeEach
void beforeEach() {
Expand Down
Loading
Loading