From 27be553ec2b55705341cfad11ed0f2b86abb65db Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 12:44:00 +0530 Subject: [PATCH 1/9] Encode query values and add shared JSON helpers --- .../com/mailerlite/sdk/util/ApiRequest.java | 14 +- .../com/mailerlite/sdk/util/ApiResource.java | 16 +- .../com/mailerlite/sdk/util/JsonBody.java | 25 +++ .../sdk/util/LenientStringArrayAdapter.java | 80 ++++++++++ .../sdk/util/RawDataAdapterFactory.java | 63 ++++++++ .../mailerlite/sdk/util/RawDataHolder.java | 23 +++ .../com/mailerlite/sdk/util/ResponseMeta.java | 8 + .../java/com/mailerlite/sdk/util/SdkGson.java | 33 ++++ .../mailerlite/sdk/tests/MockTestBase.java | 42 +++++ .../mailerlite/sdk/vcr/MockHttpClient.java | 151 ++++++++++++++++++ 10 files changed, 452 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/mailerlite/sdk/util/JsonBody.java create mode 100644 src/main/java/com/mailerlite/sdk/util/LenientStringArrayAdapter.java create mode 100644 src/main/java/com/mailerlite/sdk/util/RawDataAdapterFactory.java create mode 100644 src/main/java/com/mailerlite/sdk/util/RawDataHolder.java create mode 100644 src/main/java/com/mailerlite/sdk/util/SdkGson.java create mode 100644 src/test/java/com/mailerlite/sdk/tests/MockTestBase.java create mode 100644 src/test/java/com/mailerlite/sdk/vcr/MockHttpClient.java diff --git a/src/main/java/com/mailerlite/sdk/util/ApiRequest.java b/src/main/java/com/mailerlite/sdk/util/ApiRequest.java index 32ab1c1..45d7696 100644 --- a/src/main/java/com/mailerlite/sdk/util/ApiRequest.java +++ b/src/main/java/com/mailerlite/sdk/util/ApiRequest.java @@ -7,6 +7,8 @@ **************************************************/ package com.mailerlite.sdk.util; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.HashMap; /** @@ -29,6 +31,16 @@ public void addQueryParameter(String name, String value) queryParameters.put(name, value); } + /** + * Removes a query parameter. + * + * @param name the name + */ + public void removeQueryParameter(String name) + { + queryParameters.remove(name); + } + /** * Gets the query parameters. * @@ -44,7 +56,7 @@ public String getQueryParameters() query = query.concat("&"); } - query = query.concat(name).concat("=").concat(queryParameters.get(name)); + query = query.concat(name).concat("=").concat(URLEncoder.encode(queryParameters.get(name), StandardCharsets.UTF_8)); } return "?".concat(query); diff --git a/src/main/java/com/mailerlite/sdk/util/ApiResource.java b/src/main/java/com/mailerlite/sdk/util/ApiResource.java index feb0888..92e2e42 100644 --- a/src/main/java/com/mailerlite/sdk/util/ApiResource.java +++ b/src/main/java/com/mailerlite/sdk/util/ApiResource.java @@ -13,6 +13,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.TimeZone; /** * The Class ApiResource. @@ -38,8 +39,7 @@ public void parseDates() { String dateStr = dateStrField.get(this).toString(); - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Date date = formatter.parse(dateStr); + Date date = parseDate(dateStr); field.setAccessible(true); @@ -84,4 +84,16 @@ public void parseDates() { } } } + + private Date parseDate(String dateStr) throws ParseException + { + if (dateStr.length() > 10 && dateStr.charAt(10) == 'T') { + SimpleDateFormat isoFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + isoFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); + + return isoFormatter.parse(dateStr); + } + + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr); + } } diff --git a/src/main/java/com/mailerlite/sdk/util/JsonBody.java b/src/main/java/com/mailerlite/sdk/util/JsonBody.java new file mode 100644 index 0000000..8b6f79e --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/util/JsonBody.java @@ -0,0 +1,25 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.util; + +/** + * Serializes request bodies the same way for every endpoint. + */ +public class JsonBody { + + /** + * Serializes a request body to JSON. + * + * @param body the body + * @return the JSON string + */ + public static String toJson(Object body) + { + return SdkGson.plain().toJson(body); + } +} diff --git a/src/main/java/com/mailerlite/sdk/util/LenientStringArrayAdapter.java b/src/main/java/com/mailerlite/sdk/util/LenientStringArrayAdapter.java new file mode 100644 index 0000000..461c833 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/util/LenientStringArrayAdapter.java @@ -0,0 +1,80 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.util; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +/** + * Reads a JSON array into a String array. Strings and numbers are kept as they are, + * and objects or arrays are kept as their JSON text. + */ +public class LenientStringArrayAdapter extends TypeAdapter { + + /** + * Writes the array. + * + * @param out the writer + * @param value the value + * @throws IOException Signals that an I/O exception has occurred. + */ + @Override + public void write(JsonWriter out, String[] value) throws IOException { + if (value == null) { + out.nullValue(); + return; + } + + out.beginArray(); + for (String item : value) { + out.value(item); + } + out.endArray(); + } + + /** + * Reads the array. + * + * @param in the reader + * @return the string array + * @throws IOException Signals that an I/O exception has occurred. + */ + @Override + public String[] read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + JsonElement element = JsonParser.parseReader(in); + + if (!element.isJsonArray()) { + return new String[] { asString(element) }; + } + + List items = new ArrayList(); + for (JsonElement item : element.getAsJsonArray()) { + items.add(asString(item)); + } + + return items.toArray(new String[0]); + } + + private String asString(JsonElement element) + { + return element.isJsonPrimitive() ? element.getAsString() : element.toString(); + } +} diff --git a/src/main/java/com/mailerlite/sdk/util/RawDataAdapterFactory.java b/src/main/java/com/mailerlite/sdk/util/RawDataAdapterFactory.java new file mode 100644 index 0000000..a595418 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/util/RawDataAdapterFactory.java @@ -0,0 +1,63 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.util; + +import java.io.IOException; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * Deserializes a {@link RawDataHolder} as usual and also hands it the raw JSON object. + */ +public class RawDataAdapterFactory implements TypeAdapterFactory { + + /** + * Creates the type adapter. + * + * @param the generic type + * @param gson the gson instance + * @param type the type token + * @return the type adapter, or null for types that do not hold raw data + */ + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + + if (!RawDataHolder.class.isAssignableFrom(type.getRawType())) { + return null; + } + + TypeAdapter delegate = gson.getDelegateAdapter(this, type); + TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + + return new TypeAdapter() { + + @Override + public void write(JsonWriter out, T value) throws IOException { + delegate.write(out, value); + } + + @Override + public T read(JsonReader in) throws IOException { + JsonElement tree = elementAdapter.read(in); + T value = delegate.fromJsonTree(tree); + + if (value != null && tree.isJsonObject()) { + ((RawDataHolder) value).setData(tree.getAsJsonObject()); + } + + return value; + } + }; + } +} diff --git a/src/main/java/com/mailerlite/sdk/util/RawDataHolder.java b/src/main/java/com/mailerlite/sdk/util/RawDataHolder.java new file mode 100644 index 0000000..b48ce17 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/util/RawDataHolder.java @@ -0,0 +1,23 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.util; + +import com.google.gson.JsonObject; + +/** + * Implemented by API objects that keep the raw JSON object they were parsed from. + */ +public interface RawDataHolder { + + /** + * Sets the raw JSON object. + * + * @param data the raw JSON object + */ + void setData(JsonObject data); +} diff --git a/src/main/java/com/mailerlite/sdk/util/ResponseMeta.java b/src/main/java/com/mailerlite/sdk/util/ResponseMeta.java index 7bead1f..268fa7c 100644 --- a/src/main/java/com/mailerlite/sdk/util/ResponseMeta.java +++ b/src/main/java/com/mailerlite/sdk/util/ResponseMeta.java @@ -48,6 +48,14 @@ public class ResponseMeta { @SerializedName("total") public int total; + /** The next cursor. */ + @SerializedName("next_cursor") + public String nextCursor; + + /** The previous cursor. */ + @SerializedName("prev_cursor") + public String previousCursor; + /** The aggregations. */ @SerializedName("aggregations") public HashMap aggregations = new HashMap(); diff --git a/src/main/java/com/mailerlite/sdk/util/SdkGson.java b/src/main/java/com/mailerlite/sdk/util/SdkGson.java new file mode 100644 index 0000000..790d3a4 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/util/SdkGson.java @@ -0,0 +1,33 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * The shared Gson instance with the SDK exclusion strategies and no custom type adapters. + */ +public class SdkGson { + + /** The gson instance. */ + private static final Gson GSON = new GsonBuilder() + .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) + .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) + .create(); + + /** + * Returns the shared Gson instance. + * + * @return the gson instance + */ + public static Gson plain() + { + return GSON; + } +} diff --git a/src/test/java/com/mailerlite/sdk/tests/MockTestBase.java b/src/test/java/com/mailerlite/sdk/tests/MockTestBase.java new file mode 100644 index 0000000..dffc17a --- /dev/null +++ b/src/test/java/com/mailerlite/sdk/tests/MockTestBase.java @@ -0,0 +1,42 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.tests; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +import com.mailerlite.sdk.util.MailerLiteHttpClientFactory; +import com.mailerlite.sdk.vcr.MockHttpClient; + +/** + * Base for tests that check the request the SDK builds, without calling the API. + */ +public class MockTestBase extends TestBase { + + /** The mock http client. */ + protected MockHttpClient http; + + /** + * Installs the mock http client. + */ + @BeforeEach + public void installMockClient() + { + http = new MockHttpClient(); + MailerLiteHttpClientFactory.getInstance().setClient(http); + } + + /** + * Removes the mock http client. + */ + @AfterEach + public void removeMockClient() + { + MailerLiteHttpClientFactory.getInstance().setClient(null); + } +} diff --git a/src/test/java/com/mailerlite/sdk/vcr/MockHttpClient.java b/src/test/java/com/mailerlite/sdk/vcr/MockHttpClient.java new file mode 100644 index 0000000..438ed24 --- /dev/null +++ b/src/test/java/com/mailerlite/sdk/vcr/MockHttpClient.java @@ -0,0 +1,151 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.vcr; + +import java.net.URLDecoder; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandler; +import java.net.http.HttpResponse.BodySubscriber; +import java.net.http.HttpResponse.BodySubscribers; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +/** + * Records the last request instead of sending it, and answers with a canned response. + */ +public class MockHttpClient extends HttpClientVcr { + + /** The last request. */ + private HttpRequest lastRequest; + + /** The last request body. */ + private String lastBody; + + /** The canned response status code. */ + private int statusCode = 200; + + /** The canned response body. */ + private String responseBody = "{}"; + + /** + * Sets the canned response. + * + * @param statusCode the status code + * @param responseBody the response body + */ + public void respondWith(int statusCode, String responseBody) + { + this.statusCode = statusCode; + this.responseBody = responseBody; + } + + /** + * Records the request and returns the canned response. + * + * @param the generic type + * @param request the request + * @param responseBodyHandler the response body handler + * @return the http response + */ + @SuppressWarnings("unchecked") + @Override + public HttpResponse send(HttpRequest request, BodyHandler responseBodyHandler) + { + lastRequest = request; + lastBody = request.bodyPublisher().map(p -> { + BodySubscriber bodySubscriber = BodySubscribers.ofString(StandardCharsets.UTF_8); + p.subscribe(new StringSubscriber(bodySubscriber)); + return bodySubscriber.getBody().toCompletableFuture().join(); + }).orElse(""); + + HttpClientVcrResponse response = new HttpClientVcrResponse(); + response.statusCode = statusCode; + response.body = responseBody; + response.headers = new HashMap>(); + + return (HttpResponse) response; + } + + /** + * Whether any request was sent. + * + * @return true if a request was sent + */ + public boolean hasRequest() + { + return lastRequest != null; + } + + /** + * The HTTP method of the last request. + * + * @return the method + */ + public String method() + { + return lastRequest.method(); + } + + /** + * The path of the last request, without the /api prefix. + * + * @return the path + */ + public String path() + { + return lastRequest.uri().getPath().replaceFirst("^/api", ""); + } + + /** + * The decoded query parameters of the last request. + * + * @return the query parameters + */ + public Map query() + { + Map params = new HashMap(); + String rawQuery = lastRequest.uri().getRawQuery(); + + if (rawQuery == null || rawQuery.isEmpty()) { + return params; + } + + for (String pair : rawQuery.split("&")) { + String[] parts = pair.split("=", 2); + params.put(URLDecoder.decode(parts[0], StandardCharsets.UTF_8), parts.length > 1 ? URLDecoder.decode(parts[1], StandardCharsets.UTF_8) : ""); + } + + return params; + } + + /** + * The JSON body of the last request. + * + * @return the body + */ + public JsonObject body() + { + return JsonParser.parseString(lastBody).getAsJsonObject(); + } + + /** + * The raw body of the last request. + * + * @return the raw body + */ + public String rawBody() + { + return lastBody; + } +} From dbb8df3733c135dc9a08f99a9a05cfe204d92dbd Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 12:44:00 +0530 Subject: [PATCH 2/9] Parse dates on list responses --- .../com/mailerlite/sdk/fields/FieldList.java | 20 +++++++++++++++++-- .../com/mailerlite/sdk/forms/FormsList.java | 20 +++++++++++++++++-- .../sdk/groups/GroupSubscribersList.java | 20 +++++++++++++++++-- .../com/mailerlite/sdk/groups/GroupsList.java | 20 +++++++++++++++++-- .../mailerlite/sdk/segments/SegmentsList.java | 20 +++++++++++++++++-- .../susbcribers/SingleSubscriberImport.java | 16 ++++++++++++++- .../sdk/susbcribers/SubscriberImportList.java | 20 +++++++++++++++++-- .../mailerlite/sdk/webhooks/WebhooksList.java | 20 +++++++++++++++++-- 8 files changed, 141 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/mailerlite/sdk/fields/FieldList.java b/src/main/java/com/mailerlite/sdk/fields/FieldList.java index 5f5cae8..07294da 100644 --- a/src/main/java/com/mailerlite/sdk/fields/FieldList.java +++ b/src/main/java/com/mailerlite/sdk/fields/FieldList.java @@ -20,12 +20,28 @@ public class FieldList extends PaginatedResponse { public Field[] fields; /** - * Post deserialise. + * Parses the dates of every item. */ - public void postDeserialise() + @Override + public void postDeserialize() { + if (fields == null) { + return; + } + for (Field f : fields) { f.parseDates(); } } + + /** + * Post deserialise. + * + * @deprecated misspelled, use {@link #postDeserialize()} + */ + @Deprecated + public void postDeserialise() + { + postDeserialize(); + } } diff --git a/src/main/java/com/mailerlite/sdk/forms/FormsList.java b/src/main/java/com/mailerlite/sdk/forms/FormsList.java index add1d0f..0b27dff 100644 --- a/src/main/java/com/mailerlite/sdk/forms/FormsList.java +++ b/src/main/java/com/mailerlite/sdk/forms/FormsList.java @@ -20,12 +20,28 @@ public class FormsList extends PaginatedResponse { public Form[] forms; /** - * Post deserialise. + * Parses the dates of every item. */ - public void postDeserialise() + @Override + public void postDeserialize() { + if (forms == null) { + return; + } + for (Form f : forms) { f.parseDates(); } } + + /** + * Post deserialise. + * + * @deprecated misspelled, use {@link #postDeserialize()} + */ + @Deprecated + public void postDeserialise() + { + postDeserialize(); + } } diff --git a/src/main/java/com/mailerlite/sdk/groups/GroupSubscribersList.java b/src/main/java/com/mailerlite/sdk/groups/GroupSubscribersList.java index 1033308..b37ad4c 100644 --- a/src/main/java/com/mailerlite/sdk/groups/GroupSubscribersList.java +++ b/src/main/java/com/mailerlite/sdk/groups/GroupSubscribersList.java @@ -21,12 +21,28 @@ public class GroupSubscribersList extends PaginatedResponse { public Subscriber[] subscribers; /** - * Post deserialise. + * Parses the dates of every item. */ - public void postDeserialise() + @Override + public void postDeserialize() { + if (subscribers == null) { + return; + } + for (Subscriber s : subscribers) { s.parseDates(); } } + + /** + * Post deserialise. + * + * @deprecated misspelled, use {@link #postDeserialize()} + */ + @Deprecated + public void postDeserialise() + { + postDeserialize(); + } } diff --git a/src/main/java/com/mailerlite/sdk/groups/GroupsList.java b/src/main/java/com/mailerlite/sdk/groups/GroupsList.java index eb3327e..41b71d9 100644 --- a/src/main/java/com/mailerlite/sdk/groups/GroupsList.java +++ b/src/main/java/com/mailerlite/sdk/groups/GroupsList.java @@ -20,12 +20,28 @@ public class GroupsList extends PaginatedResponse { public Group[] groups; /** - * Post deserialise. + * Parses the dates of every item. */ - public void postDeserialise() + @Override + public void postDeserialize() { + if (groups == null) { + return; + } + for (Group g : groups) { g.parseDates(); } } + + /** + * Post deserialise. + * + * @deprecated misspelled, use {@link #postDeserialize()} + */ + @Deprecated + public void postDeserialise() + { + postDeserialize(); + } } diff --git a/src/main/java/com/mailerlite/sdk/segments/SegmentsList.java b/src/main/java/com/mailerlite/sdk/segments/SegmentsList.java index 53bdf90..713c295 100644 --- a/src/main/java/com/mailerlite/sdk/segments/SegmentsList.java +++ b/src/main/java/com/mailerlite/sdk/segments/SegmentsList.java @@ -20,12 +20,28 @@ public class SegmentsList extends PaginatedResponse { public Segment[] segments; /** - * Post deserialise. + * Parses the dates of every item. */ - public void postDeserialise() + @Override + public void postDeserialize() { + if (segments == null) { + return; + } + for (Segment s : segments) { s.parseDates(); } } + + /** + * Post deserialise. + * + * @deprecated misspelled, use {@link #postDeserialize()} + */ + @Deprecated + public void postDeserialise() + { + postDeserialize(); + } } diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SingleSubscriberImport.java b/src/main/java/com/mailerlite/sdk/susbcribers/SingleSubscriberImport.java index ada25c3..617700d 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/SingleSubscriberImport.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SingleSubscriberImport.java @@ -19,11 +19,25 @@ public class SingleSubscriberImport extends MailerLiteResponse { @SerializedName("data") public SubscriberImport subscriberImport; + /** + * Parses the dates of the import. + */ + @Override + public void postDeserialize() + { + if (subscriberImport != null) { + subscriberImport.parseDates(); + } + } + /** * Post desirialize. + * + * @deprecated misspelled, use {@link #postDeserialize()} */ + @Deprecated public void postDesirialize() { - subscriberImport.parseDates(); + postDeserialize(); } } diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberImportList.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberImportList.java index 992b70d..fcde706 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberImportList.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberImportList.java @@ -20,12 +20,28 @@ public class SubscriberImportList extends PaginatedResponse { public SubscriberImport[] imports; /** - * Post deserialise. + * Parses the dates of every item. */ - public void postDeserialise() + @Override + public void postDeserialize() { + if (imports == null) { + return; + } + for (SubscriberImport i : imports) { i.parseDates(); } } + + /** + * Post deserialise. + * + * @deprecated misspelled, use {@link #postDeserialize()} + */ + @Deprecated + public void postDeserialise() + { + postDeserialize(); + } } diff --git a/src/main/java/com/mailerlite/sdk/webhooks/WebhooksList.java b/src/main/java/com/mailerlite/sdk/webhooks/WebhooksList.java index 08802ca..d439f16 100644 --- a/src/main/java/com/mailerlite/sdk/webhooks/WebhooksList.java +++ b/src/main/java/com/mailerlite/sdk/webhooks/WebhooksList.java @@ -21,12 +21,28 @@ public class WebhooksList extends PaginatedResponse { public Webhook[] webhooks; /** - * Post deserialise. + * Parses the dates of every item. */ - public void postDeserialise() + @Override + public void postDeserialize() { + if (webhooks == null) { + return; + } + for (Webhook w : webhooks) { w.parseDates(); } } + + /** + * Post deserialise. + * + * @deprecated misspelled, use {@link #postDeserialize()} + */ + @Deprecated + public void postDeserialise() + { + postDeserialize(); + } } From 3c2b9c4a96021d9a102efcecaf1e5299e3fcb89a Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 12:44:01 +0530 Subject: [PATCH 3/9] Add subscriber list params, activity log, forget response and new fields --- .../sdk/susbcribers/ForgottenSubscriber.java | 20 ++ .../sdk/susbcribers/Subscriber.java | 29 +++ .../SubscriberActivityLogEntry.java | 57 +++++ .../SubscriberActivityLogList.java | 36 +++ .../SubscriberActivityLogRetriever.java | 76 ++++++ .../sdk/susbcribers/SubscriberBuilder.java | 58 +++-- .../susbcribers/SubscriberBuilderBody.java | 12 + .../sdk/susbcribers/SubscriberImport.java | 32 +++ .../sdk/susbcribers/SubscriberLocation.java | 40 +++ .../sdk/susbcribers/SubscriberRetriever.java | 91 +++++++ .../sdk/susbcribers/SubscriberTimezone.java | 36 +++ .../sdk/susbcribers/Subscribers.java | 34 +++ .../sdk/tests/SubscribersRequestTest.java | 230 ++++++++++++++++++ 13 files changed, 736 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/mailerlite/sdk/susbcribers/ForgottenSubscriber.java create mode 100644 src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogEntry.java create mode 100644 src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogList.java create mode 100644 src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogRetriever.java create mode 100644 src/main/java/com/mailerlite/sdk/susbcribers/SubscriberLocation.java create mode 100644 src/main/java/com/mailerlite/sdk/susbcribers/SubscriberTimezone.java create mode 100644 src/test/java/com/mailerlite/sdk/tests/SubscribersRequestTest.java diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/ForgottenSubscriber.java b/src/main/java/com/mailerlite/sdk/susbcribers/ForgottenSubscriber.java new file mode 100644 index 0000000..1d71e74 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/susbcribers/ForgottenSubscriber.java @@ -0,0 +1,20 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.susbcribers; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class ForgottenSubscriber. + */ +public class ForgottenSubscriber extends SingleSubscriber { + + /** The message. */ + @SerializedName("message") + public String message; +} diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/Subscriber.java b/src/main/java/com/mailerlite/sdk/susbcribers/Subscriber.java index 2f978b5..c30e822 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/Subscriber.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/Subscriber.java @@ -11,6 +11,7 @@ import java.util.HashMap; import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.groups.Group; import com.mailerlite.sdk.util.ApiResource; import com.mailerlite.sdk.util.ParseDate; @@ -106,4 +107,32 @@ public class Subscriber extends ApiResource { /** The fields. */ @SerializedName("fields") public HashMap fields = new HashMap(); + + /** The deleted at str. */ + @SerializedName("deleted_at") + public String deletedAtStr; + + /** The deleted at. */ + @ParseDate("deletedAtStr") + public Date deletedAt; + + /** The forget at str. */ + @SerializedName("forget_at") + public String forgetAtStr; + + /** The forget at. */ + @ParseDate("forgetAtStr") + public Date forgetAt; + + /** The groups. */ + @SerializedName("groups") + public Group[] groups; + + /** The location. */ + @SerializedName("location") + public SubscriberLocation location; + + /** The timezone. */ + @SerializedName("timezone") + public SubscriberTimezone timezone; } diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogEntry.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogEntry.java new file mode 100644 index 0000000..1ce8c2c --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogEntry.java @@ -0,0 +1,57 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.susbcribers; + +import java.util.Date; + +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.util.ApiResource; +import com.mailerlite.sdk.util.ParseDate; + +/** + * The Class SubscriberActivityLogEntry. + */ +public class SubscriberActivityLogEntry extends ApiResource { + + /** The id. */ + @SerializedName("id") + public String id; + + /** The log name. */ + @SerializedName("log_name") + public String logName; + + /** The subject id. */ + @SerializedName("subject_id") + public String subjectId; + + /** The subject type. */ + @SerializedName("subject_type") + public String subjectType; + + /** The properties. */ + @SerializedName("properties") + public JsonElement properties; + + /** The created at. */ + @SerializedName("created_at") + public String createdAtStr; + + /** The created at. */ + @ParseDate("createdAtStr") + public Date createdAt; + + /** The updated at. */ + @SerializedName("updated_at") + public String updatedAtStr; + + /** The updated at. */ + @ParseDate("updatedAtStr") + public Date updatedAt; +} diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogList.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogList.java new file mode 100644 index 0000000..9648833 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogList.java @@ -0,0 +1,36 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.susbcribers; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SubscriberActivityLogList. + */ +public class SubscriberActivityLogList extends MailerLiteResponse { + + /** The entries. */ + @SerializedName("data") + public SubscriberActivityLogEntry[] entries; + + /** + * Post deserialize. + */ + @Override + public void postDeserialize() + { + if (entries == null) { + return; + } + + for (SubscriberActivityLogEntry e : entries) { + e.parseDates(); + } + } +} diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogRetriever.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogRetriever.java new file mode 100644 index 0000000..7cafc7e --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberActivityLogRetriever.java @@ -0,0 +1,76 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.susbcribers; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteApi; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.CursorPaginatedRequest; + +/** + * The Class SubscriberActivityLogRetriever. + */ +public class SubscriberActivityLogRetriever extends CursorPaginatedRequest { + + /** The api object reference. */ + private MailerLite apiObjectReference; + + /** The subscriber id. */ + private String subscriberId; + + /** + * Instantiates a new subscriber activity log retriever. + * + * @param apiRef the api ref + * @param forSubscriberId the subscriber id + */ + public SubscriberActivityLogRetriever(MailerLite apiRef, String forSubscriberId) + { + apiObjectReference = apiRef; + subscriberId = forSubscriberId; + } + + /** + * Returns only entries of this type, for example "email_open". + * + * @param logName the log name + * @return the subscriber activity log retriever + */ + public SubscriberActivityLogRetriever logName(String logName) + { + this.addQueryParameter("filter[log_name]", logName); + + return this; + } + + /** + * Gets the activity log of the subscriber. + * + * @return the subscriber activity log list + * @throws MailerLiteException the mailer lite exception + */ + public SubscriberActivityLogList get() throws MailerLiteException + { + String endpoint = "/subscribers/".concat(subscriberId).concat("/activity-log").concat(this.getQueryParameters()); + + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + return api.getRequest(endpoint, SubscriberActivityLogList.class); + } + + /** + * Gets the single instance of SubscriberActivityLogRetriever. + * + * @return single instance of SubscriberActivityLogRetriever + */ + @Override + protected SubscriberActivityLogRetriever getInstance() { + return this; + } +} diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberBuilder.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberBuilder.java index 0544549..c562ff1 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberBuilder.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberBuilder.java @@ -13,12 +13,10 @@ import java.util.Date; import java.util.HashMap; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.mailerlite.sdk.MailerLite; import com.mailerlite.sdk.MailerLiteApi; import com.mailerlite.sdk.exceptions.MailerLiteException; -import com.mailerlite.sdk.util.JsonSerializationDeserializationStrategy; +import com.mailerlite.sdk.util.JsonBody; /** * The Class SubscriberBuilder. @@ -53,12 +51,7 @@ public SingleSubscriber create() throws MailerLiteException MailerLiteApi api = new MailerLiteApi(); api.setToken(apiObjectReference.getToken()); - Gson gson = new GsonBuilder() - .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) - .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) - .create(); - - String json = gson.toJson(builderBody); + String json = JsonBody.toJson(builderBody); SingleSubscriber subscriber = api.postRequest("/subscribers", json, SingleSubscriber.class); @@ -79,12 +72,7 @@ public SingleSubscriber update(String id) throws MailerLiteException MailerLiteApi api = new MailerLiteApi(); api.setToken(apiObjectReference.getToken()); - Gson gson = new GsonBuilder() - .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) - .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) - .create(); - - String json = gson.toJson(builderBody); + String json = JsonBody.toJson(builderBody); SingleSubscriber subscriber = api.putRequest("/subscribers/".concat(id), json, SingleSubscriber.class); @@ -220,4 +208,44 @@ public SubscriberBuilder unsubscribedAt(Date unsubscribedAt) builderBody.unsubscribedAt = formatter.format(unsubscribedAt); return this; } + + /** + * Reactivates an unsubscribed, bounced or junk subscriber on create. + * + * @param resubscribe the resubscribe + * @return the subscriber builder + */ + public SubscriberBuilder resubscribe(Boolean resubscribe) + { + builderBody.resubscribe = resubscribe; + return this; + } + + /** + * Double optin. + * + * @param doubleOptin the double optin + * @return the subscriber builder + */ + public SubscriberBuilder doubleOptin(Boolean doubleOptin) + { + builderBody.doubleOptin = doubleOptin; + return this; + } + + /** + * Adds a note. Notes are only saved when the subscriber is created. + * + * @param note the note + * @return the subscriber builder + */ + public SubscriberBuilder addNote(String note) + { + if (builderBody.notes == null) { + builderBody.notes = new ArrayList(); + } + + builderBody.notes.add(note); + return this; + } } diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberBuilderBody.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberBuilderBody.java index 5818122..99ba775 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberBuilderBody.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberBuilderBody.java @@ -52,4 +52,16 @@ public class SubscriberBuilderBody { /** The unsubscribed at. */ @SerializedName("unsubscribed_at") public String unsubscribedAt; + + /** The resubscribe. */ + @SerializedName("resubscribe") + public Boolean resubscribe; + + /** The double optin. */ + @SerializedName("double_optin") + public Boolean doubleOptin; + + /** The notes. */ + @SerializedName("notes") + public ArrayList notes; } diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberImport.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberImport.java index f172915..3238841 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberImport.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberImport.java @@ -22,6 +22,10 @@ public class SubscriberImport extends ApiResource { @SerializedName("id") public String id; + /** The account id. */ + @SerializedName("account_id") + public String accountId; + /** The total. */ @SerializedName("total") public int total; @@ -102,6 +106,30 @@ public class SubscriberImport extends ApiResource { @SerializedName("role_based_count") public int roleBasedCount; + /** The suspicious format. */ + @SerializedName("suspicious_format") + public SubscriberImportStatusEntry[] suspiciousFormat; + + /** The suspicious format count. */ + @SerializedName("suspicious_format_count") + public int suspiciousFormatCount; + + /** The duplicate. */ + @SerializedName("duplicate") + public SubscriberImportStatusEntry[] duplicate; + + /** The duplicate count. */ + @SerializedName("duplicate_count") + public int duplicateCount; + + /** The subscriber limit. */ + @SerializedName("subscriber_limit") + public SubscriberImportStatusEntry[] subscriberLimit; + + /** The subscriber limit count. */ + @SerializedName("subscriber_limit_count") + public int subscriberLimitCount; + /** The banned import emails count. */ @SerializedName("banned_import_emails_count") public int bannedImportEmailsCount; @@ -130,6 +158,10 @@ public class SubscriberImport extends ApiResource { @ParseDate("undoneAtStr") public Date undoneAt; + /** The is stopped due to free account limit exceeded. */ + @SerializedName("is_stopped_due_to_free_account_limit_exceeded") + public Boolean isStoppedDueToFreeAccountLimitExceeded; + /** The stopped at str. */ @SerializedName("stopped_at") public String stoppedAtStr; diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberLocation.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberLocation.java new file mode 100644 index 0000000..7f86295 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberLocation.java @@ -0,0 +1,40 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.susbcribers; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class SubscriberLocation. + */ +public class SubscriberLocation { + + /** The id. */ + @SerializedName("id") + public String id; + + /** The title. */ + @SerializedName("title") + public String title; + + /** The country name. */ + @SerializedName("country_name") + public String countryName; + + /** The continent name. */ + @SerializedName("continent_name") + public String continentName; + + /** The state name. */ + @SerializedName("state_name") + public String stateName; + + /** The time zone. */ + @SerializedName("time_zone") + public String timeZone; +} diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberRetriever.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberRetriever.java index f5bf264..bbc0727 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberRetriever.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberRetriever.java @@ -105,6 +105,97 @@ public SubscriberCount count() throws MailerLiteException return count; } + /** + * Sets the cursor of the page to return. + * + * @param cursor the cursor + * @return the subscriber retriever + */ + public SubscriberRetriever cursor(String cursor) + { + this.addQueryParameter("cursor", cursor); + + return this; + } + + /** + * Sets the sort order. + * + * @param sort the sort + * @return the subscriber retriever + */ + public SubscriberRetriever sort(String sort) + { + this.addQueryParameter("sort", sort); + + return this; + } + + /** + * Sets the relations to include, for example "groups". + * + * @param include the include + * @return the subscriber retriever + */ + public SubscriberRetriever include(String include) + { + this.addQueryParameter("include", include); + + return this; + } + + /** + * Sets the start date. + * + * @param startDate the start date + * @return the subscriber retriever + */ + public SubscriberRetriever startDate(String startDate) + { + this.addQueryParameter("start_date", startDate); + + return this; + } + + /** + * Sets the end date. + * + * @param endDate the end date + * @return the subscriber retriever + */ + public SubscriberRetriever endDate(String endDate) + { + this.addQueryParameter("end_date", endDate); + + return this; + } + + /** + * Includes the subscriber fields. + * + * @param withFields the with fields + * @return the subscriber retriever + */ + public SubscriberRetriever withFields(boolean withFields) + { + this.addQueryParameter("with_fields", withFields ? "1" : "0"); + + return this; + } + + /** + * Includes the subscriber groups. + * + * @param withGroups the with groups + * @return the subscriber retriever + */ + public SubscriberRetriever withGroups(boolean withGroups) + { + this.addQueryParameter("with_groups", withGroups ? "1" : "0"); + + return this; + } + /** * Gets the single instance of SubscriberRetriever. * diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberTimezone.java b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberTimezone.java new file mode 100644 index 0000000..2fb78a8 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/susbcribers/SubscriberTimezone.java @@ -0,0 +1,36 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.susbcribers; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class SubscriberTimezone. + */ +public class SubscriberTimezone { + + /** The id. */ + @SerializedName("id") + public String id; + + /** The name. */ + @SerializedName("name") + public String name; + + /** The name for humans. */ + @SerializedName("name_for_humans") + public String nameForHumans; + + /** The offset name. */ + @SerializedName("offset_name") + public String offsetName; + + /** The offset. */ + @SerializedName("offset") + public Integer offset; +} diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/Subscribers.java b/src/main/java/com/mailerlite/sdk/susbcribers/Subscribers.java index 72f3b99..7538e92 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/Subscribers.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/Subscribers.java @@ -78,4 +78,38 @@ public SubscriberImportsRetriever imports() { return new SubscriberImportsRetriever(apiObjectReference); } + + /** + * Forgets a subscriber. The API deletes the subscriber data within 30 days. + * + * @param subscriberId the subscriber id + * @return the forgotten subscriber + * @throws MailerLiteException the mailer lite exception + */ + public ForgottenSubscriber forget(String subscriberId) throws MailerLiteException + { + String endpoint = "/subscribers/".concat(subscriberId).concat("/forget"); + + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + ForgottenSubscriber response = api.postRequest(endpoint, "", ForgottenSubscriber.class); + + if (response.subscriber != null) { + response.subscriber.parseDates(); + } + + return response; + } + + /** + * Activity log of a subscriber. Takes a subscriber id, not an email. + * + * @param subscriberId the subscriber id + * @return the subscriber activity log retriever + */ + public SubscriberActivityLogRetriever activityLog(String subscriberId) + { + return new SubscriberActivityLogRetriever(apiObjectReference, subscriberId); + } } diff --git a/src/test/java/com/mailerlite/sdk/tests/SubscribersRequestTest.java b/src/test/java/com/mailerlite/sdk/tests/SubscribersRequestTest.java new file mode 100644 index 0000000..f81e8a8 --- /dev/null +++ b/src/test/java/com/mailerlite/sdk/tests/SubscribersRequestTest.java @@ -0,0 +1,230 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Instant; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.google.gson.JsonObject; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.susbcribers.ForgottenSubscriber; +import com.mailerlite.sdk.susbcribers.SingleSubscriber; +import com.mailerlite.sdk.susbcribers.SingleSubscriberImport; +import com.mailerlite.sdk.susbcribers.SubscriberActivityLogList; +import com.mailerlite.sdk.susbcribers.SubscriberImportList; + +/** + * The Class SubscribersRequestTest. + */ +public class SubscribersRequestTest extends MockTestBase { + + /** + * Test list sends the documented query params. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListSendsDocumentedParams() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[],\"links\":{},\"meta\":{\"next_cursor\":\"abc\"}}"); + + this.getMailerLite().subscribers().retriever() + .filter("status", "active") + .limit(10) + .page(2) + .cursor("abc") + .sort("-created_at") + .include("groups") + .startDate("2024-01-01") + .endDate("2024-02-01") + .withFields(true) + .withGroups(false) + .get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/subscribers", http.path()); + assertEquals("active", query.get("filter[status]")); + assertEquals("10", query.get("limit")); + assertEquals("2", query.get("page")); + assertEquals("abc", query.get("cursor")); + assertEquals("-created_at", query.get("sort")); + assertEquals("groups", query.get("include")); + assertEquals("2024-01-01", query.get("start_date")); + assertEquals("2024-02-01", query.get("end_date")); + assertEquals("1", query.get("with_fields")); + assertEquals("0", query.get("with_groups")); + } + + /** + * Test create sends the new body params. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestCreateSendsResubscribeDoubleOptinAndNotes() throws MailerLiteException + { + http.respondWith(201, "{\"data\":{\"id\":\"1\",\"email\":\"a@example.com\"}}"); + + this.getMailerLite().subscribers().builder() + .email("a@example.com") + .resubscribe(true) + .doubleOptin(false) + .addNote("first note") + .create(); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/subscribers", http.path()); + assertEquals("a@example.com", body.get("email").getAsString()); + assertTrue(body.get("resubscribe").getAsBoolean()); + assertFalse(body.get("double_optin").getAsBoolean()); + assertEquals("first note", body.getAsJsonArray("notes").get(0).getAsString()); + } + + /** + * Test create and update bodies are byte for byte what the builder always sent. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestBuilderBodyIsUnchanged() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"id\":\"1\",\"email\":\"a@example.com\"}}"); + + this.getMailerLite().subscribers().builder().email("a@example.com").addField("city", "Vilnius").addGroup("5").status("active").create(); + assertEquals("{\"email\":\"a@example.com\",\"fields\":{\"city\":\"Vilnius\"},\"groups\":[\"5\"],\"status\":\"active\"}", http.rawBody()); + + this.getMailerLite().subscribers().builder().email("a@example.com").status("unsubscribed").update("1"); + assertEquals("PUT", http.method()); + assertEquals("{\"email\":\"a@example.com\",\"status\":\"unsubscribed\"}", http.rawBody()); + } + + /** + * Test get single parses the new response fields. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestGetSingleParsesNewFields() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"id\":\"1\",\"email\":\"a@example.com\",\"deleted_at\":\"2024-01-02 03:04:05\",\"forget_at\":\"2024-02-02 03:04:05\"," + + "\"groups\":[{\"id\":\"5\",\"name\":\"Group\"}]," + + "\"location\":{\"id\":\"9\",\"title\":\"Vilnius\",\"country_name\":\"Lithuania\",\"continent_name\":\"Europe\",\"state_name\":null,\"time_zone\":\"Europe/Vilnius\"}," + + "\"timezone\":{\"id\":\"3\",\"name\":\"Europe/Vilnius\",\"name_for_humans\":\"Vilnius\",\"offset_name\":\"+02:00\",\"offset\":120}}}"); + + SingleSubscriber subscriber = this.getMailerLite().subscribers().retriever().getSingle("1"); + + assertEquals("GET", http.method()); + assertEquals("/subscribers/1", http.path()); + assertNotNull(subscriber.subscriber.deletedAt); + assertNotNull(subscriber.subscriber.forgetAt); + assertEquals("5", subscriber.subscriber.groups[0].id); + assertEquals("Lithuania", subscriber.subscriber.location.countryName); + assertEquals(120, (int) subscriber.subscriber.timezone.offset); + } + + /** + * Test forget. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestForget() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"id\":\"1\",\"email\":\"a@example.com\"},\"message\":\"Subscriber data will be completely deleted and forgotten within 30 days.\"}"); + + ForgottenSubscriber response = this.getMailerLite().subscribers().forget("1"); + + assertEquals("POST", http.method()); + assertEquals("/subscribers/1/forget", http.path()); + assertEquals("1", response.subscriber.id); + assertTrue(response.message.contains("30 days")); + } + + /** + * Test activity log. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestActivityLog() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[" + + "{\"id\":\"1\",\"log_name\":\"added_to_group\",\"subject_id\":\"10\",\"subject_type\":\"subscribers\",\"properties\":{\"group_id\":\"1\"},\"created_at\":\"2024-05-01 12:43:29\",\"updated_at\":\"2024-05-01 12:43:29\"}," + + "{\"id\":\"2\",\"log_name\":\"activated\",\"subject_id\":\"10\",\"subject_type\":\"subscribers\",\"properties\":[],\"created_at\":\"2024-05-01 12:43:29\",\"updated_at\":\"2024-05-01 12:43:29\"}]}"); + + SubscriberActivityLogList list = this.getMailerLite().subscribers().activityLog("10") + .logName("added_to_group") + .limit(5) + .page(1) + .get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/subscribers/10/activity-log", http.path()); + assertEquals("added_to_group", query.get("filter[log_name]")); + assertEquals("5", query.get("limit")); + assertEquals("1", query.get("page")); + assertEquals(2, list.entries.length); + assertEquals("1", list.entries[0].properties.getAsJsonObject().get("group_id").getAsString()); + assertTrue(list.entries[1].properties.isJsonArray()); + assertNotNull(list.entries[0].createdAt); + } + + /** + * Test the import list parses its ISO 8601 dates. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestImportListParsesIsoDates() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"7\",\"updated_at\":\"2023-11-02T13:43:10.000000Z\"}],\"links\":{},\"meta\":{}}"); + + SubscriberImportList list = this.getMailerLite().subscribers().imports().get(); + + assertEquals("GET", http.method()); + assertEquals("/subscribers/import", http.path()); + assertEquals(Instant.parse("2023-11-02T13:43:10Z"), list.imports[0].updatedAt.toInstant()); + } + + /** + * Test get import parses the new response fields. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestGetImportParsesNewFields() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"id\":\"7\",\"account_id\":\"3\",\"updated_at\":\"2023-11-02T13:43:10.000000Z\",\"suspicious_format\":[{\"id\":\"1\",\"email\":\"x@example\"}],\"suspicious_format_count\":1," + + "\"duplicate\":[],\"duplicate_count\":2,\"subscriber_limit\":[],\"subscriber_limit_count\":3,\"is_stopped_due_to_free_account_limit_exceeded\":false}}"); + + SingleSubscriberImport response = this.getMailerLite().subscribers().imports().getSingle("7"); + + assertEquals("GET", http.method()); + assertEquals("/subscribers/import/7", http.path()); + assertEquals("3", response.subscriberImport.accountId); + assertEquals("x@example", response.subscriberImport.suspiciousFormat[0].email); + assertEquals(1, response.subscriberImport.suspiciousFormatCount); + assertEquals(2, response.subscriberImport.duplicateCount); + assertEquals(3, response.subscriberImport.subscriberLimitCount); + assertFalse(response.subscriberImport.isStoppedDueToFreeAccountLimitExceeded); + assertEquals(Instant.parse("2023-11-02T13:43:10Z"), response.subscriberImport.updatedAt.toInstant()); + } +} From 4a2ebbd628c7944443dd2fdb88f8165d75e79a2c Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 12:44:01 +0530 Subject: [PATCH 4/9] Add group import and page and include params --- .../sdk/groups/GroupImportBody.java | 30 ++++ .../sdk/groups/GroupImportBuilder.java | 126 ++++++++++++++++ .../sdk/groups/GroupImportSubscriber.java | 30 ++++ .../mailerlite/sdk/groups/GroupRetriever.java | 13 ++ .../sdk/groups/GroupSubscriberImport.java | 21 +++ .../sdk/groups/GroupSubscribers.java | 13 ++ .../com/mailerlite/sdk/groups/Groups.java | 11 ++ .../sdk/tests/GroupsRequestTest.java | 139 ++++++++++++++++++ 8 files changed, 383 insertions(+) create mode 100644 src/main/java/com/mailerlite/sdk/groups/GroupImportBody.java create mode 100644 src/main/java/com/mailerlite/sdk/groups/GroupImportBuilder.java create mode 100644 src/main/java/com/mailerlite/sdk/groups/GroupImportSubscriber.java create mode 100644 src/main/java/com/mailerlite/sdk/groups/GroupSubscriberImport.java create mode 100644 src/test/java/com/mailerlite/sdk/tests/GroupsRequestTest.java diff --git a/src/main/java/com/mailerlite/sdk/groups/GroupImportBody.java b/src/main/java/com/mailerlite/sdk/groups/GroupImportBody.java new file mode 100644 index 0000000..d8937f5 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/groups/GroupImportBody.java @@ -0,0 +1,30 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.groups; + +import java.util.ArrayList; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class GroupImportBody. + */ +public class GroupImportBody { + + /** The resubscribe. */ + @SerializedName("resubscribe") + public Boolean resubscribe; + + /** The trigger automations. */ + @SerializedName("trigger_automations") + public Boolean triggerAutomations; + + /** The subscribers. */ + @SerializedName("subscribers") + public ArrayList subscribers = new ArrayList(); +} diff --git a/src/main/java/com/mailerlite/sdk/groups/GroupImportBuilder.java b/src/main/java/com/mailerlite/sdk/groups/GroupImportBuilder.java new file mode 100644 index 0000000..ba654ec --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/groups/GroupImportBuilder.java @@ -0,0 +1,126 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.groups; + +import java.util.Map; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteApi; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.JsonBody; + +/** + * Imports a list of subscribers into a group. + */ +public class GroupImportBuilder { + + /** The api object reference. */ + private MailerLite apiObjectReference; + + /** The group id. */ + private String groupId; + + /** The builder body. */ + private GroupImportBody builderBody = new GroupImportBody(); + + /** + * Instantiates a new group import builder. + * + * @param apiRef the api ref + * @param forGroupId the group id + */ + public GroupImportBuilder(MailerLite apiRef, String forGroupId) + { + apiObjectReference = apiRef; + groupId = forGroupId; + } + + /** + * Clear. + */ + public void clear() + { + builderBody = new GroupImportBody(); + } + + /** + * Adds a subscriber to import. + * + * @param email the email + * @return the group import builder + */ + public GroupImportBuilder addSubscriber(String email) + { + return addSubscriber(email, null, null); + } + + /** + * Adds a subscriber to import. + * + * @param email the email + * @param name the name, can be null + * @param fields the custom field values keyed by field key, can be null + * @return the group import builder + */ + public GroupImportBuilder addSubscriber(String email, String name, Map fields) + { + GroupImportSubscriber subscriber = new GroupImportSubscriber(); + subscriber.email = email; + subscriber.name = name; + subscriber.fields = fields; + + builderBody.subscribers.add(subscriber); + return this; + } + + /** + * Reactivates unsubscribed subscribers in the list. + * + * @param resubscribe the resubscribe + * @return the group import builder + */ + public GroupImportBuilder resubscribe(Boolean resubscribe) + { + builderBody.resubscribe = resubscribe; + return this; + } + + /** + * Sets whether imported subscribers enter automations triggered by joining the group. + * + * @param triggerAutomations the trigger automations + * @return the group import builder + */ + public GroupImportBuilder triggerAutomations(Boolean triggerAutomations) + { + builderBody.triggerAutomations = triggerAutomations; + return this; + } + + /** + * Starts the import. + * + * @return the group subscriber import + * @throws MailerLiteException the mailer lite exception + */ + public GroupSubscriberImport start() throws MailerLiteException + { + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + String json = JsonBody.toJson(builderBody); + + GroupSubscriberImport response = api.postRequest("/groups/".concat(groupId).concat("/import-subscribers"), json, GroupSubscriberImport.class); + + if (response.subscriberImport != null) { + response.subscriberImport.parseDates(); + } + + return response; + } +} diff --git a/src/main/java/com/mailerlite/sdk/groups/GroupImportSubscriber.java b/src/main/java/com/mailerlite/sdk/groups/GroupImportSubscriber.java new file mode 100644 index 0000000..931b0d0 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/groups/GroupImportSubscriber.java @@ -0,0 +1,30 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.groups; + +import java.util.Map; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class GroupImportSubscriber. + */ +public class GroupImportSubscriber { + + /** The email. */ + @SerializedName("email") + public String email; + + /** The name. */ + @SerializedName("name") + public String name; + + /** The fields. */ + @SerializedName("fields") + public Map fields; +} diff --git a/src/main/java/com/mailerlite/sdk/groups/GroupRetriever.java b/src/main/java/com/mailerlite/sdk/groups/GroupRetriever.java index 16ecf43..3e29b40 100644 --- a/src/main/java/com/mailerlite/sdk/groups/GroupRetriever.java +++ b/src/main/java/com/mailerlite/sdk/groups/GroupRetriever.java @@ -96,6 +96,19 @@ public SingleGroup getSingle(String groupId) throws MailerLiteException return group; } + /** + * Sets the page to return. + * + * @param page the page + * @return the group retriever + */ + public GroupRetriever page(int page) + { + this.addQueryParameter("page", Integer.toString(page)); + + return this; + } + /** * Gets the single instance of GroupRetriever. * diff --git a/src/main/java/com/mailerlite/sdk/groups/GroupSubscriberImport.java b/src/main/java/com/mailerlite/sdk/groups/GroupSubscriberImport.java new file mode 100644 index 0000000..d86bf1e --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/groups/GroupSubscriberImport.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.groups; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.susbcribers.SingleSubscriberImport; + +/** + * The Class GroupSubscriberImport. + */ +public class GroupSubscriberImport extends SingleSubscriberImport { + + /** The import progress url. */ + @SerializedName("import_progress_url") + public String importProgressUrl; +} diff --git a/src/main/java/com/mailerlite/sdk/groups/GroupSubscribers.java b/src/main/java/com/mailerlite/sdk/groups/GroupSubscribers.java index 60ba9ef..aa7573f 100644 --- a/src/main/java/com/mailerlite/sdk/groups/GroupSubscribers.java +++ b/src/main/java/com/mailerlite/sdk/groups/GroupSubscribers.java @@ -109,6 +109,19 @@ public MailerLiteResponse unassign(String subscriberId) throws MailerLiteExcepti return response; } + /** + * Sets the relations to include, for example "groups". + * + * @param include the include + * @return the group subscribers + */ + public GroupSubscribers include(String include) + { + this.addQueryParameter("include", include); + + return this; + } + /** * Gets the single instance of GroupSubscribers. * diff --git a/src/main/java/com/mailerlite/sdk/groups/Groups.java b/src/main/java/com/mailerlite/sdk/groups/Groups.java index b495f66..6d33726 100644 --- a/src/main/java/com/mailerlite/sdk/groups/Groups.java +++ b/src/main/java/com/mailerlite/sdk/groups/Groups.java @@ -61,6 +61,17 @@ public GroupSubscribers subscribers(String groupId) return new GroupSubscribers(apiObjectReference, groupId); } + /** + * Import builder. + * + * @param groupId the group id + * @return the group import builder + */ + public GroupImportBuilder importBuilder(String groupId) + { + return new GroupImportBuilder(apiObjectReference, groupId); + } + /** * Delete. * diff --git a/src/test/java/com/mailerlite/sdk/tests/GroupsRequestTest.java b/src/test/java/com/mailerlite/sdk/tests/GroupsRequestTest.java new file mode 100644 index 0000000..88368ae --- /dev/null +++ b/src/test/java/com/mailerlite/sdk/tests/GroupsRequestTest.java @@ -0,0 +1,139 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.google.gson.JsonObject; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.groups.GroupImportBuilder; +import com.mailerlite.sdk.groups.GroupSubscriberImport; +import com.mailerlite.sdk.groups.GroupSubscribersList; +import com.mailerlite.sdk.groups.GroupsList; + +/** + * The Class GroupsRequestTest. + */ +public class GroupsRequestTest extends MockTestBase { + + /** + * Test list sends page. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListSendsPage() throws MailerLiteException, ParseException + { + http.respondWith(200, "{\"data\":[{\"id\":\"1\",\"name\":\"G\",\"created_at\":\"2024-05-01 12:43:29\"}],\"links\":{},\"meta\":{}}"); + + GroupsList list = this.getMailerLite().groups().retriever().page(3).limit(25).nameFilter("news").sort("-name").get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/groups", http.path()); + assertEquals("3", query.get("page")); + assertEquals("25", query.get("limit")); + assertEquals("news", query.get("filter[name]")); + assertEquals("-name", query.get("sort")); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2024-05-01 12:43:29"), list.groups[0].createdAt); + } + + /** + * Test group subscribers sends include and cursor, and parses the cursor meta. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestGroupSubscribersSendsIncludeAndCursor() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[],\"links\":{},\"meta\":{\"path\":\"x\",\"per_page\":25,\"next_cursor\":\"next\",\"prev_cursor\":null}}"); + + GroupSubscribersList list = this.getMailerLite().groups().subscribers("5") + .statusFilter("active") + .limit(25) + .cursor("abc") + .include("groups") + .get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/groups/5/subscribers", http.path()); + assertEquals("active", query.get("filter[status]")); + assertEquals("25", query.get("limit")); + assertEquals("abc", query.get("cursor")); + assertEquals("groups", query.get("include")); + assertEquals("next", list.meta.nextCursor); + } + + /** + * Test import subscribers. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestImportSubscribers() throws MailerLiteException + { + http.respondWith(200, "{\"import_progress_url\":\"https://connect.mailerlite.com/api/subscribers/import/9\",\"data\":{\"id\":\"9\",\"total\":2}}"); + + Map fields = new HashMap(); + fields.put("city", "Vilnius"); + + GroupSubscriberImport response = this.getMailerLite().groups().importBuilder("5") + .addSubscriber("a@example.com") + .addSubscriber("b@example.com", "Bee", fields) + .resubscribe(true) + .triggerAutomations(false) + .start(); + + JsonObject body = http.body(); + JsonObject second = body.getAsJsonArray("subscribers").get(1).getAsJsonObject(); + + assertEquals("POST", http.method()); + assertEquals("/groups/5/import-subscribers", http.path()); + assertTrue(body.get("resubscribe").getAsBoolean()); + assertFalse(body.get("trigger_automations").getAsBoolean()); + assertEquals("a@example.com", body.getAsJsonArray("subscribers").get(0).getAsJsonObject().get("email").getAsString()); + assertEquals("b@example.com", second.get("email").getAsString()); + assertEquals("Bee", second.get("name").getAsString()); + assertEquals("Vilnius", second.getAsJsonObject("fields").get("city").getAsString()); + assertEquals("https://connect.mailerlite.com/api/subscribers/import/9", response.importProgressUrl); + assertEquals("9", response.subscriberImport.id); + } + + /** + * Test clear empties the import body. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestImportBuilderClear() throws MailerLiteException + { + http.respondWith(200, "{\"import_progress_url\":\"https://connect.mailerlite.com/api/subscribers/import/9\"}"); + + GroupImportBuilder builder = this.getMailerLite().groups().importBuilder("5").addSubscriber("a@example.com").resubscribe(true); + builder.clear(); + builder.addSubscriber("b@example.com").start(); + + JsonObject body = http.body(); + + assertEquals(1, body.getAsJsonArray("subscribers").size()); + assertEquals("b@example.com", body.getAsJsonArray("subscribers").get(0).getAsJsonObject().get("email").getAsString()); + assertFalse(body.has("resubscribe")); + } +} From b83330e62836d18f768046996a72f04b1b96d80d Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 12:44:01 +0530 Subject: [PATCH 5/9] Fix segment subscribers limit and add cursor, page, sort and filter --- .../com/mailerlite/sdk/segments/Segment.java | 9 ++ .../sdk/segments/SegmentSubscribers.java | 17 ++- .../sdk/segments/SegmentSubscribersList.java | 5 + .../sdk/segments/SegmentUpdateBody.java | 25 +++ .../com/mailerlite/sdk/segments/Segments.java | 30 ++-- .../sdk/segments/SegmentsRetriever.java | 39 +++++ .../sdk/segments/SegmentsSubscriberMeta.java | 16 ++ .../sdk/tests/SegmentsRequestTest.java | 144 ++++++++++++++++++ 8 files changed, 271 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/mailerlite/sdk/segments/SegmentUpdateBody.java create mode 100644 src/test/java/com/mailerlite/sdk/tests/SegmentsRequestTest.java diff --git a/src/main/java/com/mailerlite/sdk/segments/Segment.java b/src/main/java/com/mailerlite/sdk/segments/Segment.java index 1a50165..d5aa31d 100644 --- a/src/main/java/com/mailerlite/sdk/segments/Segment.java +++ b/src/main/java/com/mailerlite/sdk/segments/Segment.java @@ -9,6 +9,7 @@ import java.util.Date; +import com.google.gson.JsonElement; import com.google.gson.annotations.SerializedName; import com.mailerlite.sdk.util.ApiResource; import com.mailerlite.sdk.util.ParseDate; @@ -46,4 +47,12 @@ public class Segment extends ApiResource { /** The created at. */ @ParseDate("createdAtStr") public Date createdAt; + + /** The filter rules. Returned only when the list is requested with filters. */ + @SerializedName("filter") + public JsonElement filter; + + /** The automations using segment count. */ + @SerializedName("automations_using_segment_count") + public Integer automationsUsingSegmentCount; } diff --git a/src/main/java/com/mailerlite/sdk/segments/SegmentSubscribers.java b/src/main/java/com/mailerlite/sdk/segments/SegmentSubscribers.java index 2d1aa62..af91dfc 100644 --- a/src/main/java/com/mailerlite/sdk/segments/SegmentSubscribers.java +++ b/src/main/java/com/mailerlite/sdk/segments/SegmentSubscribers.java @@ -10,12 +10,12 @@ import com.mailerlite.sdk.MailerLite; import com.mailerlite.sdk.MailerLiteApi; import com.mailerlite.sdk.exceptions.MailerLiteException; -import com.mailerlite.sdk.util.ApiRequest; +import com.mailerlite.sdk.util.PaginatedRequest; /** * The Class SegmentSubscribers. */ -public class SegmentSubscribers extends ApiRequest { +public class SegmentSubscribers extends PaginatedRequest { /** The api object reference. */ private MailerLite apiObjectReference; @@ -41,9 +41,10 @@ public SegmentSubscribers(MailerLite apiRef, String forSegmentId) * @param limit the limit * @return the segment subscribers */ + @Override public SegmentSubscribers limit(int limit) { - this.addQueryParameter("limig", String.valueOf(limit)); + this.addQueryParameter("limit", String.valueOf(limit)); return this; } @@ -92,4 +93,14 @@ public SegmentSubscribersList get() throws MailerLiteException return list; } + + /** + * Gets the single instance of SegmentSubscribers. + * + * @return single instance of SegmentSubscribers + */ + @Override + protected SegmentSubscribers getInstance() { + return this; + } } diff --git a/src/main/java/com/mailerlite/sdk/segments/SegmentSubscribersList.java b/src/main/java/com/mailerlite/sdk/segments/SegmentSubscribersList.java index 4384021..83df0fe 100644 --- a/src/main/java/com/mailerlite/sdk/segments/SegmentSubscribersList.java +++ b/src/main/java/com/mailerlite/sdk/segments/SegmentSubscribersList.java @@ -10,6 +10,7 @@ import com.google.gson.annotations.SerializedName; import com.mailerlite.sdk.MailerLiteResponse; import com.mailerlite.sdk.susbcribers.Subscriber; +import com.mailerlite.sdk.util.ResponseLinks; /** * The Class SegmentSubscribersList. @@ -20,6 +21,10 @@ public class SegmentSubscribersList extends MailerLiteResponse { @SerializedName("data") public Subscriber[] subscribers; + /** The links. */ + @SerializedName("links") + public ResponseLinks links; + /** The meta. */ @SerializedName("meta") public SegmentsSubscriberMeta meta; diff --git a/src/main/java/com/mailerlite/sdk/segments/SegmentUpdateBody.java b/src/main/java/com/mailerlite/sdk/segments/SegmentUpdateBody.java new file mode 100644 index 0000000..46100e6 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/segments/SegmentUpdateBody.java @@ -0,0 +1,25 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.segments; + +import com.google.gson.JsonArray; +import com.google.gson.annotations.SerializedName; + +/** + * The Class SegmentUpdateBody. + */ +public class SegmentUpdateBody { + + /** The name. */ + @SerializedName("name") + public String name; + + /** The filter. */ + @SerializedName("filter") + public JsonArray filter; +} diff --git a/src/main/java/com/mailerlite/sdk/segments/Segments.java b/src/main/java/com/mailerlite/sdk/segments/Segments.java index a41f16f..bfe846d 100644 --- a/src/main/java/com/mailerlite/sdk/segments/Segments.java +++ b/src/main/java/com/mailerlite/sdk/segments/Segments.java @@ -7,14 +7,12 @@ **************************************************/ package com.mailerlite.sdk.segments; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; import com.mailerlite.sdk.MailerLite; import com.mailerlite.sdk.MailerLiteApi; import com.mailerlite.sdk.MailerLiteResponse; import com.mailerlite.sdk.exceptions.MailerLiteException; -import com.mailerlite.sdk.groups.NameCreatorBody; -import com.mailerlite.sdk.util.JsonSerializationDeserializationStrategy; +import com.mailerlite.sdk.util.JsonBody; /** * The Class Segments. @@ -64,19 +62,29 @@ public SegmentSubscribers subscribers(String segmentId) * @throws MailerLiteException the mailer lite exception */ public SingleSegment update(String segmentId, String newSegmentName) throws MailerLiteException + { + return update(segmentId, newSegmentName, null); + } + + /** + * Updates the name and the filter rules of a segment. + * + * @param segmentId the segment id + * @param newSegmentName the new segment name + * @param filter the filter rules, in the same shape the API returns them + * @return the single segment + * @throws MailerLiteException the mailer lite exception + */ + public SingleSegment update(String segmentId, String newSegmentName, JsonArray filter) throws MailerLiteException { MailerLiteApi api = new MailerLiteApi(); api.setToken(apiObjectReference.getToken()); - NameCreatorBody requestBody = new NameCreatorBody(); + SegmentUpdateBody requestBody = new SegmentUpdateBody(); requestBody.name = newSegmentName; + requestBody.filter = filter; - Gson gson = new GsonBuilder() - .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) - .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) - .create(); - - String json = gson.toJson(requestBody); + String json = JsonBody.toJson(requestBody); SingleSegment segment = api.putRequest("/segments/".concat(segmentId), json, SingleSegment.class); diff --git a/src/main/java/com/mailerlite/sdk/segments/SegmentsRetriever.java b/src/main/java/com/mailerlite/sdk/segments/SegmentsRetriever.java index e06ae9b..1ca5d1e 100644 --- a/src/main/java/com/mailerlite/sdk/segments/SegmentsRetriever.java +++ b/src/main/java/com/mailerlite/sdk/segments/SegmentsRetriever.java @@ -71,6 +71,45 @@ public SingleSegment getSingle(String segmentId) throws MailerLiteException return segment; } + /** + * Sets the page to return. + * + * @param page the page + * @return the segments retriever + */ + public SegmentsRetriever page(int page) + { + this.addQueryParameter("page", Integer.toString(page)); + + return this; + } + + /** + * Sets the sort order. + * + * @param sort the sort + * @return the segments retriever + */ + public SegmentsRetriever sort(String sort) + { + this.addQueryParameter("sort", sort); + + return this; + } + + /** + * Includes the segment filter rules. + * + * @param withFilter the with filter + * @return the segments retriever + */ + public SegmentsRetriever withFilter(boolean withFilter) + { + this.addQueryParameter("with_filter", withFilter ? "1" : "0"); + + return this; + } + /** * Gets the single instance of SegmentsRetriever. * diff --git a/src/main/java/com/mailerlite/sdk/segments/SegmentsSubscriberMeta.java b/src/main/java/com/mailerlite/sdk/segments/SegmentsSubscriberMeta.java index 845e2a1..5eef8bb 100644 --- a/src/main/java/com/mailerlite/sdk/segments/SegmentsSubscriberMeta.java +++ b/src/main/java/com/mailerlite/sdk/segments/SegmentsSubscriberMeta.java @@ -25,4 +25,20 @@ public class SegmentsSubscriberMeta { /** The last. */ @SerializedName("last") public int last; + + /** The path. */ + @SerializedName("path") + public String path; + + /** The per page. */ + @SerializedName("per_page") + public int perPage; + + /** The next cursor. */ + @SerializedName("next_cursor") + public String nextCursor; + + /** The previous cursor. */ + @SerializedName("prev_cursor") + public String previousCursor; } diff --git a/src/test/java/com/mailerlite/sdk/tests/SegmentsRequestTest.java b/src/test/java/com/mailerlite/sdk/tests/SegmentsRequestTest.java new file mode 100644 index 0000000..80e88af --- /dev/null +++ b/src/test/java/com/mailerlite/sdk/tests/SegmentsRequestTest.java @@ -0,0 +1,144 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.segments.SegmentSubscribersList; +import com.mailerlite.sdk.segments.SegmentsList; + +/** + * The Class SegmentsRequestTest. + */ +public class SegmentsRequestTest extends MockTestBase { + + /** + * Test list sends page, sort and with_filter, and parses the new fields. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListSendsPageSortAndWithFilter() throws MailerLiteException, ParseException + { + http.respondWith(200, "{\"data\":[{\"id\":\"1\",\"name\":\"S\",\"filter\":[[{\"operator\":\"in_any\"}]],\"automations_using_segment_count\":2,\"created_at\":\"2024-05-01 12:43:29\"}],\"links\":{},\"meta\":{}}"); + + SegmentsList list = this.getMailerLite().segments().retriever().page(2).limit(10).sort("-total").withFilter(true).get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/segments", http.path()); + assertEquals("2", query.get("page")); + assertEquals("10", query.get("limit")); + assertEquals("-total", query.get("sort")); + assertEquals("1", query.get("with_filter")); + assertEquals(2, (int) list.segments[0].automationsUsingSegmentCount); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2024-05-01 12:43:29"), list.segments[0].createdAt); + assertEquals("in_any", list.segments[0].filter.getAsJsonArray().get(0).getAsJsonArray().get(0).getAsJsonObject().get("operator").getAsString()); + } + + /** + * Test update sends the filter. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestUpdateSendsFilter() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"id\":\"1\",\"name\":\"New\",\"created_at\":\"2024-01-01 00:00:00\"}}"); + + JsonArray filter = JsonParser.parseString("[[{\"operator\":\"in_any\",\"args\":[\"groups\",[\"5\"]]}]]").getAsJsonArray(); + + this.getMailerLite().segments().update("1", "New", filter); + + JsonObject body = http.body(); + + assertEquals("PUT", http.method()); + assertEquals("/segments/1", http.path()); + assertEquals("New", body.get("name").getAsString()); + assertEquals(filter, body.getAsJsonArray("filter")); + } + + /** + * Test the name only update body is byte for byte what it always sent. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestUpdateNameBodyIsUnchanged() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"id\":\"1\",\"name\":\"New\",\"created_at\":\"2024-01-01 00:00:00\"}}"); + + this.getMailerLite().segments().update("1", "New"); + + assertEquals("PUT", http.method()); + assertEquals("{\"name\":\"New\"}", http.rawBody()); + } + + /** + * Test segment subscribers sends limit and cursor. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestSegmentSubscribersSendsLimitAndCursor() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[],\"links\":{\"next\":\"https://example.com?cursor=next\"},\"meta\":{\"path\":\"x\",\"per_page\":5,\"next_cursor\":\"next\",\"prev_cursor\":\"prev\"}}"); + + SegmentSubscribersList list = this.getMailerLite().segments().subscribers("1") + .limit(5) + .cursor("abc") + .statusFilter("active") + .get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/segments/1/subscribers", http.path()); + assertEquals("5", query.get("limit")); + assertFalse(query.containsKey("limig")); + assertEquals("abc", query.get("cursor")); + assertFalse(query.containsKey("after")); + assertEquals("active", query.get("filter[status]")); + assertEquals("next", list.meta.nextCursor); + assertEquals("prev", list.meta.previousCursor); + assertEquals(5, list.meta.perPage); + assertEquals("https://example.com?cursor=next", list.links.next); + } + + /** + * Test the old after setter still sends after. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestSegmentSubscribersAfterStillSendsAfter() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[],\"meta\":{}}"); + + this.getMailerLite().segments().subscribers("1").after("123").get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/segments/1/subscribers", http.path()); + assertEquals("123", query.get("after")); + assertFalse(query.containsKey("cursor")); + } +} From 2090cda341617fbfb5316c7a67ede5c9bad0b260 Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 12:44:01 +0530 Subject: [PATCH 6/9] Add page and is_default to fields --- .../java/com/mailerlite/sdk/fields/Field.java | 4 ++ .../mailerlite/sdk/fields/FieldRetriever.java | 13 +++++ .../sdk/tests/FieldsRequestTest.java | 54 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 src/test/java/com/mailerlite/sdk/tests/FieldsRequestTest.java diff --git a/src/main/java/com/mailerlite/sdk/fields/Field.java b/src/main/java/com/mailerlite/sdk/fields/Field.java index 5bb1fae..f2f8b2a 100644 --- a/src/main/java/com/mailerlite/sdk/fields/Field.java +++ b/src/main/java/com/mailerlite/sdk/fields/Field.java @@ -30,4 +30,8 @@ public class Field extends ApiResource { /** The type. */ @SerializedName("type") public String type; + + /** The is default. */ + @SerializedName("is_default") + public Boolean isDefault; } diff --git a/src/main/java/com/mailerlite/sdk/fields/FieldRetriever.java b/src/main/java/com/mailerlite/sdk/fields/FieldRetriever.java index 404abb5..6e3a42e 100644 --- a/src/main/java/com/mailerlite/sdk/fields/FieldRetriever.java +++ b/src/main/java/com/mailerlite/sdk/fields/FieldRetriever.java @@ -76,6 +76,19 @@ public FieldList get() throws MailerLiteException return list; } + /** + * Sets the page to return. + * + * @param page the page + * @return the field retriever + */ + public FieldRetriever page(int page) + { + this.addQueryParameter("page", Integer.toString(page)); + + return this; + } + /** * Gets the single instance of FieldRetriever. * diff --git a/src/test/java/com/mailerlite/sdk/tests/FieldsRequestTest.java b/src/test/java/com/mailerlite/sdk/tests/FieldsRequestTest.java new file mode 100644 index 0000000..a088b38 --- /dev/null +++ b/src/test/java/com/mailerlite/sdk/tests/FieldsRequestTest.java @@ -0,0 +1,54 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.fields.FieldList; + +/** + * The Class FieldsRequestTest. + */ +public class FieldsRequestTest extends MockTestBase { + + /** + * Test list sends page and parses is_default. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListSendsPage() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"1\",\"name\":\"Name\",\"key\":\"name\",\"type\":\"text\",\"is_default\":true}],\"links\":{},\"meta\":{}}"); + + FieldList list = this.getMailerLite().fields().retriever() + .page(2) + .limit(10) + .filter("keyword", "nam") + .filter("type", "text") + .sort("name") + .get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/fields", http.path()); + assertEquals("2", query.get("page")); + assertEquals("10", query.get("limit")); + assertEquals("nam", query.get("filter[keyword]")); + assertEquals("text", query.get("filter[type]")); + assertEquals("name", query.get("sort")); + assertTrue(list.fields[0].isDefault); + } +} From 9596a4ee627856df6bf5ac1313c23ead6afa5b2d Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 12:44:02 +0530 Subject: [PATCH 7/9] Add automation endpoints and parse every trigger and step type --- .../sdk/automations/Automation.java | 12 + .../AutomationActivityActionBody.java | 26 + .../automations/AutomationActivityFilter.java | 198 +++ .../AutomationAddSubscribersBody.java | 30 + .../sdk/automations/AutomationBuilder.java | 126 ++ .../automations/AutomationBuilderBody.java | 31 + .../automations/AutomationDeserializer.java | 98 +- .../sdk/automations/AutomationEndpoint.java | 59 + .../sdk/automations/AutomationReaddBody.java | 28 + .../sdk/automations/AutomationRetriever.java | 53 +- .../sdk/automations/AutomationStats.java | 2 + .../AutomationStepDeserializer.java | 64 +- .../sdk/automations/AutomationTestBody.java | 20 + .../AutomationTriggerDeserializer.java | 96 ++ .../sdk/automations/Automations.java | 259 ++++ .../sdk/automations/SingleAutomation.java | 21 + .../SingleAutomationDeserializer.java | 40 + .../activity/ActivitySubscriber.java | 28 + ...AutomationSubscriberActivityRetriever.java | 45 + .../activity/SubscriberActivity.java | 4 + .../sdk/automations/reports/AbTestSplit.java | 28 + .../sdk/automations/reports/AbTestStats.java | 58 + .../automations/reports/AbTestStatsList.java | 21 + .../reports/AbTestVariantStats.java | 30 + .../reports/AutomationEcommerceStats.java | 25 + .../reports/AutomationEmailContent.java | 20 + .../reports/AutomationEmailStats.java | 24 + .../automations/reports/AutomationEmails.java | 116 ++ .../AutomationOrderActivityRetriever.java | 113 ++ .../reports/AutomationReports.java | 171 +++ .../AutomationRunSubscribersRetriever.java | 101 ++ .../reports/AutomationStatsRequest.java | 64 + .../automations/reports/EcommerceStats.java | 32 + .../reports/EmailDeliverabilityStats.java | 61 + .../reports/EmailEngagementStats.java | 65 + .../automations/reports/ManualRunCount.java | 24 + .../automations/reports/OrderActivity.java | 46 + .../reports/OrderActivityList.java | 36 + .../automations/reports/RunSubscriber.java | 37 + .../reports/RunSubscriberList.java | 36 + .../reports/SingleAbTestStats.java | 21 + .../SingleAutomationEcommerceStats.java | 21 + .../reports/SingleAutomationEmailContent.java | 21 + .../reports/SingleAutomationEmailStats.java | 21 + .../reports/SingleStepRunCount.java | 21 + .../reports/SingleTriggerRunCount.java | 21 + .../reports/SingleTriggersRunCounts.java | 21 + .../sdk/automations/reports/StepRunCount.java | 28 + .../automations/reports/StepRunCountList.java | 21 + .../automations/reports/TriggerRunCount.java | 28 + .../reports/TriggersRunCounts.java | 24 + .../reports/UnsubscribeReason.java | 28 + .../reports/UnsubscribeReasonList.java | 21 + .../sdk/automations/steps/AbStep.java | 3 + .../automations/steps/AbTestWinnerBody.java | 20 + .../sdk/automations/steps/AutomationStep.java | 11 + .../steps/AutomationStepBuilder.java | 190 +++ .../steps/AutomationStepBuilderBody.java | 42 + .../automations/steps/AutomationStepList.java | 21 + .../steps/AutomationStepReorderBody.java | 32 + .../automations/steps/AutomationSteps.java | 138 ++ .../steps/GenericAutomationStep.java | 92 ++ .../steps/SingleAutomationStep.java | 21 + .../templates/AutomationTemplate.java | 49 + .../templates/AutomationTemplateList.java | 21 + .../AutomationTemplateRetriever.java | 70 + .../triggers/AutomationTrigger.java | 7 + .../triggers/AutomationTriggerBody.java | 26 + .../triggers/AutomationTriggerList.java | 21 + .../triggers/AutomationTriggerUpdate.java | 29 + .../triggers/AutomationTriggers.java | 106 ++ .../triggers/GenericAutomationTrigger.java | 75 ++ .../triggers/SingleAutomationTrigger.java | 21 + .../triggers/UpdatedAutomationTrigger.java | 21 + .../mailerlite/sdk/emails/SingleEmail.java | 21 + .../sdk/tests/AutomationsRequestTest.java | 1141 +++++++++++++++++ 76 files changed, 4728 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationActivityActionBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationActivityFilter.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationAddSubscribersBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationBuilder.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationBuilderBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationEndpoint.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationReaddBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationTestBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/AutomationTriggerDeserializer.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/SingleAutomation.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/SingleAutomationDeserializer.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/activity/ActivitySubscriber.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AbTestSplit.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AbTestStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AbTestStatsList.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AbTestVariantStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AutomationEcommerceStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmailContent.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmailStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmails.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AutomationOrderActivityRetriever.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AutomationReports.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AutomationRunSubscribersRetriever.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/AutomationStatsRequest.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/EcommerceStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/EmailDeliverabilityStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/EmailEngagementStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/ManualRunCount.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/OrderActivity.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/OrderActivityList.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/RunSubscriber.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/RunSubscriberList.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/SingleAbTestStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEcommerceStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEmailContent.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEmailStats.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/SingleStepRunCount.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/SingleTriggerRunCount.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/SingleTriggersRunCounts.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/StepRunCount.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/StepRunCountList.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/TriggerRunCount.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/TriggersRunCounts.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/UnsubscribeReason.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/reports/UnsubscribeReasonList.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/steps/AbTestWinnerBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepBuilder.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepBuilderBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepList.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepReorderBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/steps/AutomationSteps.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/steps/GenericAutomationStep.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/steps/SingleAutomationStep.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplate.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplateList.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplateRetriever.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerBody.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerList.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerUpdate.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggers.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/triggers/GenericAutomationTrigger.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/triggers/SingleAutomationTrigger.java create mode 100644 src/main/java/com/mailerlite/sdk/automations/triggers/UpdatedAutomationTrigger.java create mode 100644 src/main/java/com/mailerlite/sdk/emails/SingleEmail.java create mode 100644 src/test/java/com/mailerlite/sdk/tests/AutomationsRequestTest.java diff --git a/src/main/java/com/mailerlite/sdk/automations/Automation.java b/src/main/java/com/mailerlite/sdk/automations/Automation.java index e43c13b..cc9b4b2 100644 --- a/src/main/java/com/mailerlite/sdk/automations/Automation.java +++ b/src/main/java/com/mailerlite/sdk/automations/Automation.java @@ -82,6 +82,18 @@ public class Automation extends ApiResource { @ParseDate("createdAtStr") public Date createdAt; + /** The automation template id. */ + @SerializedName("automation_template_id") + public String automationTemplateId; + + /** The automation template name. */ + @SerializedName("automation_template_name") + public String automationTemplateName; + + /** The building in progress. */ + @SerializedName("building_in_progress") + public Boolean buildingInProgress; + } diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationActivityActionBody.java b/src/main/java/com/mailerlite/sdk/automations/AutomationActivityActionBody.java new file mode 100644 index 0000000..b5043f2 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationActivityActionBody.java @@ -0,0 +1,26 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationActivityActionBody. + */ +public class AutomationActivityActionBody { + + /** The destination groups. */ + @SerializedName("destination_groups") + public List destinationGroups; + + /** The filter. */ + @SerializedName("filter") + public AutomationActivityFilter filter; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationActivityFilter.java b/src/main/java/com/mailerlite/sdk/automations/AutomationActivityFilter.java new file mode 100644 index 0000000..3c158ed --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationActivityFilter.java @@ -0,0 +1,198 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import java.util.ArrayList; + +import com.google.gson.annotations.SerializedName; + +/** + * Selects the automation activity that a bulk activity action applies to. + */ +public class AutomationActivityFilter { + + /** The status. */ + @SerializedName("status") + public String status; + + /** The run ids. */ + @SerializedName("id") + public ArrayList ids; + + /** The search. */ + @SerializedName("search") + public String search; + + /** The reason. */ + @SerializedName("reason") + public String reason; + + /** The date from. */ + @SerializedName("date_from") + public String dateFrom; + + /** The date to. */ + @SerializedName("date_to") + public String dateTo; + + /** The scheduled from. */ + @SerializedName("scheduled_from") + public String scheduledFrom; + + /** The scheduled to. */ + @SerializedName("scheduled_to") + public String scheduledTo; + + /** The next step id. */ + @SerializedName("next_step") + public String nextStep; + + /** The current step id. */ + @SerializedName("current_step") + public String currentStep; + + /** The step id. */ + @SerializedName("step") + public String step; + + /** + * Status. + * + * @param status the status, for example "active" or "completed" + * @return the automation activity filter + */ + public AutomationActivityFilter status(String status) + { + this.status = status; + return this; + } + + /** + * Adds a run id. + * + * @param id the run id + * @return the automation activity filter + */ + public AutomationActivityFilter addId(String id) + { + if (ids == null) { + ids = new ArrayList(); + } + + ids.add(id); + return this; + } + + /** + * Search. + * + * @param search the search + * @return the automation activity filter + */ + public AutomationActivityFilter search(String search) + { + this.search = search; + return this; + } + + /** + * Reason. + * + * @param reason the reason + * @return the automation activity filter + */ + public AutomationActivityFilter reason(String reason) + { + this.reason = reason; + return this; + } + + /** + * Date from. + * + * @param dateFrom the date from, as YYYY-MM-DD + * @return the automation activity filter + */ + public AutomationActivityFilter dateFrom(String dateFrom) + { + this.dateFrom = dateFrom; + return this; + } + + /** + * Date to. + * + * @param dateTo the date to, as YYYY-MM-DD + * @return the automation activity filter + */ + public AutomationActivityFilter dateTo(String dateTo) + { + this.dateTo = dateTo; + return this; + } + + /** + * Scheduled from. + * + * @param scheduledFrom the scheduled from, as YYYY-MM-DD + * @return the automation activity filter + */ + public AutomationActivityFilter scheduledFrom(String scheduledFrom) + { + this.scheduledFrom = scheduledFrom; + return this; + } + + /** + * Scheduled to. + * + * @param scheduledTo the scheduled to, as YYYY-MM-DD + * @return the automation activity filter + */ + public AutomationActivityFilter scheduledTo(String scheduledTo) + { + this.scheduledTo = scheduledTo; + return this; + } + + /** + * Next step. + * + * @param nextStep the next step id + * @return the automation activity filter + */ + public AutomationActivityFilter nextStep(String nextStep) + { + this.nextStep = nextStep; + return this; + } + + /** + * Current step. + * + * @param currentStep the current step id + * @return the automation activity filter + */ + public AutomationActivityFilter currentStep(String currentStep) + { + this.currentStep = currentStep; + return this; + } + + /** + * Step. + * + * @param step the step id + * @return the automation activity filter + */ + public AutomationActivityFilter step(String step) + { + this.step = step; + return this; + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationAddSubscribersBody.java b/src/main/java/com/mailerlite/sdk/automations/AutomationAddSubscribersBody.java new file mode 100644 index 0000000..2d13641 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationAddSubscribersBody.java @@ -0,0 +1,30 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationAddSubscribersBody. + */ +public class AutomationAddSubscribersBody { + + /** The step id. */ + @SerializedName("step_id") + public String stepId; + + /** The emails. */ + @SerializedName("emails") + public List emails; + + /** The groups. */ + @SerializedName("groups") + public List groups; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationBuilder.java b/src/main/java/com/mailerlite/sdk/automations/AutomationBuilder.java new file mode 100644 index 0000000..0b94166 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationBuilder.java @@ -0,0 +1,126 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import java.util.ArrayList; +import java.util.Map; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteApi; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.JsonBody; + +/** + * The Class AutomationBuilder. + */ +public class AutomationBuilder { + + /** The api object reference. */ + private MailerLite apiObjectReference; + + /** The builder body. */ + private AutomationBuilderBody builderBody = new AutomationBuilderBody(); + + /** + * Instantiates a new automation builder. + * + * @param apiRef the api ref + */ + public AutomationBuilder(MailerLite apiRef) + { + apiObjectReference = apiRef; + } + + /** + * Clear. + */ + public void clear() + { + builderBody = new AutomationBuilderBody(); + } + + /** + * Name. + * + * @param name the name + * @return the automation builder + */ + public AutomationBuilder name(String name) + { + builderBody.name = name; + return this; + } + + /** + * Trigger data. Only sent on update, create() rejects it. + * + * @param triggerData the trigger data, for example "repeatable" + * @return the automation builder + */ + public AutomationBuilder triggerData(Map triggerData) + { + builderBody.triggerData = triggerData; + return this; + } + + /** + * Adds a trigger. Only sent on update, create() rejects it. + * + * @param trigger the trigger, with "type" and "data" + * @return the automation builder + */ + public AutomationBuilder addTrigger(Map trigger) + { + if (builderBody.triggers == null) { + builderBody.triggers = new ArrayList>(); + } + + builderBody.triggers.add(trigger); + return this; + } + + /** + * Creates a draft automation with the given name. The create endpoint accepts only the name, + * so add triggers with update() or the triggers endpoints. + * + * @return the single automation + * @throws MailerLiteException the mailer lite exception + * @throws IllegalStateException if triggerData or a trigger was set + */ + public SingleAutomation create() throws MailerLiteException + { + if (builderBody.triggerData != null || builderBody.triggers != null) { + throw new IllegalStateException("POST /automations accepts only name. Set triggerData and triggers with update()."); + } + + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + return api.postRequest("/automations", JsonBody.toJson(builderBody), SingleAutomation.class, new SingleAutomationDeserializer()); + } + + /** + * Updates an automation. The API requires the name on every update. + * + * @param automationId the automation id + * @return the single automation + * @throws MailerLiteException the mailer lite exception + * @throws IllegalStateException if name was not set + */ + public SingleAutomation update(String automationId) throws MailerLiteException + { + if (builderBody.name == null || builderBody.name.isEmpty()) { + throw new IllegalStateException("PUT /automations/{automation} requires name."); + } + + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + return api.putRequest("/automations/".concat(automationId), JsonBody.toJson(builderBody), SingleAutomation.class, new SingleAutomationDeserializer()); + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationBuilderBody.java b/src/main/java/com/mailerlite/sdk/automations/AutomationBuilderBody.java new file mode 100644 index 0000000..4446c6a --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationBuilderBody.java @@ -0,0 +1,31 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import java.util.ArrayList; +import java.util.Map; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationBuilderBody. + */ +public class AutomationBuilderBody { + + /** The name. */ + @SerializedName("name") + public String name; + + /** The trigger data. */ + @SerializedName("trigger_data") + public Map triggerData; + + /** The triggers. */ + @SerializedName("triggers") + public ArrayList> triggers; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationDeserializer.java b/src/main/java/com/mailerlite/sdk/automations/AutomationDeserializer.java index ee5b73e..0adf59b 100644 --- a/src/main/java/com/mailerlite/sdk/automations/AutomationDeserializer.java +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationDeserializer.java @@ -20,22 +20,21 @@ import com.google.gson.JsonParseException; import com.mailerlite.sdk.automations.steps.AutomationStep; import com.mailerlite.sdk.automations.triggers.AutomationTrigger; -import com.mailerlite.sdk.automations.triggers.TriggerAbandonedCart; -import com.mailerlite.sdk.automations.triggers.TriggerClicksLink; -import com.mailerlite.sdk.automations.triggers.TriggerDate; -import com.mailerlite.sdk.automations.triggers.TriggerFieldUpdated; -import com.mailerlite.sdk.automations.triggers.TriggerFormCompleted; -import com.mailerlite.sdk.automations.triggers.TriggerPurchasedAnyProduct; -import com.mailerlite.sdk.automations.triggers.TriggerPurchasedFromCategory; -import com.mailerlite.sdk.automations.triggers.TriggerPurchasedSpecificProduct; -import com.mailerlite.sdk.automations.triggers.TriggerSubscriberJoinsGroup; import com.mailerlite.sdk.util.JsonSerializationDeserializationStrategy; +import com.mailerlite.sdk.util.SdkGson; /** * The Class AutomationDeserializer. */ public class AutomationDeserializer implements JsonDeserializer { + /** The gson instance that parses automations with this deserializer. */ + private static final Gson AUTOMATION_GSON = new GsonBuilder() + .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) + .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) + .registerTypeAdapter(Automation.class, new AutomationDeserializer()) + .create(); + /** * Deserialize. * @@ -51,12 +50,7 @@ public Automation deserialize(JsonElement json, Type typeOfT, JsonDeserializatio JsonObject jsonObject = json.getAsJsonObject(); - JsonArray automationSteps = jsonObject.get("steps").getAsJsonArray(); - - Gson gson = new GsonBuilder() - .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) - .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) - .create(); + Gson gson = SdkGson.plain(); Automation automation = gson.fromJson(json, Automation.class); @@ -66,7 +60,7 @@ public Automation deserialize(JsonElement json, Type typeOfT, JsonDeserializatio AutomationStepDeserializer stepDeserializer = new AutomationStepDeserializer(); - for (JsonElement jsonStep : automationSteps) { + for (JsonElement jsonStep : jsonArrayOrEmpty(jsonObject, "steps")) { JsonObject stepObj = jsonStep.getAsJsonObject(); @@ -76,58 +70,15 @@ public Automation deserialize(JsonElement json, Type typeOfT, JsonDeserializatio automation.steps = steps.toArray(); - JsonArray automationTriggers = jsonObject.get("triggers").getAsJsonArray(); - ArrayList triggers = new ArrayList(); - for (JsonElement jsonTrigger : automationTriggers) { + AutomationTriggerDeserializer triggerDeserializer = new AutomationTriggerDeserializer(); + + for (JsonElement jsonTrigger : jsonArrayOrEmpty(jsonObject, "triggers")) { JsonObject triggerObj = jsonTrigger.getAsJsonObject(); - String type = triggerObj.get("type").getAsString(); - - switch (type) { - - case "subscriber_joins_group": - triggers.add(gson.fromJson(jsonObject, TriggerSubscriberJoinsGroup.class)); - break; - - case "clicks_link": - triggers.add(gson.fromJson(jsonObject, TriggerClicksLink.class)); - break; - - case "field_updated": - triggers.add(gson.fromJson(jsonObject, TriggerFieldUpdated.class)); - break; - - case "anniversary": - triggers.add(gson.fromJson(jsonObject, TriggerDate.class)); - break; - - case "exact_date": - triggers.add(gson.fromJson(jsonObject, TriggerDate.class)); - break; - - case "form_completed": - triggers.add(gson.fromJson(jsonObject, TriggerFormCompleted.class)); - break; - - case "purchased_any_product": - triggers.add(gson.fromJson(jsonObject, TriggerPurchasedAnyProduct.class)); - break; - - case "purchased_specific_product": - triggers.add(gson.fromJson(jsonObject, TriggerPurchasedSpecificProduct.class)); - break; - - case "purchased_from_category": - triggers.add(gson.fromJson(jsonObject, TriggerPurchasedFromCategory.class)); - break; - - case "abandoned_cart": - triggers.add(gson.fromJson(jsonObject, TriggerAbandonedCart.class)); - break; - } + triggers.add(triggerDeserializer.deserializeTrigger(triggerObj)); } automation.triggers = triggers.toArray(); @@ -135,5 +86,26 @@ public Automation deserialize(JsonElement json, Type typeOfT, JsonDeserializatio return automation; } + /** + * Gson that parses automations with this deserializer. + * + * @return the gson instance + */ + public static Gson automationGson() + { + return AUTOMATION_GSON; + } + + private JsonArray jsonArrayOrEmpty(JsonObject jsonObject, String memberName) + { + JsonElement element = jsonObject.get(memberName); + + if (element == null || !element.isJsonArray()) { + return new JsonArray(); + } + + return element.getAsJsonArray(); + } + } diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationEndpoint.java b/src/main/java/com/mailerlite/sdk/automations/AutomationEndpoint.java new file mode 100644 index 0000000..c4203b6 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationEndpoint.java @@ -0,0 +1,59 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteApi; + +/** + * Builds the API client and the endpoints under one automation. + */ +public class AutomationEndpoint { + + /** The api object reference. */ + private MailerLite apiObjectReference; + + /** The automation id. */ + private String automationId; + + /** + * Instantiates a new automation endpoint. + * + * @param apiRef the api ref + * @param forAutomationId the automation id + */ + public AutomationEndpoint(MailerLite apiRef, String forAutomationId) + { + apiObjectReference = apiRef; + automationId = forAutomationId; + } + + /** + * Creates an API client with the token set. + * + * @return the mailer lite api + */ + public MailerLiteApi api() + { + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + return api; + } + + /** + * Path under the automation, for example path("/steps") gives /automations/{id}/steps. + * + * @param suffix the suffix + * @return the path + */ + public String path(String suffix) + { + return "/automations/".concat(automationId).concat(suffix); + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationReaddBody.java b/src/main/java/com/mailerlite/sdk/automations/AutomationReaddBody.java new file mode 100644 index 0000000..bd0d069 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationReaddBody.java @@ -0,0 +1,28 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationReaddBody. + */ +public class AutomationReaddBody { + + /** The readd subscribers to. */ + @SerializedName("readd_subscribers_to") + public String readdSubscribersTo; + + /** The selected step id. */ + @SerializedName("selected_step_id") + public String selectedStepId; + + /** The filter. */ + @SerializedName("filter") + public AutomationActivityFilter filter; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationRetriever.java b/src/main/java/com/mailerlite/sdk/automations/AutomationRetriever.java index 278b8bf..8845563 100644 --- a/src/main/java/com/mailerlite/sdk/automations/AutomationRetriever.java +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationRetriever.java @@ -11,7 +11,6 @@ import java.util.List; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -20,7 +19,6 @@ import com.mailerlite.sdk.MailerLiteApi; import com.mailerlite.sdk.MailerLiteStringResponse; import com.mailerlite.sdk.exceptions.MailerLiteException; -import com.mailerlite.sdk.util.JsonSerializationDeserializationStrategy; import com.mailerlite.sdk.util.PaginatedRequest; /** @@ -80,11 +78,7 @@ public List get() throws MailerLiteException ArrayList automations = new ArrayList(); - Gson gson = new GsonBuilder() - .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) - .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) - .registerTypeAdapter(Automation.class, new AutomationDeserializer()) - .create(); + Gson gson = AutomationDeserializer.automationGson(); for(JsonElement obj : data) { @@ -120,16 +114,51 @@ public Automation getSingle(String id) throws MailerLiteException JsonObject data = jsonObject.get("data").getAsJsonObject(); - Gson gson = new GsonBuilder() - .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) - .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) - .registerTypeAdapter(Automation.class, new AutomationDeserializer()) - .create(); + Gson gson = AutomationDeserializer.automationGson(); return gson.fromJson(data, Automation.class); } + /** + * Sets the page to return. + * + * @param page the page + * @return the automation retriever + */ + public AutomationRetriever page(int page) + { + this.addQueryParameter("page", Integer.toString(page)); + + return this; + } + + /** + * Sets the sort order. + * + * @param sort the sort + * @return the automation retriever + */ + public AutomationRetriever sort(String sort) + { + this.addQueryParameter("sort", sort); + + return this; + } + + /** + * Includes the automation steps. The API includes them by default. + * + * @param withSteps the with steps + * @return the automation retriever + */ + public AutomationRetriever withSteps(boolean withSteps) + { + this.addQueryParameter("with_steps", withSteps ? "1" : "0"); + + return this; + } + /** * Gets the single instance of AutomationRetriever. * diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationStats.java b/src/main/java/com/mailerlite/sdk/automations/AutomationStats.java index cbc5878..852a5a9 100644 --- a/src/main/java/com/mailerlite/sdk/automations/AutomationStats.java +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationStats.java @@ -15,9 +15,11 @@ public class AutomationStats { /** The completed subscribers count. */ + @SerializedName("completed_subscribers_count") public int completedSubscribersCount; /** The subscribers in queue count. */ + @SerializedName("subscribers_in_queue_count") public int subscribersInQueueCount; /** The bounce rate. */ diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationStepDeserializer.java b/src/main/java/com/mailerlite/sdk/automations/AutomationStepDeserializer.java index 050dbe6..5e9bdb1 100644 --- a/src/main/java/com/mailerlite/sdk/automations/AutomationStepDeserializer.java +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationStepDeserializer.java @@ -7,17 +7,21 @@ **************************************************/ package com.mailerlite.sdk.automations; +import java.lang.reflect.Type; import java.util.ArrayList; import com.google.gson.Gson; import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import com.mailerlite.sdk.automations.steps.AbStep; import com.mailerlite.sdk.automations.steps.AutomationStep; import com.mailerlite.sdk.automations.steps.DelayStep; import com.mailerlite.sdk.automations.steps.EmailStep; -import com.mailerlite.sdk.automations.steps.action.ActionStep; +import com.mailerlite.sdk.automations.steps.GenericAutomationStep; import com.mailerlite.sdk.automations.steps.action.CopyToGroupAction; import com.mailerlite.sdk.automations.steps.action.GoToStepAction; import com.mailerlite.sdk.automations.steps.action.MarkUnsubscribedAction; @@ -31,12 +35,28 @@ import com.mailerlite.sdk.automations.steps.condition.GroupMembershipCondition; import com.mailerlite.sdk.automations.steps.condition.SegmentMembershipCondition; import com.mailerlite.sdk.automations.steps.condition.WorkflowActivityCondition; +import com.mailerlite.sdk.util.SdkGson; /** * The Class AutomationStepDeserializer. */ -public class AutomationStepDeserializer { +public class AutomationStepDeserializer implements JsonDeserializer { + /** + * Deserializes any automation step into its typed class, or GenericAutomationStep for unknown types. + * + * @param json the json + * @param typeOfT the type of T + * @param context the context + * @return the automation step + * @throws JsonParseException the json parse exception + */ + @Override + public AutomationStep deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException + { + return deserializeAutomationStep(json.getAsJsonObject(), SdkGson.plain()); + } + /** * Deserialize automation step. * @@ -50,33 +70,33 @@ public AutomationStep deserializeAutomationStep(JsonObject stepObj, Gson gson) switch (type) { - case "email": + case GenericAutomationStep.TYPE_EMAIL: EmailStep emailStep = gson.fromJson(stepObj, EmailStep.class); emailStep.parseDates(); return emailStep; - case "delay": + case GenericAutomationStep.TYPE_DELAY: DelayStep delayStep = gson.fromJson(stepObj, DelayStep.class); delayStep.parseDates(); return delayStep; - case "abtest": + case GenericAutomationStep.TYPE_AB_TEST: AbStep abStep = gson.fromJson(stepObj, AbStep.class); abStep.parseDates(); return abStep; - case "action": - ActionStep actionStep = deserializeActionStep(stepObj, gson); + case GenericAutomationStep.TYPE_ACTION: + AutomationStep actionStep = deserializeActionStep(stepObj, gson); actionStep.parseDates(); return actionStep; - case "condition": + case GenericAutomationStep.TYPE_CONDITION: ConditionStep conditionStep = deserializeConditionStep(stepObj, gson); conditionStep.parseDates(); return conditionStep; } - return null; + return gson.fromJson(stepObj, GenericAutomationStep.class); } @@ -87,42 +107,42 @@ public AutomationStep deserializeAutomationStep(JsonObject stepObj, Gson gson) * @param gson the gson * @return the action step */ - private ActionStep deserializeActionStep(JsonObject stepObj, Gson gson) + private AutomationStep deserializeActionStep(JsonObject stepObj, Gson gson) { - if (stepObj == null || stepObj.get("action_type") == null) { - return null; + if (stepObj.get("action_type") == null || stepObj.get("action_type").isJsonNull()) { + return gson.fromJson(stepObj, GenericAutomationStep.class); } String actionType = stepObj.get("action_type").getAsString(); switch (actionType) { - case "update_custom_field": + case GenericAutomationStep.ACTION_TYPE_UPDATE_CUSTOM_FIELD: return gson.fromJson(stepObj, UpdateCustomFieldAction.class); - case "mark_as_unsubscribed": + case GenericAutomationStep.ACTION_TYPE_MARK_AS_UNSUBSCRIBED: return gson.fromJson(stepObj, MarkUnsubscribedAction.class); - case "remove_from_group": + case GenericAutomationStep.ACTION_TYPE_REMOVE_FROM_GROUP: return gson.fromJson(stepObj, RemoveFromGroupAction.class); - case "go_to_step": + case GenericAutomationStep.ACTION_TYPE_GO_TO_STEP: return gson.fromJson(stepObj, GoToStepAction.class); - case "copy_to_group": + case GenericAutomationStep.ACTION_TYPE_COPY_TO_GROUP: return gson.fromJson(stepObj, CopyToGroupAction.class); - case "move_to_group": + case GenericAutomationStep.ACTION_TYPE_MOVE_TO_GROUP: return gson.fromJson(stepObj, MoveToGroupAction.class); } - return null; + return gson.fromJson(stepObj, GenericAutomationStep.class); } /** @@ -137,7 +157,7 @@ private ConditionStep deserializeConditionStep(JsonObject stepObj, Gson gson) ConditionStep step = gson.fromJson(stepObj, ConditionStep.class); - JsonArray conditions = stepObj.get("conditions").getAsJsonArray(); + JsonArray conditions = stepObj.has("conditions") && stepObj.get("conditions").isJsonArray() ? stepObj.getAsJsonArray("conditions") : new JsonArray(); ArrayList conditionItems = new ArrayList(); @@ -169,6 +189,10 @@ private ConditionStep deserializeConditionStep(JsonObject stepObj, Gson gson) case "group_membership": conditionItems.add(gson.fromJson(conditionObj, GroupMembershipCondition.class)); break; + + default: + conditionItems.add(gson.fromJson(conditionObj, ConditionBase.class)); + break; } } diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationTestBody.java b/src/main/java/com/mailerlite/sdk/automations/AutomationTestBody.java new file mode 100644 index 0000000..189368c --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationTestBody.java @@ -0,0 +1,20 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationTestBody. + */ +public class AutomationTestBody { + + /** The email. */ + @SerializedName("email") + public String email; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationTriggerDeserializer.java b/src/main/java/com/mailerlite/sdk/automations/AutomationTriggerDeserializer.java new file mode 100644 index 0000000..8dd0326 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationTriggerDeserializer.java @@ -0,0 +1,96 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import java.lang.reflect.Type; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.mailerlite.sdk.automations.triggers.AutomationTrigger; +import com.mailerlite.sdk.automations.triggers.GenericAutomationTrigger; +import com.mailerlite.sdk.automations.triggers.TriggerAbandonedCart; +import com.mailerlite.sdk.automations.triggers.TriggerClicksLink; +import com.mailerlite.sdk.automations.triggers.TriggerDate; +import com.mailerlite.sdk.automations.triggers.TriggerFieldUpdated; +import com.mailerlite.sdk.automations.triggers.TriggerFormCompleted; +import com.mailerlite.sdk.automations.triggers.TriggerPurchasedAnyProduct; +import com.mailerlite.sdk.automations.triggers.TriggerPurchasedFromCategory; +import com.mailerlite.sdk.automations.triggers.TriggerPurchasedSpecificProduct; +import com.mailerlite.sdk.automations.triggers.TriggerSubscriberJoinsGroup; +import com.mailerlite.sdk.util.SdkGson; + +/** + * Deserializes any automation trigger into its typed class, or GenericAutomationTrigger for unknown types. + */ +public class AutomationTriggerDeserializer implements JsonDeserializer { + + /** + * Deserialize. + * + * @param json the json + * @param typeOfT the type of T + * @param context the context + * @return the automation trigger + * @throws JsonParseException the json parse exception + */ + @Override + public AutomationTrigger deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException + { + return deserializeTrigger(json.getAsJsonObject()); + } + + /** + * Deserializes a trigger object. + * + * @param triggerObj the trigger object + * @return the automation trigger + */ + public AutomationTrigger deserializeTrigger(JsonObject triggerObj) + { + Gson gson = SdkGson.plain(); + JsonElement type = triggerObj.get("type"); + + switch (type == null || type.isJsonNull() ? "" : type.getAsString()) { + + case GenericAutomationTrigger.TYPE_SUBSCRIBER_JOINS_GROUP: + return gson.fromJson(triggerObj, TriggerSubscriberJoinsGroup.class); + + case GenericAutomationTrigger.TYPE_CLICKS_LINK: + return gson.fromJson(triggerObj, TriggerClicksLink.class); + + case GenericAutomationTrigger.TYPE_FIELD_UPDATED: + return gson.fromJson(triggerObj, TriggerFieldUpdated.class); + + case GenericAutomationTrigger.TYPE_ANNIVERSARY: + case GenericAutomationTrigger.TYPE_EXACT_DATE: + return gson.fromJson(triggerObj, TriggerDate.class); + + case GenericAutomationTrigger.TYPE_FORM_COMPLETED: + return gson.fromJson(triggerObj, TriggerFormCompleted.class); + + case GenericAutomationTrigger.TYPE_PURCHASED_ANY_PRODUCT: + return gson.fromJson(triggerObj, TriggerPurchasedAnyProduct.class); + + case GenericAutomationTrigger.TYPE_PURCHASED_SPECIFIC_PRODUCT: + return gson.fromJson(triggerObj, TriggerPurchasedSpecificProduct.class); + + case GenericAutomationTrigger.TYPE_PURCHASED_FROM_CATEGORY: + return gson.fromJson(triggerObj, TriggerPurchasedFromCategory.class); + + case GenericAutomationTrigger.TYPE_ABANDONED_CART: + return gson.fromJson(triggerObj, TriggerAbandonedCart.class); + + default: + return gson.fromJson(triggerObj, GenericAutomationTrigger.class); + } + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/Automations.java b/src/main/java/com/mailerlite/sdk/automations/Automations.java index 5d09a5c..c2430cb 100644 --- a/src/main/java/com/mailerlite/sdk/automations/Automations.java +++ b/src/main/java/com/mailerlite/sdk/automations/Automations.java @@ -7,8 +7,19 @@ **************************************************/ package com.mailerlite.sdk.automations; +import java.util.List; + import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteApi; +import com.mailerlite.sdk.MailerLiteResponse; import com.mailerlite.sdk.automations.activity.AutomationSubscriberActivityRetriever; +import com.mailerlite.sdk.automations.reports.AutomationEmails; +import com.mailerlite.sdk.automations.reports.AutomationReports; +import com.mailerlite.sdk.automations.steps.AutomationSteps; +import com.mailerlite.sdk.automations.templates.AutomationTemplateRetriever; +import com.mailerlite.sdk.automations.triggers.AutomationTriggers; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.JsonBody; /** * The Class Automations. @@ -47,4 +58,252 @@ public AutomationSubscriberActivityRetriever subscriberActivityRetriever() { return new AutomationSubscriberActivityRetriever(apiObjectReference); } + + /** + * Builder. + * + * @return the automation builder + */ + public AutomationBuilder builder() + { + return new AutomationBuilder(apiObjectReference); + } + + /** + * Triggers of an automation. + * + * @param automationId the automation id + * @return the automation triggers + */ + public AutomationTriggers triggers(String automationId) + { + return new AutomationTriggers(apiObjectReference, automationId); + } + + /** + * Steps of an automation. + * + * @param automationId the automation id + * @return the automation steps + */ + public AutomationSteps steps(String automationId) + { + return new AutomationSteps(apiObjectReference, automationId); + } + + /** + * Emails of an automation. + * + * @param automationId the automation id + * @return the automation emails + */ + public AutomationEmails emails(String automationId) + { + return new AutomationEmails(apiObjectReference, automationId); + } + + /** + * Reports of an automation. + * + * @param automationId the automation id + * @return the automation reports + */ + public AutomationReports reports(String automationId) + { + return new AutomationReports(apiObjectReference, automationId); + } + + /** + * Automation templates. + * + * @return the automation template retriever + */ + public AutomationTemplateRetriever templates() + { + return new AutomationTemplateRetriever(apiObjectReference); + } + + /** + * Creates an automation from a template. + * + * @param templateId the automation template id + * @return the single automation + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomation selectTemplate(String templateId) throws MailerLiteException + { + return postForAutomation("/automations/select-template/".concat(templateId)); + } + + /** + * Delete. + * + * @param automationId the automation id + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse delete(String automationId) throws MailerLiteException + { + return api().deleteRequest("/automations/".concat(automationId), MailerLiteResponse.class); + } + + /** + * Copies an automation. + * + * @param automationId the automation id + * @return the copied automation + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomation copy(String automationId) throws MailerLiteException + { + return postForAutomation("/automations/".concat(automationId).concat("/copy")); + } + + /** + * Enables an automation. + * + * @param automationId the automation id + * @return the single automation + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomation enable(String automationId) throws MailerLiteException + { + return postForAutomation("/automations/".concat(automationId).concat("/enable")); + } + + /** + * Disables an automation. + * + * @param automationId the automation id + * @return the single automation + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomation disable(String automationId) throws MailerLiteException + { + return postForAutomation("/automations/".concat(automationId).concat("/disable")); + } + + /** + * Sends a test of the automation emails to an address. + * + * @param automationId the automation id + * @param email the email address + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse test(String automationId, String email) throws MailerLiteException + { + AutomationTestBody body = new AutomationTestBody(); + body.email = email; + + return postForResponse("/automations/".concat(automationId).concat("/test"), body); + } + + /** + * Adds subscribers to an automation. + * + * @param automationId the automation id + * @param emails the subscriber emails, can be null + * @param groupIds the ids of groups whose subscribers to add, can be null + * @param stepId the step to start them at, null for the first step + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse addSubscribers(String automationId, List emails, List groupIds, String stepId) throws MailerLiteException + { + AutomationAddSubscribersBody body = new AutomationAddSubscribersBody(); + body.emails = emails; + body.groups = groupIds; + body.stepId = stepId; + + return postForResponse("/automations/".concat(automationId).concat("/add-subscribers"), body); + } + + /** + * Adds subscribers who completed, were canceled or failed back to the automation. + * + * @param automationId the automation id + * @param readdSubscribersTo where to add them back: "last_completed_step", "selected_step" or "last_failed_step" + * @param selectedStepId the step id, used with "selected_step" + * @param filter the filter selecting the subscribers + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse readd(String automationId, String readdSubscribersTo, String selectedStepId, AutomationActivityFilter filter) throws MailerLiteException + { + AutomationReaddBody body = new AutomationReaddBody(); + body.readdSubscribersTo = readdSubscribersTo; + body.selectedStepId = selectedStepId; + body.filter = filter; + + return postForResponse("/automations/".concat(automationId).concat("/readd"), body); + } + + /** + * Adds the subscribers of the filtered automation activity to groups. + * + * @param automationId the automation id + * @param destinationGroupIds the group ids + * @param filter the filter selecting the activity + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse addActivityToGroups(String automationId, List destinationGroupIds, AutomationActivityFilter filter) throws MailerLiteException + { + AutomationActivityActionBody body = new AutomationActivityActionBody(); + body.destinationGroups = destinationGroupIds; + body.filter = filter; + + return postForResponse("/automations/".concat(automationId).concat("/activity/add-to-group"), body); + } + + /** + * Cancels the filtered active automation runs. + * + * @param automationId the automation id + * @param filter the filter selecting the activity + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse cancelActivity(String automationId, AutomationActivityFilter filter) throws MailerLiteException + { + AutomationActivityActionBody body = new AutomationActivityActionBody(); + body.filter = filter; + + return postForResponse("/automations/".concat(automationId).concat("/activity/cancel-automation"), body); + } + + /** + * Skips the current delay of the filtered active automation runs. + * + * @param automationId the automation id + * @param filter the filter selecting the activity + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse skipActivityDelay(String automationId, AutomationActivityFilter filter) throws MailerLiteException + { + AutomationActivityActionBody body = new AutomationActivityActionBody(); + body.filter = filter; + + return postForResponse("/automations/".concat(automationId).concat("/activity/skip-delay"), body); + } + + private SingleAutomation postForAutomation(String endpoint) throws MailerLiteException + { + return api().postRequest(endpoint, "", SingleAutomation.class, new SingleAutomationDeserializer()); + } + + private MailerLiteResponse postForResponse(String endpoint, Object body) throws MailerLiteException + { + return api().postRequest(endpoint, JsonBody.toJson(body), MailerLiteResponse.class); + } + + private MailerLiteApi api() + { + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + return api; + } } diff --git a/src/main/java/com/mailerlite/sdk/automations/SingleAutomation.java b/src/main/java/com/mailerlite/sdk/automations/SingleAutomation.java new file mode 100644 index 0000000..74dac34 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/SingleAutomation.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleAutomation. + */ +public class SingleAutomation extends MailerLiteResponse { + + /** The automation. */ + @SerializedName("data") + public Automation automation; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/SingleAutomationDeserializer.java b/src/main/java/com/mailerlite/sdk/automations/SingleAutomationDeserializer.java new file mode 100644 index 0000000..aaa9fbb --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/SingleAutomationDeserializer.java @@ -0,0 +1,40 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations; + +import java.lang.reflect.Type; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +/** + * Deserializes a single automation response, parsing its steps and triggers by type. + */ +public class SingleAutomationDeserializer implements JsonDeserializer { + + /** + * Deserialize. + * + * @param json the json + * @param typeOfT the type of T + * @param context the context + * @return the single automation + * @throws JsonParseException the json parse exception + */ + @Override + public SingleAutomation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + + Gson gson = AutomationDeserializer.automationGson(); + + return gson.fromJson(json, SingleAutomation.class); + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/activity/ActivitySubscriber.java b/src/main/java/com/mailerlite/sdk/automations/activity/ActivitySubscriber.java new file mode 100644 index 0000000..f149e45 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/activity/ActivitySubscriber.java @@ -0,0 +1,28 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.activity; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class ActivitySubscriber. + */ +public class ActivitySubscriber { + + /** The id. */ + @SerializedName("id") + public String id; + + /** The email. */ + @SerializedName("email") + public String email; + + /** The name. */ + @SerializedName("name") + public String name; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/activity/AutomationSubscriberActivityRetriever.java b/src/main/java/com/mailerlite/sdk/automations/activity/AutomationSubscriberActivityRetriever.java index a145b71..558fc0e 100644 --- a/src/main/java/com/mailerlite/sdk/automations/activity/AutomationSubscriberActivityRetriever.java +++ b/src/main/java/com/mailerlite/sdk/automations/activity/AutomationSubscriberActivityRetriever.java @@ -132,6 +132,51 @@ public List get(String automationId) throws MailerLiteExcept } + /** + * Sets the page to return. + * + * @param page the page + * @return the automation subscriber activity retriever + */ + public AutomationSubscriberActivityRetriever page(int page) + { + this.addQueryParameter("page", Integer.toString(page)); + + return this; + } + + /** + * Sets the sort order. + * + * @param sort the sort + * @return the automation subscriber activity retriever + */ + public AutomationSubscriberActivityRetriever sort(String sort) + { + this.addQueryParameter("sort", sort); + + return this; + } + + /** + * Includes the id, email and name of each subscriber. Without it the API leaves out the subscriber. + * The API checks only whether the param is present, so false removes it. + * + * @param withSubscribers the with subscribers + * @return the automation subscriber activity retriever + */ + public AutomationSubscriberActivityRetriever withSubscribers(boolean withSubscribers) + { + if (withSubscribers) { + this.addQueryParameter("with_subscribers", "1"); + } else { + this.removeQueryParameter("with_subscribers"); + } + + return this; + } + + /** * Gets the single instance of AutomationSubscriberActivityRetriever. * diff --git a/src/main/java/com/mailerlite/sdk/automations/activity/SubscriberActivity.java b/src/main/java/com/mailerlite/sdk/automations/activity/SubscriberActivity.java index e82c88d..4779d13 100644 --- a/src/main/java/com/mailerlite/sdk/automations/activity/SubscriberActivity.java +++ b/src/main/java/com/mailerlite/sdk/automations/activity/SubscriberActivity.java @@ -42,6 +42,10 @@ public class SubscriberActivity { @SerializedName("reason_description") public String reasonDescription; + /** The subscriber. */ + @SerializedName("subscriber") + public ActivitySubscriber subscriber; + /** The step runs. */ @SerializedName("stepRuns") public StepRun[] stepRuns; diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AbTestSplit.java b/src/main/java/com/mailerlite/sdk/automations/reports/AbTestSplit.java new file mode 100644 index 0000000..3858ad6 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AbTestSplit.java @@ -0,0 +1,28 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AbTestSplit. + */ +public class AbTestSplit { + + /** The label. */ + @SerializedName("label") + public String label; + + /** The path. */ + @SerializedName("path") + public String path; + + /** The value. */ + @SerializedName("value") + public int value; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AbTestStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/AbTestStats.java new file mode 100644 index 0000000..3d18aa4 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AbTestStats.java @@ -0,0 +1,58 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import java.util.HashMap; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AbTestStats. + */ +public class AbTestStats { + + /** The step id. */ + @SerializedName("step_id") + public String stepId; + + /** The name. */ + @SerializedName("name") + public String name; + + /** The ab test winner. */ + @SerializedName("ab_test_winner") + public String abTestWinner; + + /** The parent id. */ + @SerializedName("parent_id") + public String parentId; + + /** The can select winner. */ + @SerializedName("can_select_winner") + public Boolean canSelectWinner; + + /** The a path step id. */ + @SerializedName("a_path_step_id") + public String aPathStepId; + + /** The b path step id. */ + @SerializedName("b_path_step_id") + public String bPathStepId; + + /** The c path step id. */ + @SerializedName("c_path_step_id") + public String cPathStepId; + + /** The split percentages. */ + @SerializedName("split_percentages") + public AbTestSplit[] splitPercentages; + + /** The stats. */ + @SerializedName("stats") + public HashMap stats; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AbTestStatsList.java b/src/main/java/com/mailerlite/sdk/automations/reports/AbTestStatsList.java new file mode 100644 index 0000000..9bf62a9 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AbTestStatsList.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class AbTestStatsList. + */ +public class AbTestStatsList extends MailerLiteResponse { + + /** The ab test stats. */ + @SerializedName("data") + public AbTestStats[] abTestStats; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AbTestVariantStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/AbTestVariantStats.java new file mode 100644 index 0000000..1793759 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AbTestVariantStats.java @@ -0,0 +1,30 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.automations.FloatStringValue; +import com.mailerlite.sdk.automations.steps.AbStepStats; + +/** + * The Class AbTestVariantStats. + */ +public class AbTestVariantStats extends AbStepStats { + + /** The open rate. */ + @SerializedName("open_rate") + public FloatStringValue openRate; + + /** The click rate. */ + @SerializedName("click_rate") + public FloatStringValue clickRate; + + /** The click to open rate. */ + @SerializedName("click_to_open_rate") + public FloatStringValue clickToOpenRate; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEcommerceStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEcommerceStats.java new file mode 100644 index 0000000..5b8aed9 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEcommerceStats.java @@ -0,0 +1,25 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationEcommerceStats. + */ +public class AutomationEcommerceStats { + + /** The ecommerce. */ + @SerializedName("ecommerce") + public EcommerceStats ecommerce; + + /** The best performing email. */ + @SerializedName("best_performing_email") + public JsonElement bestPerformingEmail; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmailContent.java b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmailContent.java new file mode 100644 index 0000000..42b3cfe --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmailContent.java @@ -0,0 +1,20 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationEmailContent. + */ +public class AutomationEmailContent { + + /** The html. */ + @SerializedName("html") + public String html; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmailStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmailStats.java new file mode 100644 index 0000000..fec3070 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmailStats.java @@ -0,0 +1,24 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationEmailStats. + */ +public class AutomationEmailStats { + + /** The engagement. */ + @SerializedName("engagement") + public EmailEngagementStats engagement; + + /** The deliverability. */ + @SerializedName("deliverability") + public EmailDeliverabilityStats deliverability; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmails.java b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmails.java new file mode 100644 index 0000000..3b3bfba --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationEmails.java @@ -0,0 +1,116 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.JsonObject; +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.automations.AutomationEndpoint; +import com.mailerlite.sdk.emails.SingleEmail; +import com.mailerlite.sdk.exceptions.MailerLiteException; + +/** + * The emails of an automation. The date and shop setters apply to the stats methods only. + */ +public class AutomationEmails extends AutomationStatsRequest { + + /** The automation endpoint. */ + private AutomationEndpoint automation; + + /** + * Instantiates a new automation emails. + * + * @param apiRef the api ref + * @param forAutomationId the automation id + */ + public AutomationEmails(MailerLite apiRef, String forAutomationId) + { + automation = new AutomationEndpoint(apiRef, forAutomationId); + } + + /** + * Gets the HTML content of an email. + * + * @param emailId the email id + * @return the single automation email content + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationEmailContent getContent(String emailId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/emails/".concat(emailId).concat("/content")), SingleAutomationEmailContent.class); + } + + /** + * Replaces the HTML content of an email. + * + * @param emailId the email id + * @param html the html + * @return the updated email + * @throws MailerLiteException the mailer lite exception + */ + public SingleEmail updateContent(String emailId, String html) throws MailerLiteException + { + JsonObject body = new JsonObject(); + body.addProperty("html", html); + + SingleEmail response = automation.api().putRequest(automation.path("/emails/".concat(emailId).concat("/content")), body.toString(), SingleEmail.class); + + if (response.email != null) { + response.email.parseDates(); + } + + return response; + } + + /** + * Gets the engagement and deliverability stats of an email. + * + * @param emailId the email id + * @return the single automation email stats + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationEmailStats reportStats(String emailId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/emails/".concat(emailId).concat("/report-stats")).concat(this.getQueryParameters()), SingleAutomationEmailStats.class); + } + + /** + * Gets the e-commerce stats of an email. + * + * @param emailId the email id + * @return the single automation ecommerce stats + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationEcommerceStats ecommerceOverviewStats(String emailId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/emails/".concat(emailId).concat("/ecommerce-overview-stats")).concat(this.getQueryParameters()), SingleAutomationEcommerceStats.class); + } + + /** + * Gets the reasons subscribers gave for unsubscribing from an email. + * + * @param emailId the email id + * @return the unsubscribe reason list + * @throws MailerLiteException the mailer lite exception + */ + public UnsubscribeReasonList unsubscribeReasons(String emailId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/emails/".concat(emailId).concat("/unsubscribe-reasons")), UnsubscribeReasonList.class); + } + + + + /** + * Gets the single instance of AutomationEmails. + * + * @return single instance of AutomationEmails + */ + @Override + protected AutomationEmails getInstance() { + return this; + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AutomationOrderActivityRetriever.java b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationOrderActivityRetriever.java new file mode 100644 index 0000000..d282167 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationOrderActivityRetriever.java @@ -0,0 +1,113 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteApi; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.CursorPaginatedRequest; + +/** + * Lists the orders attributed to an automation. + */ +public class AutomationOrderActivityRetriever extends CursorPaginatedRequest { + + /** The api object reference. */ + private MailerLite apiObjectReference; + + /** The endpoint. */ + private String endpoint; + + /** + * Instantiates a new automation order activity retriever. + * + * @param apiRef the api ref + * @param forEndpoint the endpoint + */ + public AutomationOrderActivityRetriever(MailerLite apiRef, String forEndpoint) + { + apiObjectReference = apiRef; + endpoint = forEndpoint; + } + + /** + * Time frame. + * + * @param timeFrame for example "month", "year", "all_time" or "custom" + * @return the automation order activity retriever + */ + public AutomationOrderActivityRetriever timeFrame(String timeFrame) + { + this.addQueryParameter("time_frame", timeFrame); + + return this; + } + + /** + * Start of a custom time frame. + * + * @param timeFrameStart the time frame start + * @return the automation order activity retriever + */ + public AutomationOrderActivityRetriever timeFrameStart(String timeFrameStart) + { + this.addQueryParameter("time_frame_start", timeFrameStart); + + return this; + } + + /** + * End of a custom time frame. + * + * @param timeFrameEnd the time frame end + * @return the automation order activity retriever + */ + public AutomationOrderActivityRetriever timeFrameEnd(String timeFrameEnd) + { + this.addQueryParameter("time_frame_end", timeFrameEnd); + + return this; + } + + /** + * Returns only orders from this shop. + * + * @param ecommerceShopId the e-commerce shop id + * @return the automation order activity retriever + */ + public AutomationOrderActivityRetriever ecommerceShopId(String ecommerceShopId) + { + this.addQueryParameter("ecommerce_shop_id", ecommerceShopId); + + return this; + } + + /** + * Gets the orders. + * + * @return the order activity list + * @throws MailerLiteException the mailer lite exception + */ + public OrderActivityList get() throws MailerLiteException + { + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + return api.getRequest(endpoint.concat(this.getQueryParameters()), OrderActivityList.class); + } + + /** + * Gets the single instance of AutomationOrderActivityRetriever. + * + * @return single instance of AutomationOrderActivityRetriever + */ + @Override + protected AutomationOrderActivityRetriever getInstance() { + return this; + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AutomationReports.java b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationReports.java new file mode 100644 index 0000000..5367a21 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationReports.java @@ -0,0 +1,171 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.automations.AutomationEndpoint; +import com.mailerlite.sdk.exceptions.MailerLiteException; + +/** + * The reports of an automation. The date and shop setters apply to the monthly totals only. + */ +public class AutomationReports extends AutomationStatsRequest { + + /** The api object reference. */ + private MailerLite apiObjectReference; + + /** The automation endpoint. */ + private AutomationEndpoint automation; + + /** + * Instantiates a new automation reports. + * + * @param apiRef the api ref + * @param forAutomationId the automation id + */ + public AutomationReports(MailerLite apiRef, String forAutomationId) + { + apiObjectReference = apiRef; + automation = new AutomationEndpoint(apiRef, forAutomationId); + } + + /** + * Gets the completed and queued run counts of every step. + * + * @return the step run count list + * @throws MailerLiteException the mailer lite exception + */ + public StepRunCountList stepRunCounts() throws MailerLiteException + { + return automation.api().getRequest(automation.path("/steps/run-counts"), StepRunCountList.class); + } + + /** + * Gets the completed and queued run counts of a step. + * + * @param stepId the step id + * @return the single step run count + * @throws MailerLiteException the mailer lite exception + */ + public SingleStepRunCount stepRunCount(String stepId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/steps/run-counts/".concat(stepId)), SingleStepRunCount.class); + } + + /** + * Gets the run counts of every trigger and of manual runs. + * + * @return the single triggers run counts + * @throws MailerLiteException the mailer lite exception + */ + public SingleTriggersRunCounts triggerRunCounts() throws MailerLiteException + { + return automation.api().getRequest(automation.path("/triggers/run-counts"), SingleTriggersRunCounts.class); + } + + /** + * Gets the run counts of a trigger. + * + * @param triggerId the trigger id + * @return the single trigger run count + * @throws MailerLiteException the mailer lite exception + */ + public SingleTriggerRunCount triggerRunCount(String triggerId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/triggers/run-counts/".concat(triggerId)), SingleTriggerRunCount.class); + } + + /** + * Gets the stats of every A/B test step. + * + * @return the A/B test stats list + * @throws MailerLiteException the mailer lite exception + */ + public AbTestStatsList abStepsStats() throws MailerLiteException + { + return automation.api().getRequest(automation.path("/ab-steps-stats"), AbTestStatsList.class); + } + + /** + * Gets the stats of an A/B test step. + * + * @param stepId the A/B test step id + * @return the single A/B test stats + * @throws MailerLiteException the mailer lite exception + */ + public SingleAbTestStats abStepStats(String stepId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/ab-steps-stats/".concat(stepId)), SingleAbTestStats.class); + } + + /** + * Subscribers who reached a step. + * + * @param stepId the step id + * @return the run subscribers retriever + */ + public AutomationRunSubscribersRetriever stepSubscribers(String stepId) + { + return new AutomationRunSubscribersRetriever(apiObjectReference, automation.path("/activity/steps/".concat(stepId).concat("/subscribers"))); + } + + /** + * Subscribers who entered through a trigger. + * + * @param triggerId the trigger id + * @return the run subscribers retriever + */ + public AutomationRunSubscribersRetriever triggerSubscribers(String triggerId) + { + return new AutomationRunSubscribersRetriever(apiObjectReference, automation.path("/activity/triggers/".concat(triggerId).concat("/subscribers"))); + } + + /** + * Orders attributed to the automation. + * + * @return the automation order activity retriever + */ + public AutomationOrderActivityRetriever orderActivity() + { + return new AutomationOrderActivityRetriever(apiObjectReference, automation.path("/order-activity")); + } + + /** + * Gets the email totals of the automation. + * + * @return the single automation email stats + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationEmailStats monthlyEmailTotals() throws MailerLiteException + { + return automation.api().getRequest(automation.path("/monthly-totals/email").concat(this.getQueryParameters()), SingleAutomationEmailStats.class); + } + + /** + * Gets the e-commerce totals of the automation. + * + * @return the single automation ecommerce stats + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationEcommerceStats monthlyEcommerceTotals() throws MailerLiteException + { + return automation.api().getRequest(automation.path("/monthly-totals/ecommerce").concat(this.getQueryParameters()), SingleAutomationEcommerceStats.class); + } + + + + /** + * Gets the single instance of AutomationReports. + * + * @return single instance of AutomationReports + */ + @Override + protected AutomationReports getInstance() { + return this; + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AutomationRunSubscribersRetriever.java b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationRunSubscribersRetriever.java new file mode 100644 index 0000000..13b879f --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationRunSubscribersRetriever.java @@ -0,0 +1,101 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteApi; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.CursorPaginatedRequest; + +/** + * Lists the subscribers who reached a step or entered through a trigger. + */ +public class AutomationRunSubscribersRetriever extends CursorPaginatedRequest { + + /** The api object reference. */ + private MailerLite apiObjectReference; + + /** The endpoint. */ + private String endpoint; + + /** + * Instantiates a new automation run subscribers retriever. + * + * @param apiRef the api ref + * @param forEndpoint the endpoint + */ + public AutomationRunSubscribersRetriever(MailerLite apiRef, String forEndpoint) + { + apiObjectReference = apiRef; + endpoint = forEndpoint; + } + + /** + * Status. + * + * @param status "completed" or "queued" + * @return the automation run subscribers retriever + */ + public AutomationRunSubscribersRetriever status(String status) + { + this.addQueryParameter("status", status); + + return this; + } + + /** + * Sets the sort order. + * + * @param sort the sort + * @return the automation run subscribers retriever + */ + public AutomationRunSubscribersRetriever sort(String sort) + { + this.addQueryParameter("sort", sort); + + return this; + } + + /** + * Adds a filter, for example "search", "date_from", "date_to" or "id". + * + * @param name the name + * @param value the value + * @return the automation run subscribers retriever + */ + public AutomationRunSubscribersRetriever filter(String name, String value) + { + this.addQueryParameter("filter[".concat(name).concat("]"), value); + + return this; + } + + /** + * Gets the subscribers. + * + * @return the run subscriber list + * @throws MailerLiteException the mailer lite exception + */ + public RunSubscriberList get() throws MailerLiteException + { + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + return api.getRequest(endpoint.concat(this.getQueryParameters()), RunSubscriberList.class); + } + + /** + * Gets the single instance of AutomationRunSubscribersRetriever. + * + * @return single instance of AutomationRunSubscribersRetriever + */ + @Override + protected AutomationRunSubscribersRetriever getInstance() { + return this; + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/AutomationStatsRequest.java b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationStatsRequest.java new file mode 100644 index 0000000..b586476 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/AutomationStatsRequest.java @@ -0,0 +1,64 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.mailerlite.sdk.util.ApiRequest; + +/** + * The date range and shop filters shared by the automation stats endpoints. + * + * @param the generic type + */ +public abstract class AutomationStatsRequest> extends ApiRequest { + + /** + * Gets the single instance. + * + * @return the instance + */ + protected abstract T getInstance(); + + /** + * First day to report on. Send together with endDate. + * + * @param startDate the start date, as YYYY-MM-DD + * @return the request + */ + public T startDate(String startDate) + { + this.addQueryParameter("start_date", startDate); + + return getInstance(); + } + + /** + * Last day to report on. Send together with startDate. + * + * @param endDate the end date, as YYYY-MM-DD + * @return the request + */ + public T endDate(String endDate) + { + this.addQueryParameter("end_date", endDate); + + return getInstance(); + } + + /** + * Reports only on orders from this shop. + * + * @param shopId the e-commerce shop id + * @return the request + */ + public T shopId(String shopId) + { + this.addQueryParameter("shop_id", shopId); + + return getInstance(); + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/EcommerceStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/EcommerceStats.java new file mode 100644 index 0000000..fc1e89f --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/EcommerceStats.java @@ -0,0 +1,32 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class EcommerceStats. + */ +public class EcommerceStats { + + /** The orders count. */ + @SerializedName("orders_count") + public int ordersCount; + + /** The revenue. */ + @SerializedName("revenue") + public double revenue; + + /** The average order value. */ + @SerializedName("average_order_value") + public String averageOrderValue; + + /** The conversion rate. */ + @SerializedName("conversion_rate") + public String conversionRate; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/EmailDeliverabilityStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/EmailDeliverabilityStats.java new file mode 100644 index 0000000..c2fece6 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/EmailDeliverabilityStats.java @@ -0,0 +1,61 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.automations.FloatStringValue; + +/** + * The Class EmailDeliverabilityStats. + */ +public class EmailDeliverabilityStats { + + /** The sent. */ + @SerializedName("sent") + public int sent; + + /** The delivered count. */ + @SerializedName("delivered_count") + public int deliveredCount; + + /** The delivered rate. */ + @SerializedName("delivered_rate") + public FloatStringValue deliveredRate; + + /** The hard bounces count. */ + @SerializedName("hard_bounces_count") + public int hardBouncesCount; + + /** The hard bounce rate. */ + @SerializedName("hard_bounce_rate") + public FloatStringValue hardBounceRate; + + /** The soft bounces count. */ + @SerializedName("soft_bounces_count") + public int softBouncesCount; + + /** The soft bounce rate. */ + @SerializedName("soft_bounce_rate") + public FloatStringValue softBounceRate; + + /** The spam count. */ + @SerializedName("spam_count") + public int spamCount; + + /** The spam rate. */ + @SerializedName("spam_rate") + public FloatStringValue spamRate; + + /** The unsubscribes count. */ + @SerializedName("unsubscribes_count") + public int unsubscribesCount; + + /** The unsubscribe rate. */ + @SerializedName("unsubscribe_rate") + public FloatStringValue unsubscribeRate; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/EmailEngagementStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/EmailEngagementStats.java new file mode 100644 index 0000000..db8d562 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/EmailEngagementStats.java @@ -0,0 +1,65 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.automations.FloatStringValue; + +/** + * The Class EmailEngagementStats. + */ +public class EmailEngagementStats { + + /** The sent. */ + @SerializedName("sent") + public int sent; + + /** The opens count. */ + @SerializedName("opens_count") + public int opensCount; + + /** The clicks count. */ + @SerializedName("clicks_count") + public int clicksCount; + + /** The total opens count. */ + @SerializedName("total_opens_count") + public int totalOpensCount; + + /** The total clicks count. */ + @SerializedName("total_clicks_count") + public int totalClicksCount; + + /** The open rate. */ + @SerializedName("open_rate") + public FloatStringValue openRate; + + /** The click rate. */ + @SerializedName("click_rate") + public FloatStringValue clickRate; + + /** The click to open rate. */ + @SerializedName("click_to_open_rate") + public FloatStringValue clickToOpenRate; + + /** The forwards count. */ + @SerializedName("forwards_count") + public int forwardsCount; + + /** The forward rate. */ + @SerializedName("forward_rate") + public FloatStringValue forwardRate; + + /** The social interactions count. */ + @SerializedName("social_interactions_count") + public int socialInteractionsCount; + + /** The social interaction rate. */ + @SerializedName("social_interaction_rate") + public FloatStringValue socialInteractionRate; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/ManualRunCount.java b/src/main/java/com/mailerlite/sdk/automations/reports/ManualRunCount.java new file mode 100644 index 0000000..f80ede6 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/ManualRunCount.java @@ -0,0 +1,24 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class ManualRunCount. + */ +public class ManualRunCount { + + /** The in progress runs. */ + @SerializedName("in_progress_runs") + public int inProgressRuns; + + /** The completed runs. */ + @SerializedName("completed_runs") + public int completedRuns; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/OrderActivity.java b/src/main/java/com/mailerlite/sdk/automations/reports/OrderActivity.java new file mode 100644 index 0000000..16fc2a2 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/OrderActivity.java @@ -0,0 +1,46 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import java.util.Date; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.automations.activity.ActivitySubscriber; +import com.mailerlite.sdk.emails.Email; +import com.mailerlite.sdk.util.ApiResource; +import com.mailerlite.sdk.util.ParseDate; + +/** + * The Class OrderActivity. + */ +public class OrderActivity extends ApiResource { + + /** The subscriber. */ + @SerializedName("subscriber") + public ActivitySubscriber subscriber; + + /** The total. */ + @SerializedName("total") + public double total; + + /** The updated at. */ + @SerializedName("updated_at") + public String updatedAtStr; + + /** The updated at. */ + @ParseDate("updatedAtStr") + public Date updatedAt; + + /** The order. */ + @SerializedName("order") + public String order; + + /** The email. */ + @SerializedName("email") + public Email email; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/OrderActivityList.java b/src/main/java/com/mailerlite/sdk/automations/reports/OrderActivityList.java new file mode 100644 index 0000000..00e753f --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/OrderActivityList.java @@ -0,0 +1,36 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.util.PaginatedResponse; + +/** + * The Class OrderActivityList. + */ +public class OrderActivityList extends PaginatedResponse { + + /** The orders. */ + @SerializedName("data") + public OrderActivity[] orders; + + /** + * Post deserialize. + */ + @Override + public void postDeserialize() + { + if (orders == null) { + return; + } + + for (OrderActivity o : orders) { + o.parseDates(); + } + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/RunSubscriber.java b/src/main/java/com/mailerlite/sdk/automations/reports/RunSubscriber.java new file mode 100644 index 0000000..3a86a3c --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/RunSubscriber.java @@ -0,0 +1,37 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import java.util.Date; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.automations.activity.ActivitySubscriber; +import com.mailerlite.sdk.util.ApiResource; +import com.mailerlite.sdk.util.ParseDate; + +/** + * The Class RunSubscriber. + */ +public class RunSubscriber extends ApiResource { + + /** The id. */ + @SerializedName("id") + public String id; + + /** The subscriber. */ + @SerializedName("subscriber") + public ActivitySubscriber subscriber; + + /** The date str. */ + @SerializedName("date") + public String dateStr; + + /** The run date. */ + @ParseDate("dateStr") + public Date runDate; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/RunSubscriberList.java b/src/main/java/com/mailerlite/sdk/automations/reports/RunSubscriberList.java new file mode 100644 index 0000000..c33367d --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/RunSubscriberList.java @@ -0,0 +1,36 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.util.PaginatedResponse; + +/** + * The Class RunSubscriberList. + */ +public class RunSubscriberList extends PaginatedResponse { + + /** The subscribers. */ + @SerializedName("data") + public RunSubscriber[] subscribers; + + /** + * Post deserialize. + */ + @Override + public void postDeserialize() + { + if (subscribers == null) { + return; + } + + for (RunSubscriber s : subscribers) { + s.parseDates(); + } + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/SingleAbTestStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/SingleAbTestStats.java new file mode 100644 index 0000000..fd5bc6c --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/SingleAbTestStats.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleAbTestStats. + */ +public class SingleAbTestStats extends MailerLiteResponse { + + /** The ab test stats. */ + @SerializedName("data") + public AbTestStats abTestStats; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEcommerceStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEcommerceStats.java new file mode 100644 index 0000000..4927701 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEcommerceStats.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleAutomationEcommerceStats. + */ +public class SingleAutomationEcommerceStats extends MailerLiteResponse { + + /** The stats. */ + @SerializedName("data") + public AutomationEcommerceStats stats; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEmailContent.java b/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEmailContent.java new file mode 100644 index 0000000..7e3924d --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEmailContent.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleAutomationEmailContent. + */ +public class SingleAutomationEmailContent extends MailerLiteResponse { + + /** The content. */ + @SerializedName("data") + public AutomationEmailContent content; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEmailStats.java b/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEmailStats.java new file mode 100644 index 0000000..28ca4bd --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/SingleAutomationEmailStats.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleAutomationEmailStats. + */ +public class SingleAutomationEmailStats extends MailerLiteResponse { + + /** The stats. */ + @SerializedName("data") + public AutomationEmailStats stats; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/SingleStepRunCount.java b/src/main/java/com/mailerlite/sdk/automations/reports/SingleStepRunCount.java new file mode 100644 index 0000000..d6c9f06 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/SingleStepRunCount.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleStepRunCount. + */ +public class SingleStepRunCount extends MailerLiteResponse { + + /** The step run count. */ + @SerializedName("data") + public StepRunCount stepRunCount; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/SingleTriggerRunCount.java b/src/main/java/com/mailerlite/sdk/automations/reports/SingleTriggerRunCount.java new file mode 100644 index 0000000..3279cfe --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/SingleTriggerRunCount.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleTriggerRunCount. + */ +public class SingleTriggerRunCount extends MailerLiteResponse { + + /** The trigger run count. */ + @SerializedName("data") + public TriggerRunCount triggerRunCount; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/SingleTriggersRunCounts.java b/src/main/java/com/mailerlite/sdk/automations/reports/SingleTriggersRunCounts.java new file mode 100644 index 0000000..ded3770 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/SingleTriggersRunCounts.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleTriggersRunCounts. + */ +public class SingleTriggersRunCounts extends MailerLiteResponse { + + /** The triggers run counts. */ + @SerializedName("data") + public TriggersRunCounts triggersRunCounts; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/StepRunCount.java b/src/main/java/com/mailerlite/sdk/automations/reports/StepRunCount.java new file mode 100644 index 0000000..0444eac --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/StepRunCount.java @@ -0,0 +1,28 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class StepRunCount. + */ +public class StepRunCount { + + /** The step id. */ + @SerializedName("step_id") + public String stepId; + + /** The completed step runs. */ + @SerializedName("completed_step_runs") + public int completedStepRuns; + + /** The in queue step runs. */ + @SerializedName("in_queue_step_runs") + public int inQueueStepRuns; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/StepRunCountList.java b/src/main/java/com/mailerlite/sdk/automations/reports/StepRunCountList.java new file mode 100644 index 0000000..0bab12d --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/StepRunCountList.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class StepRunCountList. + */ +public class StepRunCountList extends MailerLiteResponse { + + /** The step run counts. */ + @SerializedName("data") + public StepRunCount[] stepRunCounts; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/TriggerRunCount.java b/src/main/java/com/mailerlite/sdk/automations/reports/TriggerRunCount.java new file mode 100644 index 0000000..81dff0f --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/TriggerRunCount.java @@ -0,0 +1,28 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class TriggerRunCount. + */ +public class TriggerRunCount { + + /** The id. */ + @SerializedName("id") + public String id; + + /** The completed runs. */ + @SerializedName("completed_runs") + public int completedRuns; + + /** The queued runs. */ + @SerializedName("queued_runs") + public int queuedRuns; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/TriggersRunCounts.java b/src/main/java/com/mailerlite/sdk/automations/reports/TriggersRunCounts.java new file mode 100644 index 0000000..0462a44 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/TriggersRunCounts.java @@ -0,0 +1,24 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class TriggersRunCounts. + */ +public class TriggersRunCounts { + + /** The triggers. */ + @SerializedName("triggers") + public TriggerRunCount[] triggers; + + /** The manual runs. */ + @SerializedName("manual_runs") + public ManualRunCount manualRuns; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/UnsubscribeReason.java b/src/main/java/com/mailerlite/sdk/automations/reports/UnsubscribeReason.java new file mode 100644 index 0000000..cc3253a --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/UnsubscribeReason.java @@ -0,0 +1,28 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class UnsubscribeReason. + */ +public class UnsubscribeReason { + + /** The label. */ + @SerializedName("label") + public String label; + + /** The count. */ + @SerializedName("count") + public int count; + + /** The percentage. */ + @SerializedName("percentage") + public String percentage; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/reports/UnsubscribeReasonList.java b/src/main/java/com/mailerlite/sdk/automations/reports/UnsubscribeReasonList.java new file mode 100644 index 0000000..02a47c6 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/reports/UnsubscribeReasonList.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.reports; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class UnsubscribeReasonList. + */ +public class UnsubscribeReasonList extends MailerLiteResponse { + + /** The reasons. */ + @SerializedName("data") + public UnsubscribeReason[] reasons; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/AbStep.java b/src/main/java/com/mailerlite/sdk/automations/steps/AbStep.java index 63a50c4..659331b 100644 --- a/src/main/java/com/mailerlite/sdk/automations/steps/AbStep.java +++ b/src/main/java/com/mailerlite/sdk/automations/steps/AbStep.java @@ -9,7 +9,9 @@ import java.util.HashMap; +import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.util.LenientStringArrayAdapter; /** * The Class AbStep. @@ -42,6 +44,7 @@ public class AbStep extends AutomationStep { /** The split percentages. */ @SerializedName("split_percentages") + @JsonAdapter(LenientStringArrayAdapter.class) public String[] splitPercentages; /** The stats. */ diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/AbTestWinnerBody.java b/src/main/java/com/mailerlite/sdk/automations/steps/AbTestWinnerBody.java new file mode 100644 index 0000000..f9f81fb --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/steps/AbTestWinnerBody.java @@ -0,0 +1,20 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.steps; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AbTestWinnerBody. + */ +public class AbTestWinnerBody { + + /** The ab test winner. */ + @SerializedName("ab_test_winner") + public String abTestWinner; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStep.java b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStep.java index 914fe73..82aba18 100644 --- a/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStep.java +++ b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStep.java @@ -9,13 +9,16 @@ import java.util.Date; +import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.automations.AutomationStepDeserializer; import com.mailerlite.sdk.util.ApiResource; import com.mailerlite.sdk.util.ParseDate; /** * The Class AutomationStep. */ +@JsonAdapter(AutomationStepDeserializer.class) public abstract class AutomationStep extends ApiResource { /** The id. */ @@ -54,4 +57,12 @@ public abstract class AutomationStep extends ApiResource { /** The broken. */ @SerializedName("broken") public Boolean broken; + + /** The description. */ + @SerializedName("description") + public String description; + + /** The type count. */ + @SerializedName("type_count") + public Integer typeCount; } diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepBuilder.java b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepBuilder.java new file mode 100644 index 0000000..6f86c95 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepBuilder.java @@ -0,0 +1,190 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.steps; + +import java.util.HashMap; +import java.util.Map; + +import com.mailerlite.sdk.automations.SingleAutomation; +import com.mailerlite.sdk.automations.SingleAutomationDeserializer; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.JsonBody; +import com.mailerlite.sdk.automations.AutomationEndpoint; + +/** + * Creates, updates or copies an automation step. + */ +public class AutomationStepBuilder { + + /** The automation endpoint. */ + private AutomationEndpoint automation; + + /** The builder body. */ + private AutomationStepBuilderBody builderBody = new AutomationStepBuilderBody(); + + /** + * Instantiates a new automation step builder. + * + * @param forAutomation the automation endpoint + */ + public AutomationStepBuilder(AutomationEndpoint forAutomation) + { + automation = forAutomation; + } + + /** + * Clear. + */ + public void clear() + { + builderBody = new AutomationStepBuilderBody(); + } + + /** + * Type. Only sent on create. + * + * @param type the step type, one of the GenericAutomationStep TYPE_ constants + * @return the automation step builder + */ + public AutomationStepBuilder type(String type) + { + builderBody.type = type; + return this; + } + + /** + * Parent id. + * + * @param parentId the id of the step this step comes after + * @return the automation step builder + */ + public AutomationStepBuilder parentId(String parentId) + { + builderBody.parentId = parentId; + return this; + } + + /** + * Branch of the parent step. Sent on create and copy. + * + * @param branch one of the GenericAutomationStep BRANCH_ constants + * @return the automation step builder + */ + public AutomationStepBuilder branch(String branch) + { + builderBody.branch = branch; + return this; + } + + /** + * Branch that an existing step in the chosen condition branch moves to. Sent on create and copy. + * + * @param moveToBranch "yes" or "no" + * @return the automation step builder + */ + public AutomationStepBuilder moveToBranch(String moveToBranch) + { + builderBody.moveToBranch = moveToBranch; + return this; + } + + /** + * Step configuration. Sent on create and update. + * + * @param data the step configuration + * @return the automation step builder + */ + public AutomationStepBuilder data(Map data) + { + builderBody.data = data; + return this; + } + + /** + * Adds a value to the step configuration. Sent on create and update. + * + * @param key the key, for example "action_type" + * @param value the value + * @return the automation step builder + */ + public AutomationStepBuilder addData(String key, Object value) + { + if (builderBody.data == null) { + builderBody.data = new HashMap(); + } + + builderBody.data.put(key, value); + return this; + } + + /** + * For delay steps, recalculates the wait of subscribers already in the delay. Only sent on update. + * + * @param rescheduleWaitingSubscribers the reschedule waiting subscribers + * @return the automation step builder + */ + public AutomationStepBuilder rescheduleWaitingSubscribers(Boolean rescheduleWaitingSubscribers) + { + builderBody.rescheduleWaitingSubscribers = rescheduleWaitingSubscribers; + return this; + } + + /** + * Creates the step. + * + * @return the single automation step + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationStep create() throws MailerLiteException + { + AutomationStepBuilderBody body = new AutomationStepBuilderBody(); + body.type = builderBody.type; + body.parentId = builderBody.parentId; + body.branch = builderBody.branch; + body.moveToBranch = builderBody.moveToBranch; + body.data = builderBody.data; + + return automation.api().postRequest(automation.path("/steps"), JsonBody.toJson(body), SingleAutomationStep.class); + } + + /** + * Updates a step. + * + * @param stepId the step id + * @return the single automation step + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationStep update(String stepId) throws MailerLiteException + { + AutomationStepBuilderBody body = new AutomationStepBuilderBody(); + body.parentId = builderBody.parentId; + body.data = builderBody.data; + body.rescheduleWaitingSubscribers = builderBody.rescheduleWaitingSubscribers; + + return automation.api().putRequest(automation.path("/steps/".concat(stepId)), JsonBody.toJson(body), SingleAutomationStep.class); + } + + /** + * Copies a step to the place set with parentId, branch and moveToBranch. + * + * @param stepId the id of the step to copy + * @return the updated automation + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomation copy(String stepId) throws MailerLiteException + { + AutomationStepBuilderBody body = new AutomationStepBuilderBody(); + body.parentId = builderBody.parentId; + body.branch = builderBody.branch; + body.moveToBranch = builderBody.moveToBranch; + + return automation.api().postRequest(automation.path("/steps/".concat(stepId)).concat("/copy"), JsonBody.toJson(body), SingleAutomation.class, new SingleAutomationDeserializer()); + } + + +} diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepBuilderBody.java b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepBuilderBody.java new file mode 100644 index 0000000..3c91aab --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepBuilderBody.java @@ -0,0 +1,42 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.steps; + +import java.util.Map; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationStepBuilderBody. + */ +public class AutomationStepBuilderBody { + + /** The type. */ + @SerializedName("type") + public String type; + + /** The parent id. */ + @SerializedName("parent_id") + public String parentId; + + /** The branch. */ + @SerializedName("branch") + public String branch; + + /** The move to branch. */ + @SerializedName("move_to_branch") + public String moveToBranch; + + /** The data. */ + @SerializedName("data") + public Map data; + + /** The reschedule waiting subscribers. */ + @SerializedName("reschedule_waiting_subscribers") + public Boolean rescheduleWaitingSubscribers; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepList.java b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepList.java new file mode 100644 index 0000000..07a609b --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepList.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.steps; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class AutomationStepList. + */ +public class AutomationStepList extends MailerLiteResponse { + + /** The steps. */ + @SerializedName("data") + public AutomationStep[] steps; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepReorderBody.java b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepReorderBody.java new file mode 100644 index 0000000..88bbeb5 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationStepReorderBody.java @@ -0,0 +1,32 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.steps; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationStepReorderBody. + */ +public class AutomationStepReorderBody { + + /** The dragged step id. */ + @SerializedName("dragged_step_id") + public String draggedStepId; + + /** The new parent step id. */ + @SerializedName("new_parent_step_id") + public String newParentStepId; + + /** The branch. */ + @SerializedName("branch") + public String branch; + + /** The branch for child. */ + @SerializedName("branch_for_child") + public String branchForChild; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/AutomationSteps.java b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationSteps.java new file mode 100644 index 0000000..c354fb1 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/steps/AutomationSteps.java @@ -0,0 +1,138 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.steps; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteResponse; +import com.mailerlite.sdk.automations.SingleAutomation; +import com.mailerlite.sdk.automations.SingleAutomationDeserializer; +import com.mailerlite.sdk.automations.reports.SingleAbTestStats; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.ApiRequest; +import com.mailerlite.sdk.util.JsonBody; +import com.mailerlite.sdk.automations.AutomationEndpoint; + +/** + * The steps of an automation. + */ +public class AutomationSteps { + + /** The automation endpoint. */ + private AutomationEndpoint automation; + + /** + * Instantiates a new automation steps. + * + * @param apiRef the api ref + * @param forAutomationId the automation id + */ + public AutomationSteps(MailerLite apiRef, String forAutomationId) + { + automation = new AutomationEndpoint(apiRef, forAutomationId); + } + + /** + * Builder to create, update or copy a step. + * + * @return the automation step builder + */ + public AutomationStepBuilder builder() + { + return new AutomationStepBuilder(automation); + } + + /** + * Gets the steps of the automation. + * + * @return the automation step list + * @throws MailerLiteException the mailer lite exception + */ + public AutomationStepList get() throws MailerLiteException + { + return automation.api().getRequest(automation.path("/steps/index"), AutomationStepList.class); + } + + /** + * Gets a single step. + * + * @param stepId the step id + * @return the single automation step + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationStep getSingle(String stepId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/steps/".concat(stepId)), SingleAutomationStep.class); + } + + /** + * Deletes a step. + * + * @param stepId the step id + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse delete(String stepId) throws MailerLiteException + { + return automation.api().deleteRequest(automation.path("/steps/".concat(stepId)), MailerLiteResponse.class); + } + + /** + * Deletes a condition step and the given branch below it. + * + * @param stepId the step id + * @param branchToDelete "all", "yes" or "no" + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse delete(String stepId, String branchToDelete) throws MailerLiteException + { + ApiRequest query = new ApiRequest(); + query.addQueryParameter("branch_to_delete", branchToDelete); + + return automation.api().deleteRequest(automation.path("/steps/".concat(stepId)).concat(query.getQueryParameters()), MailerLiteResponse.class); + } + + /** + * Moves a step to a new place in the workflow. + * + * @param draggedStepId the id of the step to move + * @param newParentStepId the step to place it after, null for the start of the workflow + * @param branch the branch of the new parent, one of the GenericAutomationStep BRANCH_ constants, can be null + * @param branchForChild the branch of the moved condition that the steps below it go to, "yes" or "no", can be null + * @return the updated automation + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomation reorder(String draggedStepId, String newParentStepId, String branch, String branchForChild) throws MailerLiteException + { + AutomationStepReorderBody body = new AutomationStepReorderBody(); + body.draggedStepId = draggedStepId; + body.newParentStepId = newParentStepId; + body.branch = branch; + body.branchForChild = branchForChild; + + return automation.api().postRequest(automation.path("/steps/reorder"), JsonBody.toJson(body), SingleAutomation.class, new SingleAutomationDeserializer()); + } + + /** + * Selects the winner of an A/B test step. + * + * @param stepId the A/B test step id + * @param abTestWinner the winning path + * @return the A/B test stats + * @throws MailerLiteException the mailer lite exception + */ + public SingleAbTestStats selectAbTestWinner(String stepId, String abTestWinner) throws MailerLiteException + { + AbTestWinnerBody body = new AbTestWinnerBody(); + body.abTestWinner = abTestWinner; + + return automation.api().putRequest(automation.path("/steps/".concat(stepId)).concat("/select-ab-test-winner"), JsonBody.toJson(body), SingleAbTestStats.class); + } + + +} diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/GenericAutomationStep.java b/src/main/java/com/mailerlite/sdk/automations/steps/GenericAutomationStep.java new file mode 100644 index 0000000..154ef11 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/steps/GenericAutomationStep.java @@ -0,0 +1,92 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.steps; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.util.RawDataAdapterFactory; +import com.mailerlite.sdk.util.RawDataHolder; + +/** + * An automation step of any type. The type specific fields are in {@link #data}. + */ +@JsonAdapter(RawDataAdapterFactory.class) +public class GenericAutomationStep extends AutomationStep implements RawDataHolder { + + /** The email step type. */ + public static final String TYPE_EMAIL = "email"; + + /** The condition step type. */ + public static final String TYPE_CONDITION = "condition"; + + /** The delay step type. */ + public static final String TYPE_DELAY = "delay"; + + /** The action step type. */ + public static final String TYPE_ACTION = "action"; + + /** The A/B test step type. */ + public static final String TYPE_AB_TEST = "abtest"; + + /** The webhook step type. */ + public static final String TYPE_WEBHOOK = "webhook"; + + /** The yes branch of a condition. */ + public static final String BRANCH_YES = "yes"; + + /** The no branch of a condition. */ + public static final String BRANCH_NO = "no"; + + /** The A path of an A/B test. */ + public static final String BRANCH_A_PATH = "a_path"; + + /** The B path of an A/B test. */ + public static final String BRANCH_B_PATH = "b_path"; + + /** The C path of an A/B test. */ + public static final String BRANCH_C_PATH = "c_path"; + + /** The update custom field action type. */ + public static final String ACTION_TYPE_UPDATE_CUSTOM_FIELD = "update_custom_field"; + + /** The mark as unsubscribed action type. */ + public static final String ACTION_TYPE_MARK_AS_UNSUBSCRIBED = "mark_as_unsubscribed"; + + /** The remove from group action type. */ + public static final String ACTION_TYPE_REMOVE_FROM_GROUP = "remove_from_group"; + + /** The go to step action type. */ + public static final String ACTION_TYPE_GO_TO_STEP = "go_to_step"; + + /** The copy to group action type. */ + public static final String ACTION_TYPE_COPY_TO_GROUP = "copy_to_group"; + + /** The move to group action type. */ + public static final String ACTION_TYPE_MOVE_TO_GROUP = "move_to_group"; + + /** The send internal email notification action type. */ + public static final String ACTION_TYPE_SEND_INTERNAL_EMAIL_NOTIFICATION = "send_internal_email_notification"; + + /** The action type, set for action steps. */ + @SerializedName("action_type") + public String actionType; + + /** The raw step object, including the type specific fields. */ + public transient JsonObject data; + + /** + * Sets the raw step object. + * + * @param data the raw step object + */ + @Override + public void setData(JsonObject data) { + this.data = data; + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/steps/SingleAutomationStep.java b/src/main/java/com/mailerlite/sdk/automations/steps/SingleAutomationStep.java new file mode 100644 index 0000000..cadb657 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/steps/SingleAutomationStep.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.steps; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleAutomationStep. + */ +public class SingleAutomationStep extends MailerLiteResponse { + + /** The step. */ + @SerializedName("data") + public AutomationStep step; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplate.java b/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplate.java new file mode 100644 index 0000000..f42826a --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplate.java @@ -0,0 +1,49 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.templates; + +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationTemplate. + */ +public class AutomationTemplate { + + /** The id. */ + @SerializedName("id") + public String id; + + /** The name. */ + @SerializedName("name") + public String name; + + /** The type. */ + @SerializedName("type") + public String type; + + /** The workflow. */ + @SerializedName("workflow") + public JsonElement workflow; + + /** The description. */ + @SerializedName("description") + public String description; + + /** The excerpt. */ + @SerializedName("excerpt") + public String excerpt; + + /** The workflow steps description. */ + @SerializedName("workflow_steps_description") + public String[] workflowStepsDescription; + + /** The url. */ + @SerializedName("url") + public String url; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplateList.java b/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplateList.java new file mode 100644 index 0000000..79ff539 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplateList.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.templates; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.util.PaginatedResponse; + +/** + * The Class AutomationTemplateList. + */ +public class AutomationTemplateList extends PaginatedResponse { + + /** The templates. */ + @SerializedName("data") + public AutomationTemplate[] templates; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplateRetriever.java b/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplateRetriever.java new file mode 100644 index 0000000..9d76446 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/templates/AutomationTemplateRetriever.java @@ -0,0 +1,70 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.templates; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteApi; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.CursorPaginatedRequest; + +/** + * The Class AutomationTemplateRetriever. + */ +public class AutomationTemplateRetriever extends CursorPaginatedRequest { + + /** The api object reference. */ + private MailerLite apiObjectReference; + + /** + * Instantiates a new automation template retriever. + * + * @param apiRef the api ref + */ + public AutomationTemplateRetriever(MailerLite apiRef) + { + apiObjectReference = apiRef; + } + + /** + * Adds a filter, for example "type" or "category". + * + * @param name the name + * @param value the value + * @return the automation template retriever + */ + public AutomationTemplateRetriever filter(String name, String value) + { + this.addQueryParameter("filter[".concat(name).concat("]"), value); + + return this; + } + + /** + * Gets the automation templates. + * + * @return the automation template list + * @throws MailerLiteException the mailer lite exception + */ + public AutomationTemplateList get() throws MailerLiteException + { + MailerLiteApi api = new MailerLiteApi(); + api.setToken(apiObjectReference.getToken()); + + return api.getRequest("/automation-templates".concat(this.getQueryParameters()), AutomationTemplateList.class); + } + + /** + * Gets the single instance of AutomationTemplateRetriever. + * + * @return single instance of AutomationTemplateRetriever + */ + @Override + protected AutomationTemplateRetriever getInstance() { + return this; + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTrigger.java b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTrigger.java index 14db00f..a0f4d33 100644 --- a/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTrigger.java +++ b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTrigger.java @@ -7,11 +7,14 @@ **************************************************/ package com.mailerlite.sdk.automations.triggers; +import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.automations.AutomationTriggerDeserializer; /** * The Class AutomationTrigger. */ +@JsonAdapter(AutomationTriggerDeserializer.class) public abstract class AutomationTrigger { /** The id. */ @@ -25,4 +28,8 @@ public abstract class AutomationTrigger { /** The broken. */ @SerializedName("broken") public Boolean broken; + + /** The complete. */ + @SerializedName("complete") + public Boolean complete; } diff --git a/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerBody.java b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerBody.java new file mode 100644 index 0000000..72ee3e2 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerBody.java @@ -0,0 +1,26 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.triggers; + +import java.util.Map; + +import com.google.gson.annotations.SerializedName; + +/** + * The Class AutomationTriggerBody. + */ +public class AutomationTriggerBody { + + /** The type. */ + @SerializedName("type") + public String type; + + /** The data. */ + @SerializedName("data") + public Map data; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerList.java b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerList.java new file mode 100644 index 0000000..5829bea --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerList.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.triggers; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class AutomationTriggerList. + */ +public class AutomationTriggerList extends MailerLiteResponse { + + /** The triggers. */ + @SerializedName("data") + public AutomationTrigger[] triggers; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerUpdate.java b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerUpdate.java new file mode 100644 index 0000000..63c56bf --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggerUpdate.java @@ -0,0 +1,29 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.triggers; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.automations.TriggerData; + +/** + * The Class AutomationTriggerUpdate. + */ +public class AutomationTriggerUpdate { + + /** The trigger. */ + @SerializedName("trigger") + public AutomationTrigger trigger; + + /** The trigger data. */ + @SerializedName("trigger_data") + public TriggerData triggerData; + + /** The qualified subscribers count. Only set for group and segment triggers. */ + @SerializedName("qualified_subscribers_count") + public Integer qualifiedSubscribersCount; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggers.java b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggers.java new file mode 100644 index 0000000..cf26e4f --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/triggers/AutomationTriggers.java @@ -0,0 +1,106 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.triggers; + +import java.util.Map; + +import com.mailerlite.sdk.MailerLite; +import com.mailerlite.sdk.MailerLiteResponse; +import com.mailerlite.sdk.exceptions.MailerLiteException; +import com.mailerlite.sdk.util.JsonBody; +import com.mailerlite.sdk.automations.AutomationEndpoint; + +/** + * The triggers of an automation. + */ +public class AutomationTriggers { + + /** The automation endpoint. */ + private AutomationEndpoint automation; + + /** + * Instantiates a new automation triggers. + * + * @param apiRef the api ref + * @param forAutomationId the automation id + */ + public AutomationTriggers(MailerLite apiRef, String forAutomationId) + { + automation = new AutomationEndpoint(apiRef, forAutomationId); + } + + /** + * Gets the triggers of the automation. + * + * @return the automation trigger list + * @throws MailerLiteException the mailer lite exception + */ + public AutomationTriggerList get() throws MailerLiteException + { + return automation.api().getRequest(automation.path("/triggers"), AutomationTriggerList.class); + } + + /** + * Gets a single trigger. + * + * @param triggerId the trigger id + * @return the single automation trigger + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationTrigger getSingle(String triggerId) throws MailerLiteException + { + return automation.api().getRequest(automation.path("/triggers/".concat(triggerId)), SingleAutomationTrigger.class); + } + + /** + * Creates a trigger. + * + * @param type the trigger type, one of the GenericAutomationTrigger TYPE_ constants + * @param data the trigger configuration, can be null + * @return the single automation trigger + * @throws MailerLiteException the mailer lite exception + */ + public SingleAutomationTrigger create(String type, Map data) throws MailerLiteException + { + AutomationTriggerBody body = new AutomationTriggerBody(); + body.type = type; + body.data = data; + + return automation.api().postRequest(automation.path("/triggers"), JsonBody.toJson(body), SingleAutomationTrigger.class); + } + + /** + * Updates a trigger. + * + * @param triggerId the trigger id + * @param data the trigger configuration + * @return the updated trigger with the automation trigger data + * @throws MailerLiteException the mailer lite exception + */ + public UpdatedAutomationTrigger update(String triggerId, Map data) throws MailerLiteException + { + AutomationTriggerBody body = new AutomationTriggerBody(); + body.data = data; + + return automation.api().putRequest(automation.path("/triggers/".concat(triggerId)), JsonBody.toJson(body), UpdatedAutomationTrigger.class); + } + + /** + * Deletes a trigger. + * + * @param triggerId the trigger id + * @return the mailer lite response + * @throws MailerLiteException the mailer lite exception + */ + public MailerLiteResponse delete(String triggerId) throws MailerLiteException + { + return automation.api().deleteRequest(automation.path("/triggers/".concat(triggerId)), MailerLiteResponse.class); + } + + +} diff --git a/src/main/java/com/mailerlite/sdk/automations/triggers/GenericAutomationTrigger.java b/src/main/java/com/mailerlite/sdk/automations/triggers/GenericAutomationTrigger.java new file mode 100644 index 0000000..3ada964 --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/triggers/GenericAutomationTrigger.java @@ -0,0 +1,75 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.triggers; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.JsonAdapter; +import com.mailerlite.sdk.util.RawDataAdapterFactory; +import com.mailerlite.sdk.util.RawDataHolder; + +/** + * An automation trigger of any type. The type specific fields are in {@link #data}. + */ +@JsonAdapter(RawDataAdapterFactory.class) +public class GenericAutomationTrigger extends AutomationTrigger implements RawDataHolder { + + /** The subscriber joins group trigger type. */ + public static final String TYPE_SUBSCRIBER_JOINS_GROUP = "subscriber_joins_group"; + + /** The subscriber joins segment trigger type. */ + public static final String TYPE_SUBSCRIBER_JOINS_SEGMENT = "subscriber_joins_segment"; + + /** The clicks link trigger type. */ + public static final String TYPE_CLICKS_LINK = "clicks_link"; + + /** The field updated trigger type. */ + public static final String TYPE_FIELD_UPDATED = "field_updated"; + + /** The anniversary trigger type. */ + public static final String TYPE_ANNIVERSARY = "anniversary"; + + /** The exact date trigger type. */ + public static final String TYPE_EXACT_DATE = "exact_date"; + + /** The form completed trigger type. */ + public static final String TYPE_FORM_COMPLETED = "form_completed"; + + /** The manual trigger type. */ + public static final String TYPE_MANUAL = "manual"; + + /** The purchased any product trigger type. */ + public static final String TYPE_PURCHASED_ANY_PRODUCT = "purchased_any_product"; + + /** The purchased specific product trigger type. */ + public static final String TYPE_PURCHASED_SPECIFIC_PRODUCT = "purchased_specific_product"; + + /** The purchased from category trigger type. */ + public static final String TYPE_PURCHASED_FROM_CATEGORY = "purchased_from_category"; + + /** The abandoned cart trigger type. */ + public static final String TYPE_ABANDONED_CART = "abandoned_cart"; + + /** The abandoned checkout trigger type. */ + public static final String TYPE_ABANDONED_CHECKOUT = "abandoned_checkout"; + + /** The purchase frequency trigger type. */ + public static final String TYPE_PURCHASE_FREQUENCY = "purchase_frequency"; + + /** The raw trigger object, including the type specific fields. */ + public transient JsonObject data; + + /** + * Sets the raw trigger object. + * + * @param data the raw trigger object + */ + @Override + public void setData(JsonObject data) { + this.data = data; + } +} diff --git a/src/main/java/com/mailerlite/sdk/automations/triggers/SingleAutomationTrigger.java b/src/main/java/com/mailerlite/sdk/automations/triggers/SingleAutomationTrigger.java new file mode 100644 index 0000000..0a91c3a --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/triggers/SingleAutomationTrigger.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.triggers; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleAutomationTrigger. + */ +public class SingleAutomationTrigger extends MailerLiteResponse { + + /** The trigger. */ + @SerializedName("data") + public AutomationTrigger trigger; +} diff --git a/src/main/java/com/mailerlite/sdk/automations/triggers/UpdatedAutomationTrigger.java b/src/main/java/com/mailerlite/sdk/automations/triggers/UpdatedAutomationTrigger.java new file mode 100644 index 0000000..03ea11d --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/automations/triggers/UpdatedAutomationTrigger.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.automations.triggers; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class UpdatedAutomationTrigger. + */ +public class UpdatedAutomationTrigger extends MailerLiteResponse { + + /** The update. */ + @SerializedName("data") + public AutomationTriggerUpdate update; +} diff --git a/src/main/java/com/mailerlite/sdk/emails/SingleEmail.java b/src/main/java/com/mailerlite/sdk/emails/SingleEmail.java new file mode 100644 index 0000000..810baba --- /dev/null +++ b/src/main/java/com/mailerlite/sdk/emails/SingleEmail.java @@ -0,0 +1,21 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.emails; + +import com.google.gson.annotations.SerializedName; +import com.mailerlite.sdk.MailerLiteResponse; + +/** + * The Class SingleEmail. + */ +public class SingleEmail extends MailerLiteResponse { + + /** The email. */ + @SerializedName("data") + public Email email; +} diff --git a/src/test/java/com/mailerlite/sdk/tests/AutomationsRequestTest.java b/src/test/java/com/mailerlite/sdk/tests/AutomationsRequestTest.java new file mode 100644 index 0000000..49fe534 --- /dev/null +++ b/src/test/java/com/mailerlite/sdk/tests/AutomationsRequestTest.java @@ -0,0 +1,1141 @@ +/************************************************* + * MailerLite Java SDK + * https://github.com/mailerlite/mailerlite-java + * + * @author MailerLite + * https://mailerlite.com + **************************************************/ +package com.mailerlite.sdk.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mailerlite.sdk.automations.Automation; +import com.mailerlite.sdk.automations.AutomationActivityFilter; +import com.mailerlite.sdk.automations.SingleAutomation; +import com.mailerlite.sdk.automations.activity.SubscriberActivity; +import com.mailerlite.sdk.automations.reports.AbTestStats; +import com.mailerlite.sdk.automations.reports.AutomationEmailStats; +import com.mailerlite.sdk.automations.reports.EcommerceStats; +import com.mailerlite.sdk.automations.reports.OrderActivity; +import com.mailerlite.sdk.automations.reports.RunSubscriberList; +import com.mailerlite.sdk.automations.reports.TriggersRunCounts; +import com.mailerlite.sdk.automations.reports.UnsubscribeReason; +import com.mailerlite.sdk.automations.steps.AbStep; +import com.mailerlite.sdk.automations.steps.AutomationStep; +import com.mailerlite.sdk.automations.steps.DelayStep; +import com.mailerlite.sdk.automations.steps.EmailStep; +import com.mailerlite.sdk.automations.steps.GenericAutomationStep; +import com.mailerlite.sdk.automations.steps.action.CopyToGroupAction; +import com.mailerlite.sdk.automations.steps.condition.ConditionStep; +import com.mailerlite.sdk.automations.templates.AutomationTemplateList; +import com.mailerlite.sdk.automations.triggers.AutomationTrigger; +import com.mailerlite.sdk.automations.triggers.GenericAutomationTrigger; +import com.mailerlite.sdk.automations.triggers.TriggerSubscriberJoinsGroup; +import com.mailerlite.sdk.automations.triggers.UpdatedAutomationTrigger; +import com.mailerlite.sdk.exceptions.MailerLiteException; + +/** + * The Class AutomationsRequestTest. + */ +public class AutomationsRequestTest extends MockTestBase { + + /** An automation with trigger, step and action types the typed parser does not know. */ + private static final String AUTOMATION_JSON = "{\"data\":{\"id\":\"100\",\"name\":\"Flow\",\"enabled\":false," + + "\"automation_template_id\":7,\"automation_template_name\":\"Welcome\",\"building_in_progress\":false," + + "\"stats\":{\"completed_subscribers_count\":4,\"subscribers_in_queue_count\":2}," + + "\"triggers\":[" + + "{\"id\":\"1\",\"type\":\"subscriber_joins_group\",\"group_ids\":[\"5\"],\"complete\":true,\"broken\":false}," + + "{\"id\":\"2\",\"type\":\"subscriber_joins_segment\",\"segment_id\":\"9\",\"complete\":true,\"broken\":false}," + + "{\"id\":\"3\",\"type\":\"manual\",\"complete\":true,\"broken\":false}," + + "{\"id\":\"4\",\"type\":\"abandoned_checkout\",\"complete\":true,\"broken\":false}," + + "{\"id\":\"5\",\"type\":\"purchase_frequency\",\"interval\":30,\"complete\":true,\"broken\":false}]," + + "\"steps\":[" + + "{\"id\":\"11\",\"type\":\"email\",\"name\":\"Hi\",\"description\":\"Send email\",\"type_count\":1}," + + "{\"id\":\"12\",\"type\":\"webhook\",\"url\":\"https://example.com/hook\",\"parent_id\":\"11\"}," + + "{\"id\":\"13\",\"type\":\"action\",\"action_type\":\"send_internal_email_notification\",\"parent_id\":\"12\"}," + + "{\"id\":\"14\",\"type\":\"action\",\"action_type\":null,\"parent_id\":\"13\"}," + + "{\"id\":\"15\",\"type\":\"abtest\",\"parent_id\":\"14\",\"split_percentages\":[{\"label\":\"A\",\"path\":\"a_path\",\"value\":50},{\"label\":\"B\",\"path\":\"b_path\",\"value\":50}]}]}}"; + + /** A single trigger. */ + private static final String TRIGGER_JSON = "{\"data\":{\"id\":\"3\",\"type\":\"manual\",\"complete\":true,\"broken\":false}}"; + + /** A single step. */ + private static final String STEP_JSON = "{\"data\":{\"id\":\"12\",\"type\":\"webhook\",\"parent_id\":\"11\",\"url\":\"https://example.com/hook\",\"complete\":true,\"broken\":false,\"description\":\"Webhook\"}}"; + + /** A/B test stats. */ + private static final String AB_STATS_JSON = "{\"step_id\":\"20\",\"name\":\"Test\",\"ab_test_winner\":\"a\",\"can_select_winner\":true,\"split_percentages\":[{\"label\":\"A\",\"path\":\"a_path\",\"value\":50},{\"label\":\"B\",\"path\":\"b_path\",\"value\":50}]," + + "\"stats\":{\"a_path\":{\"subscribers\":10,\"sent\":10,\"opens\":5,\"clicks\":1,\"open_rate\":{\"float\":0.5,\"string\":\"50%\"}}}}"; + + /** + * Test the parser falls back to the generic types for unknown triggers, steps and actions. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestParserNeverReturnsNullForUnknownTypes() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + Automation automation = this.getMailerLite().automations().retriever().getSingle("100"); + + assertEquals("GET", http.method()); + assertEquals("/automations/100", http.path()); + assertEquals(5, automation.triggers.length); + assertInstanceOf(TriggerSubscriberJoinsGroup.class, automation.triggers[0]); + assertEquals("1", ((TriggerSubscriberJoinsGroup) automation.triggers[0]).id); + + for (int i = 1; i < 5; i++) { + assertInstanceOf(GenericAutomationTrigger.class, automation.triggers[i]); + } + + GenericAutomationTrigger segmentTrigger = (GenericAutomationTrigger) automation.triggers[1]; + assertEquals(GenericAutomationTrigger.TYPE_SUBSCRIBER_JOINS_SEGMENT, segmentTrigger.type); + assertEquals("2", segmentTrigger.id); + assertTrue(segmentTrigger.complete); + assertEquals("9", segmentTrigger.data.get("segment_id").getAsString()); + assertEquals(GenericAutomationTrigger.TYPE_MANUAL, ((GenericAutomationTrigger) automation.triggers[2]).type); + assertEquals(GenericAutomationTrigger.TYPE_ABANDONED_CHECKOUT, ((GenericAutomationTrigger) automation.triggers[3]).type); + assertEquals(GenericAutomationTrigger.TYPE_PURCHASE_FREQUENCY, ((GenericAutomationTrigger) automation.triggers[4]).type); + + assertEquals(5, automation.steps.length); + assertInstanceOf(AbStep.class, automation.steps[4]); + assertEquals("a_path", JsonParser.parseString(((AbStep) automation.steps[4]).splitPercentages[0]).getAsJsonObject().get("path").getAsString()); + assertInstanceOf(EmailStep.class, automation.steps[0]); + assertEquals("Send email", ((EmailStep) automation.steps[0]).description); + + GenericAutomationStep webhook = (GenericAutomationStep) automation.steps[1]; + assertEquals(GenericAutomationStep.TYPE_WEBHOOK, webhook.type); + assertEquals("https://example.com/hook", webhook.data.get("url").getAsString()); + + GenericAutomationStep notification = (GenericAutomationStep) automation.steps[2]; + assertEquals(GenericAutomationStep.ACTION_TYPE_SEND_INTERNAL_EMAIL_NOTIFICATION, notification.actionType); + assertInstanceOf(GenericAutomationStep.class, automation.steps[3]); + + assertEquals("7", automation.automationTemplateId); + assertEquals("Welcome", automation.automationTemplateName); + assertEquals(4, automation.stats.completedSubscribersCount); + assertEquals(2, automation.stats.subscribersInQueueCount); + } + + /** + * Test list sends page, sort and with_steps. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListSendsPageSortAndWithSteps() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"1\",\"name\":\"Flow\"}],\"links\":{},\"meta\":{}}"); + + List automations = this.getMailerLite().automations().retriever() + .page(2) + .limit(10) + .sort("-created_at") + .withSteps(false) + .filter("enabled", "true") + .get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/", http.path()); + assertEquals("2", query.get("page")); + assertEquals("10", query.get("limit")); + assertEquals("-created_at", query.get("sort")); + assertEquals("0", query.get("with_steps")); + assertEquals("true", query.get("filter[enabled]")); + assertEquals(1, automations.size()); + assertEquals(0, automations.get(0).steps.length); + } + + /** + * Test create. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestCreate() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + SingleAutomation response = this.getMailerLite().automations().builder().name("Flow").create(); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/automations", http.path()); + assertEquals("Flow", body.get("name").getAsString()); + assertEquals(1, body.size()); + assertEquals("100", response.automation.id); + assertEquals(5, response.automation.triggers.length); + } + + /** + * Test create refuses triggers and trigger data, which the create endpoint does not accept. + */ + @Test + public void TestCreateRejectsTriggers() + { + Map trigger = new HashMap(); + trigger.put("type", "subscriber_joins_group"); + + assertThrows(IllegalStateException.class, () -> this.getMailerLite().automations().builder().name("Flow").addTrigger(trigger).create()); + assertThrows(IllegalStateException.class, () -> this.getMailerLite().automations().builder().name("Flow").triggerData(new HashMap()).create()); + assertFalse(http.hasRequest()); + } + + /** + * Test update requires a name. + */ + @Test + public void TestUpdateRequiresName() + { + assertThrows(IllegalStateException.class, () -> this.getMailerLite().automations().builder().triggerData(new HashMap()).update("100")); + assertFalse(http.hasRequest()); + } + + /** + * Test with_subscribers is sent only when true. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestActivityWithSubscribersFalseSendsNothing() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[]}"); + + this.getMailerLite().automations().subscriberActivityRetriever().filter("status", "active").withSubscribers(false).get("100"); + assertFalse(http.query().containsKey("with_subscribers")); + + this.getMailerLite().automations().subscriberActivityRetriever().filter("status", "active").withSubscribers(true).withSubscribers(false).get("100"); + assertFalse(http.query().containsKey("with_subscribers")); + + this.getMailerLite().automations().subscriberActivityRetriever().filter("status", "active").withSubscribers(true).get("100"); + assertEquals("1", http.query().get("with_subscribers")); + } + + /** + * Test update. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestUpdate() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + Map triggerData = new HashMap(); + triggerData.put("repeatable", true); + + Map trigger = new HashMap(); + trigger.put("type", "subscriber_joins_group"); + + this.getMailerLite().automations().builder().name("Renamed").triggerData(triggerData).addTrigger(trigger).update("100"); + + JsonObject body = http.body(); + + assertEquals("PUT", http.method()); + assertEquals("/automations/100", http.path()); + assertEquals("Renamed", body.get("name").getAsString()); + assertTrue(body.getAsJsonObject("trigger_data").get("repeatable").getAsBoolean()); + assertEquals("subscriber_joins_group", body.getAsJsonArray("triggers").get(0).getAsJsonObject().get("type").getAsString()); + } + + /** + * Test delete. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestDelete() throws MailerLiteException + { + http.respondWith(204, ""); + + assertEquals(204, this.getMailerLite().automations().delete("100").responseStatusCode); + assertEquals("DELETE", http.method()); + assertEquals("/automations/100", http.path()); + } + + /** + * Test copy. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestCopy() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + assertEquals("100", this.getMailerLite().automations().copy("100").automation.id); + assertEquals("POST", http.method()); + assertEquals("/automations/100/copy", http.path()); + } + + /** + * Test enable. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestEnable() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + assertEquals("100", this.getMailerLite().automations().enable("100").automation.id); + assertEquals("POST", http.method()); + assertEquals("/automations/100/enable", http.path()); + } + + /** + * Test disable. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestDisable() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + assertEquals("100", this.getMailerLite().automations().disable("100").automation.id); + assertEquals("POST", http.method()); + assertEquals("/automations/100/disable", http.path()); + } + + /** + * Test send test emails. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestTest() throws MailerLiteException + { + http.respondWith(204, ""); + + this.getMailerLite().automations().test("100", "me@example.com"); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/test", http.path()); + assertEquals("me@example.com", http.body().get("email").getAsString()); + } + + /** + * Test activity sends page and sort and parses the subscriber. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestActivity() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"1\",\"status\":\"Completed\",\"subscriber\":{\"id\":\"9\",\"email\":\"a@example.com\",\"name\":\"A\"}}],\"links\":{},\"meta\":{}}"); + + List activity = this.getMailerLite().automations().subscriberActivityRetriever() + .page(2) + .limit(10) + .sort("-date") + .withSubscribers(true) + .filter("status", "completed") + .filter("search", "a+b@example.com") + .filter("date_from", "2024-01-01") + .get("100"); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/activity", http.path()); + assertEquals("2", query.get("page")); + assertEquals("10", query.get("limit")); + assertEquals("-date", query.get("sort")); + assertEquals("1", query.get("with_subscribers")); + assertEquals("completed", query.get("filter[status]")); + assertEquals("a+b@example.com", query.get("filter[search]")); + assertEquals("2024-01-01", query.get("filter[date_from]")); + assertEquals("a@example.com", activity.get(0).subscriber.email); + } + + /** + * Test add subscribers. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestAddSubscribers() throws MailerLiteException + { + http.respondWith(204, ""); + + this.getMailerLite().automations().addSubscribers("100", Arrays.asList("a@example.com"), Arrays.asList("5"), "11"); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/add-subscribers", http.path()); + assertEquals("a@example.com", body.getAsJsonArray("emails").get(0).getAsString()); + assertEquals("5", body.getAsJsonArray("groups").get(0).getAsString()); + assertEquals("11", body.get("step_id").getAsString()); + } + + /** + * Test readd. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestReadd() throws MailerLiteException + { + http.respondWith(204, ""); + + AutomationActivityFilter filter = new AutomationActivityFilter().status("failed").addId("1").search("a@").dateFrom("2024-01-01").dateTo("2024-02-01").step("11"); + + this.getMailerLite().automations().readd("100", "selected_step", "11", filter); + + JsonObject body = http.body(); + JsonObject sentFilter = body.getAsJsonObject("filter"); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/readd", http.path()); + assertEquals("selected_step", body.get("readd_subscribers_to").getAsString()); + assertEquals("11", body.get("selected_step_id").getAsString()); + assertEquals("failed", sentFilter.get("status").getAsString()); + assertEquals("1", sentFilter.getAsJsonArray("id").get(0).getAsString()); + assertEquals("a@", sentFilter.get("search").getAsString()); + assertEquals("2024-01-01", sentFilter.get("date_from").getAsString()); + assertEquals("2024-02-01", sentFilter.get("date_to").getAsString()); + assertEquals("11", sentFilter.get("step").getAsString()); + } + + /** + * Test add activity to groups. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestAddActivityToGroups() throws MailerLiteException + { + http.respondWith(204, ""); + + AutomationActivityFilter filter = new AutomationActivityFilter().status("active").reason("x").scheduledFrom("2024-01-01").scheduledTo("2024-02-01").nextStep("12").currentStep("11"); + + this.getMailerLite().automations().addActivityToGroups("100", Arrays.asList("5"), filter); + + JsonObject body = http.body(); + JsonObject sentFilter = body.getAsJsonObject("filter"); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/activity/add-to-group", http.path()); + assertEquals("5", body.getAsJsonArray("destination_groups").get(0).getAsString()); + assertEquals("active", sentFilter.get("status").getAsString()); + assertEquals("x", sentFilter.get("reason").getAsString()); + assertEquals("2024-01-01", sentFilter.get("scheduled_from").getAsString()); + assertEquals("2024-02-01", sentFilter.get("scheduled_to").getAsString()); + assertEquals("12", sentFilter.get("next_step").getAsString()); + assertEquals("11", sentFilter.get("current_step").getAsString()); + } + + /** + * Test cancel activity. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestCancelActivity() throws MailerLiteException + { + http.respondWith(204, ""); + + this.getMailerLite().automations().cancelActivity("100", new AutomationActivityFilter().status("active")); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/activity/cancel-automation", http.path()); + assertEquals("active", body.getAsJsonObject("filter").get("status").getAsString()); + assertEquals(1, body.size()); + } + + /** + * Test skip activity delay. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestSkipActivityDelay() throws MailerLiteException + { + http.respondWith(204, ""); + + this.getMailerLite().automations().skipActivityDelay("100", new AutomationActivityFilter().status("active")); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/activity/skip-delay", http.path()); + assertEquals("active", body.getAsJsonObject("filter").get("status").getAsString()); + assertEquals(1, body.size()); + } + + /** + * Test list triggers. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListTriggers() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"3\",\"type\":\"manual\",\"complete\":true},{\"id\":\"4\",\"type\":\"subscriber_joins_group\",\"group_ids\":[\"5\"]}]}"); + + AutomationTrigger[] triggers = this.getMailerLite().automations().triggers("100").get().triggers; + + assertEquals("GET", http.method()); + assertEquals("/automations/100/triggers", http.path()); + GenericAutomationTrigger manual = assertInstanceOf(GenericAutomationTrigger.class, triggers[0]); + assertEquals(GenericAutomationTrigger.TYPE_MANUAL, manual.type); + assertEquals("3", manual.data.get("id").getAsString()); + TriggerSubscriberJoinsGroup joins = assertInstanceOf(TriggerSubscriberJoinsGroup.class, triggers[1]); + assertEquals("5", joins.groupIds[0]); + } + + /** + * Test get trigger. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestGetTrigger() throws MailerLiteException + { + http.respondWith(200, TRIGGER_JSON); + + assertInstanceOf(GenericAutomationTrigger.class, this.getMailerLite().automations().triggers("100").getSingle("3").trigger); + assertEquals("GET", http.method()); + assertEquals("/automations/100/triggers/3", http.path()); + } + + /** + * Test create trigger. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestCreateTrigger() throws MailerLiteException + { + http.respondWith(200, TRIGGER_JSON); + + Map data = new HashMap(); + data.put("group_ids", Arrays.asList("5")); + + this.getMailerLite().automations().triggers("100").create(GenericAutomationTrigger.TYPE_SUBSCRIBER_JOINS_GROUP, data); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/triggers", http.path()); + assertEquals("subscriber_joins_group", body.get("type").getAsString()); + assertEquals("5", body.getAsJsonObject("data").getAsJsonArray("group_ids").get(0).getAsString()); + } + + /** + * Test update trigger. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestUpdateTrigger() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"trigger\":{\"id\":\"3\",\"type\":\"subscriber_joins_segment\",\"segment_id\":\"9\",\"segment\":{\"id\":\"9\",\"name\":\"S\"},\"broken\":false,\"complete\":true}," + + "\"trigger_data\":{\"track_ecommerce\":false,\"broken_workflow\":false,\"complete_workflow\":false,\"repeatable\":true,\"valid\":true},\"qualified_subscribers_count\":12}}"); + + Map data = new HashMap(); + data.put("segment_id", "9"); + + UpdatedAutomationTrigger response = this.getMailerLite().automations().triggers("100").update("3", data); + + JsonObject body = http.body(); + + assertEquals("PUT", http.method()); + assertEquals("/automations/100/triggers/3", http.path()); + assertEquals("9", body.getAsJsonObject("data").get("segment_id").getAsString()); + assertEquals(1, body.size()); + assertEquals("3", response.update.trigger.id); + assertEquals(GenericAutomationTrigger.TYPE_SUBSCRIBER_JOINS_SEGMENT, response.update.trigger.type); + assertEquals("9", assertInstanceOf(GenericAutomationTrigger.class, response.update.trigger).data.get("segment_id").getAsString()); + assertTrue(response.update.triggerData.repeatable); + assertTrue(response.update.triggerData.valid); + assertEquals(12, (int) response.update.qualifiedSubscribersCount); + } + + /** + * Test delete trigger. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestDeleteTrigger() throws MailerLiteException + { + http.respondWith(204, ""); + + this.getMailerLite().automations().triggers("100").delete("3"); + + assertEquals("DELETE", http.method()); + assertEquals("/automations/100/triggers/3", http.path()); + } + + /** + * Test list steps. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListSteps() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"12\",\"type\":\"webhook\",\"url\":\"https://example.com/hook\"}," + + "{\"id\":\"13\",\"type\":\"email\",\"subject\":\"Hi\"},{\"id\":\"14\",\"type\":\"delay\",\"unit\":\"days\"}," + + "{\"id\":\"15\",\"type\":\"action\",\"action_type\":\"copy_to_group\",\"group_ids\":[\"5\"]},{\"id\":\"16\",\"type\":\"condition\"}]}"); + + AutomationStep[] steps = this.getMailerLite().automations().steps("100").get().steps; + + assertEquals("GET", http.method()); + assertEquals("/automations/100/steps/index", http.path()); + assertEquals("https://example.com/hook", assertInstanceOf(GenericAutomationStep.class, steps[0]).data.get("url").getAsString()); + assertEquals("Hi", assertInstanceOf(EmailStep.class, steps[1]).subject); + assertEquals("days", assertInstanceOf(DelayStep.class, steps[2]).unit); + assertEquals("5", assertInstanceOf(CopyToGroupAction.class, steps[3]).groupIds[0]); + assertEquals(0, assertInstanceOf(ConditionStep.class, steps[4]).conditions.length); + } + + /** + * Test get step. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestGetStep() throws MailerLiteException + { + http.respondWith(200, STEP_JSON); + + GenericAutomationStep step = assertInstanceOf(GenericAutomationStep.class, this.getMailerLite().automations().steps("100").getSingle("12").step); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/steps/12", http.path()); + assertEquals("11", step.parentId); + assertEquals("Webhook", step.description); + } + + /** + * Test create step. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestCreateStep() throws MailerLiteException + { + http.respondWith(200, STEP_JSON); + + this.getMailerLite().automations().steps("100").builder() + .type(GenericAutomationStep.TYPE_ACTION) + .parentId("11") + .branch(GenericAutomationStep.BRANCH_YES) + .moveToBranch(GenericAutomationStep.BRANCH_NO) + .addData("action_type", GenericAutomationStep.ACTION_TYPE_COPY_TO_GROUP) + .rescheduleWaitingSubscribers(true) + .create(); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/steps", http.path()); + assertEquals("action", body.get("type").getAsString()); + assertEquals("11", body.get("parent_id").getAsString()); + assertEquals("yes", body.get("branch").getAsString()); + assertEquals("no", body.get("move_to_branch").getAsString()); + assertEquals("copy_to_group", body.getAsJsonObject("data").get("action_type").getAsString()); + assertEquals(5, body.size()); + } + + /** + * Test update step. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestUpdateStep() throws MailerLiteException + { + http.respondWith(200, STEP_JSON); + + this.getMailerLite().automations().steps("100").builder() + .type(GenericAutomationStep.TYPE_DELAY) + .parentId("11") + .branch(GenericAutomationStep.BRANCH_YES) + .addData("value", 2) + .rescheduleWaitingSubscribers(true) + .update("12"); + + JsonObject body = http.body(); + + assertEquals("PUT", http.method()); + assertEquals("/automations/100/steps/12", http.path()); + assertEquals("11", body.get("parent_id").getAsString()); + assertEquals(2, body.getAsJsonObject("data").get("value").getAsInt()); + assertTrue(body.get("reschedule_waiting_subscribers").getAsBoolean()); + assertEquals(3, body.size()); + } + + /** + * Test delete step. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestDeleteStep() throws MailerLiteException + { + http.respondWith(204, ""); + + this.getMailerLite().automations().steps("100").delete("12"); + + assertEquals("DELETE", http.method()); + assertEquals("/automations/100/steps/12", http.path()); + assertTrue(http.query().isEmpty()); + + this.getMailerLite().automations().steps("100").delete("12", "yes"); + + assertEquals("DELETE", http.method()); + assertEquals("/automations/100/steps/12", http.path()); + assertEquals("yes", http.query().get("branch_to_delete")); + } + + /** + * Test copy step. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestCopyStep() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + SingleAutomation response = this.getMailerLite().automations().steps("100").builder() + .parentId("11") + .branch(GenericAutomationStep.BRANCH_A_PATH) + .moveToBranch(GenericAutomationStep.BRANCH_YES) + .copy("12"); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/steps/12/copy", http.path()); + assertEquals("11", body.get("parent_id").getAsString()); + assertEquals("a_path", body.get("branch").getAsString()); + assertEquals("yes", body.get("move_to_branch").getAsString()); + assertEquals("100", response.automation.id); + } + + /** + * Test reorder steps. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestReorderSteps() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + this.getMailerLite().automations().steps("100").reorder("12", "11", GenericAutomationStep.BRANCH_NO, GenericAutomationStep.BRANCH_YES); + + JsonObject body = http.body(); + + assertEquals("POST", http.method()); + assertEquals("/automations/100/steps/reorder", http.path()); + assertEquals("12", body.get("dragged_step_id").getAsString()); + assertEquals("11", body.get("new_parent_step_id").getAsString()); + assertEquals("no", body.get("branch").getAsString()); + assertEquals("yes", body.get("branch_for_child").getAsString()); + } + + /** + * Test select A/B test winner. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestSelectAbTestWinner() throws MailerLiteException + { + http.respondWith(200, "{\"data\":" + AB_STATS_JSON + "}"); + + String winner = this.getMailerLite().automations().steps("100").selectAbTestWinner("20", "a").abTestStats.abTestWinner; + + assertEquals("PUT", http.method()); + assertEquals("/automations/100/steps/20/select-ab-test-winner", http.path()); + assertEquals("a", http.body().get("ab_test_winner").getAsString()); + assertEquals("a", winner); + } + + /** + * Test get email content. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestGetEmailContent() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"html\":\"

Hi

\"}}"); + + assertEquals("

Hi

", this.getMailerLite().automations().emails("100").getContent("30").content.html); + assertEquals("GET", http.method()); + assertEquals("/automations/100/emails/30/content", http.path()); + } + + /** + * Test update email content. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestUpdateEmailContent() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"id\":\"30\",\"subject\":\"Hi\"}}"); + + assertEquals("30", this.getMailerLite().automations().emails("100").updateContent("30", "

Hi

").email.id); + assertEquals("PUT", http.method()); + assertEquals("/automations/100/emails/30/content", http.path()); + assertEquals("

Hi

", http.body().get("html").getAsString()); + } + + /** + * Test email report stats. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestEmailReportStats() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"engagement\":{\"sent\":10,\"open_rate\":{\"float\":0.5,\"string\":\"50%\"}},\"deliverability\":{\"delivered_count\":9}}}"); + + AutomationEmailStats stats = this.getMailerLite().automations().emails("100") + .startDate("2024-01-01").endDate("2024-01-31").shopId("8") + .reportStats("30").stats; + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/emails/30/report-stats", http.path()); + assertEquals("2024-01-01", query.get("start_date")); + assertEquals("2024-01-31", query.get("end_date")); + assertEquals("8", query.get("shop_id")); + assertEquals(10, stats.engagement.sent); + assertEquals("50%", stats.engagement.openRate.stringValue); + assertEquals(9, stats.deliverability.deliveredCount); + } + + /** + * Test email ecommerce overview stats. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestEmailEcommerceOverviewStats() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"ecommerce\":{\"orders_count\":3,\"revenue\":12.5,\"average_order_value\":\"4.17\",\"conversion_rate\":\"1%\"}}}"); + + EcommerceStats stats = this.getMailerLite().automations().emails("100") + .startDate("2024-01-01").endDate("2024-01-31").shopId("8") + .ecommerceOverviewStats("30").stats.ecommerce; + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/emails/30/ecommerce-overview-stats", http.path()); + assertEquals("2024-01-01", query.get("start_date")); + assertEquals("2024-01-31", query.get("end_date")); + assertEquals("8", query.get("shop_id")); + assertEquals(3, stats.ordersCount); + assertEquals(12.5, stats.revenue); + } + + /** + * Test email unsubscribe reasons. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestEmailUnsubscribeReasons() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"label\":\"Too many emails\",\"count\":\"2\",\"percentage\":\"50%\"}]}"); + + UnsubscribeReason reason = this.getMailerLite().automations().emails("100").unsubscribeReasons("30").reasons[0]; + + assertEquals("GET", http.method()); + assertEquals("/automations/100/emails/30/unsubscribe-reasons", http.path()); + assertEquals(2, reason.count); + assertEquals("50%", reason.percentage); + } + + /** + * Test list templates. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListTemplates() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"1\",\"name\":\"Welcome\",\"type\":\"welcome\",\"workflow\":{\"triggers\":[{\"type\":\"subscriber_joins_group\"}]},\"workflow_steps_description\":[\"Send a welcome email\"],\"url\":\"https://example.com\"}],\"links\":{},\"meta\":{\"total\":1}}"); + + AutomationTemplateList list = this.getMailerLite().automations().templates() + .filter("type", "ecommerce").filter("category", "2").limit(10).page(2).get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automation-templates", http.path()); + assertEquals("ecommerce", query.get("filter[type]")); + assertEquals("2", query.get("filter[category]")); + assertEquals("10", query.get("limit")); + assertEquals("2", query.get("page")); + assertEquals("Welcome", list.templates[0].name); + assertEquals("subscriber_joins_group", list.templates[0].workflow.getAsJsonObject().getAsJsonArray("triggers").get(0).getAsJsonObject().get("type").getAsString()); + assertEquals("Send a welcome email", list.templates[0].workflowStepsDescription[0]); + assertEquals(1, list.meta.total); + } + + /** + * Test select template. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestSelectTemplate() throws MailerLiteException + { + http.respondWith(200, AUTOMATION_JSON); + + assertEquals("100", this.getMailerLite().automations().selectTemplate("1").automation.id); + assertEquals("POST", http.method()); + assertEquals("/automations/select-template/1", http.path()); + } + + /** + * Test step run counts. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestStepRunCounts() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"step_id\":\"11\",\"completed_step_runs\":4,\"in_queue_step_runs\":1}]}"); + + assertEquals(4, this.getMailerLite().automations().reports("100").stepRunCounts().stepRunCounts[0].completedStepRuns); + assertEquals("GET", http.method()); + assertEquals("/automations/100/steps/run-counts", http.path()); + } + + /** + * Test step run count. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestStepRunCount() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"step_id\":\"11\",\"completed_step_runs\":4,\"in_queue_step_runs\":1}}"); + + assertEquals(1, this.getMailerLite().automations().reports("100").stepRunCount("11").stepRunCount.inQueueStepRuns); + assertEquals("GET", http.method()); + assertEquals("/automations/100/steps/run-counts/11", http.path()); + } + + /** + * Test trigger run counts. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestTriggerRunCounts() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"triggers\":[{\"id\":\"1\",\"completed_runs\":3,\"queued_runs\":2}],\"manual_runs\":{\"in_progress_runs\":1,\"completed_runs\":5}}}"); + + TriggersRunCounts counts = this.getMailerLite().automations().reports("100").triggerRunCounts().triggersRunCounts; + + assertEquals("GET", http.method()); + assertEquals("/automations/100/triggers/run-counts", http.path()); + assertEquals(3, counts.triggers[0].completedRuns); + assertEquals(5, counts.manualRuns.completedRuns); + } + + /** + * Test trigger run count. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestTriggerRunCount() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"completed_runs\":3,\"queued_runs\":2}}"); + + assertEquals(2, this.getMailerLite().automations().reports("100").triggerRunCount("1").triggerRunCount.queuedRuns); + assertEquals("GET", http.method()); + assertEquals("/automations/100/triggers/run-counts/1", http.path()); + } + + /** + * Test A/B steps stats. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestAbStepsStats() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[" + AB_STATS_JSON + "]}"); + + AbTestStats stats = this.getMailerLite().automations().reports("100").abStepsStats().abTestStats[0]; + + assertEquals("GET", http.method()); + assertEquals("/automations/100/ab-steps-stats", http.path()); + assertEquals("20", stats.stepId); + assertEquals("b_path", stats.splitPercentages[1].path); + assertEquals(50, stats.splitPercentages[1].value); + assertEquals("50%", stats.stats.get("a_path").openRate.stringValue); + } + + /** + * Test A/B step stats. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestAbStepStats() throws MailerLiteException + { + http.respondWith(200, "{\"data\":" + AB_STATS_JSON + "}"); + + assertEquals(10, this.getMailerLite().automations().reports("100").abStepStats("20").abTestStats.stats.get("a_path").subscribers); + assertEquals("GET", http.method()); + assertEquals("/automations/100/ab-steps-stats/20", http.path()); + } + + /** + * Test step subscribers. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestStepSubscribers() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"1\",\"subscriber\":{\"id\":\"9\",\"email\":\"a@example.com\"},\"date\":\"2024-01-01 10:00:00\"}],\"links\":{},\"meta\":{}}"); + + RunSubscriberList list = this.getMailerLite().automations().reports("100").stepSubscribers("11") + .status("completed").limit(10).page(2).sort("-date") + .filter("date_from", "2024-01-01").filter("date_to", "2024-01-31").filter("search", "a@").filter("id", "1") + .get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/activity/steps/11/subscribers", http.path()); + assertEquals("completed", query.get("status")); + assertEquals("10", query.get("limit")); + assertEquals("2", query.get("page")); + assertEquals("-date", query.get("sort")); + assertEquals("2024-01-01", query.get("filter[date_from]")); + assertEquals("2024-01-31", query.get("filter[date_to]")); + assertEquals("a@", query.get("filter[search]")); + assertEquals("1", query.get("filter[id]")); + assertEquals("a@example.com", list.subscribers[0].subscriber.email); + assertNotNull(list.subscribers[0].runDate); + } + + /** + * Test trigger subscribers. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestTriggerSubscribers() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[],\"links\":{},\"meta\":{}}"); + + this.getMailerLite().automations().reports("100").triggerSubscribers("1").status("queued").limit(5).get(); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/activity/triggers/1/subscribers", http.path()); + assertEquals("queued", query.get("status")); + assertEquals("5", query.get("limit")); + } + + /** + * Test order activity. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestOrderActivity() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"subscriber\":{\"email\":\"a@example.com\",\"id\":\"9\"},\"total\":19.99,\"updated_at\":\"2024-01-01 10:00:00\",\"order\":\"5\",\"email\":{\"id\":\"30\"}}]}"); + + OrderActivity order = this.getMailerLite().automations().reports("100").orderActivity() + .timeFrame("custom").timeFrameStart("2024-01-01").timeFrameEnd("2024-01-31").ecommerceShopId("8").limit(10).page(2) + .get().orders[0]; + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/order-activity", http.path()); + assertEquals("custom", query.get("time_frame")); + assertEquals("2024-01-01", query.get("time_frame_start")); + assertEquals("2024-01-31", query.get("time_frame_end")); + assertEquals("8", query.get("ecommerce_shop_id")); + assertEquals("10", query.get("limit")); + assertEquals("2", query.get("page")); + assertEquals(19.99, order.total); + assertEquals("30", order.email.id); + } + + /** + * Test monthly email totals. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestMonthlyEmailTotals() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"engagement\":{\"sent\":10},\"deliverability\":{\"sent\":10}}}"); + + assertEquals(10, this.getMailerLite().automations().reports("100").startDate("2024-01-01").endDate("2024-01-31").shopId("8").monthlyEmailTotals().stats.engagement.sent); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/monthly-totals/email", http.path()); + assertEquals("2024-01-01", query.get("start_date")); + assertEquals("2024-01-31", query.get("end_date")); + assertEquals("8", query.get("shop_id")); + } + + /** + * Test monthly ecommerce totals. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestMonthlyEcommerceTotals() throws MailerLiteException + { + http.respondWith(200, "{\"data\":{\"ecommerce\":{\"orders_count\":3,\"revenue\":12.5,\"average_order_value\":0},\"best_performing_email\":null}}"); + + assertEquals(3, this.getMailerLite().automations().reports("100").startDate("2024-01-01").endDate("2024-01-31").shopId("8").monthlyEcommerceTotals().stats.ecommerce.ordersCount); + + Map query = http.query(); + + assertEquals("GET", http.method()); + assertEquals("/automations/100/monthly-totals/ecommerce", http.path()); + assertEquals("2024-01-01", query.get("start_date")); + assertEquals("2024-01-31", query.get("end_date")); + assertEquals("8", query.get("shop_id")); + } +} From 70b2d2ab08eff3e2f696b927b4f89adca3f9070c Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 17:26:49 +0530 Subject: [PATCH 8/9] Parse dates on subscriber groups --- .../sdk/susbcribers/Subscriber.java | 19 +++++++++++++++++++ .../sdk/tests/SubscribersRequestTest.java | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mailerlite/sdk/susbcribers/Subscriber.java b/src/main/java/com/mailerlite/sdk/susbcribers/Subscriber.java index c30e822..6bfeec3 100644 --- a/src/main/java/com/mailerlite/sdk/susbcribers/Subscriber.java +++ b/src/main/java/com/mailerlite/sdk/susbcribers/Subscriber.java @@ -135,4 +135,23 @@ public class Subscriber extends ApiResource { /** The timezone. */ @SerializedName("timezone") public SubscriberTimezone timezone; + + /** + * Parses the subscriber dates and the dates of its groups. + */ + @Override + public void parseDates() + { + super.parseDates(); + + if (groups == null) { + return; + } + + for (Group group : groups) { + if (group != null) { + group.parseDates(); + } + } + } } diff --git a/src/test/java/com/mailerlite/sdk/tests/SubscribersRequestTest.java b/src/test/java/com/mailerlite/sdk/tests/SubscribersRequestTest.java index f81e8a8..b3fc337 100644 --- a/src/test/java/com/mailerlite/sdk/tests/SubscribersRequestTest.java +++ b/src/test/java/com/mailerlite/sdk/tests/SubscribersRequestTest.java @@ -123,7 +123,7 @@ public void TestBuilderBodyIsUnchanged() throws MailerLiteException public void TestGetSingleParsesNewFields() throws MailerLiteException { http.respondWith(200, "{\"data\":{\"id\":\"1\",\"email\":\"a@example.com\",\"deleted_at\":\"2024-01-02 03:04:05\",\"forget_at\":\"2024-02-02 03:04:05\"," - + "\"groups\":[{\"id\":\"5\",\"name\":\"Group\"}]," + + "\"groups\":[{\"id\":\"5\",\"name\":\"Group\",\"created_at\":\"2024-03-02 03:04:05\"}]," + "\"location\":{\"id\":\"9\",\"title\":\"Vilnius\",\"country_name\":\"Lithuania\",\"continent_name\":\"Europe\",\"state_name\":null,\"time_zone\":\"Europe/Vilnius\"}," + "\"timezone\":{\"id\":\"3\",\"name\":\"Europe/Vilnius\",\"name_for_humans\":\"Vilnius\",\"offset_name\":\"+02:00\",\"offset\":120}}}"); @@ -134,6 +134,7 @@ public void TestGetSingleParsesNewFields() throws MailerLiteException assertNotNull(subscriber.subscriber.deletedAt); assertNotNull(subscriber.subscriber.forgetAt); assertEquals("5", subscriber.subscriber.groups[0].id); + assertNotNull(subscriber.subscriber.groups[0].createdAt); assertEquals("Lithuania", subscriber.subscriber.location.countryName); assertEquals(120, (int) subscriber.subscriber.timezone.offset); } From 81d4b9ad8d707234a5578e8985df90387ebee77d Mon Sep 17 00:00:00 2001 From: Kavan Pancholi Date: Fri, 30 Oct 2026 17:30:05 +0530 Subject: [PATCH 9/9] Fall back to generic steps and conditions when type is missing --- .../AutomationStepDeserializer.java | 31 +++++++++++++------ .../sdk/tests/AutomationsRequestTest.java | 20 +++++++++++- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/mailerlite/sdk/automations/AutomationStepDeserializer.java b/src/main/java/com/mailerlite/sdk/automations/AutomationStepDeserializer.java index 5e9bdb1..e176370 100644 --- a/src/main/java/com/mailerlite/sdk/automations/AutomationStepDeserializer.java +++ b/src/main/java/com/mailerlite/sdk/automations/AutomationStepDeserializer.java @@ -66,8 +66,12 @@ public AutomationStep deserialize(JsonElement json, Type typeOfT, JsonDeserializ */ public AutomationStep deserializeAutomationStep(JsonObject stepObj, Gson gson) { - String type = stepObj.get("type").getAsString(); - + String type = stringOrNull(stepObj, "type"); + + if (type == null) { + return gson.fromJson(stepObj, GenericAutomationStep.class); + } + switch (type) { case GenericAutomationStep.TYPE_EMAIL: @@ -109,12 +113,12 @@ public AutomationStep deserializeAutomationStep(JsonObject stepObj, Gson gson) */ private AutomationStep deserializeActionStep(JsonObject stepObj, Gson gson) { - if (stepObj.get("action_type") == null || stepObj.get("action_type").isJsonNull()) { + String actionType = stringOrNull(stepObj, "action_type"); + + if (actionType == null) { return gson.fromJson(stepObj, GenericAutomationStep.class); } - - String actionType = stepObj.get("action_type").getAsString(); - + switch (actionType) { case GenericAutomationStep.ACTION_TYPE_UPDATE_CUSTOM_FIELD: @@ -166,9 +170,9 @@ private ConditionStep deserializeConditionStep(JsonObject stepObj, Gson gson) JsonObject conditionObj = el.getAsJsonObject(); - String conditionType = conditionObj.get("type").getAsString(); - - switch (conditionType) { + String conditionType = stringOrNull(conditionObj, "type"); + + switch (conditionType == null ? "" : conditionType) { case "workflow_activity": conditionItems.add(gson.fromJson(conditionObj, WorkflowActivityCondition.class)); @@ -198,7 +202,14 @@ private ConditionStep deserializeConditionStep(JsonObject stepObj, Gson gson) step.conditions = conditionItems.toArray(); - + return step; } + + private static String stringOrNull(JsonObject obj, String key) + { + JsonElement value = obj.get(key); + + return value == null || value.isJsonNull() ? null : value.getAsString(); + } } diff --git a/src/test/java/com/mailerlite/sdk/tests/AutomationsRequestTest.java b/src/test/java/com/mailerlite/sdk/tests/AutomationsRequestTest.java index 49fe534..a447190 100644 --- a/src/test/java/com/mailerlite/sdk/tests/AutomationsRequestTest.java +++ b/src/test/java/com/mailerlite/sdk/tests/AutomationsRequestTest.java @@ -611,7 +611,25 @@ public void TestListSteps() throws MailerLiteException assertEquals("5", assertInstanceOf(CopyToGroupAction.class, steps[3]).groupIds[0]); assertEquals(0, assertInstanceOf(ConditionStep.class, steps[4]).conditions.length); } - + + /** + * Test list steps falls back to generic types when a type is missing. + * + * @throws MailerLiteException the mailer lite exception + */ + @Test + public void TestListStepsWithoutType() throws MailerLiteException + { + http.respondWith(200, "{\"data\":[{\"id\":\"20\"},{\"id\":\"21\",\"type\":null}," + + "{\"id\":\"22\",\"type\":\"condition\",\"conditions\":[{\"id\":\"1\"}]}]}"); + + AutomationStep[] steps = this.getMailerLite().automations().steps("100").get().steps; + + assertEquals("20", assertInstanceOf(GenericAutomationStep.class, steps[0]).id); + assertEquals("21", assertInstanceOf(GenericAutomationStep.class, steps[1]).id); + assertEquals(1, assertInstanceOf(ConditionStep.class, steps[2]).conditions.length); + } + /** * Test get step. *