emailhunter 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+ require 'ostruct'
6
+
7
+ module EmailHunter
8
+ class Campaigns
9
+ API_URL = 'https://api.hunter.io/v2/campaigns'
10
+
11
+ attr_reader :key, :params, :action, :campaign_id, :data
12
+
13
+ def initialize(key, action: :list, campaign_id: nil, data: nil, params: {})
14
+ @key = key
15
+ @action = action
16
+ @campaign_id = campaign_id
17
+ @data = data
18
+ @params = params
19
+ end
20
+
21
+ def hunt
22
+ case action
23
+ when :list
24
+ list_campaigns
25
+ when :recipients
26
+ list_recipients
27
+ when :add_recipient
28
+ add_recipient
29
+ when :delete_recipient
30
+ delete_recipient
31
+ else
32
+ raise ArgumentError, "Unknown action: #{action}"
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def list_campaigns
39
+ response_data = fetch_campaigns_data
40
+ return nil if response_data.empty?
41
+
42
+ # Convert to OpenStruct for easy access
43
+ result = OpenStruct.new(response_data)
44
+
45
+ # Convert campaigns array to OpenStruct objects if it exists
46
+ if result.data.is_a?(Hash) && result.data[:campaigns].is_a?(Array)
47
+ campaigns_array = result.data[:campaigns].map { |c| OpenStruct.new(c) }
48
+ result.data = OpenStruct.new(result.data.merge(campaigns: campaigns_array))
49
+ elsif result.data.is_a?(OpenStruct) && result.data.campaigns.is_a?(Array)
50
+ result.data.campaigns = result.data.campaigns.map { |c| OpenStruct.new(c) }
51
+ end
52
+
53
+ result
54
+ end
55
+
56
+ def list_recipients
57
+ response_data = fetch_recipients_data
58
+ return nil if response_data.empty?
59
+
60
+ result = OpenStruct.new(response_data)
61
+
62
+ # Convert recipients array to OpenStruct objects if it exists
63
+ if result.data.is_a?(Hash) && result.data[:recipients].is_a?(Array)
64
+ recipients_array = result.data[:recipients].map { |r| OpenStruct.new(r) }
65
+ result.data = OpenStruct.new(result.data.merge(recipients: recipients_array))
66
+ elsif result.data.is_a?(OpenStruct) && result.data.recipients.is_a?(Array)
67
+ result.data.recipients = result.data.recipients.map { |r| OpenStruct.new(r) }
68
+ end
69
+
70
+ result
71
+ end
72
+
73
+ def add_recipient
74
+ response_data = post_recipient_data
75
+ return nil if response_data.empty?
76
+
77
+ OpenStruct.new(response_data)
78
+ end
79
+
80
+ def delete_recipient
81
+ response = delete_recipient_data
82
+ response.success?
83
+ end
84
+
85
+ def fetch_campaigns_data
86
+ connection = Faraday.new
87
+ request_params = {
88
+ api_key: key,
89
+ limit: params.fetch(:limit, 20),
90
+ offset: params.fetch(:offset, 0)
91
+ }
92
+
93
+ response = connection.get(API_URL, request_params)
94
+
95
+ return {} unless response.success?
96
+
97
+ JSON.parse(response.body, symbolize_names: true)
98
+ end
99
+
100
+ def fetch_recipients_data
101
+ connection = Faraday.new
102
+ url = "#{API_URL}/#{campaign_id}/recipients"
103
+ request_params = {
104
+ api_key: key,
105
+ limit: params.fetch(:limit, 20),
106
+ offset: params.fetch(:offset, 0)
107
+ }
108
+
109
+ response = connection.get(url, request_params)
110
+
111
+ return {} unless response.success?
112
+
113
+ JSON.parse(response.body, symbolize_names: true)
114
+ end
115
+
116
+ def post_recipient_data
117
+ connection = Faraday.new
118
+ url = "#{API_URL}/#{campaign_id}/recipients"
119
+ request_data = data.merge(api_key: key)
120
+
121
+ response = connection.post(url) do |req|
122
+ req.headers['Content-Type'] = 'application/json'
123
+ req.body = request_data.to_json
124
+ end
125
+
126
+ return {} unless response.success?
127
+
128
+ JSON.parse(response.body, symbolize_names: true)
129
+ end
130
+
131
+ def delete_recipient_data
132
+ connection = Faraday.new
133
+ email = data[:email]
134
+ url = "#{API_URL}/#{campaign_id}/recipients/#{email}"
135
+
136
+ connection.delete(url, api_key: key)
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+ require_relative 'lead_enrichment'
5
+ require_relative 'company_enrichment'
6
+
7
+ module EmailHunter
8
+ class CombinedEnrichment
9
+ attr_reader :key, :email, :linkedin
10
+
11
+ def initialize(key, email: nil, linkedin: nil)
12
+ @key = key
13
+ @email = email
14
+ @linkedin = linkedin
15
+
16
+ raise ArgumentError, 'Either email or linkedin must be provided' if email.nil? && linkedin.nil?
17
+ end
18
+
19
+ def hunt
20
+ # First get lead enrichment data
21
+ lead_data = LeadEnrichment.new(key, email: email, linkedin: linkedin).hunt
22
+ return nil if lead_data.nil?
23
+
24
+ # Extract domain from employment if available
25
+ domain = lead_data.data.employment&.domain
26
+ return lead_data if domain.nil?
27
+
28
+ # Get company enrichment data
29
+ company_data = CompanyEnrichment.new(domain, key).hunt
30
+
31
+ # Combine the data
32
+ OpenStruct.new(
33
+ lead: lead_data,
34
+ company: company_data,
35
+ meta: OpenStruct.new(
36
+ email: email,
37
+ linkedin: linkedin,
38
+ domain: domain
39
+ )
40
+ )
41
+ rescue StandardError => e
42
+ # If company enrichment fails, just return lead data
43
+ OpenStruct.new(
44
+ lead: lead_data,
45
+ company: nil,
46
+ meta: OpenStruct.new(
47
+ email: email,
48
+ linkedin: linkedin,
49
+ error: e.message
50
+ )
51
+ )
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+ require 'ostruct'
6
+
7
+ module EmailHunter
8
+ class Company
9
+ API_URL = 'https://api.hunter.io/v2/companies/find'
10
+
11
+ attr_reader :domain, :key
12
+
13
+ def initialize(domain, key)
14
+ @domain = domain
15
+ @key = key
16
+ end
17
+
18
+ def hunt
19
+ response_data = fetch_company_data
20
+ return nil if response_data.empty?
21
+
22
+ # Convert nested data structure to a Struct
23
+ data = response_data[:data]
24
+ meta = response_data[:meta]
25
+
26
+ result = OpenStruct.new(
27
+ data: OpenStruct.new(data),
28
+ meta: OpenStruct.new(meta)
29
+ )
30
+
31
+ # Recursively convert nested hashes to OpenStructs for deeper access
32
+ convert_hash_to_struct(result.data, data)
33
+
34
+ result
35
+ end
36
+
37
+ private
38
+
39
+ def fetch_company_data
40
+ @fetch_company_data ||= begin
41
+ connection = Faraday.new
42
+ response = connection.get(API_URL, domain: domain, api_key: key)
43
+
44
+ return {} unless response.success?
45
+
46
+ JSON.parse(response.body, symbolize_names: true)
47
+ end
48
+ end
49
+
50
+ def convert_hash_to_struct(struct, hash)
51
+ hash.each do |key, value|
52
+ if value.is_a?(Hash)
53
+ struct[key] = OpenStruct.new(value)
54
+ convert_hash_to_struct(struct[key], value)
55
+ elsif value.is_a?(Array) && value.first.is_a?(Hash)
56
+ struct[key] = value.map { |item| OpenStruct.new(item) }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+ require 'ostruct'
6
+
7
+ module EmailHunter
8
+ class CompanyEnrichment
9
+ API_URL = 'https://api.hunter.io/v2/companies/find'
10
+
11
+ attr_reader :domain, :key
12
+
13
+ def initialize(domain, key)
14
+ @domain = domain
15
+ @key = key
16
+ end
17
+
18
+ def hunt
19
+ response_data = fetch_enrichment_data
20
+ return nil if response_data.empty?
21
+
22
+ # Convert nested data structure to OpenStruct
23
+ data = response_data[:data]
24
+ meta = response_data[:meta]
25
+
26
+ result = OpenStruct.new(
27
+ data: OpenStruct.new(data),
28
+ meta: OpenStruct.new(meta)
29
+ )
30
+
31
+ # Recursively convert nested hashes to OpenStructs for deeper access
32
+ convert_hash_to_struct(result.data, data)
33
+
34
+ result
35
+ end
36
+
37
+ private
38
+
39
+ def fetch_enrichment_data
40
+ @fetch_enrichment_data ||= begin
41
+ connection = Faraday.new
42
+ response = connection.get(API_URL, domain: domain, api_key: key)
43
+
44
+ return {} unless response.success?
45
+
46
+ JSON.parse(response.body, symbolize_names: true)
47
+ end
48
+ end
49
+
50
+ def convert_hash_to_struct(struct, hash)
51
+ hash.each do |key, value|
52
+ if value.is_a?(Hash)
53
+ struct[key] = OpenStruct.new(value)
54
+ convert_hash_to_struct(struct[key], value)
55
+ elsif value.is_a?(Array) && value.first.is_a?(Hash)
56
+ struct[key] = value.map { |item| OpenStruct.new(item) }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,27 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
  require 'json'
3
5
 
4
- API_COUNT_URL = 'https://api.hunter.io/v2/email-count?'.freeze
5
-
6
6
  module EmailHunter
7
7
  class Count
8
- attr_reader :data, :meta, :domain
8
+ API_URL = 'https://api.hunter.io/v2/email-count'
9
+
10
+ attr_reader :domain
9
11
 
10
12
  def initialize(domain)
11
13
  @domain = domain
12
14
  end
13
15
 
14
16
  def hunt
15
- Struct.new(*data.keys).new(*data.values)
17
+ response_data = fetch_count_data
18
+ return nil if response_data.empty?
19
+
20
+ Struct.new(*response_data.keys).new(*response_data.values)
16
21
  end
17
22
 
18
- def apiresponse
19
- @data ||= begin
20
- response = Faraday.new("#{API_COUNT_URL}domain=#{domain}").get
23
+ private
24
+
25
+ def fetch_count_data
26
+ @fetch_count_data ||= begin
27
+ connection = Faraday.new
28
+ response = connection.get(API_URL, domain: domain)
21
29
 
22
- return [] unless response.success?
30
+ return {} unless response.success?
23
31
 
24
- JSON.parse(response.body, { symbolize_names: true })
32
+ JSON.parse(response.body, symbolize_names: true)
25
33
  end
26
34
  end
27
35
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ module EmailHunter
7
+ class Discover
8
+ API_URL = 'https://api.hunter.io/v2/discover'
9
+
10
+ attr_reader :query, :key, :params
11
+
12
+ def initialize(query, key, params = {})
13
+ @query = query
14
+ @key = key
15
+ @params = params
16
+ end
17
+
18
+ def hunt
19
+ response_data = fetch_discover_data
20
+ return nil if response_data.empty?
21
+
22
+ # Convert to OpenStruct for easy access
23
+ result = OpenStruct.new(response_data)
24
+
25
+ # Recursively convert nested hashes to OpenStructs
26
+ convert_hash_to_struct(result, response_data)
27
+
28
+ result
29
+ end
30
+
31
+ private
32
+
33
+ def convert_hash_to_struct(struct, hash)
34
+ hash.each do |key, value|
35
+ if value.is_a?(Hash)
36
+ struct[key] = OpenStruct.new(value)
37
+ convert_hash_to_struct(struct[key], value)
38
+ elsif value.is_a?(Array) && value.first.is_a?(Hash)
39
+ struct[key] = value.map { |item| OpenStruct.new(item) }
40
+ end
41
+ end
42
+ end
43
+
44
+ def limit
45
+ params.fetch(:limit, 100).to_i
46
+ end
47
+
48
+ def offset
49
+ params.fetch(:offset, 0).to_i
50
+ end
51
+
52
+ def filters
53
+ params.fetch(:filters, {})
54
+ end
55
+
56
+ def fetch_discover_data
57
+ @fetch_discover_data ||= begin
58
+ connection = Faraday.new
59
+ request_data = {
60
+ query: query,
61
+ api_key: key,
62
+ limit: limit,
63
+ offset: offset
64
+ }
65
+
66
+ # Add filters if provided
67
+ request_data[:filters] = filters unless filters.empty?
68
+
69
+ response = connection.post(API_URL) do |req|
70
+ req.headers['Content-Type'] = 'application/json'
71
+ req.body = request_data.to_json
72
+ end
73
+
74
+ return {} unless response.success?
75
+
76
+ JSON.parse(response.body, symbolize_names: true)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -3,11 +3,11 @@
3
3
  require 'faraday'
4
4
  require 'json'
5
5
 
6
- API_EXIST_URL = 'https://api.emailhunter.co/v1/exist?'
7
-
8
6
  module EmailHunter
9
7
  class Exist
10
- attr_reader :status, :email, :exist, :sources, :key
8
+ API_URL = 'https://api.emailhunter.co/v1/exist'
9
+
10
+ attr_reader :email, :key
11
11
 
12
12
  def initialize(email, key)
13
13
  @email = email
@@ -15,16 +15,22 @@ module EmailHunter
15
15
  end
16
16
 
17
17
  def hunt
18
- Struct.new(*data.keys).new(*data.values)
18
+ response_data = fetch_exist_data
19
+ return nil if response_data.empty?
20
+
21
+ Struct.new(*response_data.keys).new(*response_data.values)
19
22
  end
20
23
 
21
- def data
22
- @data ||= begin
23
- response = Faraday.new("#{API_EXIST_URL}email=#{email}&api_key=#{key}").get
24
+ private
25
+
26
+ def fetch_exist_data
27
+ @fetch_exist_data ||= begin
28
+ connection = Faraday.new
29
+ response = connection.get(API_URL, email: email, api_key: key)
24
30
 
25
31
  return {} unless response.success?
26
32
 
27
- JSON.parse(response.body, { symbolize_names: true })
33
+ JSON.parse(response.body, symbolize_names: true)
28
34
  end
29
35
  end
30
36
  end
@@ -3,10 +3,10 @@
3
3
  require 'faraday'
4
4
  require 'json'
5
5
 
6
- API_FINDER_URL = 'https://api.hunter.io/v2/email-finder?'
7
-
8
6
  module EmailHunter
9
7
  class Finder
8
+ API_FINDER_URL = 'https://api.hunter.io/v2/email-finder'
9
+
10
10
  attr_reader :email, :score, :sources, :domain, :meta, :key, :first_name, :last_name
11
11
 
12
12
  def initialize(domain, first_name, last_name, key)
@@ -22,12 +22,26 @@ module EmailHunter
22
22
 
23
23
  def data
24
24
  @data ||= begin
25
- response = Faraday.new("#{API_FINDER_URL}domain=#{domain}&first_name=#{first_name}&last_name=#{last_name}&api_key=#{key}").get
25
+ response = fetch_finder_data
26
26
 
27
- return [] unless response.success?
27
+ return {} unless response.success?
28
28
 
29
- JSON.parse(response.body, { symbolize_names: true })
29
+ JSON.parse(response.body, symbolize_names: true)
30
30
  end
31
31
  end
32
+
33
+ private
34
+
35
+ def fetch_finder_data
36
+ connection = Faraday.new
37
+ params = {
38
+ domain: domain,
39
+ first_name: first_name,
40
+ last_name: last_name,
41
+ api_key: key
42
+ }
43
+
44
+ connection.get(API_FINDER_URL, params)
45
+ end
32
46
  end
33
47
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+ require 'ostruct'
6
+
7
+ module EmailHunter
8
+ class LeadEnrichment
9
+ API_URL = 'https://api.hunter.io/v2/people/find'
10
+
11
+ attr_reader :key, :email, :linkedin
12
+
13
+ def initialize(key, email: nil, linkedin: nil)
14
+ @key = key
15
+ @email = email
16
+ @linkedin = linkedin
17
+
18
+ raise ArgumentError, 'Either email or linkedin must be provided' if email.nil? && linkedin.nil?
19
+ end
20
+
21
+ def hunt
22
+ response_data = fetch_enrichment_data
23
+ return nil if response_data.empty?
24
+
25
+ # Convert nested data structure to OpenStruct
26
+ data = response_data[:data]
27
+ meta = response_data[:meta]
28
+
29
+ result = OpenStruct.new(
30
+ data: OpenStruct.new(data),
31
+ meta: OpenStruct.new(meta)
32
+ )
33
+
34
+ # Recursively convert nested hashes to OpenStructs for deeper access
35
+ convert_hash_to_struct(result.data, data)
36
+
37
+ result
38
+ end
39
+
40
+ private
41
+
42
+ def fetch_enrichment_data
43
+ @fetch_enrichment_data ||= begin
44
+ connection = Faraday.new
45
+ request_params = { api_key: key }
46
+
47
+ request_params[:email] = email if email
48
+ request_params[:linkedin_handle] = linkedin if linkedin
49
+
50
+ response = connection.get(API_URL, request_params)
51
+
52
+ return {} unless response.success?
53
+
54
+ JSON.parse(response.body, symbolize_names: true)
55
+ end
56
+ end
57
+
58
+ def convert_hash_to_struct(struct, hash)
59
+ hash.each do |key, value|
60
+ if value.is_a?(Hash)
61
+ struct[key] = OpenStruct.new(value)
62
+ convert_hash_to_struct(struct[key], value)
63
+ elsif value.is_a?(Array) && value.first.is_a?(Hash)
64
+ struct[key] = value.map { |item| OpenStruct.new(item) }
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end