snov 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 66024313d2ed01c16ffeeaec3f536f93b00957250903c5d18e3d30458ba4e413
4
+ data.tar.gz: e915c4231981bd3fad2d4fd6a7eb18dfcdcc2005058d97202a7374cc76df25a0
5
+ SHA512:
6
+ metadata.gz: ba368d2617e6b8ca49cb9bcde3c75ed8b43348dd187f7a1f60a459b596f9e1999b282eb940114dae99354330583cc33dcc90e95c8c0a1b13d2fe482daf713058
7
+ data.tar.gz: eef471ba1b9bdcf927fa489addafaf3283f083a6067d7a7b3bba8b414dcbccbf31edc2769ad405fb4abc59cb3129753dee699ab86080faced65e1855435ee4d5
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ /.rspec_status
11
+ /gems.locked
12
+ /vendor/bundle
13
+ /.vscode
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,13 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ AllCops:
5
+ NewCops: enable
6
+ Exclude:
7
+ - 'vendor/**/*'
8
+
9
+ Style:
10
+ Enabled: false
11
+
12
+ Metrics/AbcSize:
13
+ Max: 25
@@ -0,0 +1,15 @@
1
+ ---
2
+ language: ruby
3
+ gemfile: gems.rb
4
+ cache: bundler
5
+ rvm:
6
+ - 2.4
7
+ - 2.7
8
+ before_install:
9
+ - yes | gem update --system --force
10
+ - gem install bundler
11
+
12
+ script:
13
+ - bundle install
14
+ - bundle exec rake
15
+ - bin/rubocop
@@ -0,0 +1,5 @@
1
+ ## [0.1.0]
2
+ * GetUserLists
3
+ * GetProspectList
4
+ * GetAllProspectsFromList
5
+ * GetProspectsByEmail
@@ -0,0 +1,143 @@
1
+ [![Build Status](https://travis-ci.org/NEXL-LTS/snov-ruby.svg?branch=main)](https://travis-ci.org/NEXL-LTS/snov-ruby)
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'snov'
9
+ ```
10
+
11
+ And then execute:
12
+
13
+ $ bundle install
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install snov
18
+
19
+ ## Usage
20
+
21
+ set `SNOV_USER_ID` and `SNOV_SECRET` environment variables
22
+
23
+
24
+ ### GetProfileByEmail
25
+
26
+ see https://snov.io/api#GetProfileByEmail
27
+
28
+ ```ruby
29
+ prospect = Snov::GetProfileByEmail.new(email: "gavin.vanrooyen@octagon.com")
30
+
31
+ puts prospect.success
32
+ puts prospect.id
33
+ puts prospect.name
34
+ puts prospect.first_name
35
+ puts prospect.last_name
36
+ puts prospect.industry
37
+ puts prospect.country
38
+ puts prospect.locality
39
+ prospect.social.each do |social_info|
40
+ puts social.link
41
+ puts social.type
42
+ end
43
+ prospect.current_jobs.each do |social_info|
44
+ puts social.company_name
45
+ puts social.position
46
+ # etc
47
+ end
48
+ # etc
49
+ ```
50
+
51
+ ### GetProspectList
52
+
53
+ see https://snov.io/api#FindProspectbyEmail
54
+
55
+ ```ruby
56
+ prospects = Snov::GetProspectsByEmail.new(email: "gavin.vanrooyen@octagon.com")
57
+ prospects.each do |prospect|
58
+ puts prospect.id
59
+ puts prospect.name
60
+ puts prospect.first_name
61
+ puts prospect.last_name
62
+ puts prospect.industry
63
+ puts prospect.country
64
+ puts prospect.locality
65
+ prospect.social.each do |social_info|
66
+ puts social.link
67
+ puts social.type
68
+ end
69
+ # etc
70
+ end
71
+ ```
72
+
73
+ ### GetUserLists
74
+
75
+ see https://snov.io/api#UserLists
76
+
77
+ ```ruby
78
+ lists = Snov::GetUserLists.new
79
+ lists.each do |list|
80
+ puts list.id
81
+ puts list.name
82
+ puts list.is_deleted
83
+ puts list.contacts
84
+ puts list.creation_date.date
85
+ puts list.deletion_date.date
86
+ end
87
+ ```
88
+
89
+ ### GetProspectList
90
+
91
+ see https://snov.io/api#ViewProspectsInList
92
+
93
+ ```ruby
94
+ prospects = Snov::GetProspectList.new(list_id: 1, page: 1, per_page: 100)
95
+ prospects.each do |prospect|
96
+ puts prospect.id
97
+ puts prospect.name
98
+ puts prospect.first_name
99
+ puts prospect.last_name
100
+ puts prospect.source
101
+ prospect.emails.each do |email_info|
102
+ puts email_info.email
103
+ puts email_info.is_verified
104
+ puts email_info.job_status
105
+ # etc
106
+ end
107
+ end
108
+ ```
109
+
110
+ ### GetAllProspectsFromList
111
+
112
+ convenience wrapper for `GetProspectList` to get all the prospects on all the pages
113
+
114
+ see https://snov.io/api#ViewProspectsInList
115
+
116
+ ```ruby
117
+ prospects = Snov::GetAllProspectsFromList.new(list_id: 1)
118
+ prospects.each do |prospect|
119
+ puts prospect.id
120
+ puts prospect.name
121
+ puts prospect.first_name
122
+ puts prospect.last_name
123
+ puts prospect.source
124
+ prospect.emails.each do |email_info|
125
+ puts email_info.email
126
+ puts email_info.is_verified
127
+ puts email_info.job_status
128
+ # etc
129
+ end
130
+ end
131
+ ```
132
+
133
+
134
+ ## Development
135
+
136
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
137
+
138
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
139
+
140
+ ## Contributing
141
+
142
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/snov.
143
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "snov"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../gems.rb",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../gems.rb",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rubocop", "rubocop")
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/gems.rb ADDED
@@ -0,0 +1,11 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in snov.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
8
+ gem "rubocop"
9
+ gem "rubocop-rspec"
10
+ gem "simplecov"
11
+ gem "webmock"
@@ -0,0 +1,26 @@
1
+ require "snov/version"
2
+
3
+ module Snov
4
+ class Error < StandardError; end
5
+
6
+ def self.client
7
+ if !use_fake?
8
+ Client.new(client_id: ENV['SNOV_USER_ID'], client_secret: ENV['SNOV_SECRET'])
9
+ else
10
+ FakeClient.new
11
+ end
12
+ end
13
+
14
+ def self.use_fake?
15
+ ENV['SNOV_USE_FAKE'].present? || (!ENV.key?('SNOV_USER_ID') && !ENV.key?('SNOV_SECRET'))
16
+ end
17
+ end
18
+
19
+ require 'active_model'
20
+ require 'snov/client'
21
+ require 'snov/fake_client'
22
+ require 'snov/get_profile_by_email'
23
+ require 'snov/get_all_prospects_from_list'
24
+ require 'snov/get_prospects_by_email'
25
+ require 'snov/get_prospect_list'
26
+ require 'snov/get_user_lists'
@@ -0,0 +1,104 @@
1
+ require 'faraday'
2
+ require 'multi_json'
3
+
4
+ module Snov
5
+ class Client
6
+ class SnovError < ::Snov::Error; end
7
+
8
+ class TimedOut < SnovError; end
9
+
10
+ class UnauthorizedError < SnovError; end
11
+
12
+ class BadGatewayError < SnovError; end
13
+
14
+ class ForbiddenError < SnovError; end
15
+
16
+ class GatewayTimeOut < SnovError; end
17
+
18
+ class BadRequest < SnovError; end
19
+
20
+ class AuthError < SnovError; end
21
+
22
+ class MethodNotAllowed < SnovError; end
23
+ ERROR_CLASSES = { 401 => UnauthorizedError, 502 => BadGatewayError, 403 => ForbiddenError,
24
+ 504 => GatewayTimeOut, 400 => BadRequest, 405 => MethodNotAllowed }
25
+
26
+ def initialize(client_id:, client_secret:, access_token: nil, timeout_seconds: 60)
27
+ self.client_id = client_id.to_str
28
+ self.client_secret = client_secret.to_str
29
+ @access_token = access_token
30
+ @timeout_seconds = timeout_seconds.to_int
31
+ end
32
+
33
+ def get(path, params = {})
34
+ resp = conn.get(path) do |req|
35
+ req.body = MultiJson.dump(params.merge('access_token' => access_token))
36
+ req.options.timeout = timeout_seconds # open/read timeout in seconds
37
+ req.options.open_timeout = timeout_seconds # connection open timeout in seconds
38
+ end
39
+ parse_response(resp, path, params)
40
+ rescue Faraday::TimeoutError, Timeout::Error => e
41
+ raise TimedOut, e.message
42
+ end
43
+
44
+ def post(path, params = {})
45
+ resp = conn.post(path) do |req|
46
+ req.body = MultiJson.dump(params.merge('access_token' => access_token))
47
+ req.options.timeout = timeout_seconds # open/read timeout in seconds
48
+ req.options.open_timeout = timeout_seconds # connection open timeout in seconds
49
+ end
50
+ parse_response(resp, path, params)
51
+ rescue Faraday::TimeoutError, Timeout::Error => e
52
+ raise TimedOut, e.message
53
+ end
54
+
55
+ private
56
+
57
+ def parse_response(resp, path, _params)
58
+ unless resp.success?
59
+ raise ERROR_CLASSES.fetch(resp.status, SnovError),
60
+ "#{path} (#{resp.status})"
61
+ end
62
+ MultiJson.load(resp.body)
63
+ end
64
+
65
+ attr_accessor :client_id, :client_secret, :timeout_seconds
66
+
67
+ def access_token
68
+ return @access_token if @access_token
69
+
70
+ @access_token = generate_access_token
71
+ end
72
+
73
+ def access_token_params
74
+ { 'grant_type' => 'client_credentials', 'client_id' => client_id, 'client_secret' => client_secret }
75
+ end
76
+
77
+ def generate_access_token
78
+ resp = conn.post('/v1/oauth/access_token') do |req|
79
+ req.body = MultiJson.dump(access_token_params)
80
+ req.options.timeout = timeout_seconds # open/read timeout in seconds
81
+ req.options.open_timeout = timeout_seconds # connection open timeout in seconds
82
+ end
83
+ handle_error(resp, "POST /v1/oauth/access_token")
84
+ raise AuthError, 'Snov auth failed' if resp.body.blank?
85
+
86
+ MultiJson.load(resp.body).fetch("access_token")
87
+ rescue Timeout::Error => e
88
+ raise TimedOut, e.message
89
+ end
90
+
91
+ def handle_error(resp, prefix)
92
+ return if resp.success?
93
+
94
+ raise ERROR_CLASSES.fetch(resp.status, SnovError), "#{prefix} (#{resp.status})"
95
+ end
96
+
97
+ def conn
98
+ @conn ||= Faraday.new(
99
+ url: 'https://api.snov.io',
100
+ headers: { 'Content-Type' => 'application/json' }
101
+ )
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,14 @@
1
+ module Snov
2
+ class FakeClient
3
+ def get(path)
4
+ data = File.read("#{__dir__}/fake_client/get#{path.tr("/", "_")}.json")
5
+ MultiJson.load(data)
6
+ end
7
+
8
+ def post(path, params = {})
9
+ params.to_a.map(&:join).join("&")
10
+ data = File.read("#{__dir__}/fake_client/post#{path.tr("/", "_")}.json")
11
+ MultiJson.load(data)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,46 @@
1
+ [
2
+ {
3
+ "id": 1818597,
4
+ "name": "FirstSend",
5
+ "contacts": 1,
6
+ "isDeleted": false,
7
+ "creationDate": {
8
+ "date": "2020-04-07 08:25:44.000000",
9
+ "timezone_type": 3,
10
+ "timezone": "UTC"
11
+ },
12
+ "deletionDate": null
13
+ },
14
+ {
15
+ "id": 1505383,
16
+ "name": "All prospects",
17
+ "contacts": 10,
18
+ "isDeleted": true,
19
+ "creationDate": {
20
+ "date": "2019-12-17 15:07:30.000000",
21
+ "timezone_type": 3,
22
+ "timezone": "UTC"
23
+ },
24
+ "deletionDate": {
25
+ "date": "2020-02-17 14:05:44.000000",
26
+ "timezone_type": 3,
27
+ "timezone": "UTC"
28
+ }
29
+ },
30
+ {
31
+ "id": 1479070,
32
+ "name": "EMAIL",
33
+ "contacts": 13,
34
+ "isDeleted": true,
35
+ "creationDate": {
36
+ "date": "2019-12-06 10:51:01.000000",
37
+ "timezone_type": 3,
38
+ "timezone": "UTC"
39
+ },
40
+ "deletionDate": {
41
+ "date": "2020-02-17 14:05:48.000000",
42
+ "timezone_type": 3,
43
+ "timezone": "UTC"
44
+ }
45
+ }
46
+ ]
@@ -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,75 @@
1
+ {
2
+ "success": true,
3
+ "data": [
4
+ {
5
+ "id": "xusD3-T_K5IktGoaa8Jc8A==",
6
+ "name": "Gavin Vanrooyen",
7
+ "firstName": "Gavin",
8
+ "lastName": "Vanrooyen",
9
+ "industry": "Entertainment",
10
+ "country": "United States",
11
+ "locality": "Greater Atlanta Area",
12
+ "social": [
13
+ {
14
+ "link": "https:\/\/www.linkedin.com\/in\/gavin-vanrooyen-809073755\/",
15
+ "type": "linkedIn"
16
+ }
17
+ ],
18
+ "lastUpdateDate": {
19
+ "date": "2019-09-11 12:37:58.000000",
20
+ "timezone_type": 3,
21
+ "timezone": "UTC"
22
+ },
23
+ "currentJob": [
24
+ {
25
+ "companyName": "Octagon",
26
+ "position": "Senior Brand Director",
27
+ "socialLink": "https:\/\/www.linkedin.com\/company\/659333",
28
+ "site": "http:\/\/octagon.com",
29
+ "locality": "United States",
30
+ "state": null,
31
+ "city": null,
32
+ "street": null,
33
+ "street2": null,
34
+ "postal": null,
35
+ "founded": null,
36
+ "startDate": "2018-07-31",
37
+ "endDate": null,
38
+ "size": "1-10",
39
+ "industry": "Entertainment",
40
+ "companyType": "Public Company",
41
+ "country": "United States"
42
+ }
43
+ ],
44
+ "previousJob": [
45
+ {
46
+ "companyName": "UPS",
47
+ "position": "Manager, Sponsorships and Events",
48
+ "socialLink": "https:\/\/www.linkedin.com\/company\/1523574",
49
+ "site": "http:\/\/www.ups.com\/",
50
+ "locality": "United States",
51
+ "state": "GA",
52
+ "city": "Atlanta",
53
+ "street": "55 Glenlake Parkway, NE",
54
+ "street2": null,
55
+ "postal": "30328",
56
+ "founded": "1907",
57
+ "startDate": null,
58
+ "endDate": null,
59
+ "size": "10001+",
60
+ "industry": "Logistics and Supply Chain",
61
+ "companyType": "Public Company",
62
+ "country": "United States"
63
+ }
64
+ ],
65
+ "lists": [
66
+ {
67
+ "id": 1250344,
68
+ "name": "People List"
69
+ }
70
+ ],
71
+ "campaigns": []
72
+ }
73
+ ]
74
+ }
75
+
@@ -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,26 @@
1
+ module Snov
2
+ class GetAllProspectsFromList
3
+ include Enumerable
4
+
5
+ attr_reader :client, :list_id, :max, :per_page
6
+
7
+ def initialize(list_id:, max: 9999, per_page: 100, client: Snov.client)
8
+ @client = client
9
+ @list_id = list_id
10
+ @max = max.to_int
11
+ @per_page = per_page
12
+ end
13
+
14
+ def each(&block)
15
+ (1..max).each do |page|
16
+ list = GetProspectList.new(list_id: list_id, page: page, per_page: per_page,
17
+ client: client)
18
+ prospects = list.prospects
19
+
20
+ prospects.each(&block)
21
+
22
+ break if prospects.size < per_page
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,84 @@
1
+ require 'active_support/core_ext/array'
2
+
3
+ module Snov
4
+ class GetProfileByEmail
5
+ attr_reader :client, :email
6
+
7
+ def initialize(email:, client: Snov.client)
8
+ @client = client
9
+ @email = email.to_str
10
+ end
11
+
12
+ def each(&block)
13
+ prospects.each(&block)
14
+ end
15
+
16
+ def prospect
17
+ @prospect ||= ProspectResult.new(raw_result)
18
+ end
19
+
20
+ def method_missing(method_name, *arguments, &block)
21
+ if prospect.respond_to?(method_name)
22
+ prospect.public_send(method_name, *arguments, &block)
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ def respond_to_missing?(method_name, include_private = false)
29
+ prospect.respond_to?(method_name) || super
30
+ end
31
+
32
+ def raw_result
33
+ @raw_result ||= client.post("/v1/get-profile-by-email",
34
+ 'email' => email)
35
+ .deep_transform_keys! { |key| key.underscore }
36
+ end
37
+
38
+ class Job
39
+ include ActiveModel::Model
40
+
41
+ attr_accessor :company_name, :position, :social_link, :site, :locality, :state, :city
42
+ attr_accessor :street, :street2, :postal, :founded, :start_date, :end_date, :size
43
+ attr_accessor :industry, :company_type, :country
44
+ end
45
+
46
+ class Social
47
+ include ActiveModel::Model
48
+
49
+ attr_accessor :link, :type
50
+ end
51
+
52
+ class List
53
+ include ActiveModel::Model
54
+
55
+ attr_accessor :id, :name
56
+ end
57
+
58
+ class ProspectResult
59
+ include ActiveModel::Model
60
+
61
+ attr_accessor :id, :name, :first_name, :last_name, :industry, :country, :locality, :success, :source
62
+ attr_accessor :logo, :last_update_date, :message
63
+ attr_reader :social, :current_jobs, :previous_jobs
64
+
65
+ def social=(val)
66
+ @social = Array.wrap(val).map do |rel|
67
+ Social.new(rel)
68
+ end
69
+ end
70
+
71
+ def current_jobs=(val)
72
+ @current_jobs = Array.wrap(val).map do |rel|
73
+ Job.new(rel)
74
+ end
75
+ end
76
+
77
+ def previous_jobs=(val)
78
+ @previous_jobs = Array.wrap(val).map do |rel|
79
+ Job.new(rel)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,59 @@
1
+ require 'active_support/core_ext/array'
2
+
3
+ module Snov
4
+ class GetProspectList
5
+ include Enumerable
6
+
7
+ attr_reader :client, :list_id, :page, :per_page
8
+
9
+ def initialize(list_id:, page:, per_page: 100, client: Snov.client)
10
+ @client = client
11
+ @list_id = list_id
12
+ @page = page
13
+ @per_page = per_page
14
+ end
15
+
16
+ def each(&block)
17
+ prospects.each(&block)
18
+ end
19
+
20
+ def prospects
21
+ @prospects ||= raw_result.fetch('prospects').map do |result|
22
+ ProspectResult.new(result)
23
+ end
24
+ end
25
+
26
+ def raw_result
27
+ @raw_result ||= client.post("/v1/prospect-list",
28
+ 'listId' => list_id.to_s,
29
+ 'page' => page.to_s,
30
+ 'perPage' => per_page.to_s)
31
+ .deep_transform_keys! { |key| key.underscore }
32
+ end
33
+
34
+ class ProspectEmail
35
+ include ActiveModel::Model
36
+
37
+ attr_accessor :email, :is_verified, :job_status, :domain_type, :is_valid_format
38
+ attr_accessor :is_disposable, :is_webmail, :is_gibberish, :smtp_status, :probability
39
+ attr_accessor :status_type_text, :status_verify_text, :email_verify_text
40
+ end
41
+
42
+ class ProspectResult
43
+ include ActiveModel::Model
44
+
45
+ attr_accessor :id, :name, :first_name, :last_name, :source
46
+ attr_reader :emails
47
+
48
+ def emails=(val)
49
+ @emails = Array.wrap(val).map do |rel|
50
+ ProspectEmail.new(rel)
51
+ end
52
+ end
53
+
54
+ def email
55
+ emails.first&.email
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,92 @@
1
+ require 'active_support/core_ext/array'
2
+ require_relative 'types/date_details'
3
+
4
+ module Snov
5
+ class GetProspectsByEmail
6
+ include Enumerable
7
+
8
+ attr_reader :client, :email
9
+
10
+ def initialize(email:, client: Snov.client)
11
+ @client = client
12
+ @email = email.to_str
13
+ end
14
+
15
+ def each(&block)
16
+ prospects.each(&block)
17
+ end
18
+
19
+ def prospects
20
+ @prospects ||= raw_result.fetch('data', []).map do |result|
21
+ ProspectResult.new(result)
22
+ end
23
+ end
24
+
25
+ def raw_result
26
+ @raw_result ||= client.post("/v1/get-prospects-by-email",
27
+ 'email' => email)
28
+ .deep_transform_keys! { |key| key.underscore }
29
+ end
30
+
31
+ class Job
32
+ include ActiveModel::Model
33
+
34
+ attr_accessor :company_name, :position, :social_link, :site, :locality, :state, :city
35
+ attr_accessor :street, :street2, :postal, :founded, :start_date, :end_date, :size
36
+ attr_accessor :industry, :company_type, :country
37
+ end
38
+
39
+ class Social
40
+ include ActiveModel::Model
41
+
42
+ attr_accessor :link, :type
43
+ end
44
+
45
+ class List
46
+ include ActiveModel::Model
47
+
48
+ attr_accessor :id, :name
49
+ end
50
+
51
+ class ProspectResult
52
+ include ActiveModel::Model
53
+
54
+ attr_accessor :id, :name, :first_name, :last_name, :industry, :country, :locality
55
+ attr_reader :social, :current_job, :previous_job, :lists, :campaigns, :last_update_date
56
+
57
+ def social=(val)
58
+ @social = Array.wrap(val).map do |rel|
59
+ Social.new(rel)
60
+ end
61
+ end
62
+
63
+ def current_job=(val)
64
+ @current_job = Array.wrap(val).map do |rel|
65
+ Job.new(rel)
66
+ end
67
+ end
68
+
69
+ def previous_job=(val)
70
+ @previous_job = Array.wrap(val).map do |rel|
71
+ Job.new(rel)
72
+ end
73
+ end
74
+
75
+ def lists=(val)
76
+ @lists = Array.wrap(val).map do |rel|
77
+ List.new(rel)
78
+ end
79
+ end
80
+
81
+ def campaigns=(val)
82
+ @campaigns = Array.wrap(val).map do |rel|
83
+ OpenStruct.new(rel)
84
+ end
85
+ end
86
+
87
+ def last_update_date=(val)
88
+ @last_update_date = Types::DateDetails.new(val.to_hash)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'types/date_details'
2
+
3
+ module Snov
4
+ class GetUserLists
5
+ include Enumerable
6
+
7
+ attr_reader :client
8
+
9
+ def initialize(client: Snov.client)
10
+ @client = client
11
+ end
12
+
13
+ def each(&block)
14
+ all.each(&block)
15
+ end
16
+
17
+ def all
18
+ @all ||= raw_result.map { |result| UserList.new(result) }
19
+ end
20
+
21
+ def raw_result
22
+ @raw_result ||= client.get("/v1/get-user-lists").map do |val|
23
+ val.deep_transform_keys! { |key| key.underscore }
24
+ end
25
+ end
26
+
27
+ class UserList
28
+ include ActiveModel::Model
29
+
30
+ attr_accessor :id, :name, :is_deleted, :contacts
31
+ attr_reader :creation_date, :deletion_date
32
+
33
+ def creation_date=(val)
34
+ @creation_date = Types::DateDetails.new(val.to_hash)
35
+ end
36
+
37
+ def deletion_date=(val)
38
+ @deletion_date = val
39
+ @deletion_date = Types::DateDetails.new(val.to_hash) if val
40
+ end
41
+
42
+ def to_h
43
+ { id: id, is_deleted: is_deleted, name: name, contacts: contacts }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,9 @@
1
+ module Snov
2
+ module Types
3
+ class DateDetails
4
+ include ActiveModel::Model
5
+
6
+ attr_accessor :date, :timezone_type, :timezone
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Snov
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'lib/snov/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "snov"
5
+ spec.version = Snov::VERSION
6
+ spec.authors = ["Grant Petersen-Speelman"]
7
+ spec.email = ["grantspeelman@gmail.com"]
8
+
9
+ spec.summary = %q{Snov client to interact with snov api}
10
+ spec.description = %q{Snov client to interact with snov api}
11
+ spec.homepage = "https://github.com/NEXL-LTS/snov-ruby"
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
13
+
14
+ spec.metadata["homepage_uri"] = spec.homepage
15
+ spec.metadata["source_code_uri"] = "https://github.com/NEXL-LTS/snov-ruby"
16
+ spec.metadata["changelog_uri"] = "https://github.com/NEXL-LTS/snov-ruby/CHANGELOG.md"
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+ spec.add_dependency 'activemodel'
27
+ spec.add_dependency 'activesupport'
28
+ spec.add_dependency 'faraday'
29
+ spec.add_dependency 'multi_json'
30
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snov
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Grant Petersen-Speelman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-11-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: multi_json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Snov client to interact with snov api
70
+ email:
71
+ - grantspeelman@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".rubocop.yml"
79
+ - ".travis.yml"
80
+ - CHANGELOG.md
81
+ - README.md
82
+ - Rakefile
83
+ - bin/console
84
+ - bin/rspec
85
+ - bin/rubocop
86
+ - bin/setup
87
+ - gems.rb
88
+ - lib/snov.rb
89
+ - lib/snov/client.rb
90
+ - lib/snov/fake_client.rb
91
+ - lib/snov/fake_client/get_v1_get-user-lists.json
92
+ - lib/snov/fake_client/post_v1_get-profile-by-email.json
93
+ - lib/snov/fake_client/post_v1_get-prospects-by-email.json
94
+ - lib/snov/fake_client/post_v1_prospect-list.json
95
+ - lib/snov/get_all_prospects_from_list.rb
96
+ - lib/snov/get_profile_by_email.rb
97
+ - lib/snov/get_prospect_list.rb
98
+ - lib/snov/get_prospects_by_email.rb
99
+ - lib/snov/get_user_lists.rb
100
+ - lib/snov/types/date_details.rb
101
+ - lib/snov/version.rb
102
+ - snov.gemspec
103
+ homepage: https://github.com/NEXL-LTS/snov-ruby
104
+ licenses: []
105
+ metadata:
106
+ homepage_uri: https://github.com/NEXL-LTS/snov-ruby
107
+ source_code_uri: https://github.com/NEXL-LTS/snov-ruby
108
+ changelog_uri: https://github.com/NEXL-LTS/snov-ruby/CHANGELOG.md
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 2.4.0
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubygems_version: 3.1.4
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Snov client to interact with snov api
128
+ test_files: []