-
Notifications
You must be signed in to change notification settings - Fork 7
added ContactImportAPI #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sarco3t
wants to merge
4
commits into
railsware:main
Choose a base branch
from
sarco3t:contact-imports-api
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
contact_lists = Mailtrap::ContactListsAPI.new 3229, client | ||
contacts = Mailtrap::ContactsAPI.new 3229, client | ||
contact_fields = Mailtrap::ContactFieldsAPI.new 3229, client | ||
contact_imports = Mailtrap::ContactImportsAPI.new 3229, client | ||
|
||
# Set your API credentials as environment variables | ||
# export MAILTRAP_API_KEY='your-api-key' | ||
|
@@ -12,6 +13,7 @@ | |
# contact_lists = Mailtrap::ContactListsAPI.new | ||
# contacts = Mailtrap::ContactsAPI.new | ||
# contact_fields = Mailtrap::ContactFieldsAPI.new | ||
# contact_imports = Mailtrap::ContactImportsAPI.new | ||
|
||
# Create new contact list | ||
list = contact_lists.create(name: 'Test List') | ||
|
@@ -135,8 +137,97 @@ | |
# Delete contact | ||
contacts.delete(contact.id) | ||
|
||
# Delete contact list | ||
contact_lists.delete(list.id) | ||
|
||
# Delete contact field | ||
contact_fields.delete(field.id) | ||
|
||
# Create a new contact import | ||
contact_import = contact_imports.create( | ||
[ | ||
{ | ||
email: 'imported@example.com', | ||
fields: { | ||
first_name: 'Jane', | ||
}, | ||
list_ids_included: [list.id], | ||
list_ids_excluded: [] | ||
} | ||
] | ||
) | ||
# => ContactImport.new( | ||
# id: 1, | ||
# status: 'created', | ||
# list_ids: [1], | ||
# created_contacts_count: 1, | ||
# updated_contacts_count: 0, | ||
# contacts_over_limit_count: 0 | ||
# ) | ||
|
||
# Get a contact import by ID | ||
contact_imports.get(contact_import.id) | ||
# => ContactImport.new( | ||
# id: 1, | ||
# status: 'started', | ||
# list_ids: [1], | ||
# created_contacts_count: 1, | ||
# updated_contacts_count: 0, | ||
# contacts_over_limit_count: 0 | ||
# ) | ||
|
||
# Create a new contact import using ContactsImportRequest builder | ||
import_request = Mailtrap::ContactsImportRequest.new | ||
|
||
# Add contacts using the builder pattern | ||
import_request | ||
.upsert( | ||
email: 'john.doe@example.com', | ||
fields: { first_name: 'John' } | ||
) | ||
.add_to_lists(email: 'john.doe@example.com', list_ids: [list.id]) | ||
.upsert( | ||
email: 'jane.smith@example.com', | ||
fields: { first_name: 'Jane' } | ||
) | ||
.add_to_lists(email: 'jane.smith@example.com', list_ids: [list.id]) | ||
.remove_from_lists(email: 'jane.smith@example.com', list_ids: []) | ||
|
||
# Execute the import | ||
contact_imports.create(import_request) | ||
# => ContactImport.new( | ||
# id: 2, | ||
# status: 'created', | ||
# list_ids: [1], | ||
# created_contacts_count: 2, | ||
# updated_contacts_count: 0, | ||
# contacts_over_limit_count: 0 | ||
# ) | ||
|
||
# Alternative: Step-by-step building | ||
builder = Mailtrap::ContactsImportRequest.new | ||
builder.upsert(email: 'jane.doe@example.com', fields: { first_name: 'Jane' }) | ||
builder.add_to_lists(email: 'jane.doe@example.com', list_ids: [list.id]) | ||
|
||
contact_import_2 = contact_imports.create(builder) | ||
# => ContactImport.new( | ||
# id: 3, | ||
# status: 'created', | ||
# list_ids: [1], | ||
# created_contacts_count: 1, | ||
# updated_contacts_count: 0, | ||
# contacts_over_limit_count: 0 | ||
# ) | ||
|
||
sleep 3 # Wait for the import to complete (if needed) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove hardcoded sleep from production example. The -sleep 3 # Wait for the import to complete (if needed)
+# In production, consider polling the import status instead of sleeping
+# loop do
+# import_status = contact_imports.get(contact_import_2.id)
+# break if %w[completed failed].include?(import_status.status)
+# sleep 1
+# end 🤖 Prompt for AI Agents
|
||
|
||
# Get the import status | ||
contact_imports.get(contact_import_2.id) | ||
# => ContactImport.new( | ||
# id: 3, | ||
# status: 'completed', | ||
# list_ids: [1], | ||
# created_contacts_count: 1, | ||
# updated_contacts_count: 0, | ||
# contacts_over_limit_count: 0 | ||
# ) | ||
|
||
# Delete contact list | ||
contact_lists.delete(list.id) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# frozen_string_literal: true | ||
|
||
module Mailtrap | ||
# Data Transfer Object for Contact Import | ||
# @attr_reader id [String] The contact import ID | ||
# @attr_reader status [String] The status of the import (created, started, finished, failed) | ||
# @attr_reader created_contacts_count [Integer, nil] Number of contacts created in this import | ||
# @attr_reader updated_contacts_count [Integer, nil] Number of contacts updated in this import | ||
# @attr_reader contacts_over_limit_count [Integer, nil] Number of contacts over the allowed limit | ||
ContactImport = Struct.new( | ||
:id, | ||
:status, | ||
:created_contacts_count, | ||
:updated_contacts_count, | ||
:contacts_over_limit_count, | ||
keyword_init: true | ||
) do | ||
# @return [Hash] The contact attributes as a hash | ||
def to_h | ||
super.compact | ||
end | ||
end | ||
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative 'contact_import' | ||
require_relative 'contacts_import_request' | ||
|
||
module Mailtrap | ||
class ContactImportsAPI | ||
include BaseAPI | ||
|
||
self.supported_options = %i[email fields list_ids_included list_ids_excluded] | ||
|
||
self.response_class = ContactImport | ||
|
||
# Retrieves a specific contact import | ||
# @param import_id [String] The contact import identifier | ||
# @return [ContactImport] Contact import object | ||
# @!macro api_errors | ||
def get(import_id) | ||
base_get(import_id) | ||
end | ||
|
||
# Create contacts import | ||
# @param contacts [Array<Hash>, ContactsImportRequest, #to_a] Any object that responds to #to_a and returns an array of contact hashes. # rubocop:disable Layout/LineLength | ||
# Accepts Array<Hash>, ContactsImportRequest, or any other object implementing #to_a | ||
# When using Array<Hash>, each contact object should have the following keys: | ||
# - email [String] The contact's email address | ||
# - fields [Hash] Object of fields in the format: field_merge_tag => String, Integer, Float, Boolean, or ISO-8601 date string (yyyy-mm-dd) # rubocop:disable Layout/LineLength | ||
# - list_ids_included [Array<Integer>] List IDs to include the contact in | ||
# - list_ids_excluded [Array<Integer>] List IDs to exclude the contact from | ||
# @return [ContactImport] Created contact list object | ||
# @!macro api_errors | ||
# @raise [ArgumentError] If invalid options are provided | ||
def create(contacts) | ||
contact_data = contacts.to_a | ||
contact_data.each do |contact| | ||
validate_options!(contact, supported_options) | ||
end | ||
response = client.post(base_path, contacts: contact_data) | ||
handle_response(response) | ||
end | ||
alias start create | ||
|
||
private | ||
|
||
def base_path | ||
"/api/accounts/#{account_id}/contacts/imports" | ||
end | ||
end | ||
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# frozen_string_literal: true | ||
|
||
module Mailtrap | ||
# A builder class for creating contact import requests | ||
# Allows you to build a collection of contacts with their associated fields and list memberships | ||
class ContactsImportRequest | ||
def initialize | ||
@data = {} | ||
end | ||
|
||
# Creates or updates a contact with the provided email and fields | ||
# @param email [String] The contact's email address | ||
# @param fields [Hash] Contact fields in the format: field_merge_tag => String, Integer, Float, Boolean, or ISO-8601 date string (yyyy-mm-dd) # rubocop:disable Layout/LineLength | ||
# @return [ContactsImportRequest] Returns self for method chaining | ||
def upsert(email:, fields: {}) | ||
unless @data[email] | ||
@data[email] = { email:, fields:, list_ids_included: [], list_ids_excluded: [] } | ||
return self | ||
end | ||
|
||
@data[email][:fields].merge!(fields) | ||
|
||
self | ||
end | ||
|
||
# Adds a contact to the specified lists | ||
# @param email [String] The contact's email address | ||
# @param list_ids [Array<Integer>] Array of list IDs to add the contact to | ||
# @return [ContactsImportRequest] Returns self for method chaining | ||
def add_to_lists(email:, list_ids:) | ||
unless @data[email] | ||
@data[email] = { email:, fields: {}, list_ids_included: list_ids, list_ids_excluded: [] } | ||
return self | ||
end | ||
|
||
@data[email][:list_ids_included] |= list_ids | ||
|
||
self | ||
end | ||
|
||
# Removes a contact from the specified lists | ||
# @param email [String] The contact's email address | ||
# @param list_ids [Array<Integer>] Array of list IDs to remove the contact from | ||
# @return [ContactsImportRequest] Returns self for method chaining | ||
def remove_from_lists(email:, list_ids:) | ||
unless @data[email] | ||
@data[email] = { email:, fields: {}, list_ids_included: [], list_ids_excluded: list_ids } | ||
return self | ||
end | ||
|
||
@data[email][:list_ids_excluded] |= list_ids | ||
|
||
self | ||
end | ||
|
||
# Converts the import request to a JSON-serializable array | ||
# @return [Array<Hash>] Array of contact objects ready for import | ||
def as_json | ||
@data.values | ||
end | ||
alias to_a as_json | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is not elegant and exposes the confusing underlying API. Instead I suggest this:
@IgorDobryn thoughts?