amorail 0.3.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rubocop.yml +19 -1
- data/README.md +7 -1
- data/Rakefile +7 -3
- data/amorail.gemspec +4 -3
- data/lib/amorail.rb +3 -0
- data/lib/amorail/client.rb +8 -4
- data/lib/amorail/config.rb +2 -0
- data/lib/amorail/entities/company.rb +2 -0
- data/lib/amorail/entities/contact.rb +3 -0
- data/lib/amorail/entities/contact_link.rb +2 -0
- data/lib/amorail/entities/elementable.rb +39 -0
- data/lib/amorail/entities/lead.rb +4 -1
- data/lib/amorail/entities/leadable.rb +3 -0
- data/lib/amorail/entities/note.rb +19 -0
- data/lib/amorail/entities/task.rb +11 -23
- data/lib/amorail/entities/webhook.rb +44 -0
- data/lib/amorail/entity.rb +17 -9
- data/lib/amorail/entity/finders.rb +19 -14
- data/lib/amorail/entity/params.rb +2 -0
- data/lib/amorail/entity/{persistance.rb → persistence.rb} +24 -0
- data/lib/amorail/exceptions.rb +2 -0
- data/lib/amorail/property.rb +8 -0
- data/lib/amorail/railtie.rb +4 -1
- data/lib/amorail/version.rb +3 -1
- data/lib/tasks/amorail.rake +2 -0
- data/spec/client_spec.rb +2 -0
- data/spec/company_spec.rb +2 -0
- data/spec/contact_link_spec.rb +2 -0
- data/spec/contact_spec.rb +17 -0
- data/spec/entity_spec.rb +2 -0
- data/spec/fixtures/{account_response.json → accounts/response_1.json} +5 -5
- data/spec/fixtures/{account2_response.json → accounts/response_2.json} +1 -1
- data/spec/fixtures/{contact_create.json → contacts/create.json} +1 -1
- data/spec/fixtures/{contact_find_query.json → contacts/find_many.json} +3 -5
- data/spec/fixtures/{contact_find.json → contacts/find_one.json} +5 -6
- data/spec/fixtures/contacts/links.json +16 -0
- data/spec/fixtures/{my_contact_find.json → contacts/my_contact_find.json} +2 -3
- data/spec/fixtures/contacts/update.json +13 -0
- data/spec/fixtures/leads/create.json +13 -0
- data/spec/fixtures/leads/find_many.json +73 -0
- data/spec/fixtures/leads/links.json +16 -0
- data/spec/fixtures/leads/update.json +13 -0
- data/spec/fixtures/leads/update_errors.json +12 -0
- data/spec/fixtures/webhooks/list.json +24 -0
- data/spec/fixtures/webhooks/subscribe.json +17 -0
- data/spec/fixtures/webhooks/unsubscribe.json +17 -0
- data/spec/helpers/webmock_helpers.rb +92 -13
- data/spec/lead_spec.rb +30 -0
- data/spec/my_contact_spec.rb +2 -0
- data/spec/note_spec.rb +28 -0
- data/spec/property_spec.rb +2 -0
- data/spec/spec_helper.rb +4 -2
- data/spec/support/elementable_example.rb +54 -0
- data/spec/support/entity_class_example.rb +2 -0
- data/spec/support/leadable_example.rb +2 -0
- data/spec/support/my_contact.rb +2 -0
- data/spec/support/my_entity.rb +2 -0
- data/spec/task_spec.rb +8 -28
- data/spec/webhook_spec.rb +61 -0
- metadata +60 -33
- data/.hound.yml +0 -12
- data/spec/fixtures/contact_update.json +0 -5
- data/spec/fixtures/contacts_links.json +0 -15
- data/spec/fixtures/leads.json +0 -69
- data/spec/fixtures/leads_links.json +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6047ec19aa4839d30b29fc1cb9ee38079a04812b2ed6547d2e24e1e8ed16a57d
|
4
|
+
data.tar.gz: 64bfbcd2f8574b70c420a274bd8707533b4f4334020d180fda7acb85cdcee509
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55fc29183cff4df2db947a76ceae748d289ebab1f1e88310e7c13234dd75886c87e9f68c41b782ba251be69f2226f386501974108ce2cc00fdc656e1ccdfe059
|
7
|
+
data.tar.gz: da64fc02f0bc506319bd543e7b35cb5dfdd3b112cc04458f25904c5d9ece1bc38df8d659ca1d705e17fcea8e7cd82e954c7f4642048fb2ed627a03c0f1802b8c
|
data/.rubocop.yml
CHANGED
@@ -6,7 +6,9 @@ AllCops:
|
|
6
6
|
- 'spec/**/*.rb'
|
7
7
|
Exclude:
|
8
8
|
- 'bin/**/*'
|
9
|
-
|
9
|
+
- Rakefile
|
10
|
+
- Gemfile
|
11
|
+
- '*.gemspec'
|
10
12
|
DisplayCopNames: true
|
11
13
|
StyleGuideCopsOnly: false
|
12
14
|
|
@@ -39,5 +41,21 @@ Metrics/LineLength:
|
|
39
41
|
Exclude:
|
40
42
|
- 'spec/**/*.rb'
|
41
43
|
|
44
|
+
Metrics/BlockLength:
|
45
|
+
Exclude:
|
46
|
+
- 'spec/**/*.rb'
|
47
|
+
|
42
48
|
Style/WordArray:
|
43
49
|
Enabled: false
|
50
|
+
|
51
|
+
Style/SymbolArray:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
Style/SignalException:
|
55
|
+
Enabled: false
|
56
|
+
|
57
|
+
Layout/MultilineMethodCallBraceLayout:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
Lint/MissingCopEnableDirective:
|
61
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](https://travis-ci.org/teachbase/amorail)
|
1
|
+
[](https://rubygems.org/gems/amorail) [](https://travis-ci.org/teachbase/amorail)
|
2
2
|
|
3
3
|
# Amorail
|
4
4
|
|
@@ -128,6 +128,12 @@ Or using query:
|
|
128
128
|
Amorail::Company.find_by_query("vip")
|
129
129
|
```
|
130
130
|
|
131
|
+
Or using arbitrary params:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
Amorail::Company.where(query: "test", limit_rows: 10)
|
135
|
+
```
|
136
|
+
|
131
137
|
Also you can update objects, e.g:
|
132
138
|
|
133
139
|
```ruby
|
data/Rakefile
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require 'rspec/core/rake_task'
|
3
|
-
|
3
|
+
require "rubocop/rake_task"
|
4
4
|
|
5
|
-
|
5
|
+
Dir.glob('lib/tasks/*.rake').each { |r| import r }
|
6
6
|
|
7
|
-
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
8
|
|
9
9
|
task :console do
|
10
10
|
sh 'pry -r ./lib/amorail.rb'
|
11
11
|
end
|
12
|
+
|
13
|
+
RuboCop::RakeTask.new
|
14
|
+
|
15
|
+
task default: [:rubocop, :spec]
|
data/amorail.gemspec
CHANGED
@@ -22,9 +22,10 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
23
|
spec.add_development_dependency "rspec", "~> 3.4"
|
24
24
|
spec.add_development_dependency "webmock"
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.
|
25
|
+
spec.add_development_dependency "pry"
|
26
|
+
spec.add_development_dependency "shoulda-matchers", "~> 2.0"
|
27
|
+
spec.add_development_dependency "rubocop", "~> 0.49"
|
28
|
+
spec.add_dependency "anyway_config", ">= 1.0"
|
28
29
|
spec.add_dependency "faraday"
|
29
30
|
spec.add_dependency "faraday_middleware"
|
30
31
|
spec.add_dependency 'activemodel'
|
data/lib/amorail.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'amorail/version'
|
2
4
|
require 'amorail/config'
|
3
5
|
require 'amorail/client'
|
@@ -35,6 +37,7 @@ module Amorail
|
|
35
37
|
client = Client.new(client) unless client.is_a?(Client)
|
36
38
|
ClientRegistry.client = client
|
37
39
|
yield
|
40
|
+
ensure
|
38
41
|
ClientRegistry.client = nil
|
39
42
|
end
|
40
43
|
|
data/lib/amorail/client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
require 'faraday_middleware'
|
3
5
|
require 'json'
|
@@ -6,6 +8,8 @@ require 'active_support'
|
|
6
8
|
module Amorail
|
7
9
|
# Amorail http client
|
8
10
|
class Client
|
11
|
+
SUCCESS_STATUS_CODES = [200, 204].freeze
|
12
|
+
|
9
13
|
attr_reader :usermail, :api_key, :api_endpoint
|
10
14
|
|
11
15
|
def initialize(api_endpoint: Amorail.config.api_endpoint,
|
@@ -15,9 +19,9 @@ module Amorail
|
|
15
19
|
@api_key = api_key
|
16
20
|
@usermail = usermail
|
17
21
|
@connect = Faraday.new(url: api_endpoint) do |faraday|
|
18
|
-
faraday.adapter Faraday.default_adapter
|
19
22
|
faraday.response :json, content_type: /\bjson$/
|
20
23
|
faraday.use :instrumentation
|
24
|
+
faraday.adapter Faraday.default_adapter
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
@@ -41,10 +45,10 @@ module Amorail
|
|
41
45
|
end
|
42
46
|
|
43
47
|
def safe_request(method, url, params = {})
|
44
|
-
|
48
|
+
public_send(method, url, params)
|
45
49
|
rescue ::Amorail::AmoUnauthorizedError
|
46
50
|
authorize
|
47
|
-
|
51
|
+
public_send(method, url, params)
|
48
52
|
end
|
49
53
|
|
50
54
|
def get(url, params = {})
|
@@ -72,7 +76,7 @@ module Amorail
|
|
72
76
|
end
|
73
77
|
|
74
78
|
def handle_response(response) # rubocop:disable all
|
75
|
-
return response if
|
79
|
+
return response if SUCCESS_STATUS_CODES.include?(response.status)
|
76
80
|
|
77
81
|
case response.status
|
78
82
|
when 301
|
data/lib/amorail/config.rb
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Amorail
|
4
|
+
# Provides common functionallity for entities
|
5
|
+
# that can be attached to another objects.
|
6
|
+
module Elementable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
ELEMENT_TYPES = {
|
10
|
+
contact: 1,
|
11
|
+
lead: 2,
|
12
|
+
company: 3,
|
13
|
+
task: 4
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
included do
|
17
|
+
amo_field :element_id, :element_type
|
18
|
+
|
19
|
+
validates :element_id, :element_type,
|
20
|
+
presence: true
|
21
|
+
end
|
22
|
+
|
23
|
+
ELEMENT_TYPES.each do |type, value|
|
24
|
+
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
25
|
+
def #{type}=(val) # def contact=(val)
|
26
|
+
#{type}! if val # contact! if val
|
27
|
+
end # end
|
28
|
+
|
29
|
+
def #{type}? # def contact?
|
30
|
+
self.element_type == #{value} # self.element_type == 1
|
31
|
+
end # end
|
32
|
+
|
33
|
+
def #{type}! # def contact!
|
34
|
+
self.element_type = #{value} # self.element_type = 1
|
35
|
+
end # end
|
36
|
+
CODE
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Amorail
|
2
4
|
# AmoCRM lead entity
|
3
5
|
class Lead < Amorail::Entity
|
4
6
|
amo_names "leads"
|
5
7
|
|
6
|
-
amo_field :name, :price, :status_id, :tags
|
8
|
+
amo_field :name, :price, :status_id, :pipeline_id, :tags
|
7
9
|
|
8
10
|
validates :name, :status_id, presence: true
|
9
11
|
|
@@ -15,6 +17,7 @@ module Amorail
|
|
15
17
|
# Return list of associated contacts
|
16
18
|
def contacts
|
17
19
|
fail NotPersisted if id.nil?
|
20
|
+
|
18
21
|
@contacts ||=
|
19
22
|
begin
|
20
23
|
links = Amorail::ContactLink.find_by_leads(id)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Amorail
|
2
4
|
# Lead associations
|
3
5
|
module Leadable
|
@@ -22,6 +24,7 @@ module Amorail
|
|
22
24
|
# Return all linked leads
|
23
25
|
def leads
|
24
26
|
return [] if linked_leads_id.empty?
|
27
|
+
|
25
28
|
@leads ||= Amorail::Lead.find_all(linked_leads_id)
|
26
29
|
end
|
27
30
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'amorail/entities/elementable'
|
4
|
+
|
5
|
+
module Amorail
|
6
|
+
# AmoCRM note entity
|
7
|
+
class Note < Amorail::Entity
|
8
|
+
include Elementable
|
9
|
+
|
10
|
+
amo_names 'notes'
|
11
|
+
|
12
|
+
amo_field :note_type, :text
|
13
|
+
|
14
|
+
validates :note_type, :text,
|
15
|
+
presence: true
|
16
|
+
|
17
|
+
validates :element_type, inclusion: ELEMENT_TYPES.values
|
18
|
+
end
|
19
|
+
end
|
@@ -1,32 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'amorail/entities/elementable'
|
4
|
+
|
1
5
|
module Amorail
|
2
6
|
# AmoCRM task entity
|
3
7
|
class Task < Amorail::Entity
|
4
|
-
|
5
|
-
|
6
|
-
amo_field :element_id, :element_type, :text,
|
7
|
-
:task_type, complete_till: :timestamp
|
8
|
+
include Elementable
|
8
9
|
|
9
|
-
|
10
|
-
:element_type, :complete_till,
|
11
|
-
:task_type,
|
12
|
-
presence: true
|
13
|
-
|
14
|
-
validates :element_type, inclusion: 1..2
|
10
|
+
amo_names 'tasks'
|
15
11
|
|
16
|
-
|
17
|
-
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
18
|
-
def #{prop[:name]}=(val)
|
19
|
-
#{prop[:name]}! if val
|
20
|
-
end
|
12
|
+
amo_field :task_type, :text, complete_till: :timestamp
|
21
13
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
14
|
+
validates :task_type, :text, :complete_till,
|
15
|
+
presence: true
|
25
16
|
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
CODE
|
30
|
-
end
|
17
|
+
validates :element_type, inclusion:
|
18
|
+
ELEMENT_TYPES.reject { |type, _| type == :task }.values
|
31
19
|
end
|
32
20
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Amorail
|
4
|
+
# AmoCRM webhook entity
|
5
|
+
class Webhook < Entity
|
6
|
+
amo_names 'webhooks'
|
7
|
+
|
8
|
+
amo_field :id, :url, :events, :disabled
|
9
|
+
|
10
|
+
def self.list
|
11
|
+
response = client.safe_request(:get, remote_url('list'))
|
12
|
+
|
13
|
+
return [] if response.body.blank?
|
14
|
+
|
15
|
+
response.body['response'].fetch(amo_response_name, []).map do |attributes|
|
16
|
+
new.reload_model(attributes)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.subscribe(webhooks)
|
21
|
+
perform_webhooks_request('subscribe', webhooks) do |data|
|
22
|
+
data.map { |attrs| new.reload_model(attrs) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.unsubscribe(webhooks)
|
27
|
+
perform_webhooks_request('unsubscribe', webhooks)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.perform_webhooks_request(action, webhooks, &block)
|
31
|
+
response = client.safe_request(
|
32
|
+
:post,
|
33
|
+
remote_url(action),
|
34
|
+
request: { webhooks: { action => webhooks } }
|
35
|
+
)
|
36
|
+
|
37
|
+
return response unless block
|
38
|
+
|
39
|
+
block.call(response.body['response'].dig(amo_response_name, 'subscribe'))
|
40
|
+
end
|
41
|
+
|
42
|
+
private_class_method :perform_webhooks_request
|
43
|
+
end
|
44
|
+
end
|
data/lib/amorail/entity.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
2
4
|
|
3
5
|
module Amorail
|
@@ -62,7 +64,7 @@ module Amorail
|
|
62
64
|
end
|
63
65
|
|
64
66
|
require 'amorail/entity/params'
|
65
|
-
require 'amorail/entity/
|
67
|
+
require 'amorail/entity/persistence'
|
66
68
|
require 'amorail/entity/finders'
|
67
69
|
|
68
70
|
def reload_model(info)
|
@@ -77,6 +79,7 @@ module Amorail
|
|
77
79
|
attrs.each do |k, v|
|
78
80
|
action = "#{k}="
|
79
81
|
next unless respond_to?(action)
|
82
|
+
|
80
83
|
send(action, v)
|
81
84
|
end
|
82
85
|
self
|
@@ -84,9 +87,11 @@ module Amorail
|
|
84
87
|
|
85
88
|
def merge_custom_fields(fields)
|
86
89
|
return if fields.nil?
|
90
|
+
|
87
91
|
fields.each do |f|
|
88
92
|
fname = f['code'] || f['name']
|
89
93
|
next if fname.nil?
|
94
|
+
|
90
95
|
fname = "#{fname.downcase}="
|
91
96
|
fval = f.fetch('values').first.fetch('value')
|
92
97
|
send(fname, fval) if respond_to?(fname)
|
@@ -108,15 +113,18 @@ module Amorail
|
|
108
113
|
)
|
109
114
|
end
|
110
115
|
|
116
|
+
# We can have response with 200 or 204 here.
|
117
|
+
# 204 response has no body, so we don't want to parse it.
|
111
118
|
def handle_response(response, method)
|
112
|
-
return false
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
119
|
+
return false if response.status == 204
|
120
|
+
|
121
|
+
data = send(
|
122
|
+
"extract_data_#{method}",
|
123
|
+
response.body['response'][self.class.amo_response_name]
|
124
|
+
)
|
125
|
+
reload_model(data)
|
126
|
+
rescue InvalidRecord
|
127
|
+
false
|
120
128
|
end
|
121
129
|
end
|
122
130
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Amorail # :nodoc: all
|
2
4
|
class Entity
|
3
5
|
class << self
|
@@ -11,38 +13,41 @@ module Amorail # :nodoc: all
|
|
11
13
|
def find!(id)
|
12
14
|
rec = find(id)
|
13
15
|
fail RecordNotFound unless rec
|
16
|
+
|
14
17
|
rec
|
15
18
|
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
# General method to load many records by proving some filters
|
21
|
+
def where(options)
|
20
22
|
response = client.safe_request(
|
21
23
|
:get,
|
22
24
|
remote_url('list'),
|
23
|
-
|
25
|
+
options
|
24
26
|
)
|
25
27
|
load_many(response)
|
26
28
|
end
|
27
29
|
|
30
|
+
def find_all(*ids)
|
31
|
+
ids = ids.first if ids.size == 1 && ids.first.is_a?(Array)
|
32
|
+
|
33
|
+
where(id: ids)
|
34
|
+
end
|
35
|
+
|
28
36
|
# Find AMO entities by query
|
29
37
|
# Returns array of matching entities.
|
30
|
-
def find_by_query(
|
31
|
-
|
32
|
-
:get,
|
33
|
-
remote_url('list'),
|
34
|
-
query: q
|
35
|
-
)
|
36
|
-
load_many(response)
|
38
|
+
def find_by_query(query)
|
39
|
+
where(query: query)
|
37
40
|
end
|
38
41
|
|
39
42
|
private
|
40
43
|
|
44
|
+
# We can have response with 200 or 204 here.
|
45
|
+
# 204 response has no body, so we don't want to parse it.
|
41
46
|
def load_many(response)
|
42
|
-
return []
|
47
|
+
return [] if response.status == 204
|
43
48
|
|
44
|
-
|
45
|
-
|
49
|
+
response.body['response'].fetch(amo_response_name, [])
|
50
|
+
.map { |info| new.reload_model(info) }
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|