ruby-pardot 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +9 -0
  4. data/Gemfile +3 -1
  5. data/Gemfile.lock +5 -5
  6. data/README.rdoc +19 -17
  7. data/Rakefile +2 -3
  8. data/lib/pardot/authentication.rb +23 -12
  9. data/lib/pardot/client.rb +17 -6
  10. data/lib/pardot/error.rb +6 -2
  11. data/lib/pardot/http.rb +47 -44
  12. data/lib/pardot/objects/custom_fields.rb +13 -17
  13. data/lib/pardot/objects/emails.rb +9 -14
  14. data/lib/pardot/objects/list_memberships.rb +8 -12
  15. data/lib/pardot/objects/lists.rb +20 -25
  16. data/lib/pardot/objects/opportunities.rb +21 -26
  17. data/lib/pardot/objects/prospect_accounts.rb +6 -7
  18. data/lib/pardot/objects/prospects.rb +26 -30
  19. data/lib/pardot/objects/users.rb +17 -21
  20. data/lib/pardot/objects/visitor_activities.rb +15 -19
  21. data/lib/pardot/objects/visitors.rb +17 -21
  22. data/lib/pardot/objects/visits.rb +15 -19
  23. data/lib/pardot/version.rb +1 -1
  24. data/ruby-pardot.gemspec +14 -12
  25. data/spec/pardot/authentication_spec.rb +78 -44
  26. data/spec/pardot/client_spec.rb +50 -15
  27. data/spec/pardot/error_spec.rb +6 -4
  28. data/spec/pardot/http_spec.rb +83 -92
  29. data/spec/pardot/objects/custom_fields_spec.rb +48 -53
  30. data/spec/pardot/objects/emails_spec.rb +34 -36
  31. data/spec/pardot/objects/lists_spec.rb +34 -38
  32. data/spec/pardot/objects/opportunities_spec.rb +58 -61
  33. data/spec/pardot/objects/prospect_accounts_spec.rb +72 -75
  34. data/spec/pardot/objects/prospects_spec.rb +56 -56
  35. data/spec/pardot/objects/users_spec.rb +58 -61
  36. data/spec/pardot/objects/visitor_activities_spec.rb +57 -61
  37. data/spec/pardot/objects/visitors_spec.rb +56 -61
  38. data/spec/pardot/objects/visits_spec.rb +56 -61
  39. data/spec/spec_helper.rb +2 -0
  40. data/spec/support/client_support.rb +40 -4
  41. data/spec/support/fakeweb.rb +13 -8
  42. metadata +8 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e618137557812f8899ff1d06b37bedb49d72cc51e191a091c15b5135780e3bd5
4
- data.tar.gz: 22b0992ead0f91fa432af3ccfbad1ea1b1cb65080c7898b8ed9cc9695fbcfa64
3
+ metadata.gz: 9d135372bc02b957ea7f65dca69f08405a6b6ef3c2a1a62c95e26570daf13b21
4
+ data.tar.gz: 57d82933ff9755c178f807dfe4d6cb879043e4e7596eb8a334278cced3a8fac4
5
5
  SHA512:
6
- metadata.gz: 3038da0a48d2608cb4395e4ec8ce0a8fcbd3962357279a4ce76b9e74eb936ea22f4942ded8261aa9507af0bb93501b0a07a8c91b05f1fdb6c1b7fb3cf188c87a
7
- data.tar.gz: 7fffe6dd67e999a0c294c170dea8929e2885b4957d08bdfc812338696497db02af39015751fed5ea708b9e5090d09fbbb8594f20b548ad4c5a1d5e16e0b5577f
6
+ metadata.gz: aa3dfe9f4c8081ebced940fc0e422f6b5d80a72c32046fbf331abc0ca5497598093f0ff7cb00d7ff1c3ec19a62f8c551198675725fd052bcd95b18edab3c3cbe
7
+ data.tar.gz: 11269265532b8065240c8fc122420bcd9462d44d6198902291804de8711731c4ca62593f98bbdf0aea450e6783792c3826253ef04ef5dfcf7fd13a9a114aedd0
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ .vscode
5
+ bin
data/.rubocop.yml ADDED
@@ -0,0 +1,9 @@
1
+ AllCops:
2
+ NewCops: enable
3
+
4
+ Metrics/BlockLength:
5
+ Enabled: false
6
+ Metrics/MethodLength:
7
+ Enabled: false
8
+ Layout/LineLength:
9
+ Enabled: false
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
- source :gemcutter
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in ruby-pardot.gemspec
4
6
  gemspec
data/Gemfile.lock CHANGED
@@ -1,12 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-pardot (1.3.2)
4
+ ruby-pardot (1.4.0)
5
5
  crack (= 0.4.3)
6
6
  httparty (= 0.18.1)
7
7
 
8
8
  GEM
9
- remote: http://rubygems.org/
9
+ remote: https://rubygems.org/
10
10
  specs:
11
11
  crack (0.4.3)
12
12
  safe_yaml (~> 1.0.0)
@@ -17,7 +17,7 @@ GEM
17
17
  multi_xml (>= 0.5.2)
18
18
  mime-types (3.3.1)
19
19
  mime-types-data (~> 3.2015)
20
- mime-types-data (3.2020.0512)
20
+ mime-types-data (3.2020.1104)
21
21
  multi_xml (0.6.0)
22
22
  rspec (3.5.0)
23
23
  rspec-core (~> 3.5.0)
@@ -39,9 +39,9 @@ PLATFORMS
39
39
 
40
40
  DEPENDENCIES
41
41
  bundler (>= 1.10)
42
- fakeweb
42
+ fakeweb (= 1.3.0)
43
43
  rspec (= 3.5.0)
44
44
  ruby-pardot!
45
45
 
46
46
  BUNDLED WITH
47
- 2.1.4
47
+ 2.2.7
data/README.rdoc CHANGED
@@ -8,16 +8,18 @@ Add the following to your Gemfile
8
8
 
9
9
  === Authentication
10
10
 
11
- The client will authenticate before performing other API calls, but you can manually authenticate as well
11
+ In order to use this client, an access token retrieved from Salesforce OAuth must be specified. See
12
+ the [authetication documentation on developer.pardot.com](https://developer.pardot.com/kb/authentication/) for more information.
12
13
 
13
14
  require "ruby-pardot"
14
15
 
15
- client = Pardot::Client.new email, password, user_key
16
-
17
- # will raise a Pardot::ResponseError if login fails
18
- # will raise a Pardot::NetError if the http call fails
19
- client.authenticate
20
-
16
+ version = 3 # or 4
17
+ access_token = '<access_token>' # Retrieve an access token from Salesforce using OAuth
18
+ business_unit_id = '<business_unit_id>' # Specify the Business Unit ID of the account to access
19
+ client = Pardot::Client.new nil, nil, nil, version, access_token, business_unit_id
20
+
21
+ Usage of the username, password, and API key authentication is deprecated and will be removed in an upcoming release.
22
+
21
23
  === Object Types
22
24
 
23
25
  The available objects are:
@@ -33,15 +35,15 @@ The available objects are:
33
35
  * visits
34
36
 
35
37
  === Querying Objects
36
-
38
+
37
39
  http://developer.pardot.com/kb/api-version-3/querying-prospects
38
-
40
+
39
41
  Most objects accept limit, offset, sort_by, and sord_order parameters
40
42
 
41
43
  prospects = client.prospects.query(:assigned => false, :sort_by => "last_activity_at", :limit => 20)
42
-
44
+
43
45
  prospects["total_results"] # number of prospects found
44
-
46
+
45
47
  prospects["prospect"].each do |prospect|
46
48
  puts prospect["first_name"]
47
49
  end
@@ -53,11 +55,11 @@ See each individual object's API reference page for available methods
53
55
  http://developer.pardot.com/kb/api-version-3/using-prospects
54
56
 
55
57
  prospect = client.prospects.create("user@test.com", :first_name => "John", :last_name => "Doe")
56
-
58
+
57
59
  prospect.each do |key, value|
58
60
  puts "#{key} is #{value}"
59
61
  end
60
-
62
+
61
63
  === Emails
62
64
 
63
65
  See each individual call's [API reference page](http://developer.pardot.com/kb/api-version-3/introduction-table-of-contents).
@@ -66,15 +68,15 @@ See each individual call's [API reference page](http://developer.pardot.com/kb/a
66
68
  @pardot.emails.read_by_id(email_id)
67
69
  @pardot.emails.send_to_list(:email_template_id => template_id, 'list_ids[]' => list_id, :campaign_id => campaign_id)
68
70
  @pardot.emails.send_to_prospect(prospect_id, :campaign_id => campaign_id, :email_template_id => template_id)
69
-
71
+
70
72
  === Output formats
71
-
73
+
72
74
  client.format = "simple" # default
73
75
  client.format = "mobile"
74
76
  client.format = "full"
75
77
 
76
78
  === Error handling
77
-
79
+
78
80
  Pardot will respond with an error message when you provide invalid parameters
79
81
 
80
82
  begin
@@ -84,7 +86,7 @@ Pardot will respond with an error message when you provide invalid parameters
84
86
  end
85
87
 
86
88
  Performing API calls across the internet is inherently unsafe, so be sure to catch the exceptions
87
-
89
+
88
90
  begin
89
91
  visitor = client.visitors.query(:id_greater_than => 200)
90
92
  rescue Pardot::NetError => e
data/Rakefile CHANGED
@@ -1,11 +1,10 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
-
5
4
  require 'rspec/core'
6
5
  require 'rspec/core/rake_task'
7
6
 
8
- desc "Run all specs"
7
+ desc 'Run all specs'
9
8
  RSpec::Core::RakeTask.new(:spec) do |t|
10
- t.pattern = "./spec/**/*_spec.rb"
9
+ t.pattern = './spec/**/*_spec.rb'
11
10
  end
@@ -1,29 +1,40 @@
1
1
  module Pardot
2
2
  module Authentication
3
-
3
+ # @deprecated Use of username and password authentication is deprecated.
4
4
  def authenticate
5
- resp = post "login", nil, nil, nil, :email => @email, :password => @password, :user_key => @user_key
6
- update_version(resp["version"]) if resp && resp["version"]
7
- @api_key = resp && resp["api_key"]
5
+ if using_salesforce_access_token?
6
+ raise 'Authentication not available when using Salesforce access token. See https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_oauth_and_connected_apps.htm for more information.'
7
+ end
8
+
9
+ warn '[DEPRECATION] Use of username and password authentication is deprecated in favor of Salesforce OAuth. See https://developer.pardot.com/kb/authentication/ for more information.'
10
+ resp = post 'login', nil, nil, nil, email: @email, password: @password, user_key: @user_key
11
+ update_version(resp['version']) if resp && resp['version']
12
+ @api_key = resp && resp['api_key']
8
13
  end
9
-
14
+
10
15
  def authenticated?
11
- @api_key != nil
16
+ !@api_key.nil? || !@salesforce_access_token.nil?
17
+ end
18
+
19
+ def using_salesforce_access_token?
20
+ @salesforce_access_token != nil
12
21
  end
13
-
22
+
14
23
  def reauthenticate
24
+ if using_salesforce_access_token?
25
+ raise 'Reauthentication not available when using Salesforce access token. See https://developer.salesforce.com/docs/atlas.en-us.mobile_sdk.meta/mobile_sdk/oauth_refresh_token_flow.htm for more information.'
26
+ end
27
+
28
+ warn '[DEPRECATION] Use Salesforce OAuth to refresh the Salesforce access token. See https://developer.salesforce.com/docs/atlas.en-us.mobile_sdk.meta/mobile_sdk/oauth_refresh_token_flow.htm for more information.'
15
29
  @api_key = nil
16
30
  authenticate
17
31
  end
18
32
 
19
33
  private
20
34
 
21
- def update_version version
22
- if version.is_a? Array
23
- version = version.last
24
- end
35
+ def update_version(version)
36
+ version = version.last if version.is_a? Array
25
37
  @version = version if version.to_i > 3
26
38
  end
27
-
28
39
  end
29
40
  end
data/lib/pardot/client.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  module Pardot
2
-
3
2
  class Client
4
-
5
3
  include HTTParty
6
4
  base_uri 'https://pi.pardot.com'
7
5
  format :xml
@@ -21,16 +19,29 @@ module Pardot
21
19
  include Objects::Visits
22
20
  include Objects::VisitorActivities
23
21
 
24
- attr_accessor :email, :password, :user_key, :api_key, :version, :format
22
+ attr_accessor :email, :password, :user_key, :api_key, :version, :salesforce_access_token, :business_unit_id, :format
23
+
24
+ # @deprecated Arguments email, password and user_key are deprecated. Use salesforce_access_token with Salesforce OAuth.
25
+ def initialize(email = nil, password = nil, user_key = nil, version = 3, salesforce_access_token = nil, business_unit_id = nil)
26
+ unless email.nil? || password.nil? || user_key.nil?
27
+ warn '[DEPRECATION] Use of username and password authentication is deprecated in favor of Salesforce OAuth. See https://developer.pardot.com/kb/authentication/ for more information.'
28
+ end
29
+
30
+ if !salesforce_access_token.nil? && business_unit_id.nil?
31
+ raise 'business_unit_id required when using Salesforce access_token'
32
+ end
33
+ if !business_unit_id.nil? && (!business_unit_id.start_with?('0Uv') || business_unit_id.length != 18)
34
+ raise "Invalid business_unit_id value. Expected ID to start with '0Uv' and be length of 18 characters."
35
+ end
25
36
 
26
- def initialize email, password, user_key, version = 3
27
37
  @email = email
28
38
  @password = password
29
39
  @user_key = user_key
30
40
  @version = version
41
+ @salesforce_access_token = salesforce_access_token
42
+ @business_unit_id = business_unit_id
31
43
 
32
- @format = "simple"
44
+ @format = 'simple'
33
45
  end
34
-
35
46
  end
36
47
  end
data/lib/pardot/error.rb CHANGED
@@ -1,19 +1,23 @@
1
1
  module Pardot
2
2
  class Error < StandardError; end
3
+
3
4
  class NetError < Error; end
5
+
4
6
  class ExpiredApiKeyError < Error; end
5
7
 
8
+ class AccessTokenExpiredError < Error; end
9
+
6
10
  class ResponseError < Error
7
11
  def initialize(res)
8
12
  @res = res
9
13
  end
10
14
 
11
15
  def to_s
12
- @res["__content__"]
16
+ @res['__content__']
13
17
  end
14
18
 
15
19
  def code
16
- @res["code"].to_i
20
+ @res['code'].to_i
17
21
  end
18
22
 
19
23
  def inspect
data/lib/pardot/http.rb CHANGED
@@ -1,77 +1,80 @@
1
1
  module Pardot
2
2
  module Http
3
-
4
- def get object, path, params = {}, num_retries = 0
3
+ def get(object, path, params = {}, num_retries = 0)
5
4
  smooth_params object, params
6
5
  full_path = fullpath object, path
7
6
  headers = create_auth_header object
8
- check_response self.class.get(full_path, :query => params, :headers => headers)
9
-
7
+ check_response self.class.get(full_path, query: params, headers: headers)
10
8
  rescue Pardot::ExpiredApiKeyError => e
11
9
  handle_expired_api_key :get, object, path, params, num_retries, e
12
-
13
10
  rescue SocketError, Interrupt, EOFError, SystemCallError, Timeout::Error, MultiXml::ParseError => e
14
- raise Pardot::NetError.new(e)
11
+ raise Pardot::NetError, e
15
12
  end
16
-
17
- def post object, path, params = {}, num_retries = 0, bodyParams = {}
13
+
14
+ def post(object, path, params = {}, num_retries = 0, bodyParams = {})
18
15
  smooth_params object, params
19
16
  full_path = fullpath object, path
20
17
  headers = create_auth_header object
21
- check_response self.class.post(full_path, :query => params, :body => bodyParams, :headers => headers)
22
-
18
+ check_response self.class.post(full_path, query: params, body: bodyParams, headers: headers)
23
19
  rescue Pardot::ExpiredApiKeyError => e
24
20
  handle_expired_api_key :post, object, path, params, num_retries, e
25
-
26
21
  rescue SocketError, Interrupt, EOFError, SystemCallError, Timeout::Error, MultiXml::ParseError => e
27
- raise Pardot::NetError.new(e)
22
+ raise Pardot::NetError, e
28
23
  end
29
-
24
+
30
25
  protected
31
-
32
- def handle_expired_api_key method, object, path, params, num_retries, e
26
+
27
+ # @deprecated With Salesforce OAuth, this method will never be invoked.
28
+ def handle_expired_api_key(method, object, path, params, num_retries, e)
33
29
  raise e unless num_retries == 0
34
-
30
+
35
31
  reauthenticate
36
-
32
+
37
33
  send(method, object, path, params, 1)
38
34
  end
39
-
40
- def smooth_params object, params
41
- return if object == "login"
42
-
35
+
36
+ def smooth_params(object, params)
37
+ return if object == 'login'
38
+
43
39
  authenticate unless authenticated?
44
- params.merge! :format => @format
40
+ params.merge! format: @format
45
41
  end
46
42
 
47
- def create_auth_header object
48
- return if object == "login"
49
- { :Authorization => "Pardot api_key=#{@api_key}, user_key=#{@user_key}" }
43
+ def create_auth_header(object)
44
+ return if object == 'login'
45
+
46
+ if using_salesforce_access_token?
47
+ {
48
+ :Authorization => "Bearer #{@salesforce_access_token}",
49
+ 'Pardot-Business-Unit-Id' => @business_unit_id
50
+ }
51
+ else
52
+ { Authorization: "Pardot api_key=#{@api_key}, user_key=#{@user_key}" }
53
+ end
50
54
  end
51
-
52
- def check_response http_response
53
- rsp = http_response["rsp"]
54
-
55
- error = rsp["err"] if rsp
56
- error ||= "Unknown Failure: #{rsp.inspect}" if rsp && rsp["stat"] == "fail"
55
+
56
+ def check_response(http_response)
57
+ rsp = http_response['rsp']
58
+
59
+ error = rsp['err'] if rsp
60
+ error ||= "Unknown Failure: #{rsp.inspect}" if rsp && rsp['stat'] == 'fail'
57
61
  content = error['__content__'] if error.is_a?(Hash)
58
-
59
- if [error, content].include?("Invalid API key or user key") && @api_key
60
- raise ExpiredApiKeyError.new @api_key
62
+
63
+ if [error, content].include?('access_token is invalid') && using_salesforce_access_token?
64
+ raise AccessTokenExpiredError,
65
+ 'Access token is invalid. Use Salesforce OAuth to refresh the existing Salesforce access token or to retrieve a new token. See https://developer.salesforce.com/docs/atlas.en-us.mobile_sdk.meta/mobile_sdk/oauth_refresh_token_flow.htm for more information.'
61
66
  end
62
-
63
- raise ResponseError.new error if error
64
-
67
+ raise ExpiredApiKeyError, @api_key if [error, content].include?('Invalid API key or user key') && @api_key
68
+
69
+ raise ResponseError, error if error
70
+
65
71
  rsp
66
72
  end
67
-
68
- def fullpath object, path
69
- full = File.join("/api", object, "version", @version.to_s)
70
- unless path.nil?
71
- full = File.join(full, path)
72
- end
73
+
74
+ def fullpath(object, path)
75
+ full = File.join('/api', object, 'version', @version.to_s)
76
+ full = File.join(full, path) unless path.nil?
73
77
  full
74
78
  end
75
-
76
79
  end
77
80
  end
@@ -1,37 +1,33 @@
1
1
  module Pardot
2
2
  module Objects
3
3
  module CustomFields
4
-
5
4
  def custom_fields
6
5
  @custom_fields ||= CustomFields.new self
7
6
  end
8
-
7
+
9
8
  class CustomFields
10
-
11
- def initialize client
9
+ def initialize(client)
12
10
  @client = client
13
11
  end
14
-
15
- def query params
16
- result = get "/do/query", params, "result"
17
- result["total_results"] = result["total_results"].to_i if result["total_results"]
12
+
13
+ def query(params)
14
+ result = get '/do/query', params, 'result'
15
+ result['total_results'] = result['total_results'].to_i if result['total_results']
18
16
  result
19
17
  end
20
-
18
+
21
19
  protected
22
-
23
- def get path, params = {}, result = "customField"
24
- response = @client.get "customField", path, params
20
+
21
+ def get(path, params = {}, result = 'customField')
22
+ response = @client.get 'customField', path, params
25
23
  result ? response[result] : response
26
24
  end
27
-
28
- def post path, params = {}, result = "user"
29
- response = @client.post "customField", path, params
25
+
26
+ def post(path, params = {}, result = 'user')
27
+ response = @client.post 'customField', path, params
30
28
  result ? response[result] : response
31
29
  end
32
-
33
30
  end
34
-
35
31
  end
36
32
  end
37
33
  end