Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.mailtrap.examples.contactimports;

import io.mailtrap.config.MailtrapConfig;
import io.mailtrap.factory.MailtrapClientFactory;
import io.mailtrap.model.request.contactimports.Contact;
import io.mailtrap.model.request.contactimports.ImportContactsRequest;
import io.mailtrap.model.request.contacts.UpdateContact;
import io.mailtrap.model.request.contacts.UpdateContactRequest;

import java.util.Collections;
import java.util.List;
import java.util.Map;

public class ContactImports {

private static final String TOKEN = "<YOUR MAILTRAP TOKEN>";
private static final long ACCOUNT_ID = 1L;
private static final long LIST_1_ID = 1L;
private static final long LIST_2_ID = 2L;
private static final String EMAIL = "contact_email@email.com";

public static void main(String[] args) {
final var config = new MailtrapConfig.Builder()
.token(TOKEN)
.build();

final var client = MailtrapClientFactory.createMailtrapClient(config);

var importRequest = new ImportContactsRequest(
List.of(new Contact(EMAIL, Map.of("first_name", "Nick"), List.of(LIST_1_ID), List.of(LIST_2_ID))));

var createResponse = client.contactsApi().contactImports()
.importContacts(ACCOUNT_ID, importRequest);

System.out.println(createResponse);

var contactImportResponse = client.contactsApi().contactImports()
.getContactImport(ACCOUNT_ID, createResponse.getId());

System.out.println(contactImportResponse);
}
}
28 changes: 28 additions & 0 deletions src/main/java/io/mailtrap/api/contactimports/ContactImports.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.mailtrap.api.contactimports;

import io.mailtrap.model.request.contactimports.ImportContactsRequest;
import io.mailtrap.model.response.contactimports.ContactsImportResponse;
import io.mailtrap.model.response.contactimports.CreateContactsImportResponse;

public interface ContactImports {

/**
* Import contacts in bulk with support for custom fields and list management.
* Existing contacts with matching email addresses will be updated automatically.
* Up to 50,000 contacts per request
*
* @param accountId unique account ID
* @param request request body
* @return contact data
*/
CreateContactsImportResponse importContacts(long accountId, ImportContactsRequest request);

/**
* Get Contact Import
*
* @param accountId unique account ID
* @param importId unique Contact Import ID
* @return contact data
*/
ContactsImportResponse getContactImport(long accountId, long importId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.mailtrap.api.contactimports;

import io.mailtrap.Constants;
import io.mailtrap.CustomValidator;
import io.mailtrap.api.apiresource.ApiResourceWithValidation;
import io.mailtrap.config.MailtrapConfig;
import io.mailtrap.http.RequestData;
import io.mailtrap.model.request.contactimports.ImportContactsRequest;
import io.mailtrap.model.response.contactimports.ContactsImportResponse;
import io.mailtrap.model.response.contactimports.CreateContactsImportResponse;

public class ContactImportsImpl extends ApiResourceWithValidation implements ContactImports {

public ContactImportsImpl(final MailtrapConfig config, final CustomValidator validator) {
super(config, validator);
this.apiHost = Constants.GENERAL_HOST;
}

@Override
public CreateContactsImportResponse importContacts(long accountId, ImportContactsRequest request) {

validateRequestBodyAndThrowException(request);

return httpClient.post(
String.format(apiHost + "/api/accounts/%s/contacts/imports", accountId),
request,
new RequestData(),
CreateContactsImportResponse.class
);
}

@Override
public ContactsImportResponse getContactImport(long accountId, long importId) {
return httpClient.get(
String.format(apiHost + "/api/accounts/%s/contacts/imports/%s", accountId, importId),
new RequestData(),
ContactsImportResponse.class
);
}
}
2 changes: 2 additions & 0 deletions src/main/java/io/mailtrap/client/api/MailtrapContactsApi.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.mailtrap.client.api;

import io.mailtrap.api.contactimports.ContactImports;
import io.mailtrap.api.contactlists.ContactLists;
import io.mailtrap.api.contacts.Contacts;
import lombok.Getter;
Expand All @@ -15,4 +16,5 @@
public class MailtrapContactsApi {
private final ContactLists contactLists;
private final Contacts contacts;
private final ContactImports contactImports;
}
8 changes: 5 additions & 3 deletions src/main/java/io/mailtrap/factory/MailtrapClientFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.mailtrap.api.attachments.AttachmentsImpl;
import io.mailtrap.api.billing.BillingImpl;
import io.mailtrap.api.bulkemails.BulkEmailsImpl;
import io.mailtrap.api.contactimports.ContactImportsImpl;
import io.mailtrap.api.contactlists.ContactListsImpl;
import io.mailtrap.api.contacts.ContactsImpl;
import io.mailtrap.api.inboxes.InboxesImpl;
Expand Down Expand Up @@ -43,18 +44,19 @@ public static MailtrapClient createMailtrapClient(MailtrapConfig config) {
final var testingApi = createTestingApi(config, customValidator);
final var bulkSendingApi = createBulkSendingApi(config, customValidator);
final var generalApi = createGeneralApi(config);
final var contactsApi = createContactsApi(config);
final var contactsApi = createContactsApi(config, customValidator);

final var sendingContextHolder = configureSendingContext(config);

return new MailtrapClient(sendingApi, testingApi, bulkSendingApi, generalApi, contactsApi, sendingContextHolder);
}

private static MailtrapContactsApi createContactsApi(MailtrapConfig config) {
private static MailtrapContactsApi createContactsApi(MailtrapConfig config, CustomValidator customValidator) {
final var contactLists = new ContactListsImpl(config);
final var contacts = new ContactsImpl(config);
final var contactImports = new ContactImportsImpl(config, customValidator);

return new MailtrapContactsApi(contactLists, contacts);
return new MailtrapContactsApi(contactLists, contacts, contactImports);
}

private static MailtrapGeneralApi createGeneralApi(MailtrapConfig config) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.mailtrap.model.request.contactimports;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class Contact {

private String email;

private Map<String, Object> fields;

@JsonProperty("list_ids_included")
private List<Long> listIdsIncluded;

@JsonProperty("list_ids_excluded")
private List<Long> listIdsExcluded;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.mailtrap.model.request.contactimports;

import io.mailtrap.model.AbstractModel;
import java.util.List;

import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class ImportContactsRequest extends AbstractModel {

@Size(max = 50_000, message = "Maximum 50000 contacts per request")
private List<Contact> contacts;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.mailtrap.model.response.contactimports;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

public enum ContactImportStatus {
CREATED("created"),
STARTED("started"),
FINISHED("finished"),
FAILED("failed");

private final String value;

ContactImportStatus(String value) {
this.value = value;
}

@JsonValue
public String getValue() {
return value;
}

@JsonCreator
public static ContactImportStatus fromValue(Object value) {
for (ContactImportStatus level : ContactImportStatus.values()) {
if (level.value.equalsIgnoreCase((String) value)) {
return level;
}
}

throw new IllegalArgumentException("Unknown value: " + value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.mailtrap.model.response.contactimports;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class ContactsImportResponse {

private long id;

private ContactImportStatus status;

@JsonProperty("created_contacts_count")
private Long createdContactsCount;

@JsonProperty("updated_contacts_count")
private Long updatedContactsCount;

@JsonProperty("contacts_over_limit_count")
private Long contactsOverLimitCount;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.mailtrap.model.response.contactimports;

import lombok.Data;

@Data
public class CreateContactsImportResponse {

private long id;

private ContactImportStatus status;

}
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ void test_listUserAndInviteAccountAccessesWithProjectIdsQueryParam() {
AccountAccessResponse accountAccessResponse = accountAccessResponses.get(0);
assertEquals(accountAccessResponse.getId(), accountAccessId);
assertEquals(SpecifierType.API_TOKEN, accountAccessResponse.getSpecifierType());
assertEquals(((ApiTokenSpecifier) accountAccessResponse.getSpecifier()).getToken(), "token-value-11-22-33");
assertEquals(accountAccessResponse.getResources().size(), 2);
assertEquals("token-value-11-22-33", ((ApiTokenSpecifier) accountAccessResponse.getSpecifier()).getToken());
assertEquals(2, accountAccessResponse.getResources().size());
assertEquals(accountAccessResponse.getResources().get(0).getResourceId(), projectId);
}

Expand Down
4 changes: 2 additions & 2 deletions src/test/java/io/mailtrap/api/billing/BillingImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void getCurrentBillingCycleUsage() {
BillingResponse billingResponse = api.getCurrentBillingCycleUsage(accountId);

assertNotNull(billingResponse);
assertEquals(billingResponse.getTestingBillingInfo().getPlan().getName(), "Individual");
assertEquals(billingResponse.getSendingBillingInfo().getPlan().getName(), "Basic 10K");
assertEquals("Individual", billingResponse.getTestingBillingInfo().getPlan().getName());
assertEquals("Basic 10K", billingResponse.getSendingBillingInfo().getPlan().getName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.mailtrap.api.contactimports;

import io.mailtrap.Constants;
import io.mailtrap.config.MailtrapConfig;
import io.mailtrap.exception.InvalidRequestBodyException;
import io.mailtrap.factory.MailtrapClientFactory;
import io.mailtrap.model.request.contactimports.Contact;
import io.mailtrap.model.request.contactimports.ImportContactsRequest;
import io.mailtrap.model.response.contactimports.ContactImportStatus;
import io.mailtrap.model.response.contactimports.ContactsImportResponse;
import io.mailtrap.model.response.contactimports.CreateContactsImportResponse;
import io.mailtrap.testutils.BaseTest;
import io.mailtrap.testutils.DataMock;
import io.mailtrap.testutils.TestHttpClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

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

public class ContactImportsImplTest extends BaseTest {

private ContactImports api;

@BeforeEach
public void init() {
TestHttpClient httpClient = new TestHttpClient(List.of(
DataMock.build(Constants.GENERAL_HOST + "/api/accounts/" + accountId + "/contacts/imports",
"POST", "api/contactimports/createContactsImportRequest.json", "api/contactimports/createContactsImportResponse.json"),

DataMock.build(Constants.GENERAL_HOST + "/api/accounts/" + accountId + "/contacts/imports/" + importId,
"GET", null, "api/contactimports/getContactsImportResponse.json")
));

MailtrapConfig testConfig = new MailtrapConfig.Builder()
.httpClient(httpClient)
.token("dummy_token")
.build();

api = MailtrapClientFactory.createMailtrapClient(testConfig).contactsApi().contactImports();
}

@Test
void test_importContacts() {
final var firstContact = new Contact("customer1@example.com", Map.of("full_name", "Jane Doe"), List.of(1L), List.of(2L));
final var secondContact = new Contact("customer2@example.com", Map.of("full_name", "John Doe"), List.of(3L), List.of(4L));
final var request = new ImportContactsRequest(List.of(firstContact, secondContact));

CreateContactsImportResponse contactImportResponse = api.importContacts(accountId, request);

assertEquals(importId, contactImportResponse.getId());
assertSame(ContactImportStatus.STARTED, contactImportResponse.getStatus());
}

@Test
void test_importContacts_should_fail_validation() {
InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> api.importContacts(accountId, new ImportContactsRequest(generateContacts())));

assertEquals("Invalid request body. Violations: contacts=Maximum 50000 contacts per request", exception.getMessage());
}

private List<Contact> generateContacts() {
List<Contact> contacts = new ArrayList<>();

for (int i = 0; i < 50001; i++) {
contacts.add(new Contact("stub_contact_%d@example.com".formatted(i), Map.of(), List.of(), List.of()));
}

return contacts;
}

@Test
void test_getContactImport() {
ContactsImportResponse contactImport = api.getContactImport(accountId, importId);

assertEquals(importId, contactImport.getId());
assertSame(ContactImportStatus.FINISHED, contactImport.getStatus());
assertEquals(1L, contactImport.getCreatedContactsCount());
assertEquals(3L, contactImport.getUpdatedContactsCount());
assertEquals(3L, contactImport.getContactsOverLimitCount());
}
}
Loading