amorail 0.5.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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rubocop.yml +61 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +5 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +245 -0
  8. data/Rakefile +15 -0
  9. data/amorail.gemspec +33 -0
  10. data/lib/amorail.rb +49 -0
  11. data/lib/amorail/client.rb +101 -0
  12. data/lib/amorail/config.rb +17 -0
  13. data/lib/amorail/entities/company.rb +23 -0
  14. data/lib/amorail/entities/contact.rb +29 -0
  15. data/lib/amorail/entities/contact_link.rb +32 -0
  16. data/lib/amorail/entities/elementable.rb +37 -0
  17. data/lib/amorail/entities/lead.rb +26 -0
  18. data/lib/amorail/entities/leadable.rb +29 -0
  19. data/lib/amorail/entities/note.rb +17 -0
  20. data/lib/amorail/entities/task.rb +18 -0
  21. data/lib/amorail/entities/webhook.rb +42 -0
  22. data/lib/amorail/entity.rb +128 -0
  23. data/lib/amorail/entity/finders.rb +67 -0
  24. data/lib/amorail/entity/params.rb +95 -0
  25. data/lib/amorail/entity/persistence.rb +66 -0
  26. data/lib/amorail/exceptions.rb +25 -0
  27. data/lib/amorail/property.rb +130 -0
  28. data/lib/amorail/railtie.rb +8 -0
  29. data/lib/amorail/version.rb +4 -0
  30. data/lib/tasks/amorail.rake +6 -0
  31. data/spec/client_spec.rb +123 -0
  32. data/spec/company_spec.rb +82 -0
  33. data/spec/contact_link_spec.rb +40 -0
  34. data/spec/contact_spec.rb +187 -0
  35. data/spec/entity_spec.rb +55 -0
  36. data/spec/fixtures/accounts/response_1.json +344 -0
  37. data/spec/fixtures/accounts/response_2.json +195 -0
  38. data/spec/fixtures/amorail_test.yml +3 -0
  39. data/spec/fixtures/contacts/create.json +13 -0
  40. data/spec/fixtures/contacts/find_many.json +57 -0
  41. data/spec/fixtures/contacts/find_one.json +41 -0
  42. data/spec/fixtures/contacts/links.json +16 -0
  43. data/spec/fixtures/contacts/my_contact_find.json +47 -0
  44. data/spec/fixtures/contacts/update.json +13 -0
  45. data/spec/fixtures/leads/create.json +13 -0
  46. data/spec/fixtures/leads/find_many.json +73 -0
  47. data/spec/fixtures/leads/links.json +16 -0
  48. data/spec/fixtures/leads/update.json +13 -0
  49. data/spec/fixtures/leads/update_errors.json +12 -0
  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 +279 -0
  54. data/spec/lead_spec.rb +101 -0
  55. data/spec/my_contact_spec.rb +48 -0
  56. data/spec/note_spec.rb +26 -0
  57. data/spec/property_spec.rb +45 -0
  58. data/spec/spec_helper.rb +20 -0
  59. data/spec/support/elementable_example.rb +52 -0
  60. data/spec/support/entity_class_example.rb +15 -0
  61. data/spec/support/leadable_example.rb +33 -0
  62. data/spec/support/my_contact.rb +3 -0
  63. data/spec/support/my_entity.rb +4 -0
  64. data/spec/task_spec.rb +49 -0
  65. data/spec/webhook_spec.rb +59 -0
  66. metadata +319 -0
@@ -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
+ }
@@ -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
+ }
@@ -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
+ }
@@ -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
+ }
@@ -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
+ }
@@ -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
+ }
@@ -0,0 +1,279 @@
1
+ # rubocop: disable Metrics/ModuleLength
2
+ module AmoWebMock
3
+ def mock_api
4
+ authorize_stub(
5
+ Amorail.config.api_endpoint,
6
+ Amorail.config.usermail,
7
+ Amorail.config.api_key)
8
+
9
+ account_info_stub(Amorail.config.api_endpoint)
10
+ end
11
+
12
+ def mock_custom_api(endpoint, usermail, api_key, properties = 'response_2.json')
13
+ authorize_stub(
14
+ endpoint,
15
+ usermail,
16
+ api_key
17
+ )
18
+
19
+ account_info_stub(endpoint, properties)
20
+ end
21
+
22
+ def authorize_stub(endpoint, usermail, api_key)
23
+ cookie = 'PHPSESSID=58vorte6dd4t7h6mtuig9l0p50; path=/; domain=amocrm.ru'
24
+ stub_request(:post, "#{endpoint}/private/api/auth.php?type=json")
25
+ .with(
26
+ body: "{\"USER_LOGIN\":\"#{usermail}\",\"USER_HASH\":\"#{api_key}\"}"
27
+ )
28
+ .to_return(
29
+ status: 200,
30
+ body: "",
31
+ headers: {
32
+ 'Set-Cookie' => cookie
33
+ })
34
+ end
35
+
36
+ def account_info_stub(endpoint, properties = 'response_1.json')
37
+ stub_request(:get, endpoint + '/private/api/v2/json/accounts/current')
38
+ .to_return(
39
+ body: File.read("./spec/fixtures/accounts/#{properties}"),
40
+ headers: { 'Content-Type' => 'application/json' },
41
+ status: 200
42
+ )
43
+ end
44
+
45
+ def unauthorized_account_info_stub(endpoint)
46
+ stub_request(:get, endpoint + '/private/api/v2/json/accounts/current')
47
+ .to_return(
48
+ body: "", status: 401
49
+ )
50
+ end
51
+
52
+ def bad_req_account_info_stub(endpoint)
53
+ stub_request(:post, endpoint + '/private/api/v2/json/accounts/current')
54
+ .with(body: "{}")
55
+ .to_return(
56
+ body: "",
57
+ status: 400
58
+ )
59
+ end
60
+
61
+ def contact_create_stub(endpoint)
62
+ stub_request(:post, endpoint + '/private/api/v2/json/contacts/set')
63
+ .to_return(
64
+ body: File.read('./spec/fixtures/contacts/create.json'),
65
+ headers: { 'Content-Type' => 'application/json' },
66
+ status: 200
67
+ )
68
+ end
69
+
70
+ def contact_update_stub(endpoint)
71
+ stub_request(:post, endpoint + '/private/api/v2/json/contacts/set')
72
+ .to_return(
73
+ body: File.read('./spec/fixtures/contacts/update.json'),
74
+ headers: {
75
+ 'Content-Type' => 'application/json'
76
+ },
77
+ status: 200
78
+ )
79
+ end
80
+
81
+ def contact_find_stub(endpoint, id, success = true)
82
+ if success
83
+ stub_request(
84
+ :get,
85
+ "#{endpoint}/private/api/v2/json/contacts/list?id=#{id}")
86
+ .to_return(
87
+ body: File.read('./spec/fixtures/contacts/find_one.json'),
88
+ headers: { 'Content-Type' => 'application/json' },
89
+ status: 200
90
+ )
91
+ else
92
+ stub_request(
93
+ :get,
94
+ "#{endpoint}/private/api/v2/json/contacts/list?id=#{id}")
95
+ .to_return(body: nil, status: 204)
96
+ end
97
+ end
98
+
99
+ def my_contact_find_stub(endpoint, id, success = true)
100
+ if success
101
+ stub_request(
102
+ :get,
103
+ "#{endpoint}/private/api/v2/json/contacts/list?id=#{id}")
104
+ .to_return(
105
+ body: File.read('./spec/fixtures/contacts/my_contact_find.json'),
106
+ headers: { 'Content-Type' => 'application/json' },
107
+ status: 200
108
+ )
109
+ else
110
+ stub_request(
111
+ :get,
112
+ "#{endpoint}/private/api/v2/json/contacts/list?id=#{id}")
113
+ .to_return(body: nil, status: 204)
114
+ end
115
+ end
116
+
117
+ def contacts_find_query_stub(endpoint, query, success = true)
118
+ if success
119
+ stub_request(
120
+ :get,
121
+ "#{endpoint}/private/api/v2/json/contacts/list?query=#{query}")
122
+ .to_return(
123
+ body: File.read('./spec/fixtures/contacts/find_many.json'),
124
+ headers: { 'Content-Type' => 'application/json' },
125
+ status: 200
126
+ )
127
+ else
128
+ stub_request(
129
+ :get,
130
+ "#{endpoint}/private/api/v2/json/contacts/list?query=#{query}")
131
+ .to_return(status: 204)
132
+ end
133
+ end
134
+
135
+ def contacts_find_all_stub(endpoint, ids, success = true)
136
+ if success
137
+ stub_request(
138
+ :get,
139
+ "#{endpoint}/private/api/v2/json/contacts/list?#{ids.to_query('id')}")
140
+ .to_return(
141
+ body: File.read('./spec/fixtures/contacts/find_many.json'),
142
+ headers: { 'Content-Type' => 'application/json' },
143
+ status: 200
144
+ )
145
+ else
146
+ stub_request(
147
+ :get,
148
+ "#{endpoint}/private/api/v2/json/contacts/list?#{ids.to_query('id')}")
149
+ .to_return(status: 204)
150
+ end
151
+ end
152
+
153
+ def contacts_where_stub(endpoint, success = true, **params)
154
+ if success
155
+ stub_request(
156
+ :get,
157
+ "#{endpoint}/private/api/v2/json/contacts/list"
158
+ ).with(
159
+ query: params
160
+ ).to_return(
161
+ body: File.read('./spec/fixtures/contacts/find_many.json'),
162
+ headers: { 'Content-Type' => 'application/json' },
163
+ status: 200
164
+ )
165
+ else
166
+ stub_request(
167
+ :get,
168
+ "#{endpoint}/private/api/v2/json/contacts/list?query=#{query}")
169
+ .to_return(status: 204)
170
+ end
171
+ end
172
+
173
+ def company_create_stub(endpoint)
174
+ stub_request(:post, endpoint + '/private/api/v2/json/company/set')
175
+ .to_return(
176
+ body: File.read('./spec/fixtures/contacts/create.json'),
177
+ headers: { 'Content-Type' => 'application/json' },
178
+ status: 200
179
+ )
180
+ end
181
+
182
+ def leads_stub(endpoint, ids, success = true)
183
+ if success
184
+ stub_request(
185
+ :get,
186
+ "#{endpoint}/private/api/v2/json/leads/list?#{ids.to_query('id')}")
187
+ .to_return(
188
+ body: File.read('./spec/fixtures/leads/find_many.json'),
189
+ headers: { 'Content-Type' => 'application/json' },
190
+ status: 200
191
+ )
192
+ else
193
+ stub_request(
194
+ :get,
195
+ "#{endpoint}/private/api/v2/json/leads/list?#{ids.to_query('id')}")
196
+ .to_return(status: 204)
197
+ end
198
+ end
199
+
200
+ def lead_create_stub(endpoint)
201
+ stub_request(:post, endpoint + '/private/api/v2/json/leads/set')
202
+ .to_return(
203
+ body: File.read('./spec/fixtures/leads/create.json'),
204
+ headers: { 'Content-Type' => 'application/json' },
205
+ status: 200
206
+ )
207
+ end
208
+
209
+ def lead_update_stub(endpoint, success = true)
210
+ fixture_file =
211
+ if success
212
+ './spec/fixtures/leads/update.json'
213
+ else
214
+ './spec/fixtures/leads/update_errors.json'
215
+ end
216
+
217
+ stub_request(:post, endpoint + '/private/api/v2/json/leads/set')
218
+ .to_return(
219
+ body: File.read(fixture_file),
220
+ headers: {
221
+ 'Content-Type' => 'application/json'
222
+ },
223
+ status: 200
224
+ )
225
+ end
226
+
227
+ def contacts_links_stub(endpoint, ids)
228
+ stub_request(:get, endpoint + "/private/api/v2/json/contacts/links?#{ids.to_query('contacts_link')}")
229
+ .to_return(
230
+ body: File.read('./spec/fixtures/contacts/links.json'),
231
+ headers: { 'Content-Type' => 'application/json' },
232
+ status: 200
233
+ )
234
+ end
235
+
236
+ def leads_links_stub(endpoint, ids, success = true)
237
+ if success
238
+ stub_request(:get, endpoint + "/private/api/v2/json/contacts/links?#{ids.to_query('deals_link')}")
239
+ .to_return(
240
+ body: File.read('./spec/fixtures/leads/links.json'),
241
+ headers: { 'Content-Type' => 'application/json' },
242
+ status: 200
243
+ )
244
+ else
245
+ stub_request(:get, endpoint + "/private/api/v2/json/contacts/links?#{ids.to_query('deals_link')}")
246
+ .to_return(status: 204)
247
+ end
248
+ end
249
+
250
+ def webhooks_list_stub(endpoint, empty: false)
251
+ body = empty ? '' : File.read('./spec/fixtures/webhooks/list.json')
252
+ stub_request(:get, "#{endpoint}/private/api/v2/json/webhooks/list")
253
+ .to_return(
254
+ body: body,
255
+ headers: { 'Content-Type' => 'application/json' },
256
+ status: 200
257
+ )
258
+ end
259
+
260
+ def webhooks_subscribe_stub(endpoint, webhooks)
261
+ stub_request(:post, "#{endpoint}/private/api/v2/json/webhooks/subscribe")
262
+ .with(body: { request: { webhooks: { subscribe: webhooks } } }.to_json)
263
+ .to_return(
264
+ body: File.read('./spec/fixtures/webhooks/subscribe.json'),
265
+ headers: { 'Content-Type' => 'application/json' },
266
+ status: 200
267
+ )
268
+ end
269
+
270
+ def webhooks_unsubscribe_stub(endpoint, webhooks)
271
+ stub_request(:post, "#{endpoint}/private/api/v2/json/webhooks/unsubscribe")
272
+ .with(body: { request: { webhooks: { unsubscribe: webhooks } } }.to_json)
273
+ .to_return(
274
+ body: File.read('./spec/fixtures/webhooks/unsubscribe.json'),
275
+ headers: { 'Content-Type' => 'application/json' },
276
+ status: 200
277
+ )
278
+ end
279
+ end
@@ -0,0 +1,101 @@
1
+ require "spec_helper"
2
+
3
+ describe Amorail::Lead do
4
+ before { mock_api }
5
+
6
+ describe "validations" do
7
+ it { should validate_presence_of(:name) }
8
+ it { should validate_presence_of(:status_id) }
9
+ end
10
+
11
+ describe ".attributes" do
12
+ subject { described_class.attributes }
13
+
14
+ it_behaves_like 'entity_class'
15
+
16
+ specify do
17
+ is_expected.to include(
18
+ :name,
19
+ :price,
20
+ :status_id,
21
+ :pipeline_id,
22
+ :tags
23
+ )
24
+ end
25
+ end
26
+
27
+ describe "#params" do
28
+ let(:lead) do
29
+ described_class.new(
30
+ name: 'Test',
31
+ price: 100,
32
+ status_id: 2,
33
+ pipeline_id: 17,
34
+ tags: 'test lead'
35
+ )
36
+ end
37
+
38
+ subject { lead.params }
39
+
40
+ specify { is_expected.to include(:last_modified) }
41
+ specify { is_expected.to include(name: 'Test') }
42
+ specify { is_expected.to include(price: 100) }
43
+ specify { is_expected.to include(status_id: 2) }
44
+ specify { is_expected.to include(pipeline_id: 17) }
45
+ specify { is_expected.to include(tags: 'test lead') }
46
+ end
47
+
48
+ describe "#contacts" do
49
+ let(:lead) { described_class.new(id: 2) }
50
+
51
+ it "fails if not persisted" do
52
+ expect { described_class.new.contacts }
53
+ .to raise_error(Amorail::Entity::NotPersisted)
54
+ end
55
+
56
+ context "has contacts" do
57
+ before { leads_links_stub(Amorail.config.api_endpoint, [2]) }
58
+ before { contacts_find_all_stub(Amorail.config.api_endpoint, [101, 102]) }
59
+
60
+ it "loads contacts for lead" do
61
+ res = lead.contacts
62
+ expect(res.size).to eq 2
63
+ expect(res.first.id).to eq 101
64
+ expect(res.last.id).to eq 102
65
+ end
66
+ end
67
+
68
+ context "no contacts" do
69
+ before { leads_links_stub(Amorail.config.api_endpoint, [2], false) }
70
+
71
+ it "returns empty" do
72
+ expect(lead.contacts).to be_empty
73
+ end
74
+ end
75
+ end
76
+
77
+ describe "#update" do
78
+ subject { lead.update }
79
+
80
+ let(:lead) { described_class.new(name: 'RSpec lead', status_id: 142) }
81
+
82
+ before do
83
+ lead_create_stub(Amorail.config.api_endpoint)
84
+ lead.save!
85
+ end
86
+
87
+ context 'with errors in response' do
88
+ before do
89
+ lead_update_stub(Amorail.config.api_endpoint, false)
90
+ lead.name = 'Updated name'
91
+ end
92
+
93
+ it { is_expected.to be_falsey }
94
+
95
+ specify do
96
+ subject
97
+ expect(lead.errors[:base]).to include('Last modified date is older than in database')
98
+ end
99
+ end
100
+ end
101
+ end