amorail 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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