-
Notifications
You must be signed in to change notification settings - Fork 5
Contacts API #49
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
base: main
Are you sure you want to change the base?
Contacts API #49
Changes from all commits
8b2cac6
4471f3f
1f7c59b
01e8b32
159c35b
e99c504
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
require 'mailtrap' | ||
|
||
client = Mailtrap::Client.new(api_key: 'your-api-key') | ||
contact_fields = Mailtrap::ContactFieldsAPI.new 3229, client | ||
|
||
# Set your API credentials as environment variables | ||
# export MAILTRAP_API_KEY='your-api-key' | ||
# export MAILTRAP_ACCOUNT_ID=your-account-id | ||
# | ||
# contact_fields = Mailtrap::ContactFieldsAPI.new | ||
|
||
# Create new contact field | ||
field = contact_fields.create(name: 'Updated name', data_type: 'text', merge_tag: 'updated_name') | ||
|
||
# Get all contact fields | ||
contact_fields.list | ||
|
||
# Update contact field | ||
contact_fields.update(field.id, name: 'Updated name 2', merge_tag: 'updated_name_2') | ||
|
||
# Get contact field | ||
field = contact_fields.get(field.id) | ||
|
||
# Delete contact field | ||
contact_fields.delete(field.id) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
require 'mailtrap' | ||
|
||
client = Mailtrap::Client.new(api_key: 'your-api-key') | ||
contact_list = Mailtrap::ContactListsAPI.new 3229, client | ||
contacts = Mailtrap::ContactsAPI.new 3229, client | ||
|
||
# Set your API credentials as environment variables | ||
# export MAILTRAP_API_KEY='your-api-key' | ||
# export MAILTRAP_ACCOUNT_ID=your-account-id | ||
# | ||
# contact_list = Mailtrap::ContactListsAPI.new | ||
# contacts = Mailtrap::ContactsAPI.new | ||
|
||
# Create new contact list | ||
list = contact_list.create(name: 'Test List') | ||
|
||
# Get all contact lists | ||
contact_list.list | ||
|
||
# Update contact list | ||
contact_list.update(list.id, name: 'Test List Updated') | ||
|
||
# Get contact list | ||
list = contact_list.get(list.id) | ||
|
||
# Create new contact | ||
contact = contacts.create(email: '[email protected]', fields: { first_name: 'John Doe' }, list_ids: [list.id]) | ||
|
||
# Get contact | ||
contact = contacts.get(contact.id) | ||
|
||
# Update contact using id | ||
updated_contact = contacts.update(contact.id, email: '[email protected]', fields: { first_name: 'Jane Doe' }) | ||
|
||
# Update contact using email | ||
contacts.update(updated_contact.data.email, email: '[email protected]', fields: { first_name: 'Jane Doe' }) | ||
|
||
# Remove contact from lists | ||
contacts.remove_from_lists(contact.id, [list.id]) | ||
|
||
# Add contact to lists | ||
contacts.add_to_lists(contact.id, [list.id]) | ||
|
||
# Delete contact | ||
contacts.delete(contact.id) | ||
|
||
# Delete contact list | ||
contact_list.delete(list.id) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# frozen_string_literal: true | ||
|
||
module Mailtrap | ||
module BaseAPI | ||
attr_reader :account_id, :client | ||
|
||
def self.included(base) | ||
base.extend(ClassMethods) | ||
end | ||
|
||
module ClassMethods | ||
def supported_options(options) | ||
@supported_options = options | ||
end | ||
|
||
def get_supported_options # rubocop:disable Naming/AccessorMethodName | ||
@supported_options | ||
end | ||
|
||
def response_class(response_class) | ||
@response_class = response_class | ||
end | ||
|
||
def get_response_class # rubocop:disable Naming/AccessorMethodName | ||
@response_class | ||
end | ||
end | ||
|
||
# @param account_id [Integer] The account ID | ||
# @param client [Mailtrap::Client] The client instance | ||
# @raise [ArgumentError] If account_id is nil | ||
def initialize(account_id = ENV.fetch('MAILTRAP_ACCOUNT_ID'), client = Mailtrap::Client.new) | ||
raise ArgumentError, 'account_id is required' if account_id.nil? | ||
Comment on lines
+29
to
+33
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. 💡 Verification agent 🧩 Analysis chainVerify account_id parameter type consistency The comment indicates 🏁 Script executed: #!/bin/bash
# Description: Check how account_id is used across the codebase
# Check if account_id is used in string interpolation (which would work with both types)
rg -A 2 'account_id' --type ruby
# Check if there are any type conversions for account_id
ast-grep --pattern 'account_id.to_$_' Length of output: 1980 Ensure consistent Currently,
Pick one approach and update 🤖 Prompt for AI Agents
|
||
|
||
@account_id = account_id | ||
@client = client | ||
end | ||
|
||
private | ||
|
||
def supported_options | ||
self.class.get_supported_options | ||
end | ||
|
||
def response_class | ||
self.class.get_response_class | ||
end | ||
|
||
def validate_options!(options, supported_options) | ||
invalid_options = options.keys - supported_options | ||
return if invalid_options.empty? | ||
|
||
raise ArgumentError, "invalid options are given: #{invalid_options}, supported_options: #{supported_options}" | ||
end | ||
|
||
def build_entity(options, response_class) | ||
response_class.new(options.slice(*response_class.members)) | ||
end | ||
|
||
def base_get(id) | ||
response = client.get("#{base_path}/#{id}") | ||
handle_response(response) | ||
end | ||
|
||
def base_create(options, supported_options_override = supported_options) | ||
validate_options!(options, supported_options_override) | ||
response = client.post(base_path, wrap_request(options)) | ||
handle_response(response) | ||
end | ||
|
||
def base_update(id, options, supported_options_override = supported_options) | ||
validate_options!(options, supported_options_override) | ||
response = client.patch("#{base_path}/#{id}", wrap_request(options)) | ||
handle_response(response) | ||
end | ||
|
||
def base_delete(id) | ||
client.delete("#{base_path}/#{id}") | ||
end | ||
|
||
def base_list | ||
response = client.get(base_path) | ||
response.map { |item| handle_response(item) } | ||
end | ||
|
||
def handle_response(response) | ||
build_entity(response, response_class) | ||
end | ||
|
||
def wrap_request(options) | ||
options | ||
end | ||
|
||
def base_path | ||
raise NotImplementedError, 'base_path must be implemented in the including class' | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# frozen_string_literal: true | ||
|
||
module Mailtrap | ||
# Data Transfer Object for Contact | ||
# @see https://api-docs.mailtrap.io/docs/mailtrap-api-docs/220a54e31e5ca-contact | ||
# @attr_reader id [String] The contact ID | ||
# @attr_reader email [String] The contact's email address | ||
# @attr_reader fields [Hash] Object of fields with merge tags | ||
# @attr_reader list_ids [Array<Integer>] Array of list IDs | ||
# @attr_reader status [String] The contact status (subscribed/unsubscribed) | ||
# @attr_reader created_at [Integer] The creation timestamp | ||
# @attr_reader updated_at [Integer] The last update timestamp | ||
Contact = Struct.new( | ||
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. @IgorDobryn if the only motivation for resource classes it to achieve strictness, then we can do this: contact_hash = {id: 1}
contact_hash.default_proc = proc { |_, k| raise "unknown key '#{k}'" } Thoughts? 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. It can work, but rather unexpected. So, I'd prefer to keep separate class |
||
:id, | ||
:email, | ||
:fields, | ||
:list_ids, | ||
:status, | ||
:created_at, | ||
:updated_at, | ||
keyword_init: true | ||
) do | ||
# @return [Hash] The contact attributes as a hash | ||
def to_h | ||
super.compact | ||
end | ||
end | ||
|
||
# Data Transfer Object for Contact Update Response | ||
# @see https://api-docs.mailtrap.io/docs/mailtrap-api-docs/16eab4fff9740-contact-update-response | ||
# @attr_reader action [String] The performed action (created/updated) | ||
# @attr_reader data [Contact, Hash] The contact data | ||
ContactUpdateResponse = Struct.new(:action, :data, keyword_init: true) do | ||
def initialize(*) | ||
super | ||
self.data = Contact.new(data) if data.is_a?(Hash) | ||
end | ||
|
||
# @return [Hash] The response attributes as a hash | ||
def to_h | ||
super.compact | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# frozen_string_literal: true | ||
|
||
module Mailtrap | ||
# Data Transfer Object for Contact Field | ||
# @see https://api-docs.mailtrap.io/docs/mailtrap-api-docs/33efe96c91dcc-get-all-contact-fields | ||
# @attr_reader id [Integer] The contact field ID | ||
# @attr_reader name [String] The name of the contact field (max 80 characters) | ||
# @attr_reader data_type [String] The data type of the field | ||
# Allowed values: text, integer, float, boolean, date | ||
# @attr_reader merge_tag [String] Personalize your campaigns by adding a merge tag. | ||
# This field will be replaced with unique contact details for each recipient (max 80 characters) | ||
ContactField = Struct.new(:id, :name, :data_type, :merge_tag, keyword_init: true) do | ||
# @return [Hash] The contact field attributes as a hash | ||
def to_h | ||
super.compact | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative 'contact_field' | ||
|
||
module Mailtrap | ||
class ContactFieldsAPI | ||
include BaseAPI | ||
|
||
supported_options %i[name data_type merge_tag] | ||
|
||
response_class ContactField | ||
|
||
# Retrieves a specific contact field | ||
# @param field_id [Integer] The contact field identifier | ||
# @return [ContactField] Contact field object | ||
# @!macro api_errors | ||
def get(field_id) | ||
base_get(field_id) | ||
end | ||
|
||
# Creates a new contact field | ||
# @param [Hash] options The parameters to create | ||
# @option options [String] :name The contact field name | ||
# @option options [String] :data_type The data type of the field | ||
# @option options [String] :merge_tag The merge tag of the field | ||
# @return [ContactField] Created contact field object | ||
# @!macro api_errors | ||
# @raise [ArgumentError] If invalid options are provided | ||
def create(options) | ||
base_create(options) | ||
end | ||
|
||
# Updates an existing contact field | ||
# @param field_id [Integer] The contact field ID | ||
# @param [Hash] options The parameters to update | ||
# @option options [String] :name The contact field name | ||
# @option options [String] :merge_tag The merge tag of the field | ||
# @return [ContactField] Updated contact field object | ||
# @!macro api_errors | ||
# @raise [ArgumentError] If invalid options are provided | ||
def update(field_id, options) | ||
base_update(field_id, options, %i[name merge_tag]) | ||
end | ||
|
||
# Deletes a contact field | ||
# @param field_id [Integer] The contact field ID | ||
# @return nil | ||
# @!macro api_errors | ||
def delete(field_id) | ||
base_delete(field_id) | ||
end | ||
|
||
# Lists all contact fields for the account | ||
# @return [Array<ContactField>] Array of contact field objects | ||
# @!macro api_errors | ||
def list | ||
base_list | ||
end | ||
|
||
private | ||
|
||
def base_path | ||
"/api/accounts/#{account_id}/contacts/fields" | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# frozen_string_literal: true | ||
|
||
module Mailtrap | ||
# Data Transfer Object for Contact List | ||
# @see https://api-docs.mailtrap.io/docs/mailtrap-api-docs/6ec7a37234af2-contact-list | ||
# @attr_reader id [Integer] The contact list ID | ||
# @attr_reader name [String] The name of the contact list | ||
ContactList = Struct.new(:id, :name, keyword_init: true) do | ||
# @return [Hash] The contact list attributes as a hash | ||
def to_h | ||
super.compact | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative 'contact_list' | ||
|
||
module Mailtrap | ||
class ContactListsAPI | ||
include BaseAPI | ||
|
||
supported_options %i[name] | ||
|
||
response_class ContactList | ||
|
||
# Retrieves a specific contact list | ||
# @param list_id [Integer] The contact list identifier | ||
# @return [ContactList] Contact list object | ||
# @!macro api_errors | ||
def get(list_id) | ||
base_get(list_id) | ||
end | ||
|
||
# Creates a new contact list | ||
# @param [Hash] options The parameters to create | ||
# @option options [String] :name The contact list name | ||
# @return [ContactList] Created contact list object | ||
# @!macro api_errors | ||
# @raise [ArgumentError] If invalid options are provided | ||
def create(options) | ||
base_create(options) | ||
end | ||
|
||
# Updates an existing contact list | ||
# @param list_id [Integer] The contact list ID | ||
# @param [Hash] options The parameters to update | ||
# @option options [String] :name The contact list name | ||
# @return [ContactList] Updated contact list object | ||
# @!macro api_errors | ||
# @raise [ArgumentError] If invalid options are provided | ||
def update(list_id, options) | ||
base_update(list_id, options) | ||
end | ||
|
||
# Deletes a contact list | ||
# @param list_id [Integer] The contact list ID | ||
# @return nil | ||
# @!macro api_errors | ||
def delete(list_id) | ||
base_delete(list_id) | ||
end | ||
|
||
# Lists all contact lists for the account | ||
# @return [Array<ContactList>] Array of contact list objects | ||
# @!macro api_errors | ||
def list | ||
base_list | ||
end | ||
|
||
private | ||
|
||
def base_path | ||
"/api/accounts/#{account_id}/contacts/lists" | ||
end | ||
end | ||
end |
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.
Remove unnecessary RuboCop disables
The RuboCop disables for
Naming/AccessorMethodName
are unnecessary and should be removed.Also applies to: 24-26
🧰 Tools
🪛 RuboCop (1.75.5)
[warning] 16-16: Unnecessary disabling of
Naming/AccessorMethodName
.(Lint/RedundantCopDisableDirective)
🤖 Prompt for AI Agents