Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +0 -12
  3. data/.rubocop.yml +19 -1
  4. data/README.md +7 -1
  5. data/Rakefile +7 -3
  6. data/amorail.gemspec +4 -3
  7. data/lib/amorail.rb +3 -0
  8. data/lib/amorail/client.rb +8 -4
  9. data/lib/amorail/config.rb +2 -0
  10. data/lib/amorail/entities/company.rb +2 -0
  11. data/lib/amorail/entities/contact.rb +3 -0
  12. data/lib/amorail/entities/contact_link.rb +2 -0
  13. data/lib/amorail/entities/elementable.rb +39 -0
  14. data/lib/amorail/entities/lead.rb +4 -1
  15. data/lib/amorail/entities/leadable.rb +3 -0
  16. data/lib/amorail/entities/note.rb +19 -0
  17. data/lib/amorail/entities/task.rb +11 -23
  18. data/lib/amorail/entities/webhook.rb +44 -0
  19. data/lib/amorail/entity.rb +17 -9
  20. data/lib/amorail/entity/finders.rb +19 -14
  21. data/lib/amorail/entity/params.rb +2 -0
  22. data/lib/amorail/entity/{persistance.rb → persistence.rb} +24 -0
  23. data/lib/amorail/exceptions.rb +2 -0
  24. data/lib/amorail/property.rb +8 -0
  25. data/lib/amorail/railtie.rb +4 -1
  26. data/lib/amorail/version.rb +3 -1
  27. data/lib/tasks/amorail.rake +2 -0
  28. data/spec/client_spec.rb +2 -0
  29. data/spec/company_spec.rb +2 -0
  30. data/spec/contact_link_spec.rb +2 -0
  31. data/spec/contact_spec.rb +17 -0
  32. data/spec/entity_spec.rb +2 -0
  33. data/spec/fixtures/{account_response.json → accounts/response_1.json} +5 -5
  34. data/spec/fixtures/{account2_response.json → accounts/response_2.json} +1 -1
  35. data/spec/fixtures/contact_update.json +0 -5
  36. data/spec/fixtures/{contact_create.json → contacts/create.json} +1 -1
  37. data/spec/fixtures/{contact_find_query.json → contacts/find_many.json} +3 -5
  38. data/spec/fixtures/{contact_find.json → contacts/find_one.json} +5 -6
  39. data/spec/fixtures/contacts/links.json +16 -0
  40. data/spec/fixtures/{my_contact_find.json → contacts/my_contact_find.json} +2 -3
  41. data/spec/fixtures/contacts/update.json +13 -0
  42. data/spec/fixtures/contacts_links.json +0 -15
  43. data/spec/fixtures/leads.json +0 -69
  44. data/spec/fixtures/leads/create.json +13 -0
  45. data/spec/fixtures/leads/find_many.json +73 -0
  46. data/spec/fixtures/leads/links.json +16 -0
  47. data/spec/fixtures/leads/update.json +13 -0
  48. data/spec/fixtures/leads/update_errors.json +12 -0
  49. data/spec/fixtures/leads_links.json +0 -15
  50. data/spec/fixtures/webhooks/list.json +24 -0
  51. data/spec/fixtures/webhooks/subscribe.json +17 -0
  52. data/spec/fixtures/webhooks/unsubscribe.json +17 -0
  53. data/spec/helpers/webmock_helpers.rb +92 -13
  54. data/spec/lead_spec.rb +30 -0
  55. data/spec/my_contact_spec.rb +2 -0
  56. data/spec/note_spec.rb +28 -0
  57. data/spec/property_spec.rb +2 -0
  58. data/spec/spec_helper.rb +4 -2
  59. data/spec/support/elementable_example.rb +54 -0
  60. data/spec/support/entity_class_example.rb +2 -0
  61. data/spec/support/leadable_example.rb +2 -0
  62. data/spec/support/my_contact.rb +2 -0
  63. data/spec/support/my_entity.rb +2 -0
  64. data/spec/task_spec.rb +8 -28
  65. data/spec/webhook_spec.rb +61 -0
  66. metadata +60 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
---
2
- SHA1:
3
- metadata.gz: 8db673fd4edfbf45eb53a5d0f975a89d7895fdba
4
- data.tar.gz: 356888cd7462e7c1ec8c0b427f422faf6b2da05e
2
+ SHA256:
3
+ metadata.gz: 6047ec19aa4839d30b29fc1cb9ee38079a04812b2ed6547d2e24e1e8ed16a57d
4
+ data.tar.gz: 64bfbcd2f8574b70c420a274bd8707533b4f4334020d180fda7acb85cdcee509
5
5
SHA512:
6
- metadata.gz: 97c770c6157118cb4613528c1b0f3ce57f958bb973426b3113bf5c5ee0f7da40d197dc516401568ca0fcc615764484de9936e3ff8f82df2d0c4f59dd406aacd2
7
- data.tar.gz: 965e56642519d357ba3eba530bfdd1a8b1f967bb0d8e11ab0dc54ccab032ef82ae40c97a91c0ed396f4cd3a19e72f8a796ea306afae7513616cc0023422fcb64
6
+ metadata.gz: 55fc29183cff4df2db947a76ceae748d289ebab1f1e88310e7c13234dd75886c87e9f68c41b782ba251be69f2226f386501974108ce2cc00fdc656e1ccdfe059
7
+ data.tar.gz: da64fc02f0bc506319bd543e7b35cb5dfdd3b112cc04458f25904c5d9ece1bc38df8d659ca1d705e17fcea8e7cd82e954c7f4642048fb2ed627a03c0f1802b8c
data/.hound.yml DELETED
@@ -1,12 +0,0 @@
1
- ruby:
2
- enabled: true
3
- config_file: .rubocop.yml
4
-
5
- javascript:
6
- enabled: false
7
-
8
- coffeescript:
9
- enabled: false
10
-
11
- sass:
12
- enabled: false
data/.rubocop.yml CHANGED
@@ -6,7 +6,9 @@ AllCops:
6
6
- 'spec/**/*.rb'
7
7
Exclude:
8
8
- 'bin/**/*'
9
- RunRailsCops: true
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
- [![Build Status](https://travis-ci.org/teachbase/amorail.svg?branch=master)](https://travis-ci.org/teachbase/amorail)
1
+ [![Gem Version](https://badge.fury.io/rb/amorail.svg)](https://rubygems.org/gems/amorail) [![Build Status](https://travis-ci.org/teachbase/amorail.svg?branch=master)](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
- Dir.glob('lib/tasks/*.rake').each {|r| import r}
3
+ require "rubocop/rake_task"
4
4
5
- RSpec::Core::RakeTask.new(:spec)
5
+ Dir.glob('lib/tasks/*.rake').each { |r| import r }
6
6
7
- task :default => :spec
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 'pry'
26
- spec.add_development_dependency 'shoulda-matchers', "~> 2.0"
27
- spec.add_dependency "anyway_config", "~> 0", ">= 0.3"
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#x2F;
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
- send(method, url, params)
48
+ public_send(method, url, params)
45
49
rescue ::Amorail::AmoUnauthorizedError
46
50
authorize
47
- send(method, url, params)
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 response.status == 200 || response.status == 204
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require 'anyway'
2
4
3
5
module Amorail
data/lib/amorail/entities/company.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require 'amorail/entities/leadable'
2
4
3
5
module Amorail
data/lib/amorail/entities/contact.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require 'amorail/entities/leadable'
2
4
3
5
module Amorail
@@ -22,6 +24,7 @@ module Amorail
22
24
23
25
def company
24
26
return if linked_company_id.nil?
27
+
25
28
@company ||= Amorail::Company.find(linked_company_id)
26
29
end
27
30
end
data/lib/amorail/entities/contact_link.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
module Amorail
2
4
# AmoCRM contact-link join model
3
5
class ContactLink < Amorail::Entity
data/lib/amorail/entities/elementable.rb ADDED
@@ -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
data/lib/amorail/entities/lead.rb CHANGED
@@ -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)
data/lib/amorail/entities/leadable.rb CHANGED
@@ -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
data/lib/amorail/entities/note.rb ADDED
@@ -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
data/lib/amorail/entities/task.rb CHANGED
@@ -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
- amo_names "tasks"
8
+ include Elementable
5
-
6
- amo_field :element_id, :element_type, :text,
7
- :task_type, complete_till: :timestamp
8
9
9
- validates :text, :element_id,
10
+ amo_names 'tasks'
10
- :element_type, :complete_till,
11
- :task_type,
12
- presence: true
13
-
14
- validates :element_type, inclusion: 1..2
15
11
16
- [{ name: "contact", val: 1 }, { name: "lead", val: 2 }].each do |prop|
12
+ amo_field :task_type, :text, complete_till: :timestamp
17
- class_eval <<-CODE, __FILE__, __LINE__ + 1
18
- def #{prop[:name]}=(val)
19
- #{prop[:name]}! if val
20
- end
21
13
22
- def #{prop[:name]}?
23
- self.element_type == #{prop[:val]}
14
+ validates :task_type, :text, :complete_till,
15
+ presence: true
24
- end
25
16
26
- def #{prop[:name]}!
27
- self.element_type = #{prop[:val]}
17
+ validates :element_type, inclusion:
18
+ ELEMENT_TYPES.reject { |type, _| type == :task }.values
28
- end
29
- CODE
30
- end
31
19
end
32
20
end
data/lib/amorail/entities/webhook.rb ADDED
@@ -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/persistance'
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 unless response.status == 200
113
- extract_method = "extract_data_#{method}"
114
- reload_model(
115
- send(extract_method,
116
- response.body['response'][self.class.amo_response_name]
117
- )
118
- ) if respond_to?(extract_method, true)
119
- self
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
data/lib/amorail/entity/finders.rb CHANGED
@@ -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
- def find_all(*ids)
18
- ids = ids.first if ids.size == 1 && ids.first.is_a?(Array)
20
+ # General method to load many records by proving some filters
21
+ def where(options)
19
-
20
22
response = client.safe_request(
21
23
:get,
22
24
remote_url('list'),
23
- id: ids
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(q)
31
- response = client.safe_request(
38
+ def find_by_query(query)
39
+ where(query: query)
32
- :get,
33
- remote_url('list'),
34
- query: q
35
- )
36
- load_many(response)
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 [] unless response.status == 200
47
+ return [] if response.status == 204
43
48
44
- (response.body['response'][amo_response_name] || [])
45
- .map { |info| new.reload_model(info) }
49
+ response.body['response'].fetch(amo_response_name, [])
50
+ .map { |info| new.reload_model(info) }
46
51
end
47
52
end
48
53
data/lib/amorail/entity/params.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "active_support/core_ext/hash/indifferent_access"
2
4
3
5
module Amorail # :nodoc: all
data/lib/amorail/entity/{persistance.rb → persistence.rb} RENAMED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
module Amorail # :nodoc: all
2
4
class Entity
3
5
class InvalidRecord < ::Amorail::Error; end
@@ -13,6 +15,7 @@ module Amorail # :nodoc: all
13
15
14
16
def save
15
17
return false unless valid?
18
+
16
19
new_record? ? push('add') : push('update')
17
20
end
18
21
@@ -22,6 +25,7 @@ module Amorail # :nodoc: all
22
25
23
26
def update(attrs = {})
24
27
return false if new_record?
28
+
25
29
merge_params(attrs)
26
30
push('update')
27
31
end
@@ -32,6 +36,7 @@ module Amorail # :nodoc: all
32
36
33
37
def reload
34
38
fail NotPersisted if id.nil?
39
+
35
40
load_record(id)
36
41
end
37
42
@@ -40,5 +45,24 @@ module Amorail # :nodoc: all
40
45
def extract_data_add(response)
41
46
response.fetch('add').first
42
47
end
48
+
49
+ # Update response can have status 200 and contain errors.
50
+ # In case of errors "update" key in a response is a Hash with "errors" key.
51
+ # If there are no errors "update" key is an Array with entities attributes.
52
+ def extract_data_update(response)
53
+ case data = response.fetch('update')
54
+ when Array
55
+ data.first
56
+ when Hash
57
+ merge_errors(data)
58
+ raise(InvalidRecord)
59
+ end
60
+ end
61
+
62
+ def merge_errors(data)
63
+ data.fetch("errors").each do |_, message|
64
+ errors.add(:base, message)
65
+ end
66
+ end
43
67
end
44
68
end
data/lib/amorail/exceptions.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
# Amorail Exceptions.
2
4
# Every class is name of HTTP response error code(status)
3
5
module Amorail
data/lib/amorail/property.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
module Amorail
2
4
# Return hash key as method call
3
5
module MethodMissing
@@ -8,6 +10,10 @@ module Amorail
8
10
super
9
11
end
10
12
end
13
+
14
+ def respond_to_missing?(method_sym, *args)
15
+ args.size.zero? && data.key?(method_sym.to_s)
16
+ end
11
17
end
12
18
13
19
class Property # :nodoc: all
@@ -22,6 +28,7 @@ module Amorail
22
28
data['custom_fields'].fetch(source_name, []).each do |contact|
23
29
identifier = contact['code'].presence || contact['name'].presence
24
30
next if identifier.nil?
31
+
25
32
hash[identifier.downcase] = PropertyItem.new(contact)
26
33
end
27
34
new hash
@@ -114,6 +121,7 @@ module Amorail
114
121
prop_item = PropertyItem.new(tt)
115
122
identifier = tt['code'].presence || tt['name'].presence
116
123
next if identifier.nil?
124
+
117
125
hash[identifier.downcase] = prop_item
118
126
hash[identifier] = prop_item
119
127
end
data/lib/amorail/railtie.rb CHANGED
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
module Amorail
4
+ # Add amorail rake tasks
2
5
class Railtie < Rails::Railtie
3
6
rake_tasks do
4
- load File.expand_path('../../tasks/amorail.rake', __FILE__)
7
+ load File.expand_path('../tasks/amorail.rake', __dir__)
5
8
end
6
9
end
7
10
end
data/lib/amorail/version.rb CHANGED
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
# Amorail version
2
4
module Amorail
3
- VERSION = "0.3.4".freeze
5
+ VERSION = '0.6.0'
4
6
end
data/lib/tasks/amorail.rake CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
namespace :amorail do
2
4
desc 'Check Amorail configuration'
3
5
task :check do
data/spec/client_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
3
5
describe Amorail::Client do
data/spec/company_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
3
5
describe Amorail::Company do
data/spec/contact_link_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
3
5
describe Amorail::ContactLink do
data/spec/contact_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
3
5
describe Amorail::Contact do
@@ -136,6 +138,21 @@ describe Amorail::Contact do
136
138
end
137
139
end
138
140
141
+ describe ".where" do
142
+ before { contacts_where_stub(Amorail.config.api_endpoint, query: 'xxx', limit_rows: 10, limit_offset: 100) }
143
+
144
+ it "loads entities" do
145
+ res = described_class.where(query: 'xxx', limit_rows: 10, limit_offset: 100)
146
+ expect(res.size).to eq 2
147
+ expect(res.first.id).to eq 101
148
+ expect(res.last.id).to eq 102
149
+ expect(res.first.company_name).to eq "Foo Inc."
150
+ expect(res.last.email).to eq "foo2@tb.com"
151
+ expect(res.first.phone).to eq "1111 111 111"
152
+ expect(res.first.params[:id]).to eq 101
153
+ end
154
+ end
155
+
139
156
describe "#save" do
140
157
before { contact_create_stub(Amorail.config.api_endpoint) }
141
158
data/spec/entity_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
3
5
describe MyEntity do
data/spec/fixtures/{account_response.json → accounts/response_1.json} RENAMED
@@ -141,9 +141,9 @@
141
141
}
142
142
},
143
143
{
144
- "id": "116302",
145
- "name": "teachbase_id",
146
- "multiple": "N",
144
+ "id": "116302",
145
+ "name": "teachbase_id",
146
+ "multiple": "N",
147
147
"type_id": "8"
148
148
}
149
149
],
@@ -162,7 +162,7 @@
162
162
"multiple": "N",
163
163
"type_id": "3"
164
164
}
165
- ],
165
+ ],
166
166
"companies": [
167
167
{
168
168
"id": "1460589",
@@ -341,4 +341,4 @@
341
341
},
342
342
"server_time": 1422442143
343
343
}
344
- }
344
+ }
data/spec/fixtures/{account2_response.json → accounts/response_2.json} RENAMED
@@ -192,4 +192,4 @@
192
192
},
193
193
"server_time": 1422442143
194
194
}
195
- }
195
+ }
data/spec/fixtures/contact_update.json DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "response": {
3
- "contacts": null
4
- }
5
- }
data/spec/fixtures/{contact_create.json → contacts/create.json} RENAMED
@@ -10,4 +10,4 @@
10
10
},
11
11
"server_time": 1423139130
12
12
}
13
- }
13
+ }
data/spec/fixtures/{contact_find_query.json → contacts/find_many.json} RENAMED
@@ -7,8 +7,7 @@
7
7
"account_id": "8195968",
8
8
"last_modified": 1423139130,
9
9
"company_name": "Foo Inc.",
10
- "custom_fields":
10
+ "custom_fields": [
11
- [
12
11
{
13
12
"id": "1460591",
14
13
"name": "Email",
@@ -39,8 +38,7 @@
39
38
"account_id": "8195968",
40
39
"last_modified": 1423139150,
41
40
"company_name": "Foo Inc.",
42
- "custom_fields":
41
+ "custom_fields": [
43
- [
44
42
{
45
43
"id": "1460591",
46
44
"name": "Email",
@@ -56,4 +54,4 @@
56
54
}
57
55
]
58
56
}
59
- }
57
+ }
data/spec/fixtures/{contact_find.json → contacts/find_one.json} RENAMED
@@ -7,12 +7,11 @@
7
7
"account_id": "8195968",
8
8
"last_modified": 1423139130,
9
9
"company_name": "Foo Inc.",
10
- "linked_leads_id": [
11
- "1872746",
12
- "1885024"
10
+ "linked_leads_id": [
11
+ "1872746",
12
+ "1885024"
13
13
],
14
- "custom_fields":
14
+ "custom_fields": [
15
- [
16
15
{
17
16
"id": "1460591",
18
17
"name": "Email",
@@ -39,4 +38,4 @@
39
38
}
40
39
]
41
40
}
42
- }
41
+ }
data/spec/fixtures/contacts/links.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "response": {
3
+ "links": [
4
+ {
5
+ "contact_id": "101",
6
+ "lead_id": "1",
7
+ "last_modified": 1374741830
8
+ },
9
+ {
10
+ "contact_id": "101",
11
+ "lead_id": "2",
12
+ "last_modified": 1374839942
13
+ }
14
+ ]
15
+ }
16
+ }
data/spec/fixtures/{my_contact_find.json → contacts/my_contact_find.json} RENAMED
@@ -7,8 +7,7 @@
7
7
"account_id": "8195968",
8
8
"last_modified": 1423139130,
9
9
"company_name": "Foo Inc.",
10
- "custom_fields":
10
+ "custom_fields": [
11
- [
12
11
{
13
12
"id": "1460591",
14
13
"name": "Email",
@@ -45,4 +44,4 @@
45
44
}
46
45
]
47
46
}
48
- }
47
+ }
data/spec/fixtures/contacts/update.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "response": {
3
+ "contacts": {
4
+ "update": [
5
+ {
6
+ "id": 12509853,
7
+ "last_modified": 1501256276
8
+ }
9
+ ]
10
+ },
11
+ "server_time": 1501452197
12
+ }
13
+ }
data/spec/fixtures/contacts_links.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "response": {
3
- "links": [
4
- {
5
- "contact_id": "101",
6
- "lead_id": "1",
7
- "last_modified": 1374741830
8
- },
9
- {
10
- "contact_id": "101",
11
- "lead_id": "2",
12
- "last_modified": 1374839942
13
- }]
14
- }
15
- }
data/spec/fixtures/leads.json DELETED
@@ -1,69 +0,0 @@
1
- {
2
- "response": {
3
- "leads": [
4
- {
5
- "id": "1",
6
- "name": "Research new technologies",
7
- "last_modified": 1374656336,
8
- "status_id": "7046196",
9
- "price": "500000",
10
- "responsible_user_id": "103586",
11
- "tags":[
12
- {
13
- "id": "960472",
14
- "name": "USA"},
15
- {
16
- "id": "960854",
17
- "name": "Lead"
18
- }
19
- ],
20
- "date_create": 1386014400,
21
- "account_id": "7046192",
22
- "created_user_id": "4502311",
23
- "custom_fields": [
24
- {
25
- "id": "484604",
26
- "name": "field",
27
- "values": [
28
- {
29
- "value": "text"
30
- }
31
- ]
32
- }
33
- ]
34
- },
35
- {
36
- "id": "2",
37
- "name": "Sell it!",
38
- "last_modified": 1374656336,
39
- "status_id": "7046196",
40
- "price": "100000",
41
- "responsible_user_id": "103586",
42
- "tags":[
43
- {
44
- "id": "960472",
45
- "name": "USA"},
46
- {
47
- "id": "960854",
48
- "name": "Lead"
49
- }
50
- ],
51
- "date_create": 1386014400,
52
- "account_id": "7046192",
53
- "created_user_id": "4502311",
54
- "custom_fields": [
55
- {
56
- "id": "484604",
57
- "name": "field",
58
- "values": [
59
- {
60
- "value": "text"
61
- }
62
- ]
63
- }
64
- ]
65
- }
66
- ],
67
- "server_time": 1374839787
68
- }
69
- }
data/spec/fixtures/leads/create.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "response": {
3
+ "leads": {
4
+ "add": [
5
+ {
6
+ "id": 3980037,
7
+ "request_id": 0
8
+ }
9
+ ]
10
+ },
11
+ "server_time": 1502394640
12
+ }
13
+ }
data/spec/fixtures/leads/find_many.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "response": {
3
+ "leads": [
4
+ {
5
+ "id": "1",
6
+ "name": "Research new technologies",
7
+ "last_modified": 1374656336,
8
+ "status_id": "7046196",
9
+ "pipeline_id": 683506,
10
+ "price": "500000",
11
+ "responsible_user_id": "103586",
12
+ "tags": [
13
+ {
14
+ "id": "960472",
15
+ "name": "USA"
16
+ },
17
+ {
18
+ "id": "960854",
19
+ "name": "Lead"
20
+ }
21
+ ],
22
+ "date_create": 1386014400,
23
+ "account_id": "7046192",
24
+ "created_user_id": "4502311",
25
+ "custom_fields": [
26
+ {
27
+ "id": "484604",
28
+ "name": "field",
29
+ "values": [
30
+ {
31
+ "value": "text"
32
+ }
33
+ ]
34
+ }
35
+ ]
36
+ },
37
+ {
38
+ "id": "2",
39
+ "name": "Sell it!",
40
+ "last_modified": 1374656336,
41
+ "status_id": "7046196",
42
+ "pipeline_id": 683506,
43
+ "price": "100000",
44
+ "responsible_user_id": "103586",
45
+ "tags": [
46
+ {
47
+ "id": "960472",
48
+ "name": "USA"
49
+ },
50
+ {
51
+ "id": "960854",
52
+ "name": "Lead"
53
+ }
54
+ ],
55
+ "date_create": 1386014400,
56
+ "account_id": "7046192",
57
+ "created_user_id": "4502311",
58
+ "custom_fields": [
59
+ {
60
+ "id": "484604",
61
+ "name": "field",
62
+ "values": [
63
+ {
64
+ "value": "text"
65
+ }
66
+ ]
67
+ }
68
+ ]
69
+ }
70
+ ],
71
+ "server_time": 1374839787
72
+ }
73
+ }
data/spec/fixtures/leads/links.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "response": {
3
+ "links": [
4
+ {
5
+ "contact_id": "101",
6
+ "lead_id": "2",
7
+ "last_modified": 1374839942
8
+ },
9
+ {
10
+ "contact_id": "102",
11
+ "lead_id": "2",
12
+ "last_modified": 1374839942
13
+ }
14
+ ]
15
+ }
16
+ }
data/spec/fixtures/leads/update.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "response": {
3
+ "leads": {
4
+ "update": [
5
+ {
6
+ "id": 3103031,
7
+ "last_modified": 1502393989
8
+ }
9
+ ]
10
+ },
11
+ "server_time": 1502393993
12
+ }
13
+ }
data/spec/fixtures/leads/update_errors.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "response": {
3
+ "leads": {
4
+ "update": {
5
+ "errors": {
6
+ "3103031": "Last modified date is older than in database"
7
+ }
8
+ }
9
+ },
10
+ "server_time": 1502391257
11
+ }
12
+ }
data/spec/fixtures/leads_links.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "response": {
3
- "links": [
4
- {
5
- "contact_id": "101",
6
- "lead_id": "2",
7
- "last_modified": 1374839942
8
- },
9
- {
10
- "contact_id": "102",
11
- "lead_id": "2",
12
- "last_modified": 1374839942
13
- }]
14
- }
15
- }
data/spec/fixtures/webhooks/list.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "response": {
3
+ "webhooks": [
4
+ {
5
+ "id": "1",
6
+ "url": "http://example.org",
7
+ "events": [
8
+ "add_contact"
9
+ ],
10
+ "disabled": false
11
+ },
12
+ {
13
+ "id": "2",
14
+ "url": "http://example.com",
15
+ "events": [
16
+ "add_contact",
17
+ "add_company"
18
+ ],
19
+ "disabled": true
20
+ }
21
+ ],
22
+ "server_time": 1539938502
23
+ }
24
+ }
data/spec/fixtures/webhooks/subscribe.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "response": {
3
+ "webhooks": {
4
+ "subscribe": [
5
+ {
6
+ "url": "http://example.org",
7
+ "result": true
8
+ },
9
+ {
10
+ "url": "http://example.com",
11
+ "result": true
12
+ }
13
+ ]
14
+ },
15
+ "server_time": 1539941636
16
+ }
17
+ }
data/spec/fixtures/webhooks/unsubscribe.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "response": {
3
+ "webhooks": {
4
+ "unsubscribe": [
5
+ {
6
+ "url": "http://example.org",
7
+ "result": true
8
+ },
9
+ {
10
+ "url": "http://example.com",
11
+ "result": true
12
+ }
13
+ ]
14
+ },
15
+ "server_time": 1539941911
16
+ }
17
+ }
data/spec/helpers/webmock_helpers.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
# rubocop: disable Metrics/ModuleLength
2
4
module AmoWebMock
3
5
def mock_api
@@ -9,7 +11,7 @@ module AmoWebMock
9
11
account_info_stub(Amorail.config.api_endpoint)
10
12
end
11
13
12
- def mock_custom_api(endpoint, usermail, api_key, properties = 'account2_response.json')
14
+ def mock_custom_api(endpoint, usermail, api_key, properties = 'response_2.json')
13
15
authorize_stub(
14
16
endpoint,
15
17
usermail,
@@ -33,10 +35,10 @@ module AmoWebMock
33
35
})
34
36
end
35
37
36
- def account_info_stub(endpoint, properties = 'account_response.json')
38
+ def account_info_stub(endpoint, properties = 'response_1.json')
37
39
stub_request(:get, endpoint + '/private/api/v2/json/accounts/current')
38
40
.to_return(
39
- body: File.read("./spec/fixtures/#{properties}"),
41
+ body: File.read("./spec/fixtures/accounts/#{properties}"),
40
42
headers: { 'Content-Type' => 'application/json' },
41
43
status: 200
42
44
)
@@ -61,7 +63,7 @@ module AmoWebMock
61
63
def contact_create_stub(endpoint)
62
64
stub_request(:post, endpoint + '/private/api/v2/json/contacts/set')
63
65
.to_return(
64
- body: File.read('./spec/fixtures/contact_create.json'),
66
+ body: File.read('./spec/fixtures/contacts/create.json'),
65
67
headers: { 'Content-Type' => 'application/json' },
66
68
status: 200
67
69
)
@@ -70,7 +72,7 @@ module AmoWebMock
70
72
def contact_update_stub(endpoint)
71
73
stub_request(:post, endpoint + '/private/api/v2/json/contacts/set')
72
74
.to_return(
73
- body: File.read('./spec/fixtures/contact_update.json'),
75
+ body: File.read('./spec/fixtures/contacts/update.json'),
74
76
headers: {
75
77
'Content-Type' => 'application/json'
76
78
},
@@ -84,7 +86,7 @@ module AmoWebMock
84
86
:get,
85
87
"#{endpoint}/private/api/v2/json/contacts/list?id=#{id}")
86
88
.to_return(
87
- body: File.read('./spec/fixtures/contact_find.json'),
89
+ body: File.read('./spec/fixtures/contacts/find_one.json'),
88
90
headers: { 'Content-Type' => 'application/json' },
89
91
status: 200
90
92
)
@@ -102,7 +104,7 @@ module AmoWebMock
102
104
:get,
103
105
"#{endpoint}/private/api/v2/json/contacts/list?id=#{id}")
104
106
.to_return(
105
- body: File.read('./spec/fixtures/my_contact_find.json'),
107
+ body: File.read('./spec/fixtures/contacts/my_contact_find.json'),
106
108
headers: { 'Content-Type' => 'application/json' },
107
109
status: 200
108
110
)
@@ -120,7 +122,7 @@ module AmoWebMock
120
122
:get,
121
123
"#{endpoint}/private/api/v2/json/contacts/list?query=#{query}")
122
124
.to_return(
123
- body: File.read('./spec/fixtures/contact_find_query.json'),
125
+ body: File.read('./spec/fixtures/contacts/find_many.json'),
124
126
headers: { 'Content-Type' => 'application/json' },
125
127
status: 200
126
128
)
@@ -138,7 +140,7 @@ module AmoWebMock
138
140
:get,
139
141
"#{endpoint}/private/api/v2/json/contacts/list?#{ids.to_query('id')}")
140
142
.to_return(
141
- body: File.read('./spec/fixtures/contact_find_query.json'),
143
+ body: File.read('./spec/fixtures/contacts/find_many.json'),
142
144
headers: { 'Content-Type' => 'application/json' },
143
145
status: 200
144
146
)
@@ -150,10 +152,30 @@ module AmoWebMock
150
152
end
151
153
end
152
154
155
+ def contacts_where_stub(endpoint, success = true, **params)
156
+ if success
157
+ stub_request(
158
+ :get,
159
+ "#{endpoint}/private/api/v2/json/contacts/list"
160
+ ).with(
161
+ query: params
162
+ ).to_return(
163
+ body: File.read('./spec/fixtures/contacts/find_many.json'),
164
+ headers: { 'Content-Type' => 'application/json' },
165
+ status: 200
166
+ )
167
+ else
168
+ stub_request(
169
+ :get,
170
+ "#{endpoint}/private/api/v2/json/contacts/list?query=#{query}")
171
+ .to_return(status: 204)
172
+ end
173
+ end
174
+
153
175
def company_create_stub(endpoint)
154
176
stub_request(:post, endpoint + '/private/api/v2/json/company/set')
155
177
.to_return(
156
- body: File.read('./spec/fixtures/contact_create.json'),
178
+ body: File.read('./spec/fixtures/contacts/create.json'),
157
179
headers: { 'Content-Type' => 'application/json' },
158
180
status: 200
159
181
)
@@ -165,7 +187,7 @@ module AmoWebMock
165
187
:get,
166
188
"#{endpoint}/private/api/v2/json/leads/list?#{ids.to_query('id')}")
167
189
.to_return(
168
- body: File.read('./spec/fixtures/leads.json'),
190
+ body: File.read('./spec/fixtures/leads/find_many.json'),
169
191
headers: { 'Content-Type' => 'application/json' },
170
192
status: 200
171
193
)
@@ -177,10 +199,37 @@ module AmoWebMock
177
199
end
178
200
end
179
201
202
+ def lead_create_stub(endpoint)
203
+ stub_request(:post, endpoint + '/private/api/v2/json/leads/set')
204
+ .to_return(
205
+ body: File.read('./spec/fixtures/leads/create.json'),
206
+ headers: { 'Content-Type' => 'application/json' },
207
+ status: 200
208
+ )
209
+ end
210
+
211
+ def lead_update_stub(endpoint, success = true)
212
+ fixture_file =
213
+ if success
214
+ './spec/fixtures/leads/update.json'
215
+ else
216
+ './spec/fixtures/leads/update_errors.json'
217
+ end
218
+
219
+ stub_request(:post, endpoint + '/private/api/v2/json/leads/set')
220
+ .to_return(
221
+ body: File.read(fixture_file),
222
+ headers: {
223
+ 'Content-Type' => 'application/json'
224
+ },
225
+ status: 200
226
+ )
227
+ end
228
+
180
229
def contacts_links_stub(endpoint, ids)
181
230
stub_request(:get, endpoint + "/private/api/v2/json/contacts/links?#{ids.to_query('contacts_link')}")
182
231
.to_return(
183
- body: File.read('./spec/fixtures/contacts_links.json'),
232
+ body: File.read('./spec/fixtures/contacts/links.json'),
184
233
headers: { 'Content-Type' => 'application/json' },
185
234
status: 200
186
235
)
@@ -190,7 +239,7 @@ module AmoWebMock
190
239
if success
191
240
stub_request(:get, endpoint + "/private/api/v2/json/contacts/links?#{ids.to_query('deals_link')}")
192
241
.to_return(
193
- body: File.read('./spec/fixtures/leads_links.json'),
242
+ body: File.read('./spec/fixtures/leads/links.json'),
194
243
headers: { 'Content-Type' => 'application/json' },
195
244
status: 200
196
245
)
@@ -199,4 +248,34 @@ module AmoWebMock
199
248
.to_return(status: 204)
200
249
end
201
250
end
251
+
252
+ def webhooks_list_stub(endpoint, empty: false)
253
+ body = empty ? '' : File.read('./spec/fixtures/webhooks/list.json')
254
+ stub_request(:get, "#{endpoint}/private/api/v2/json/webhooks/list")
255
+ .to_return(
256
+ body: body,
257
+ headers: { 'Content-Type' => 'application/json' },
258
+ status: 200
259
+ )
260
+ end
261
+
262
+ def webhooks_subscribe_stub(endpoint, webhooks)
263
+ stub_request(:post, "#{endpoint}/private/api/v2/json/webhooks/subscribe")
264
+ .with(body: { request: { webhooks: { subscribe: webhooks } } }.to_json)
265
+ .to_return(
266
+ body: File.read('./spec/fixtures/webhooks/subscribe.json'),
267
+ headers: { 'Content-Type' => 'application/json' },
268
+ status: 200
269
+ )
270
+ end
271
+
272
+ def webhooks_unsubscribe_stub(endpoint, webhooks)
273
+ stub_request(:post, "#{endpoint}/private/api/v2/json/webhooks/unsubscribe")
274
+ .with(body: { request: { webhooks: { unsubscribe: webhooks } } }.to_json)
275
+ .to_return(
276
+ body: File.read('./spec/fixtures/webhooks/unsubscribe.json'),
277
+ headers: { 'Content-Type' => 'application/json' },
278
+ status: 200
279
+ )
280
+ end
202
281
end
data/spec/lead_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
3
5
describe Amorail::Lead do
@@ -18,6 +20,7 @@ describe Amorail::Lead do
18
20
:name,
19
21
:price,
20
22
:status_id,
23
+ :pipeline_id,
21
24
:tags
22
25
)
23
26
end
@@ -29,6 +32,7 @@ describe Amorail::Lead do
29
32
name: 'Test',
30
33
price: 100,
31
34
status_id: 2,
35
+ pipeline_id: 17,
32
36
tags: 'test lead'
33
37
)
34
38
end
@@ -39,6 +43,7 @@ describe Amorail::Lead do
39
43
specify { is_expected.to include(name: 'Test') }
40
44
specify { is_expected.to include(price: 100) }
41
45
specify { is_expected.to include(status_id: 2) }
46
+ specify { is_expected.to include(pipeline_id: 17) }
42
47
specify { is_expected.to include(tags: 'test lead') }
43
48
end
44
49
@@ -70,4 +75,29 @@ describe Amorail::Lead do
70
75
end
71
76
end
72
77
end
78
+
79
+ describe "#update" do
80
+ subject { lead.update }
81
+
82
+ let(:lead) { described_class.new(name: 'RSpec lead', status_id: 142) }
83
+
84
+ before do
85
+ lead_create_stub(Amorail.config.api_endpoint)
86
+ lead.save!
87
+ end
88
+
89
+ context 'with errors in response' do
90
+ before do
91
+ lead_update_stub(Amorail.config.api_endpoint, false)
92
+ lead.name = 'Updated name'
93
+ end
94
+
95
+ it { is_expected.to be_falsey }
96
+
97
+ specify do
98
+ subject
99
+ expect(lead.errors[:base]).to include('Last modified date is older than in database')
100
+ end
101
+ end
102
+ end
73
103
end
data/spec/my_contact_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
3
5
describe MyContact do
data/spec/note_spec.rb ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Amorail::Note do
6
+ before { mock_api }
7
+
8
+ it_behaves_like 'elementable'
9
+
10
+ describe 'validations' do
11
+ it { is_expected.to validate_presence_of(:text) }
12
+ it { is_expected.to validate_presence_of(:note_type) }
13
+ it { is_expected.to validate_inclusion_of(:element_type).in_range(1..4) }
14
+ end
15
+
16
+ describe '.attributes' do
17
+ subject { described_class.attributes }
18
+
19
+ it_behaves_like 'entity_class'
20
+
21
+ specify do
22
+ is_expected.to include(
23
+ :text,
24
+ :note_type
25
+ )
26
+ end
27
+ end
28
+ end
data/spec/property_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
require "webmock/rspec"
3
5
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
4
$LOAD_PATH.unshift(File.dirname(__FILE__))
3
5
@@ -10,9 +12,9 @@ require 'helpers/webmock_helpers'
10
12
11
13
# Cleanup Amorail env
12
14
ENV.delete_if { |k, _| k =~ /amorail/i }
13
- ENV["AMORAIL_CONF"] = File.expand_path("../fixtures/amorail_test.yml", __FILE__)
15
+ ENV["AMORAIL_CONF"] = File.expand_path("fixtures/amorail_test.yml", __dir__)
14
16
15
- Dir[File.expand_path("../support/**/*.rb", __FILE__)].each { |f| require f }
17
+ Dir[File.expand_path("support/**/*.rb", __dir__)].each { |f| require f }
16
18
17
19
RSpec.configure do |config|
18
20
config.mock_with :rspec
data/spec/support/elementable_example.rb ADDED
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples 'elementable' do
4
+ describe 'validations' do
5
+ it { is_expected.to validate_presence_of(:element_id) }
6
+ it { is_expected.to validate_presence_of(:element_type) }
7
+ end
8
+
9
+ describe '.attributes' do
10
+ subject { described_class.attributes }
11
+
12
+ specify do
13
+ is_expected.to include(
14
+ :element_type,
15
+ :element_id
16
+ )
17
+ end
18
+ end
19
+
20
+ describe '#params' do
21
+ subject { elementable.params }
22
+
23
+ let(:elementable) do
24
+ described_class.new(
25
+ element_id: 1,
26
+ element_type: 2
27
+ )
28
+ end
29
+
30
+ it { is_expected.to include(element_id: 1) }
31
+ it { is_expected.to include(element_type: 2) }
32
+ end
33
+
34
+ describe 'element type behaviour' do
35
+ let(:elementable) { described_class.new }
36
+
37
+ it 'set element_type on initialize' do
38
+ expect(described_class.new(lead: true).element_type).to eq 2
39
+ expect(described_class.new(lead: false).element_type).to be_nil
40
+ expect(described_class.new(contact: true).contact?).to be_truthy
41
+ end
42
+
43
+ it 'set element_type with bang method' do
44
+ elementable.contact!
45
+ expect(elementable.element_type).to eq 1
46
+
47
+ elementable.lead!
48
+ expect(elementable.element_type).to eq 2
49
+
50
+ elementable.company!
51
+ expect(elementable.element_type).to eq 3
52
+ end
53
+ end
54
+ end
data/spec/support/entity_class_example.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require 'spec_helper'
2
4
3
5
shared_examples 'entity_class' do
data/spec/support/leadable_example.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
require 'spec_helper'
2
4
3
5
shared_examples 'leadable' do
data/spec/support/my_contact.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
class MyContact < Amorail::Contact # :nodoc:
2
4
amo_property :teachbase_id
3
5
end
data/spec/support/my_entity.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
# We only need this class to set Amo names for core Entity
2
4
class MyEntity < Amorail::Entity # :nodoc:
3
5
amo_names 'entity'
data/spec/task_spec.rb CHANGED
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
require "spec_helper"
2
4
3
5
describe Amorail::Task do
4
6
before { mock_api }
5
7
8
+ it_behaves_like 'elementable'
9
+
6
10
describe "validations" do
7
- it { should validate_presence_of(:element_id) }
8
- it { should validate_presence_of(:element_type) }
9
- it { should validate_inclusion_of(:element_type).in_range(1..2) }
10
- it { should validate_presence_of(:text) }
11
+ it { is_expected.to validate_presence_of(:text) }
12
+ it { is_expected.to validate_presence_of(:task_type) }
13
+ it { is_expected.to validate_presence_of(:complete_till) }
14
+ it { is_expected.to validate_inclusion_of(:element_type).in_range(1..3) }
11
- it { should validate_presence_of(:task_type) }
12
- it { should validate_presence_of(:complete_till) }
13
15
end
14
16
15
17
describe ".attributes" do
@@ -19,8 +21,6 @@ describe Amorail::Task do
19
21
20
22
specify do
21
23
is_expected.to include(
22
- :element_type,
23
- :element_id,
24
24
:text,
25
25
:task_type,
26
26
:complete_till
@@ -28,27 +28,9 @@ describe Amorail::Task do
28
28
end
29
29
end
30
30
31
- describe "contact and lead" do
32
- let(:task) { described_class.new }
33
- it "set element_type on initialize" do
34
- expect(described_class.new(lead: true).element_type).to eq 2
35
- expect(described_class.new(contact: true).contact?).to be_truthy
36
- expect(described_class.new(lead: false).element_type).to be_nil
37
- end
38
-
39
- it "set element_type with bang method" do
40
- task.contact!
41
- expect(task.element_type).to eq 1
42
- task.lead!
43
- expect(task.element_type).to eq 2
44
- end
45
- end
46
-
47
31
describe "#params" do
48
32
let(:task) do
49
33
described_class.new(
50
- element_id: 1,
51
- element_type: 1,
52
34
text: 'Win the war',
53
35
task_type: 'test',
54
36
complete_till: '2015-05-09 12:00:00'
@@ -58,8 +40,6 @@ describe Amorail::Task do
58
40
subject { task.params }
59
41
60
42
specify { is_expected.to include(:last_modified) }
61
- specify { is_expected.to include(element_id: 1) }
62
- specify { is_expected.to include(element_type: 1) }
63
43
specify { is_expected.to include(text: 'Win the war') }
64
44
specify { is_expected.to include(task_type: 'test') }
65
45
specify {
data/spec/webhook_spec.rb ADDED
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Amorail::Webhook do
6
+ before { mock_api }
7
+
8
+ describe '.list' do
9
+ context 'there are some webhooks' do
10
+ before { webhooks_list_stub(Amorail.config.api_endpoint) }
11
+
12
+ it 'loads webhooks' do
13
+ res = described_class.list
14
+ expect(res.size).to eq 2
15
+ expect(res.first.id).to eq '1'
16
+ expect(res.first.url).to eq 'http://example.org'
17
+ expect(res.first.events).to eq ['add_contact']
18
+ expect(res.first.disabled).to eq false
19
+ expect(res.last.id).to eq '2'
20
+ expect(res.last.url).to eq 'http://example.com'
21
+ expect(res.last.events).to eq ['add_contact', 'add_company']
22
+ expect(res.last.disabled).to eq true
23
+ end
24
+ end
25
+
26
+ context 'there are not any webhooks' do
27
+ before { webhooks_list_stub(Amorail.config.api_endpoint, empty: true) }
28
+
29
+ it 'returns an empty array' do
30
+ res = described_class.list
31
+ expect(res).to eq []
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '.subscribe' do
37
+ it 'creates webhooks' do
38
+ webhooks = [
39
+ { url: 'http://example.org', events: ['add_contact'] },
40
+ { url: 'http://example.com', events: ['add_contact', 'add_company'] }
41
+ ]
42
+ stub = webhooks_subscribe_stub(Amorail.config.api_endpoint, webhooks)
43
+ res = described_class.subscribe(webhooks)
44
+ expect(stub).to have_been_requested
45
+ expect(res.first.url).to eq 'http://example.org'
46
+ expect(res.last.url).to eq 'http://example.com'
47
+ end
48
+ end
49
+
50
+ describe '.unsubscribe' do
51
+ it 'removes webhooks' do
52
+ webhooks = [
53
+ { url: 'http://example.org', events: ['add_contact'] },
54
+ { url: 'http://example.com', events: ['add_contact', 'add_company'] }
55
+ ]
56
+ stub = webhooks_unsubscribe_stub(Amorail.config.api_endpoint, webhooks)
57
+ described_class.unsubscribe(webhooks)
58
+ expect(stub).to have_been_requested
59
+ end
60
+ end
61
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
--- !ruby/object:Gem::Specification
2
2
name: amorail
3
3
version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.6.0
5
5
platform: ruby
6
6
authors:
7
7
- alekseenkoss
@@ -9,7 +9,7 @@ authors:
9
9
autorequire:
10
10
bindir: bin
11
11
cert_chain: []
12
- date: 2017-07-12 00:00:00.000000000 Z
12
+ date: 2019-11-08 00:00:00.000000000 Z
13
13
dependencies:
14
14
- !ruby/object:Gem::Dependency
15
15
name: bundler
@@ -96,25 +96,33 @@ dependencies:
96
96
- !ruby/object:Gem::Version
97
97
version: '2.0'
98
98
- !ruby/object:Gem::Dependency
99
- name: anyway_config
99
+ name: rubocop
100
100
requirement: !ruby/object:Gem::Requirement
101
101
requirements:
102
102
- - "~>"
103
103
- !ruby/object:Gem::Version
104
- version: '0'
104
+ version: '0.49'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '0.49'
112
+ - !ruby/object:Gem::Dependency
113
+ name: anyway_config
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
105
116
- - ">="
106
117
- !ruby/object:Gem::Version
107
- version: '0.3'
118
+ version: '1.0'
108
119
type: :runtime
109
120
prerelease: false
110
121
version_requirements: !ruby/object:Gem::Requirement
111
122
requirements:
112
- - - "~>"
113
- - !ruby/object:Gem::Version
114
- version: '0'
115
123
- - ">="
116
124
- !ruby/object:Gem::Version
117
- version: '0.3'
125
+ version: '1.0'
118
126
- !ruby/object:Gem::Dependency
119
127
name: faraday
120
128
requirement: !ruby/object:Gem::Requirement
@@ -180,7 +188,6 @@ extensions: []
180
188
extra_rdoc_files: []
181
189
files:
182
190
- ".gitignore"
183
- - ".hound.yml"
184
191
- ".rubocop.yml"
185
192
- ".travis.yml"
186
193
- Gemfile
@@ -194,13 +201,16 @@ files:
194
201
- lib/amorail/entities/company.rb
195
202
- lib/amorail/entities/contact.rb
196
203
- lib/amorail/entities/contact_link.rb
204
+ - lib/amorail/entities/elementable.rb
197
205
- lib/amorail/entities/lead.rb
198
206
- lib/amorail/entities/leadable.rb
207
+ - lib/amorail/entities/note.rb
199
208
- lib/amorail/entities/task.rb
209
+ - lib/amorail/entities/webhook.rb
200
210
- lib/amorail/entity.rb
201
211
- lib/amorail/entity/finders.rb
202
212
- lib/amorail/entity/params.rb
203
- - lib/amorail/entity/persistance.rb
213
+ - lib/amorail/entity/persistence.rb
204
214
- lib/amorail/exceptions.rb
205
215
- lib/amorail/property.rb
206
216
- lib/amorail/railtie.rb
@@ -211,27 +221,36 @@ files:
211
221
- spec/contact_link_spec.rb
212
222
- spec/contact_spec.rb
213
223
- spec/entity_spec.rb
214
- - spec/fixtures/account2_response.json
215
- - spec/fixtures/account_response.json
224
+ - spec/fixtures/accounts/response_1.json
225
+ - spec/fixtures/accounts/response_2.json
216
226
- spec/fixtures/amorail_test.yml
217
- - spec/fixtures/contact_create.json
218
- - spec/fixtures/contact_find.json
219
- - spec/fixtures/contact_find_query.json
220
- - spec/fixtures/contact_update.json
221
- - spec/fixtures/contacts_links.json
222
- - spec/fixtures/leads.json
223
- - spec/fixtures/leads_links.json
224
- - spec/fixtures/my_contact_find.json
227
+ - spec/fixtures/contacts/create.json
228
+ - spec/fixtures/contacts/find_many.json
229
+ - spec/fixtures/contacts/find_one.json
230
+ - spec/fixtures/contacts/links.json
231
+ - spec/fixtures/contacts/my_contact_find.json
232
+ - spec/fixtures/contacts/update.json
233
+ - spec/fixtures/leads/create.json
234
+ - spec/fixtures/leads/find_many.json
235
+ - spec/fixtures/leads/links.json
236
+ - spec/fixtures/leads/update.json
237
+ - spec/fixtures/leads/update_errors.json
238
+ - spec/fixtures/webhooks/list.json
239
+ - spec/fixtures/webhooks/subscribe.json
240
+ - spec/fixtures/webhooks/unsubscribe.json
225
241
- spec/helpers/webmock_helpers.rb
226
242
- spec/lead_spec.rb
227
243
- spec/my_contact_spec.rb
244
+ - spec/note_spec.rb
228
245
- spec/property_spec.rb
229
246
- spec/spec_helper.rb
247
+ - spec/support/elementable_example.rb
230
248
- spec/support/entity_class_example.rb
231
249
- spec/support/leadable_example.rb
232
250
- spec/support/my_contact.rb
233
251
- spec/support/my_entity.rb
234
252
- spec/task_spec.rb
253
+ - spec/webhook_spec.rb
235
254
homepage: ''
236
255
licenses:
237
256
- MIT
@@ -251,8 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
251
270
- !ruby/object:Gem::Version
252
271
version: '0'
253
272
requirements: []
254
- rubyforge_project:
273
+ rubygems_version: 3.0.4
255
- rubygems_version: 2.6.11
256
274
signing_key:
257
275
specification_version: 4
258
276
summary: Ruby API client for AmoCRM
@@ -262,24 +280,33 @@ test_files:
262
280
- spec/contact_link_spec.rb
263
281
- spec/contact_spec.rb
264
282
- spec/entity_spec.rb
265
- - spec/fixtures/account2_response.json
266
- - spec/fixtures/account_response.json
283
+ - spec/fixtures/accounts/response_1.json
284
+ - spec/fixtures/accounts/response_2.json
267
285
- spec/fixtures/amorail_test.yml
268
- - spec/fixtures/contact_create.json
269
- - spec/fixtures/contact_find.json
270
- - spec/fixtures/contact_find_query.json
271
- - spec/fixtures/contact_update.json
272
- - spec/fixtures/contacts_links.json
273
- - spec/fixtures/leads.json
274
- - spec/fixtures/leads_links.json
275
- - spec/fixtures/my_contact_find.json
286
+ - spec/fixtures/contacts/create.json
287
+ - spec/fixtures/contacts/find_many.json
288
+ - spec/fixtures/contacts/find_one.json
289
+ - spec/fixtures/contacts/links.json
290
+ - spec/fixtures/contacts/my_contact_find.json
291
+ - spec/fixtures/contacts/update.json
292
+ - spec/fixtures/leads/create.json
293
+ - spec/fixtures/leads/find_many.json
294
+ - spec/fixtures/leads/links.json
295
+ - spec/fixtures/leads/update.json
296
+ - spec/fixtures/leads/update_errors.json
297
+ - spec/fixtures/webhooks/list.json
298
+ - spec/fixtures/webhooks/subscribe.json
299
+ - spec/fixtures/webhooks/unsubscribe.json
276
300
- spec/helpers/webmock_helpers.rb
277
301
- spec/lead_spec.rb
278
302
- spec/my_contact_spec.rb
303
+ - spec/note_spec.rb
279
304
- spec/property_spec.rb
280
305
- spec/spec_helper.rb
306
+ - spec/support/elementable_example.rb
281
307
- spec/support/entity_class_example.rb
282
308
- spec/support/leadable_example.rb
283
309
- spec/support/my_contact.rb
284
310
- spec/support/my_entity.rb
285
311
- spec/task_spec.rb
312
+ - spec/webhook_spec.rb