snov 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aec74bea1292e576ef497f2250c1833593742504c74834d05749bb8efdb88884
4
- data.tar.gz: b85b04071c54d309c0dfa22c9b5c77e3a2273b4d370f0449e0b4952c2b295f6c
3
+ metadata.gz: 515392f915f68b6e2215b9d83b0669754972c869bf0760c2183801dba20ee97e
4
+ data.tar.gz: d070e267fe2bd7cfa737e06abce73affef3fd1a05b058ed4131a2c5b83025813
5
5
  SHA512:
6
- metadata.gz: 0a509e0cdf66cb198c734a94fd81ef667506a4f96686b6d7c1e5720f4b26ba5389812894201bc11cc2b537bd45cc02d92ab4d1d9bf2f7856cc63c22077de6153
7
- data.tar.gz: cc4f5022bca9c9f8e3a2fca2a04bc1b8435e4d6afbc3dd568fabce50168fdbca1dafa5397894dd63e899e564bbf66375fda450f64d6112505124435645342c2a
6
+ metadata.gz: a63119f42ed545a522e3a98783919a2b8b4aa24ff39ab660d7883f8064c8d09aa32bd6dd99add703a11c94341c4468e0169167fbd72b14480c3ed00ffbff6447
7
+ data.tar.gz: 65043cedd80d3cac9730b0251b391569770ec8c6700a2c434a35967dba3f3694793f8b7ff5fe279dd93584086f018b19d64d56f9d64fbb89ec64916e810e1593
data/.gitignore CHANGED
@@ -10,4 +10,5 @@
10
10
  /.rspec_status
11
11
  /gems.locked
12
12
  /vendor/bundle
13
- /.vscode
13
+ /.vscode
14
+ /spec/snov/moved
@@ -1,3 +1,18 @@
1
+ ## [0.3.0]
2
+ * add Faraday response into exception
3
+ * fake client to only return success result for selected queries
4
+
5
+ ## [0.2.4]
6
+ * Fix DomainSearch to_a
7
+
8
+ ## [0.2.3]
9
+ * Fix DomainSearch doing post instead of get
10
+ ## [0.2.2]
11
+ * DomainSearch Response class
12
+
13
+ ## [0.2.1]
14
+ * DomainSearch fake example data
15
+
1
16
  ## [0.2.0]
2
17
  * DomainSearch
3
18
 
data/README.md CHANGED
@@ -26,7 +26,7 @@ see https://snov.io/api#DomainSearch2
26
26
 
27
27
  ```ruby
28
28
  results = Snov::DomainSearch.new(domain: "octagon.com", type: "personal", limit: 10)
29
- results.lastId
29
+ results.last_id
30
30
  results.each do |result|
31
31
  puts result.email
32
32
  puts result.first_name
data/gems.rb CHANGED
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  # Specify your gem's dependencies in snov.gemspec
4
4
  gemspec
5
5
 
6
+ gem "byebug"
6
7
  gem "rake", "~> 12.0"
7
8
  gem "rspec", "~> 3.0"
8
9
  gem "rubocop"
@@ -7,19 +7,29 @@ module Snov
7
7
 
8
8
  class TimedOut < SnovError; end
9
9
 
10
- class UnauthorizedError < SnovError; end
10
+ class AuthError < SnovError; end
11
11
 
12
- class BadGatewayError < SnovError; end
12
+ class ResponseError < SnovError
13
+ attr_reader :response
13
14
 
14
- class ForbiddenError < SnovError; end
15
+ def initialize(message, response: nil)
16
+ super(message)
17
+ @response = response
18
+ end
19
+ end
15
20
 
16
- class GatewayTimeOut < SnovError; end
21
+ class UnauthorizedError < ResponseError; end
17
22
 
18
- class BadRequest < SnovError; end
23
+ class BadGatewayError < ResponseError; end
19
24
 
20
- class AuthError < SnovError; end
25
+ class ForbiddenError < ResponseError; end
26
+
27
+ class GatewayTimeOut < ResponseError; end
28
+
29
+ class BadRequest < ResponseError; end
30
+
31
+ class MethodNotAllowed < ResponseError; end
21
32
 
22
- class MethodNotAllowed < SnovError; end
23
33
  ERROR_CLASSES = { 401 => UnauthorizedError, 502 => BadGatewayError, 403 => ForbiddenError,
24
34
  504 => GatewayTimeOut, 400 => BadRequest, 405 => MethodNotAllowed }
25
35
 
@@ -56,8 +66,8 @@ module Snov
56
66
 
57
67
  def parse_response(resp, path, _params)
58
68
  unless resp.success?
59
- raise ERROR_CLASSES.fetch(resp.status, SnovError),
60
- "#{path} (#{resp.status})"
69
+ error_class = ERROR_CLASSES.fetch(resp.status, ResponseError)
70
+ raise error_class.new("#{path} (#{resp.status})", response: resp)
61
71
  end
62
72
  MultiJson.load(resp.body)
63
73
  end
@@ -3,6 +3,10 @@ require 'camel_snake_struct'
3
3
 
4
4
  module Snov
5
5
  class DomainSearch
6
+ Response = Class.new(CamelSnakeStruct)
7
+ Dir["#{__dir__}/fake_client/get_v2_domain-emails-with-info/*.json"].each do |example_file|
8
+ Response.example(MultiJson.load(File.read(example_file)))
9
+ end
6
10
  include Enumerable
7
11
 
8
12
  attr_reader :client, :domain, :type, :limit
@@ -16,7 +20,7 @@ module Snov
16
20
  end
17
21
 
18
22
  def each(&block)
19
- raw_result.emails.each(&block)
23
+ emails.each(&block)
20
24
  end
21
25
 
22
26
  def success
@@ -39,12 +43,20 @@ module Snov
39
43
  raw_result.company_name
40
44
  end
41
45
 
46
+ def emails
47
+ raw_result.emails
48
+ end
49
+
42
50
  def raw_result
43
- CamelSnakeStruct.new(client.post("/v2/domain-emails-with-info",
44
- 'lastId' => @last_id,
45
- 'limit' => @limit,
46
- 'type' => type.to_s,
47
- 'domain' => domain.to_s))
51
+ @raw_result ||= Response.new(client.get("/v2/domain-emails-with-info",
52
+ 'lastId' => @last_id,
53
+ 'limit' => @limit,
54
+ 'type' => type.to_s,
55
+ 'domain' => domain.to_s))
56
+ end
57
+
58
+ def to_h
59
+ raw_result.to_h
48
60
  end
49
61
  end
50
62
  end
@@ -1,14 +1,52 @@
1
1
  module Snov
2
2
  class FakeClient
3
- def get(path)
4
- data = File.read("#{__dir__}/fake_client/get#{path.tr("/", "_")}.json")
3
+ def self.folder=(val)
4
+ @folder = val
5
+ FileUtils.mkdir_p(@folder)
6
+ ["post_v1_get-profile-by-email", "get_v2_domain-emails-with-info",
7
+ "post_v1_get-prospects-by-email", "post_v1_prospect-list", "get_v1_get-user-lists"].each do |sub_folder|
8
+ FileUtils.cp_r "#{default_folder}/#{sub_folder}", @folder
9
+ end
10
+ end
11
+
12
+ def self.folder
13
+ @folder || default_folder
14
+ end
15
+
16
+ def self.reset_folder
17
+ @folder = nil
18
+ end
19
+
20
+ def self.default_folder
21
+ "#{__dir__}/fake_client"
22
+ end
23
+
24
+ def get(path, payload_hash = {})
25
+ data = File.read(filename("get", path, payload_hash))
26
+ MultiJson.load(data)
27
+ rescue Errno::ENOENT
28
+ data = File.read(filename("get", path, 'not_found' => 'true'))
5
29
  MultiJson.load(data)
6
30
  end
7
31
 
8
- def post(path, params = {})
9
- params.to_a.map(&:join).join("&")
10
- data = File.read("#{__dir__}/fake_client/post#{path.tr("/", "_")}.json")
32
+ def post(path, payload_hash = {})
33
+ data = File.read(filename("post", path, payload_hash))
11
34
  MultiJson.load(data)
35
+ rescue Errno::ENOENT => e
36
+ file = filename("post", path, 'not_found' => 'true')
37
+ if File.exist?(file)
38
+ MultiJson.load(File.read(file))
39
+ else
40
+ raise Snov::Client::BadRequest, e.message
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def filename(method, path, payload_hash)
47
+ add = payload_hash.to_a.map { |v| v.join("=") }.join("&").tr(".", "_")
48
+ add = "default" if add == ""
49
+ "#{self.class.folder}/#{method}#{path.tr("/", "_")}/#{add}.json"
12
50
  end
13
51
  end
14
52
  end
@@ -0,0 +1,21 @@
1
+ {
2
+ "success": true,
3
+ "domain": "octagon.com",
4
+ "webmail": false,
5
+ "result": 84,
6
+ "lastId": 1823487525,
7
+ "limit": 100,
8
+ "companyName": "Octagon",
9
+ "emails": [
10
+ {
11
+ "email": "ben.gillespie@octagon.com",
12
+ "firstName": "Ben",
13
+ "lastName": "Gillespie",
14
+ "position": "Senior Account Executive",
15
+ "sourcePage": "https://www.linkedin.com/pub/ben-gillespie/7/73/809",
16
+ "companyName": "Octagon",
17
+ "type": "prospect",
18
+ "status": "verified"
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1 @@
1
+ {"success":true,"domain":"","webmail":false,"result":0,"lastId":0,"limit":10,"companyName":"","emails":[]}
@@ -0,0 +1,103 @@
1
+ {
2
+ "success": true,
3
+ "id": 301592,
4
+ "source": "linkedIn",
5
+ "name": "Lizi Hamer",
6
+ "firstName": "Lizi",
7
+ "lastName": "Hamer",
8
+ "logo": "https://app.snov.io/img/peoples/010fcf23c70dfa68d880545ec89a9215.jpg",
9
+ "industry": null,
10
+ "country": "Singapore",
11
+ "locality": "Singapore",
12
+ "social": [
13
+ {
14
+ "link": "https://www.linkedin.com/in/lizihamer/",
15
+ "type": "linkedIn"
16
+ },
17
+ {
18
+ "link": "https://twitter.com/LiziHamer",
19
+ "type": "twitter"
20
+ }
21
+ ],
22
+ "currentJobs": [
23
+ {
24
+ "companyName": "Octagon",
25
+ "position": "Regional Creative Director",
26
+ "socialLink": "https://www.linkedin.com/company/165282",
27
+ "site": "www.octagon.com",
28
+ "locality": "Greater New York City Area",
29
+ "state": "Connecticut",
30
+ "city": "Stamford",
31
+ "street": "290 Harbor Dr",
32
+ "street2": "2nd Floor",
33
+ "postal": "06902",
34
+ "founded": "1983",
35
+ "startDate": "2016-01-31",
36
+ "endDate": null,
37
+ "size": "1-10",
38
+ "industry": "Marketing and Advertising",
39
+ "companyType": "Public Company",
40
+ "country": "United States"
41
+ },
42
+ {
43
+ "companyName": "SisuGirls",
44
+ "position": "Co Founder",
45
+ "socialLink": "https://www.linkedin.com/company/3841118",
46
+ "site": "http://www.sisugirls.org",
47
+ "locality": null,
48
+ "state": "SG",
49
+ "city": "Singapore",
50
+ "street": "33-03 Hong Leong Building",
51
+ "street2": null,
52
+ "postal": null,
53
+ "founded": "2014",
54
+ "startDate": "2015-07-31",
55
+ "endDate": null,
56
+ "size": "1-10",
57
+ "industry": "Health, Wellness and Fitness",
58
+ "companyType": null,
59
+ "country": "Singapore"
60
+ }
61
+ ],
62
+ "previousJobs": [
63
+ {
64
+ "companyName": "Fusion Co-innovation Labs",
65
+ "position": "Creative Entrepreneur",
66
+ "socialLink": null,
67
+ "site": null,
68
+ "locality": null,
69
+ "state": null,
70
+ "city": null,
71
+ "street": null,
72
+ "street2": null,
73
+ "postal": null,
74
+ "founded": null,
75
+ "startDate": "2013-05-31",
76
+ "endDate": "2013-10-31",
77
+ "size": null,
78
+ "industry": null,
79
+ "companyType": null,
80
+ "country": null
81
+ },
82
+ {
83
+ "companyName": "Russell Commission",
84
+ "position": "Youth Advisory Board Member",
85
+ "socialLink": null,
86
+ "site": null,
87
+ "locality": null,
88
+ "state": null,
89
+ "city": null,
90
+ "street": null,
91
+ "street2": null,
92
+ "postal": null,
93
+ "founded": null,
94
+ "startDate": "2004-06-30",
95
+ "endDate": "2006-06-30",
96
+ "size": null,
97
+ "industry": null,
98
+ "companyType": null,
99
+ "country": null
100
+ }
101
+ ],
102
+ "lastUpdateDate": "2018-02-07 10:12:28"
103
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "success": true,
3
+ "message": "We couldn't find profile with this email"
4
+ }
@@ -0,0 +1 @@
1
+ {"success":false,"errors":"Prospect with email 'no.one.home@octagon.com' not found"}
@@ -0,0 +1,55 @@
1
+ {
2
+ "success": true,
3
+ "list": {
4
+ "name": "Lead LIST",
5
+ "contacts": 3,
6
+ "creationDate": {
7
+ "date": "2020-05-19 17:34:39.000000",
8
+ "timezone_type": 3,
9
+ "timezone": "UTC"
10
+ },
11
+ "emailsCount": []
12
+ },
13
+ "prospects": [
14
+ {
15
+ "id": "226db935fc93422496fda5d5209e8cbf77cc77ec685891706028009b86608f7ce5877a3faf",
16
+ "name": "Andrew Garfiled",
17
+ "firstName": "Andrew",
18
+ "lastName": "Garfiled",
19
+ "emails": [
20
+ {
21
+ "email": "andrewexp@exp.com",
22
+ "probability": 99,
23
+ "isVerified": null,
24
+ "jobStatus": "any",
25
+ "domainType": "linkedin_email",
26
+ "isValidFormat": null,
27
+ "isDisposable": null,
28
+ "isWebmail": null,
29
+ "isGibberish": null,
30
+ "smtpStatus": null
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "id": "f20d30219b039d1408d837a748a1e2ab843c97e65080f6cf8fa7d948477d9093d87413f05f",
36
+ "name": "John Doe",
37
+ "firstName": "John",
38
+ "lastName": "Doe",
39
+ "emails": [
40
+ {
41
+ "email": "johndoe@gmail.com",
42
+ "probability": 99,
43
+ "isVerified": null,
44
+ "jobStatus": "any",
45
+ "domainType": "linkedin_email",
46
+ "isValidFormat": true,
47
+ "isDisposable": false,
48
+ "isWebmail": true,
49
+ "isGibberish": false,
50
+ "smtpStatus": 3
51
+ }
52
+ ]
53
+ }
54
+ ]
55
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "success": true,
3
+ "list": {
4
+ "name": "Lead LIST",
5
+ "contacts": 3,
6
+ "creationDate": {
7
+ "date": "2020-05-19 17:34:39.000000",
8
+ "timezone_type": 3,
9
+ "timezone": "UTC"
10
+ },
11
+ "emailsCount": []
12
+ },
13
+ "prospects": [
14
+ {
15
+ "id": "226db935fc93422496fda5d5209e8cbf77cc77ec685891706028009b86608f7ce5877a3faf",
16
+ "name": "Andrew Garfiled",
17
+ "firstName": "Andrew",
18
+ "lastName": "Garfiled",
19
+ "emails": [
20
+ {
21
+ "email": "andrewexp@exp.com",
22
+ "probability": 99,
23
+ "isVerified": null,
24
+ "jobStatus": "any",
25
+ "domainType": "linkedin_email",
26
+ "isValidFormat": null,
27
+ "isDisposable": null,
28
+ "isWebmail": null,
29
+ "isGibberish": null,
30
+ "smtpStatus": null
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "id": "f20d30219b039d1408d837a748a1e2ab843c97e65080f6cf8fa7d948477d9093d87413f05f",
36
+ "name": "John Doe",
37
+ "firstName": "John",
38
+ "lastName": "Doe",
39
+ "emails": [
40
+ {
41
+ "email": "johndoe@gmail.com",
42
+ "probability": 99,
43
+ "isVerified": null,
44
+ "jobStatus": "any",
45
+ "domainType": "linkedin_email",
46
+ "isValidFormat": true,
47
+ "isDisposable": false,
48
+ "isWebmail": true,
49
+ "isGibberish": false,
50
+ "smtpStatus": 3
51
+ }
52
+ ]
53
+ }
54
+ ]
55
+ }
@@ -1,3 +1,3 @@
1
1
  module Snov
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snov
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Grant Petersen-Speelman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-11 00:00:00.000000000 Z
11
+ date: 2021-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -134,10 +134,16 @@ files:
134
134
  - lib/snov/client.rb
135
135
  - lib/snov/domain_search.rb
136
136
  - lib/snov/fake_client.rb
137
- - lib/snov/fake_client/get_v1_get-user-lists.json
138
- - lib/snov/fake_client/post_v1_get-profile-by-email.json
139
- - lib/snov/fake_client/post_v1_get-prospects-by-email.json
140
- - lib/snov/fake_client/post_v1_prospect-list.json
137
+ - lib/snov/fake_client/get_v1_get-user-lists/default.json
138
+ - lib/snov/fake_client/get_v2_domain-emails-with-info/domain=octagon_com.json
139
+ - lib/snov/fake_client/get_v2_domain-emails-with-info/not_found=true.json
140
+ - lib/snov/fake_client/post_v1_get-profile-by-email/email=lizi_hamer@octagon_com.json
141
+ - lib/snov/fake_client/post_v1_get-profile-by-email/not_found=true.json
142
+ - lib/snov/fake_client/post_v1_get-prospects-by-email/email=gavin_vanrooyen@octagon_com.json
143
+ - lib/snov/fake_client/post_v1_get-prospects-by-email/not_found=true.json
144
+ - lib/snov/fake_client/post_v1_prospect-list/list_id=1479070&page=1&per_page=100.json
145
+ - lib/snov/fake_client/post_v1_prospect-list/list_id=1505383&page=1&per_page=100.json
146
+ - lib/snov/fake_client/post_v1_prospect-list/list_id=1818597&page=1&per_page=100.json
141
147
  - lib/snov/get_all_prospects_from_list.rb
142
148
  - lib/snov/get_profile_by_email.rb
143
149
  - lib/snov/get_prospect_list.rb
@@ -1,103 +0,0 @@
1
- {
2
- "success": true,
3
- "id": 301592,
4
- "source": "linkedIn",
5
- "name": "Lizi Hamer",
6
- "firstName": "Lizi",
7
- "lastName": "Hamer",
8
- "logo": "https://app.snov.io/img/peoples/010fcf23c70dfa68d880545ec89a9215.jpg",
9
- "industry": null,
10
- "country": "Singapore",
11
- "locality": "Singapore",
12
- "social": [
13
- {
14
- "link": "https://www.linkedin.com/in/lizihamer/",
15
- "type": "linkedIn"
16
- },
17
- {
18
- "link": "https://twitter.com/LiziHamer",
19
- "type": "twitter"
20
- }
21
- ],
22
- "currentJobs": [
23
- {
24
- "companyName": "Octagon",
25
- "position": "Regional Creative Director",
26
- "socialLink": "https://www.linkedin.com/company/165282",
27
- "site": "www.octagon.com",
28
- "locality": "Greater New York City Area",
29
- "state": "Connecticut",
30
- "city": "Stamford",
31
- "street": "290 Harbor Dr",
32
- "street2": "2nd Floor",
33
- "postal": "06902",
34
- "founded": "1983",
35
- "startDate": "2016-01-31",
36
- "endDate": null,
37
- "size": "1-10",
38
- "industry": "Marketing and Advertising",
39
- "companyType": "Public Company",
40
- "country": "United States"
41
- },
42
- {
43
- "companyName": "SisuGirls",
44
- "position": "Co Founder",
45
- "socialLink": "https://www.linkedin.com/company/3841118",
46
- "site": "http://www.sisugirls.org",
47
- "locality": null,
48
- "state": "SG",
49
- "city": "Singapore",
50
- "street": "33-03 Hong Leong Building",
51
- "street2": null,
52
- "postal": null,
53
- "founded": "2014",
54
- "startDate": "2015-07-31",
55
- "endDate": null,
56
- "size": "1-10",
57
- "industry": "Health, Wellness and Fitness",
58
- "companyType": null,
59
- "country": "Singapore"
60
- }
61
- ],
62
- "previousJobs": [
63
- {
64
- "companyName": "Fusion Co-innovation Labs",
65
- "position": "Creative Entrepreneur",
66
- "socialLink": null,
67
- "site": null,
68
- "locality": null,
69
- "state": null,
70
- "city": null,
71
- "street": null,
72
- "street2": null,
73
- "postal": null,
74
- "founded": null,
75
- "startDate": "2013-05-31",
76
- "endDate": "2013-10-31",
77
- "size": null,
78
- "industry": null,
79
- "companyType": null,
80
- "country": null
81
- },
82
- {
83
- "companyName": "Russell Commission",
84
- "position": "Youth Advisory Board Member",
85
- "socialLink": null,
86
- "site": null,
87
- "locality": null,
88
- "state": null,
89
- "city": null,
90
- "street": null,
91
- "street2": null,
92
- "postal": null,
93
- "founded": null,
94
- "startDate": "2004-06-30",
95
- "endDate": "2006-06-30",
96
- "size": null,
97
- "industry": null,
98
- "companyType": null,
99
- "country": null
100
- }
101
- ],
102
- "lastUpdateDate": "2018-02-07 10:12:28"
103
- }