pipekit 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pipekit/config.rb +105 -0
- data/lib/pipekit/deal.rb +13 -2
- data/lib/pipekit/deal_field.rb +6 -0
- data/lib/pipekit/field_repository.rb +25 -0
- data/lib/pipekit/person.rb +13 -2
- data/lib/pipekit/person_field.rb +1 -10
- data/lib/pipekit/repository.rb +22 -15
- data/lib/pipekit/request.rb +76 -23
- data/lib/pipekit/response.rb +122 -0
- data/lib/pipekit/result.rb +82 -0
- data/lib/pipekit/version.rb +1 -1
- data/lib/pipekit.rb +7 -14
- data/pipekit.gemspec +2 -2
- metadata +12 -22
- data/lib/pipekit/configurable.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a97ca3462a69b58e56337a81273147db6d6b81ca
|
4
|
+
data.tar.gz: a58a9d65ecd33575e907d124a69670692843e8e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 09e9a02a4d5021799ca0cf39a96b55d7c0b5a136c8f0427428037f395034ce203c575421fbacc36559198676fce62f3c3f24ed6b07b99cb8594ad4173d3b8f0b
|
7
|
+
data.tar.gz: 649b62d3e62ae41873880705282876663943b8e0ce38659482814fde8db3140ba8617bdf54a9905b2888679e0be71cdeb6cf7d05d0fc9862b361a32994f3b70b
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Pipekit
|
2
|
+
class Config
|
3
|
+
class << self
|
4
|
+
|
5
|
+
attr_writer :file_path
|
6
|
+
|
7
|
+
# Finds the field name in the config from the Pipedrive ID
|
8
|
+
#
|
9
|
+
# Example
|
10
|
+
#
|
11
|
+
# Config.field_name(:person, "asbasdfasc2343443")
|
12
|
+
# # => "middle_name"
|
13
|
+
#
|
14
|
+
# Config.field_name(:person, "name")
|
15
|
+
# # => "name"
|
16
|
+
def field_name(resource, key)
|
17
|
+
custom_fields(resource)
|
18
|
+
.invert
|
19
|
+
.fetch(key.to_s, key.to_s)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Finds the Pipedrive field ID from the config
|
23
|
+
#
|
24
|
+
# Example
|
25
|
+
#
|
26
|
+
# Config.field_id(:person, "middle_name")
|
27
|
+
# # => "asbasdfasc2343443"
|
28
|
+
#
|
29
|
+
# Config.field_id(:person, "name")
|
30
|
+
# # => "name"
|
31
|
+
def field_id(resource, key)
|
32
|
+
custom_fields(resource)
|
33
|
+
.fetch(key.to_s, key.to_s)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Finds the Pipedrive field value from the config
|
37
|
+
# translating from a Pipedrive ID in the config if one exists for that
|
38
|
+
# field/value
|
39
|
+
#
|
40
|
+
# Example
|
41
|
+
#
|
42
|
+
# Config.field_value(:person, "inteview_quality", 66)
|
43
|
+
# # => "Amazing"
|
44
|
+
#
|
45
|
+
# Config.field_value(:person, "inteview_quality", "value_not_there")
|
46
|
+
# # => "value_not_there"
|
47
|
+
def field_value(resource, field, value)
|
48
|
+
custom_field_values(resource, field)
|
49
|
+
.fetch(value, value)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Finds the Pipedrive field value ID from the config if one exists for that
|
53
|
+
# field/value
|
54
|
+
#
|
55
|
+
# Example
|
56
|
+
#
|
57
|
+
# Config.field_value_id(:person, "inteview_quality", "Amazing")
|
58
|
+
# # => 66
|
59
|
+
#
|
60
|
+
# Config.field_value_id(:person, "inteview_quality", "value_not_there")
|
61
|
+
# # => "value_not_there"
|
62
|
+
def field_value_id(resource, field, value)
|
63
|
+
custom_field_values(resource, field)
|
64
|
+
.invert
|
65
|
+
.fetch(value, value)
|
66
|
+
end
|
67
|
+
|
68
|
+
def fetch(key, default = nil)
|
69
|
+
config.fetch(key.to_s, default)
|
70
|
+
end
|
71
|
+
|
72
|
+
def custom_fields(resource)
|
73
|
+
fetch("fields", {})
|
74
|
+
.fetch(resource.to_s, {})
|
75
|
+
end
|
76
|
+
|
77
|
+
def custom_field_values(resource, field)
|
78
|
+
fetch("field_values", {})
|
79
|
+
.fetch(resource.to_s, {})
|
80
|
+
.fetch(field.to_s, {})
|
81
|
+
end
|
82
|
+
|
83
|
+
def file_path
|
84
|
+
@file_path || raise_config_error
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def config
|
90
|
+
@config ||= load_config
|
91
|
+
end
|
92
|
+
|
93
|
+
def raise_config_error
|
94
|
+
raise NotSetError, "You need to create a yaml file with your Pipedrive config and set the path to the file using `Pipekit.config_file_path = 'path/to/file.yml'`"
|
95
|
+
end
|
96
|
+
|
97
|
+
def load_config
|
98
|
+
yaml = ERB.new(File.read(file_path)).result
|
99
|
+
YAML.load(yaml)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
NotSetError = Class.new(Exception)
|
104
|
+
end
|
105
|
+
end
|
data/lib/pipekit/deal.rb
CHANGED
@@ -2,8 +2,19 @@ module Pipekit
|
|
2
2
|
class Deal
|
3
3
|
include Repository
|
4
4
|
|
5
|
-
def get_by_person_id(person_id)
|
6
|
-
|
5
|
+
def get_by_person_id(person_id, person_repo: Person.new)
|
6
|
+
raise UnknownPersonError, "No person ID supplied when getting deals by person ID" unless person_id
|
7
|
+
person_repo.find_deals(person_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Finds a person by their email, then finds the first deal related to that
|
11
|
+
# person and updates it with the params provided
|
12
|
+
def update_by_person(email, params, person_repo: Person.new)
|
13
|
+
person = person_repo.find_by(email: email)
|
14
|
+
deal = get_by_person_id(person[:id], person_repo: person_repo).first
|
15
|
+
update(deal[:id], params)
|
7
16
|
end
|
8
17
|
end
|
18
|
+
|
19
|
+
UnknownPersonError = Class.new(StandardError)
|
9
20
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Pipekit
|
2
|
+
module FieldRepository
|
3
|
+
def get_by_key(key)
|
4
|
+
key = Config.field_id(parent_resource, key)
|
5
|
+
search_fields("key", key)
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_by_name(name)
|
9
|
+
search_fields("name", name)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def search_fields(field_element, value)
|
15
|
+
result = request.get.select { |element| element[field_element] == value }
|
16
|
+
|
17
|
+
raise ResourceNotFoundError.new("#{parent_resource}Field searching by element #{field_element} for #{value} could not be found") if result.empty?
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
def parent_resource
|
22
|
+
resource.chomp("Field")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/pipekit/person.rb
CHANGED
@@ -3,11 +3,22 @@ module Pipekit
|
|
3
3
|
include Repository
|
4
4
|
|
5
5
|
def get_by_email(email)
|
6
|
-
request.get("
|
6
|
+
request.get("find", term: email, search_by_email: 1)
|
7
7
|
end
|
8
8
|
|
9
9
|
def get_by_name(name)
|
10
|
-
request.get("
|
10
|
+
request.get("find", term: name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_or_update(fields)
|
14
|
+
person = find_by(email: fields[:email])
|
15
|
+
update(person["id"], fields)
|
16
|
+
rescue ResourceNotFoundError
|
17
|
+
create(fields)
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_deals(id)
|
21
|
+
request.get("#{id}/deals")
|
11
22
|
end
|
12
23
|
end
|
13
24
|
end
|
data/lib/pipekit/person_field.rb
CHANGED
@@ -1,15 +1,6 @@
|
|
1
1
|
module Pipekit
|
2
2
|
class PersonField
|
3
3
|
include Repository
|
4
|
-
|
5
|
-
def get_by_id(id)
|
6
|
-
request.get("/#{uri}").select { |element| element["id"] == id }
|
7
|
-
end
|
8
|
-
|
9
|
-
def get_by_key(key)
|
10
|
-
custom_field_key = request.config["people_fields"][key] rescue nil
|
11
|
-
key = custom_field_key || key
|
12
|
-
request.get("/#{uri}").select { |element| element["key"] == key }
|
13
|
-
end
|
4
|
+
include FieldRepository
|
14
5
|
end
|
15
6
|
end
|
data/lib/pipekit/repository.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
class ConfigNotSetError < Exception; end
|
2
1
|
module Pipekit
|
3
2
|
module Repository
|
4
3
|
|
5
|
-
def initialize(request =
|
6
|
-
@request = request
|
4
|
+
def initialize(request = nil)
|
5
|
+
@request = request || Request.new(resource)
|
7
6
|
end
|
8
7
|
|
9
8
|
def all
|
10
|
-
|
9
|
+
get
|
11
10
|
end
|
12
11
|
|
13
12
|
# Public: Get all records from Pipedrive by **one** of the record's fields.
|
@@ -21,8 +20,11 @@ module Pipekit
|
|
21
20
|
# where(id: 123)
|
22
21
|
#
|
23
22
|
# Returns array of Hashes.
|
24
|
-
def where(options)
|
23
|
+
def where(options, raise_error = false)
|
25
24
|
send("get_by_#{options.keys.first}", options.values.first)
|
25
|
+
rescue ResourceNotFoundError => error
|
26
|
+
raise error if raise_error
|
27
|
+
[]
|
26
28
|
end
|
27
29
|
|
28
30
|
# Public: Get the first record by **one** field from Pipedrive.
|
@@ -37,7 +39,7 @@ module Pipekit
|
|
37
39
|
#
|
38
40
|
# Returns a Hash or nil if none found.
|
39
41
|
def find_by(options)
|
40
|
-
where(options).first
|
42
|
+
where(options, true).first
|
41
43
|
end
|
42
44
|
|
43
45
|
# Public: Create a record on Pipedrive.
|
@@ -50,7 +52,7 @@ module Pipekit
|
|
50
52
|
#
|
51
53
|
# Returns nothing.
|
52
54
|
def create(fields)
|
53
|
-
request.post(
|
55
|
+
request.post(fields)
|
54
56
|
end
|
55
57
|
|
56
58
|
# Public: Updates a record on Pipedrive.
|
@@ -63,15 +65,17 @@ module Pipekit
|
|
63
65
|
#
|
64
66
|
# Returns nothing.
|
65
67
|
def update(id, fields)
|
66
|
-
request.put(
|
68
|
+
request.put(id, fields)
|
67
69
|
end
|
68
70
|
|
69
71
|
def self.included(base)
|
70
|
-
base.
|
72
|
+
base.extend(ClassMethods)
|
71
73
|
end
|
72
74
|
|
73
75
|
module ClassMethods
|
74
|
-
|
76
|
+
def resource
|
77
|
+
to_s.split("::").last.tap { |name| name[0] = name[0].downcase }
|
78
|
+
end
|
75
79
|
end
|
76
80
|
|
77
81
|
private
|
@@ -85,18 +89,21 @@ module Pipekit
|
|
85
89
|
get_by_field(field: field, value: args[0])
|
86
90
|
end
|
87
91
|
|
92
|
+
def get(id = nil)
|
93
|
+
request.get(id)
|
94
|
+
end
|
95
|
+
|
88
96
|
def get_by_id(id)
|
89
|
-
[
|
97
|
+
[get(id)]
|
90
98
|
end
|
91
99
|
|
92
100
|
def get_by_field(field:, value:)
|
93
|
-
result = request.search_by_field(
|
101
|
+
result = request.search_by_field(field: field, value: value)
|
94
102
|
result.map { |item| get_by_id(item["id"]) }.flatten
|
95
103
|
end
|
96
104
|
|
97
|
-
def
|
98
|
-
|
99
|
-
"#{class_name.downcase}s"
|
105
|
+
def resource
|
106
|
+
self.class.resource
|
100
107
|
end
|
101
108
|
end
|
102
109
|
end
|
data/lib/pipekit/request.rb
CHANGED
@@ -5,10 +5,16 @@ module Pipekit
|
|
5
5
|
include HTTParty
|
6
6
|
|
7
7
|
PIPEDRIVE_URL = "https://api.pipedrive.com/v1"
|
8
|
+
DEFAULT_PAGINATION_LIMIT = 500
|
8
9
|
|
9
10
|
base_uri PIPEDRIVE_URL
|
10
11
|
format :json
|
11
12
|
|
13
|
+
def initialize(resource)
|
14
|
+
@resource = resource
|
15
|
+
self.class.debug_output $stdout if Config.fetch("debug_requests")
|
16
|
+
end
|
17
|
+
|
12
18
|
# Public: Pipedrive /searchField API call.
|
13
19
|
#
|
14
20
|
# type - Type of the field:
|
@@ -20,50 +26,97 @@ module Pipekit
|
|
20
26
|
#
|
21
27
|
# Examples
|
22
28
|
#
|
23
|
-
# search_by_field(
|
24
|
-
# search_by_field(
|
29
|
+
# search_by_field(field: :cohort, value: 119)
|
30
|
+
# search_by_field(field: :github_username, value: "octocat")
|
25
31
|
#
|
26
|
-
# Returns an array of
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
# Returns an array of Response objects or throws a ResourceNotFoundError if
|
33
|
+
# it couldn't find anything.
|
34
|
+
def search_by_field(field:, value:)
|
35
|
+
query = {field_type: "#{resource}Field",
|
36
|
+
field_key: Config.field_id(resource, field),
|
37
|
+
return_item_ids: true,
|
38
|
+
term: value
|
39
|
+
}
|
31
40
|
|
32
|
-
get("/searchResults/field", options
|
41
|
+
response_from self.class.get("/searchResults/field", options(query: query))
|
33
42
|
end
|
34
43
|
|
35
|
-
|
36
|
-
|
44
|
+
# Public: Pipedrive GET API call - does a GET request to the Pipedrive API
|
45
|
+
# based on the resource passed in the initialiser
|
46
|
+
#
|
47
|
+
# id - If the resource being searched for has an id
|
48
|
+
# query - An optional query string
|
49
|
+
# start - The offset with which to start the query
|
50
|
+
#
|
51
|
+
# As long as "request_all_pages" is not set to false in the config this will
|
52
|
+
# recursively call `#get` until all the pages of the request have been
|
53
|
+
# fetched from pipedrive
|
54
|
+
# Pipedrive until everything available has been received
|
55
|
+
def get(id = nil, query = {})
|
56
|
+
_get(id, query, get_request(id, query))
|
37
57
|
end
|
38
58
|
|
39
|
-
def put(
|
40
|
-
|
59
|
+
def put(id, data)
|
60
|
+
response_from self.class.put(uri(id), options(body: data))
|
41
61
|
end
|
42
62
|
|
43
|
-
def post(
|
44
|
-
|
63
|
+
def post(data)
|
64
|
+
response_from self.class.post(uri, options(body: data))
|
45
65
|
end
|
46
66
|
|
47
67
|
private
|
48
68
|
|
49
|
-
|
50
|
-
|
69
|
+
attr_reader :resource
|
70
|
+
|
71
|
+
def _get(id, query, result)
|
72
|
+
return result.response(resource) unless result.fetch_next_request?
|
73
|
+
_get(id, query, result + get_request(id, query, result.next_start))
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_request(id, query, start = 0)
|
77
|
+
response = self.class.get(uri(id), options(query: {limit: pagination_limit, start: start}.merge(query)))
|
78
|
+
Result.new(response)
|
51
79
|
end
|
52
80
|
|
53
|
-
def
|
54
|
-
|
55
|
-
response.parsed_response["data"]
|
81
|
+
def response_from(response_data)
|
82
|
+
Result.response(resource, response_data)
|
56
83
|
end
|
57
84
|
|
58
|
-
def
|
59
|
-
|
85
|
+
def uri(id = nil)
|
86
|
+
"/#{resource}s/#{id}".chomp("/")
|
60
87
|
end
|
61
88
|
|
62
89
|
def options(query: {}, body: {})
|
63
90
|
{
|
64
|
-
query:
|
65
|
-
body: body
|
91
|
+
query: query.merge(api_token: Config.fetch("api_token")),
|
92
|
+
body: parse_body(body)
|
66
93
|
}
|
67
94
|
end
|
95
|
+
|
96
|
+
# Replaces custom fields with their Pipedrive ID
|
97
|
+
# if the ID is defined in the configuration
|
98
|
+
#
|
99
|
+
# So if the body looked like this with a custom field
|
100
|
+
# called middle_name:
|
101
|
+
#
|
102
|
+
# { middle_name: "Dave" }
|
103
|
+
#
|
104
|
+
# And it has a Pipedrive ID ("123abc"), this will put in this custom ID
|
105
|
+
#
|
106
|
+
# { "123abc": "Dave" }
|
107
|
+
#
|
108
|
+
# meaning you don't have to worry about the custom IDs
|
109
|
+
def parse_body(body)
|
110
|
+
body.reduce({}) do |result, (field, value)|
|
111
|
+
field = Config.field_id(resource, field)
|
112
|
+
value = Config.field_value_id(resource, field, value)
|
113
|
+
result.tap { |result| result[field] = value }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def pagination_limit
|
118
|
+
Config.fetch("pagination_limit", DEFAULT_PAGINATION_LIMIT)
|
119
|
+
end
|
120
|
+
|
68
121
|
end
|
69
122
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Pipekit
|
2
|
+
class Response
|
3
|
+
|
4
|
+
def initialize(resource, data)
|
5
|
+
@resource = resource
|
6
|
+
@data = data || {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def ==(other)
|
10
|
+
return false unless other.respond_to?(:to_h)
|
11
|
+
to_h == other.to_h
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](key)
|
15
|
+
fetch(key)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
data.inject({}) do |result, (field, value)|
|
20
|
+
field_name = Config.field_name(resource, field)
|
21
|
+
result[field_name.to_sym] = Config.field_value(resource, field, value)
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :to_hash, :to_h
|
27
|
+
|
28
|
+
# This is more complicated than it first seems as Pipedrive returns any
|
29
|
+
# custom field you might create (such as a new cohort in the Cohort field)
|
30
|
+
# as a meaningless Pipedrive ID so it returns something semantically
|
31
|
+
# meaningnless such as "8" when it means "April 2016"
|
32
|
+
#
|
33
|
+
# There are two ways this method gets around this to bring back the
|
34
|
+
# semantically meaningful result you're looking for here, if you put in the
|
35
|
+
# config under "field_values" the IDs that Pipedrive assigns to your custom
|
36
|
+
# values (you'll have to search the API to work out what these are) it will
|
37
|
+
# look them up there.
|
38
|
+
#
|
39
|
+
# Otherwise you can plass the "find_value_on_pipedrive" flag and it will do
|
40
|
+
# a call to the Pipedrive API to look it up. This is off by default as it is
|
41
|
+
# obviously quite slow to call an API each time you want to fetch some data
|
42
|
+
#
|
43
|
+
# Options:
|
44
|
+
#
|
45
|
+
# find_value_on_pipedrive (default: false) - if set to true will look up using the Pipedrive
|
46
|
+
# API the actual value of field (rather than the Pipedrive ID)
|
47
|
+
#
|
48
|
+
# choose_first_value (default: true) - if Pipedrive returns an array of values this will
|
49
|
+
# choose the first one rather than return the array
|
50
|
+
#
|
51
|
+
# Examples:
|
52
|
+
#
|
53
|
+
# Normally you can just use the square brackets alias to fetch responses as
|
54
|
+
# though this was a hash:
|
55
|
+
#
|
56
|
+
# response[:resource] # returns: "Dave"
|
57
|
+
#
|
58
|
+
# However if you find when doing this Pipedrive returns its meaningless ID
|
59
|
+
#
|
60
|
+
# response[:cohort] # returns: 1234
|
61
|
+
#
|
62
|
+
# then you can tell Pipedrive to fetch it manually
|
63
|
+
#
|
64
|
+
# response.fetch(:cohort, find_value_on_pipedrive: true) # returns: "April
|
65
|
+
# 2016"
|
66
|
+
#
|
67
|
+
def fetch(key, default = nil, opts = {})
|
68
|
+
opts = {
|
69
|
+
find_value_on_pipedrive: false,
|
70
|
+
choose_first_value: true
|
71
|
+
}.merge(opts)
|
72
|
+
|
73
|
+
value = fetch_value(key, default)
|
74
|
+
|
75
|
+
return value_from_pipedrive(key.to_s, value) if opts[:find_value_on_pipedrive]
|
76
|
+
convert_value(key, value, opts)
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_key?(key)
|
80
|
+
data.has_key? convert_key(key)
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
attr_reader :data, :resource
|
86
|
+
|
87
|
+
def fetch_value(key, default)
|
88
|
+
data.fetch(convert_key(key), default)
|
89
|
+
end
|
90
|
+
|
91
|
+
def value_from_pipedrive(key, value)
|
92
|
+
return unless value && !value.empty?
|
93
|
+
|
94
|
+
option = field_repository
|
95
|
+
.find_by(name: key)
|
96
|
+
.fetch("options", [], choose_first_value: false)
|
97
|
+
.find { |options| options["id"] == value.to_i }
|
98
|
+
|
99
|
+
raise ResourceNotFoundError.new("Could not find field #{key}'s value '#{value}' on Pipedrive") unless option
|
100
|
+
option.fetch("label")
|
101
|
+
end
|
102
|
+
|
103
|
+
def field_repository
|
104
|
+
Object.const_get("Pipekit::#{resource.capitalize}Field").new
|
105
|
+
end
|
106
|
+
|
107
|
+
def convert_key(key)
|
108
|
+
Config.field_id(resource, key)
|
109
|
+
end
|
110
|
+
|
111
|
+
def convert_value(key, value, opts)
|
112
|
+
value = choose_first(value) if opts[:choose_first_value]
|
113
|
+
Config.field_value(resource, key, value)
|
114
|
+
end
|
115
|
+
|
116
|
+
def choose_first(result)
|
117
|
+
return result unless result.is_a? Array
|
118
|
+
return if result.empty?
|
119
|
+
result.first["value"]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# Understands how to represent the result of a request to the Pipedrive API
|
2
|
+
module Pipekit
|
3
|
+
class Result
|
4
|
+
|
5
|
+
def initialize(response_data)
|
6
|
+
@response_data = response_data
|
7
|
+
raise UnsuccessfulRequestError.new(response_data) unless success?
|
8
|
+
end
|
9
|
+
|
10
|
+
def response(resource)
|
11
|
+
raise ResourceNotFoundError.new(response_data) unless resource_found?
|
12
|
+
return Response.new(resource, response_body) unless response_body.is_a? Array
|
13
|
+
response_body.map { |data| Response.new(resource, data) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def +(other)
|
17
|
+
self.class.new(other.merged_response(response_body))
|
18
|
+
end
|
19
|
+
|
20
|
+
def fetch_next_request?
|
21
|
+
Config.fetch("request_all_pages", true) && pagination_data["more_items_in_collection"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def next_start
|
25
|
+
pagination_data["next_start"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.response(resource, response_data)
|
29
|
+
new(response_data).response(resource)
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def merged_response(other_body)
|
35
|
+
response_data.tap do |response|
|
36
|
+
response["data"] = other_body + response_body
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :response_data
|
43
|
+
|
44
|
+
def pagination_data
|
45
|
+
response_data
|
46
|
+
.fetch("additional_data", {})
|
47
|
+
.fetch("pagination", {})
|
48
|
+
end
|
49
|
+
|
50
|
+
def response_body
|
51
|
+
response_data["data"]
|
52
|
+
end
|
53
|
+
|
54
|
+
def success?
|
55
|
+
response_data["success"]
|
56
|
+
end
|
57
|
+
|
58
|
+
def resource_found?
|
59
|
+
!(response_body.nil? || response_body.empty?)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class ResourceNotFoundError < StandardError
|
64
|
+
def initialize(response)
|
65
|
+
@response = response
|
66
|
+
end
|
67
|
+
|
68
|
+
def message
|
69
|
+
"Resource not found: #{@response}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class UnsuccessfulRequestError < StandardError
|
74
|
+
def initialize(response)
|
75
|
+
@response = response
|
76
|
+
end
|
77
|
+
|
78
|
+
def message
|
79
|
+
"Request not successful: #{@response}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/pipekit/version.rb
CHANGED
data/lib/pipekit.rb
CHANGED
@@ -1,33 +1,26 @@
|
|
1
|
-
require "pipekit/
|
1
|
+
require "pipekit/config"
|
2
2
|
require "httparty"
|
3
3
|
require "pipekit/version"
|
4
4
|
require "pipekit/request"
|
5
|
+
require "pipekit/result"
|
6
|
+
require "pipekit/response"
|
5
7
|
require "pipekit/repository"
|
8
|
+
require "pipekit/field_repository"
|
6
9
|
require "pipekit/person"
|
7
10
|
require "pipekit/deal"
|
8
11
|
require "pipekit/person_field"
|
12
|
+
require "pipekit/deal_field"
|
9
13
|
require "pipekit/note"
|
10
14
|
|
11
15
|
module Pipekit
|
12
|
-
include Configurable
|
13
16
|
|
14
17
|
# Define a path to Pipedrive config file
|
15
18
|
#
|
16
19
|
# Example:
|
17
20
|
#
|
18
21
|
# Pipekit.config_file_path = File.join("config", "pipedrive.yml")
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
def config_file_path
|
23
|
-
@config_file_path || raise_config_error
|
24
|
-
end
|
25
|
-
|
26
|
-
def raise_config_error
|
27
|
-
raise ConfigNotSetError, "You need to create a yaml file with your Pipedrive config and set the path to the file using `Pipedrive.config_file_path = 'path/to/file.yml'`"
|
28
|
-
end
|
22
|
+
def self.config_file_path=(path)
|
23
|
+
Config.file_path = path
|
29
24
|
end
|
30
|
-
|
31
|
-
ConfigNotSetError = Class.new(Exception)
|
32
25
|
end
|
33
26
|
|
data/pipekit.gemspec
CHANGED
@@ -13,6 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.description = %q{Pipedrive API client for Ruby.}
|
14
14
|
spec.homepage = "https://github.com/makersacademy/pipekit"
|
15
15
|
spec.license = "MIT"
|
16
|
+
spec.required_ruby_version = '>= 1.9.1'
|
16
17
|
|
17
18
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
19
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
@@ -28,11 +29,10 @@ Gem::Specification.new do |spec|
|
|
28
29
|
spec.require_paths = ["lib"]
|
29
30
|
|
30
31
|
spec.add_dependency "httparty"
|
31
|
-
spec.add_dependency "activesupport"
|
32
32
|
|
33
33
|
spec.add_development_dependency "bundler", "~> 1.12"
|
34
34
|
spec.add_development_dependency "rake", "~> 10.0"
|
35
35
|
spec.add_development_dependency "rspec", "~> 3.0"
|
36
|
-
spec.add_development_dependency "webmock"
|
36
|
+
spec.add_development_dependency "webmock", "~> 2.1.0"
|
37
37
|
spec.add_development_dependency "pry"
|
38
38
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pipekit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jafrog
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-08-31 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|
@@ -26,20 +26,6 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '0'
|
29
|
-
- !ruby/object:Gem::Dependency
|
30
|
-
name: activesupport
|
31
|
-
requirement: !ruby/object:Gem::Requirement
|
32
|
-
requirements:
|
33
|
-
- - ">="
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
-
version: '0'
|
36
|
-
type: :runtime
|
37
|
-
prerelease: false
|
38
|
-
version_requirements: !ruby/object:Gem::Requirement
|
39
|
-
requirements:
|
40
|
-
- - ">="
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: '0'
|
43
29
|
- !ruby/object:Gem::Dependency
|
44
30
|
name: bundler
|
45
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,16 +72,16 @@ dependencies:
|
|
86
72
|
name: webmock
|
87
73
|
requirement: !ruby/object:Gem::Requirement
|
88
74
|
requirements:
|
89
|
-
- - "
|
75
|
+
- - "~>"
|
90
76
|
- !ruby/object:Gem::Version
|
91
|
-
version:
|
77
|
+
version: 2.1.0
|
92
78
|
type: :development
|
93
79
|
prerelease: false
|
94
80
|
version_requirements: !ruby/object:Gem::Requirement
|
95
81
|
requirements:
|
96
|
-
- - "
|
82
|
+
- - "~>"
|
97
83
|
- !ruby/object:Gem::Version
|
98
|
-
version:
|
84
|
+
version: 2.1.0
|
99
85
|
- !ruby/object:Gem::Dependency
|
100
86
|
name: pry
|
101
87
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,13 +116,17 @@ files:
|
|
130
116
|
- bin/console
|
131
117
|
- bin/setup
|
132
118
|
- lib/pipekit.rb
|
133
|
-
- lib/pipekit/
|
119
|
+
- lib/pipekit/config.rb
|
134
120
|
- lib/pipekit/deal.rb
|
121
|
+
- lib/pipekit/deal_field.rb
|
122
|
+
- lib/pipekit/field_repository.rb
|
135
123
|
- lib/pipekit/note.rb
|
136
124
|
- lib/pipekit/person.rb
|
137
125
|
- lib/pipekit/person_field.rb
|
138
126
|
- lib/pipekit/repository.rb
|
139
127
|
- lib/pipekit/request.rb
|
128
|
+
- lib/pipekit/response.rb
|
129
|
+
- lib/pipekit/result.rb
|
140
130
|
- lib/pipekit/version.rb
|
141
131
|
- pipekit.gemspec
|
142
132
|
homepage: https://github.com/makersacademy/pipekit
|
@@ -152,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
152
142
|
requirements:
|
153
143
|
- - ">="
|
154
144
|
- !ruby/object:Gem::Version
|
155
|
-
version:
|
145
|
+
version: 1.9.1
|
156
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
147
|
requirements:
|
158
148
|
- - ">="
|
data/lib/pipekit/configurable.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require "yaml"
|
2
|
-
require "active_support/inflector"
|
3
|
-
require "active_support/core_ext/hash/indifferent_access"
|
4
|
-
|
5
|
-
module Configurable
|
6
|
-
def config
|
7
|
-
self.class.config
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.included(base)
|
11
|
-
base.send :extend, ClassMethods
|
12
|
-
end
|
13
|
-
|
14
|
-
module ClassMethods
|
15
|
-
def config_file_path
|
16
|
-
"./config/#{name.underscore}.yml"
|
17
|
-
end
|
18
|
-
|
19
|
-
def config
|
20
|
-
@config ||= load_config.with_indifferent_access
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def load_config
|
26
|
-
config_hash = load_from_yaml
|
27
|
-
|
28
|
-
config_hash.default_proc = proc do |hash, key|
|
29
|
-
raise Configurable::KeyNotFoundError.new(key)
|
30
|
-
end
|
31
|
-
|
32
|
-
config_hash
|
33
|
-
end
|
34
|
-
|
35
|
-
def load_from_yaml
|
36
|
-
yaml = ERB.new(File.read(config_file_path)).result
|
37
|
-
YAML.load(yaml)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class KeyNotFoundError < StandardError
|
42
|
-
def initialize(key)
|
43
|
-
super("The key #{key} was not found in the configuration file")
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|