pipe_drive_ruby_wrapper 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +76 -0
- data/lib/pipe_drive/base.rb +101 -0
- data/lib/pipe_drive/deal.rb +6 -0
- data/lib/pipe_drive/deal_field.rb +11 -0
- data/lib/pipe_drive/exception.rb +36 -0
- data/lib/pipe_drive/field_base.rb +58 -0
- data/lib/pipe_drive/organization.rb +6 -0
- data/lib/pipe_drive/organization_field.rb +11 -0
- data/lib/pipe_drive/overall_source_base.rb +46 -0
- data/lib/pipe_drive/person.rb +20 -0
- data/lib/pipe_drive/person_field.rb +11 -0
- data/lib/pipe_drive/pipeline.rb +7 -0
- data/lib/pipe_drive/resource_base.rb +86 -0
- data/lib/pipe_drive/send_request.rb +103 -0
- data/lib/pipe_drive/stage.rb +19 -0
- data/lib/pipe_drive_ruby_wrapper.rb +68 -0
- data/spec/lib/deal_spec.rb +15 -0
- data/spec/lib/organization_spec.rb +15 -0
- data/spec/lib/person_spec.rb +15 -0
- data/spec/lib/send_request_spec.rb +10 -0
- data/spec/pipe_drive_ruby_wrapper_spec.rb +34 -0
- data/spec/spec_helper.rb +28 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2f24bb5abbf918344616ceabd2c5934d827b679dc3926e0a76b060556f8b0ae1
|
4
|
+
data.tar.gz: 187ecc5a550e53683944140ddd6d5581e8c75220986395ede513143552983d5c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 144a7b8c10025bf67798ccfd139df42fd68a294d5ab34cbfc29d4ec2b78b23967db94676e3c65a4fb9b865e019257377889def5d2b7b357a03ff95357b968c9e
|
7
|
+
data.tar.gz: 26487cc9cc903902a46b8dcf68cc10d59963350d917f728ebbfa4995761634bce3590f1841042965c38e06b86176f7d38a5371437f0cc6592e4ee6530c89882f
|
data/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# PipeDrive Ruby Wrapper
|
2
|
+
ruby wrapper of pipe drive api
|
3
|
+
|
4
|
+
### Install
|
5
|
+
##### Gem
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem install pipe_drive_ruby_wrapper
|
9
|
+
```
|
10
|
+
##### Gemfile
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'pipe_drive_ruby_wrapper'
|
14
|
+
```
|
15
|
+
|
16
|
+
### Configure
|
17
|
+
|
18
|
+
*You must call below instruction before you start to use this gem*
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
PipeDrive.setup do |config|
|
22
|
+
config.api_token = [Your API Token obtain from pipedrive website]
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
### Usage
|
27
|
+
*You should require first*
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'pipe_drive_ruby_wrapper'
|
31
|
+
```
|
32
|
+
|
33
|
+
use person resource as example
|
34
|
+
|
35
|
+
* list all resource
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
PipeDrive::Person.list
|
39
|
+
```
|
40
|
+
|
41
|
+
* find by id
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
PipeDrive::Person.find_by_id(1)
|
45
|
+
```
|
46
|
+
|
47
|
+
* find by other field (only return one resource)
|
48
|
+
* strict (only the same can be found)
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
PipeDrive::Person.find_by(:name, {name: 'Test'}, PipeDrive::STRICT)
|
52
|
+
```
|
53
|
+
|
54
|
+
* not strict (can be found if similar)
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
PipeDrive::Person.find_by(:name, {name: 'Test'})
|
58
|
+
```
|
59
|
+
|
60
|
+
* search for specific field (return array of resources, can be found if similar)
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
PipeDrive::Person.search(:name, {name: 'Test'})
|
64
|
+
```
|
65
|
+
|
66
|
+
* update resource
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
PipeDrive::Person.update(1, {name: 'new name'})
|
70
|
+
```
|
71
|
+
|
72
|
+
* delete resource
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
PipeDrive::Person.delete(1)
|
76
|
+
```
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module PipeDrive
|
2
|
+
class Base < OpenStruct
|
3
|
+
|
4
|
+
def initialize(attrs)
|
5
|
+
struct_attrs = attrs[:data] || PipeDrive.hash_except(attrs, [:additional_data])
|
6
|
+
struct_attrs.merge!(attrs[:additional_data]) unless attrs[:additional_data].nil?
|
7
|
+
|
8
|
+
super(struct_attrs)
|
9
|
+
end
|
10
|
+
|
11
|
+
def requester
|
12
|
+
PipeDrive.requester
|
13
|
+
end
|
14
|
+
|
15
|
+
def update(opts)
|
16
|
+
path = "/#{self.class.resource_name}s/#{id}"
|
17
|
+
opts.transform_keys!{|key| field_keys[key] || key}
|
18
|
+
requester.http_put(path, opts) do |result|
|
19
|
+
new(result)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete
|
24
|
+
path = "/#{self.class.resource_name}s/#{id}"
|
25
|
+
requester.http_del(path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def parameterize(target_string, separator)
|
29
|
+
self.class.parameterize(target_string, separator)
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def requester
|
34
|
+
PipeDrive.requester
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_by_id(id)
|
38
|
+
path = "/#{resource_name}s/#{id}"
|
39
|
+
requester.http_get(path) do |result|
|
40
|
+
result[:data].nil? ? nil : new(result)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def create(opts)
|
45
|
+
opts.transform_keys!{|key| field_keys[key] || key}
|
46
|
+
requester.http_post("/#{resource_name}s", opts) do |result|
|
47
|
+
new(result)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def update(id, opts)
|
52
|
+
path = "/#{resource_name}s/#{id}"
|
53
|
+
opts.transform_keys!{|key| field_keys[key] || key}
|
54
|
+
requester.http_put(path, opts) do |result|
|
55
|
+
new(result)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete(id)
|
60
|
+
path = "/#{resource_name}s/#{id}"
|
61
|
+
requester.http_del(path){|result| puts result}
|
62
|
+
end
|
63
|
+
|
64
|
+
def search_and_setup_by(type, opts, strict=false)
|
65
|
+
target = find_by(type, opts, strict)
|
66
|
+
if target.nil?
|
67
|
+
create(opts)
|
68
|
+
else
|
69
|
+
target.update(opts)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def parameterize(target_string, separator)
|
74
|
+
target_string.gsub!(/[\-_\ ]+/, separator)
|
75
|
+
target_string.downcase
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
def list_objects(attrs)
|
81
|
+
return [] if attrs.nil? || attrs.empty?
|
82
|
+
if attrs[:data].nil?
|
83
|
+
struct_attrs = attrs
|
84
|
+
elsif attrs[:additional_data].nil?
|
85
|
+
struct_attrs = attrs[:data].map do |data|
|
86
|
+
data
|
87
|
+
end
|
88
|
+
else
|
89
|
+
struct_attrs = attrs[:data].map do |data|
|
90
|
+
data.merge(attrs[:additional_data])
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
struct_attrs.map do |struct_attr|
|
95
|
+
new(struct_attr)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module PipeDrive
|
2
|
+
class MissingApiToken < StandardError
|
3
|
+
def initialize
|
4
|
+
err_msg = "api token not found, please setup with
|
5
|
+
PipeDrive.setup do |config|
|
6
|
+
config.api_token = [Your API Token]
|
7
|
+
end
|
8
|
+
"
|
9
|
+
super(err_msg)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class NotAllowSearchType < StandardError
|
14
|
+
def initialize(type=nil)
|
15
|
+
super("#{type} not allow search type")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class NotProvideAssignType < StandardError
|
20
|
+
def initialize(type=nil)
|
21
|
+
super("not provide #{type}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class TargetNotFound < StandardError
|
26
|
+
def initialize(class_name, search_type, search_value)
|
27
|
+
super("#{class_name}: search #{search_type} for #{search_value} not found")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class RequestError < StandardError
|
32
|
+
def initialize(response)
|
33
|
+
super(response.to_json)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module PipeDrive
|
2
|
+
class FieldBase < Base
|
3
|
+
def add_to_field_keys
|
4
|
+
resource = self.class.correspond_resource.to_sym
|
5
|
+
field_name = parameterize(name, '_').to_sym
|
6
|
+
PipeDrive.field_keys[resource][field_name] = key
|
7
|
+
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def correspond_resource
|
12
|
+
resource_name.sub('Field', '')
|
13
|
+
end
|
14
|
+
|
15
|
+
def list(&block)
|
16
|
+
path = "/#{resource_name}s"
|
17
|
+
resources = requester.http_get(path) do |result|
|
18
|
+
result[:data].nil? ? [] : list_objects(result)
|
19
|
+
end
|
20
|
+
resources.each do |resource|
|
21
|
+
yield resource
|
22
|
+
end if block_given?
|
23
|
+
resources
|
24
|
+
end
|
25
|
+
|
26
|
+
def create(opts)
|
27
|
+
new_field = super(opts)
|
28
|
+
new_field.add_to_field_keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def custom_field_setup
|
32
|
+
resource = correspond_resource.to_sym
|
33
|
+
list.each do |field|
|
34
|
+
field_name = parameterize(field.name, '_').to_sym
|
35
|
+
PipeDrive.field_keys[resource][field_name] = field.key
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def cache_keys
|
40
|
+
PipeDrive.field_keys[correspond_resource.to_sym]
|
41
|
+
end
|
42
|
+
|
43
|
+
def pipedrive_key_of(field_name)
|
44
|
+
cache_field_name = parameterize(field_name, '_').to_sym
|
45
|
+
pipedrive_key = cache_keys[cache_field_name]
|
46
|
+
return pipedrive_key unless pipedrive_key.nil?
|
47
|
+
custom_field_setup
|
48
|
+
pipedrive_key = cache_keys[cache_field_name]
|
49
|
+
if pipedrive_key.nil?
|
50
|
+
raise TargetNotFound.new(self.name, :name, field_name)
|
51
|
+
else
|
52
|
+
pipedrive_key
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module PipeDrive
|
2
|
+
class OverallSourceBase < ResourceBase
|
3
|
+
|
4
|
+
def deals(start_from=0, per_page=DEFAULT_PER_PAGE, options={}, &block)
|
5
|
+
path = "/#{resource_name}s/#{id}/deals"
|
6
|
+
params = {start: start_from, limit: per_page}
|
7
|
+
params.merge!(options)
|
8
|
+
pagination(path, params, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
|
14
|
+
def list(options={}, &block)
|
15
|
+
path = "/#{resource_name}s"
|
16
|
+
resources = requester.http_get(path, options) do |result|
|
17
|
+
result[:data].nil? ? [] : list_objects(result)
|
18
|
+
end
|
19
|
+
resources.each do |resource|
|
20
|
+
yield resource
|
21
|
+
end if block_given?
|
22
|
+
resources
|
23
|
+
end
|
24
|
+
|
25
|
+
def search(type, opts)
|
26
|
+
raise NotAllowSearchType.new(type) unless const_get('ALLOW_FOR_SEARCH_TERMS').include?(type)
|
27
|
+
raise NotProvideAssignType.new(type) if opts[type].nil?
|
28
|
+
allow_search_opts = const_get('ALLOW_FOR_ADDITION_SEARCH_OPTS') + [type]
|
29
|
+
opts = opts.slice(*allow_search_opts)
|
30
|
+
list.select do |resource|
|
31
|
+
is_match = true
|
32
|
+
opts.each_pair do |key, value|
|
33
|
+
resource_value = resource.send(key)
|
34
|
+
if resource_value.is_a?(String)
|
35
|
+
(is_match = false) && break unless resource_value.include?(value)
|
36
|
+
else
|
37
|
+
(is_match = false) && break unless resource_value == value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
is_match
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module PipeDrive
|
2
|
+
class Person < ResourceBase
|
3
|
+
ALLOW_FOR_SEARCH_TERMS = %i[name email]
|
4
|
+
ALLOW_FOR_ADDITION_SEARCH_OPTS = %i[org_id start limit]
|
5
|
+
|
6
|
+
def activities(start_from=0, per_page=DEFAULT_PER_PAGE, options={}, &block)
|
7
|
+
path = "/persons/#{id}/activities"
|
8
|
+
params = {start: start_from, limit: per_page}
|
9
|
+
params.merge!(options)
|
10
|
+
pagination(path, params, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def deals(start_from=0, per_page=DEFAULT_PER_PAGE, options={}, &block)
|
14
|
+
path = "/persons/#{id}/deals"
|
15
|
+
params = {start: start_from, limit: per_page}
|
16
|
+
params.merge!(options)
|
17
|
+
pagination(path, params, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module PipeDrive
|
2
|
+
class ResourceBase < Base
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
def pagination(path, params, &block)
|
7
|
+
self.class.send(:pagination, path, params, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def resource_name
|
13
|
+
name.split('::').last.downcase
|
14
|
+
end
|
15
|
+
|
16
|
+
def field_keys
|
17
|
+
PipeDrive.field_keys[resource_name.to_sym]
|
18
|
+
end
|
19
|
+
|
20
|
+
def list(options={}, &block)
|
21
|
+
path = "/#{resource_name}s"
|
22
|
+
params = {start_from: 0, limit: DEFAULT_PER_PAGE}
|
23
|
+
params.merge!(options)
|
24
|
+
pagination(path, params, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def pagination_list(start_from=0, per_page=DEFAULT_PER_PAGE, options={}, &block)
|
28
|
+
path = "/#{resource_name}s"
|
29
|
+
params = {start: start_from, limit: per_page}
|
30
|
+
params.merge!(options)
|
31
|
+
resources = requester.http_get(path, params) do |result|
|
32
|
+
result[:data].nil? ? nil : list_objects(result)
|
33
|
+
end
|
34
|
+
resources.each do |resource|
|
35
|
+
yield resource
|
36
|
+
end if block_given?
|
37
|
+
resources
|
38
|
+
end
|
39
|
+
|
40
|
+
def search(type, opts)
|
41
|
+
raise NotAllowSearchType.new(type) unless const_get('ALLOW_FOR_SEARCH_TERMS').include?(type)
|
42
|
+
raise NotProvideAssignType.new(type) if opts[type].nil?
|
43
|
+
params = {term: opts[type]}
|
44
|
+
allow_search_opts = const_get('ALLOW_FOR_ADDITION_SEARCH_OPTS')
|
45
|
+
params.merge!(opts.slice(*allow_search_opts))
|
46
|
+
requester.http_get("/#{resource_name}s/find", params) do |result|
|
47
|
+
result[:data].nil? ? nil : list_objects(result)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_by(type, opts, strict=false)
|
52
|
+
targets = search(type, opts)
|
53
|
+
return if targets.nil? || targets.empty?
|
54
|
+
if strict
|
55
|
+
targets.find do |target|
|
56
|
+
target.send(type) == opts[type]
|
57
|
+
end
|
58
|
+
else
|
59
|
+
targets.first
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def pagination(path, params, &block)
|
66
|
+
resources = []
|
67
|
+
loop do
|
68
|
+
next_start_from = requester.http_get(path, params) do |result|
|
69
|
+
return resources if result[:data].nil?
|
70
|
+
items = list_objects(result)
|
71
|
+
resources += items
|
72
|
+
items.each do |item|
|
73
|
+
yield item
|
74
|
+
end if block_given?
|
75
|
+
result.dig(:additional_data, :pagination, :next_start)
|
76
|
+
end
|
77
|
+
break if next_start_from.nil?
|
78
|
+
params[:start] = next_start_from
|
79
|
+
end
|
80
|
+
resources
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module PipeDrive
|
2
|
+
class SendRequest
|
3
|
+
attr_reader :host
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
raise MissingApiToken.new if PipeDrive.api_token.nil?
|
7
|
+
@host = PipeDrive.host
|
8
|
+
@api_token = PipeDrive.api_token
|
9
|
+
end
|
10
|
+
|
11
|
+
def http_get(path, params={}, header={}, &block)
|
12
|
+
begin
|
13
|
+
full_url = "#{host}/#{API_VERSION}#{path}"
|
14
|
+
uri = URI(full_url)
|
15
|
+
params.merge!(api_token: @api_token)
|
16
|
+
uri.query = URI.encode_www_form(params)
|
17
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
18
|
+
http.use_ssl = uri.scheme == 'https'
|
19
|
+
|
20
|
+
request = Net::HTTP::Get.new(uri.request_uri, header)
|
21
|
+
response = http.request(request)
|
22
|
+
result = handle_response(response)
|
23
|
+
rescue Exception => e
|
24
|
+
result = server_error_response(e.message)
|
25
|
+
end
|
26
|
+
return result unless block_given?
|
27
|
+
raise RequestError.new(result) unless success_result?(result)
|
28
|
+
yield PipeDrive.hash_except(result, [:status])
|
29
|
+
end
|
30
|
+
|
31
|
+
def http_post(path, params={}, header={}, &block)
|
32
|
+
body_request(:post, path, params, header, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def http_put(path, params={}, header={}, &block)
|
36
|
+
body_request(:put, path, params, header, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def http_del(path, params={}, header={}, &block)
|
40
|
+
body_request(:delete, path, params, header, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def body_request(method, path, params={}, header={}, &block)
|
46
|
+
begin
|
47
|
+
full_url = "#{host}/#{API_VERSION}#{path}?api_token=#{@api_token}"
|
48
|
+
uri = URI(full_url)
|
49
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
50
|
+
http.use_ssl = uri.scheme == 'https'
|
51
|
+
header['Content-Type'] = 'application/json'
|
52
|
+
|
53
|
+
request = Net::HTTP.const_get(method.to_s.capitalize).new(uri.request_uri, header)
|
54
|
+
request.body = params.to_json
|
55
|
+
response = http.request(request)
|
56
|
+
result = handle_response(response)
|
57
|
+
rescue Exception => e
|
58
|
+
result = server_error_response(e.message)
|
59
|
+
end
|
60
|
+
return result unless block_given?
|
61
|
+
raise RequestError.new(result) unless success_result?(result)
|
62
|
+
yield PipeDrive.hash_except(result, [:status])
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def handle_response(response)
|
68
|
+
result = {status: response.code.to_i}
|
69
|
+
|
70
|
+
begin
|
71
|
+
body = Oj.load(response.body)
|
72
|
+
rescue
|
73
|
+
body = {body: response.body}
|
74
|
+
end
|
75
|
+
body = deep_symbolize_keys(body)
|
76
|
+
result.merge body
|
77
|
+
end
|
78
|
+
|
79
|
+
def server_error_response(err_msg)
|
80
|
+
{status: 500, message: err_msg}
|
81
|
+
end
|
82
|
+
|
83
|
+
def success_result?(result)
|
84
|
+
result[:status].is_a?(Integer) && (result[:status] / 100 == 2)
|
85
|
+
end
|
86
|
+
|
87
|
+
def deep_symbolize_keys(data)
|
88
|
+
new_data = {}
|
89
|
+
data.each_pair do |key, value|
|
90
|
+
if value.is_a?(Hash)
|
91
|
+
new_data[key.to_sym] = deep_symbolize_keys(value)
|
92
|
+
elsif value.is_a?(Array)
|
93
|
+
new_data[key.to_sym] = value.map do |v|
|
94
|
+
deep_symbolize_keys(v)
|
95
|
+
end
|
96
|
+
else
|
97
|
+
new_data[key.to_sym] = value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
new_data
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module PipeDrive
|
2
|
+
class Stage < OverallSourceBase
|
3
|
+
ALLOW_FOR_SEARCH_TERMS = %i[name]
|
4
|
+
ALLOW_FOR_ADDITION_SEARCH_OPTS = %i[pipeline_name pipeline_id]
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def setup_stage_ids
|
9
|
+
list.each do |stage|
|
10
|
+
pipeline_name = parameterize(stage.pipeline_name, '_').to_sym
|
11
|
+
stage_name = parameterize(stage.name, '_').to_sym
|
12
|
+
PipeDrive.stage_ids[pipeline_name][stage_name] = stage.id
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'oj'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module PipeDrive
|
7
|
+
API_VERSION = 'v1'
|
8
|
+
DEFAULT_PER_PAGE = 10
|
9
|
+
STRICT = true
|
10
|
+
|
11
|
+
RESOURCE_CLASSES = %w[Organization Person Deal]
|
12
|
+
FIELD_CLASSES = %w[OrganizationField PersonField DealField]
|
13
|
+
|
14
|
+
class << self; attr_accessor :api_token, :field_keys, :stage_ids; end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def setup
|
18
|
+
yield self
|
19
|
+
|
20
|
+
if field_keys.nil?
|
21
|
+
self.field_keys = Hash.new{|hash, key| hash[key] = {}}
|
22
|
+
FIELD_CLASSES.each do |class_name|
|
23
|
+
const_get(class_name).custom_field_setup
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if stage_ids.nil?
|
28
|
+
self.stage_ids = Hash.new{|hash, key| hash[key] = {}}
|
29
|
+
Stage.setup_stage_ids
|
30
|
+
end
|
31
|
+
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def host
|
36
|
+
"https://api.pipedrive.com"
|
37
|
+
end
|
38
|
+
|
39
|
+
def requester
|
40
|
+
SendRequest.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def hash_except(hash, except_keys)
|
44
|
+
all_keys = hash.keys
|
45
|
+
remain_keys = all_keys - except_keys
|
46
|
+
hash.slice(*remain_keys)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
require 'pipe_drive/base'
|
53
|
+
require 'pipe_drive/exception'
|
54
|
+
require 'pipe_drive/send_request'
|
55
|
+
|
56
|
+
require 'pipe_drive/resource_base'
|
57
|
+
require 'pipe_drive/organization'
|
58
|
+
require 'pipe_drive/person'
|
59
|
+
require 'pipe_drive/deal'
|
60
|
+
|
61
|
+
require 'pipe_drive/overall_source_base'
|
62
|
+
require 'pipe_drive/pipeline'
|
63
|
+
require 'pipe_drive/stage'
|
64
|
+
|
65
|
+
require 'pipe_drive/field_base'
|
66
|
+
require 'pipe_drive/organization_field'
|
67
|
+
require 'pipe_drive/person_field'
|
68
|
+
require 'pipe_drive/deal_field'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe PipeDrive::Deal do
|
2
|
+
|
3
|
+
context '.resource_name' do
|
4
|
+
it 'should return resource name' do
|
5
|
+
expect(PipeDrive::Deal.resource_name).to eq('deal')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
context '.field_keys' do
|
10
|
+
it 'should obtain person custom field' do
|
11
|
+
deal_custom_fields = {product: 'product key'}
|
12
|
+
expect(PipeDrive::Deal.field_keys).to eq(deal_custom_fields)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe PipeDrive::Organization do
|
2
|
+
|
3
|
+
context '.resource_name' do
|
4
|
+
it 'should return resource name' do
|
5
|
+
expect(PipeDrive::Organization.resource_name).to eq('organization')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
context '.field_keys' do
|
10
|
+
it 'should obtain person custom field' do
|
11
|
+
org_custom_fields = {region: 'region key'}
|
12
|
+
expect(PipeDrive::Organization.field_keys).to eq(org_custom_fields)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe PipeDrive::Person do
|
2
|
+
|
3
|
+
context '.resource_name' do
|
4
|
+
it 'should return resource name' do
|
5
|
+
expect(PipeDrive::Person.resource_name).to eq('person')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
context '.field_keys' do
|
10
|
+
it 'should obtain person custom field' do
|
11
|
+
person_custom_fields = {role: 'role key'}
|
12
|
+
expect(PipeDrive::Person.field_keys).to eq(person_custom_fields)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
RSpec.describe PipeDrive::SendRequest do
|
2
|
+
|
3
|
+
context '.initialize' do
|
4
|
+
it 'should raise missing api token error if not set api token' do
|
5
|
+
PipeDrive.api_token = nil
|
6
|
+
expect{PipeDrive::SendRequest.new}.to raise_error(PipeDrive::MissingApiToken)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
RSpec.describe PipeDrive do
|
2
|
+
context '.setup' do
|
3
|
+
it 'should setup basic info for pipedrive' do
|
4
|
+
PipeDrive.setup do |config|
|
5
|
+
config.api_token = 'api token'
|
6
|
+
config.field_keys = {
|
7
|
+
person: {test: 'test_key'}
|
8
|
+
}
|
9
|
+
config.stage_ids = {
|
10
|
+
1 => {
|
11
|
+
test: 1
|
12
|
+
}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
expect(PipeDrive.api_token).to eq('api token')
|
16
|
+
expect(PipeDrive.field_keys).to eq({person: {test: 'test_key'}})
|
17
|
+
expect(PipeDrive.stage_ids).to eq({1 => {test: 1}})
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context '.host' do
|
22
|
+
it 'should return host with setup organization name' do
|
23
|
+
pipe_drive_host = "https://api.pipedrive.com"
|
24
|
+
expect(PipeDrive.host).to eq(pipe_drive_host)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context '.requester' do
|
29
|
+
it 'should setup requester with pipe drive host' do
|
30
|
+
pipe_drive_host = "https://api.pipedrive.com"
|
31
|
+
expect(PipeDrive.requester.host).to eq(pipe_drive_host)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'pipe_drive_ruby_wrapper'
|
3
|
+
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
ENV['RAILS_ENV'] ||= 'test'
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
# some (optional) config here
|
10
|
+
end
|
11
|
+
|
12
|
+
PipeDrive.setup do |config|
|
13
|
+
config.api_token = 'api_token'
|
14
|
+
config.field_keys = {
|
15
|
+
organization: {
|
16
|
+
region: 'region key'
|
17
|
+
},
|
18
|
+
person: {
|
19
|
+
role: 'role key'
|
20
|
+
},
|
21
|
+
deal: {
|
22
|
+
product: 'product key'
|
23
|
+
}
|
24
|
+
}
|
25
|
+
config.stage_ids = {
|
26
|
+
1 => {test: 1}
|
27
|
+
}
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pipe_drive_ruby_wrapper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- JiaRou Lee
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-08-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: oj
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.3'
|
41
|
+
description: ruby wrapper of some pipe drive api
|
42
|
+
email: laura34963@kdanmobile.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files:
|
46
|
+
- README.md
|
47
|
+
files:
|
48
|
+
- README.md
|
49
|
+
- lib/pipe_drive/base.rb
|
50
|
+
- lib/pipe_drive/deal.rb
|
51
|
+
- lib/pipe_drive/deal_field.rb
|
52
|
+
- lib/pipe_drive/exception.rb
|
53
|
+
- lib/pipe_drive/field_base.rb
|
54
|
+
- lib/pipe_drive/organization.rb
|
55
|
+
- lib/pipe_drive/organization_field.rb
|
56
|
+
- lib/pipe_drive/overall_source_base.rb
|
57
|
+
- lib/pipe_drive/person.rb
|
58
|
+
- lib/pipe_drive/person_field.rb
|
59
|
+
- lib/pipe_drive/pipeline.rb
|
60
|
+
- lib/pipe_drive/resource_base.rb
|
61
|
+
- lib/pipe_drive/send_request.rb
|
62
|
+
- lib/pipe_drive/stage.rb
|
63
|
+
- lib/pipe_drive_ruby_wrapper.rb
|
64
|
+
- spec/lib/deal_spec.rb
|
65
|
+
- spec/lib/organization_spec.rb
|
66
|
+
- spec/lib/person_spec.rb
|
67
|
+
- spec/lib/send_request_spec.rb
|
68
|
+
- spec/pipe_drive_ruby_wrapper_spec.rb
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
homepage: https://github.com/laura34963/pipe_drive_ruby_wrapper
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- "--charset=UTF-8"
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 2.3.1
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.7.7
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Some PipeDrive API Ruby Wrapper
|
95
|
+
test_files:
|
96
|
+
- spec/lib/deal_spec.rb
|
97
|
+
- spec/lib/organization_spec.rb
|
98
|
+
- spec/lib/person_spec.rb
|
99
|
+
- spec/lib/send_request_spec.rb
|
100
|
+
- spec/pipe_drive_ruby_wrapper_spec.rb
|
101
|
+
- spec/spec_helper.rb
|