amorail 0.4.0 → 0.7.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 (62) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rspec.yml +23 -0
  3. data/.gitignore +2 -1
  4. data/.rubocop.yml +3 -0
  5. data/CHANGELOG.md +19 -0
  6. data/README.md +49 -8
  7. data/RELEASING.md +43 -0
  8. data/amorail.gemspec +5 -3
  9. data/lib/amorail.rb +27 -6
  10. data/lib/amorail/access_token.rb +44 -0
  11. data/lib/amorail/client.rb +84 -23
  12. data/lib/amorail/config.rb +14 -8
  13. data/lib/amorail/entities/company.rb +2 -0
  14. data/lib/amorail/entities/contact.rb +3 -0
  15. data/lib/amorail/entities/contact_link.rb +2 -0
  16. data/lib/amorail/entities/elementable.rb +4 -2
  17. data/lib/amorail/entities/lead.rb +3 -0
  18. data/lib/amorail/entities/leadable.rb +3 -0
  19. data/lib/amorail/entities/note.rb +2 -0
  20. data/lib/amorail/entities/task.rb +2 -0
  21. data/lib/amorail/entities/webhook.rb +44 -0
  22. data/lib/amorail/entity.rb +17 -3
  23. data/lib/amorail/entity/finders.rb +5 -2
  24. data/lib/amorail/entity/params.rb +3 -2
  25. data/lib/amorail/entity/persistence.rb +5 -0
  26. data/lib/amorail/exceptions.rb +2 -0
  27. data/lib/amorail/property.rb +7 -3
  28. data/lib/amorail/railtie.rb +3 -1
  29. data/lib/amorail/store_adapters.rb +15 -0
  30. data/lib/amorail/store_adapters/abstract_store_adapter.rb +23 -0
  31. data/lib/amorail/store_adapters/memory_store_adapter.rb +50 -0
  32. data/lib/amorail/store_adapters/redis_store_adapter.rb +83 -0
  33. data/lib/amorail/version.rb +3 -1
  34. data/lib/tasks/amorail.rake +2 -0
  35. data/spec/access_token_spec.rb +59 -0
  36. data/spec/client_spec.rb +36 -24
  37. data/spec/company_spec.rb +2 -0
  38. data/spec/contact_link_spec.rb +2 -0
  39. data/spec/contact_spec.rb +2 -0
  40. data/spec/entity_spec.rb +2 -0
  41. data/spec/fixtures/amorail_test.yml +5 -3
  42. data/spec/fixtures/authorize.json +6 -0
  43. data/spec/fixtures/webhooks/list.json +24 -0
  44. data/spec/fixtures/webhooks/subscribe.json +17 -0
  45. data/spec/fixtures/webhooks/unsubscribe.json +17 -0
  46. data/spec/helpers/webmock_helpers.rb +80 -13
  47. data/spec/lead_spec.rb +2 -0
  48. data/spec/my_contact_spec.rb +2 -0
  49. data/spec/note_spec.rb +2 -0
  50. data/spec/property_spec.rb +2 -0
  51. data/spec/spec_helper.rb +4 -2
  52. data/spec/store_adapters/memory_store_adapter_spec.rb +56 -0
  53. data/spec/store_adapters/redis_store_adapter_spec.rb +67 -0
  54. data/spec/support/elementable_example.rb +2 -0
  55. data/spec/support/entity_class_example.rb +2 -0
  56. data/spec/support/leadable_example.rb +2 -0
  57. data/spec/support/my_contact.rb +2 -0
  58. data/spec/support/my_entity.rb +2 -0
  59. data/spec/task_spec.rb +2 -0
  60. data/spec/webhook_spec.rb +61 -0
  61. metadata +48 -17
  62. data/.travis.yml +0 -9
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Amorail
4
+ module StoreAdapters
5
+ class RedisStoreAdapter < AbstractStoreAdapter
6
+ attr_reader :storage
7
+
8
+ def initialize(**options)
9
+ begin
10
+ require 'redis'
11
+ @storage = configure_redis_client(**options)
12
+ rescue LoadError => e
13
+ msg = 'Could not load the \'redis\' gem, please add it to your gemfile or ' \
14
+ 'configure a different adapter (e.g. Amorail.store_adapter = :memory)'
15
+ raise e.class, msg, e.backtrace
16
+ end
17
+ end
18
+
19
+ def fetch_access(secret)
20
+ token = storage.get(access_key(secret))
21
+ refresh_token = storage.get(refresh_key(secret))
22
+ token.nil? ? {} : { token: token, refresh_token: refresh_token }
23
+ end
24
+
25
+ def persist_access(secret, token, refresh_token, expiration)
26
+ update_data(secret, token, refresh_token, expiration)
27
+ end
28
+
29
+ def update_access(secret, token, refresh_token, expiration)
30
+ update_data(secret, token, refresh_token, expiration)
31
+ end
32
+
33
+ def access_expired?(secret)
34
+ access_key = access_key(secret)
35
+ refresh_key = refresh_key(secret)
36
+ storage.get(refresh_key) && storage.get(access_key).nil?
37
+ end
38
+
39
+ private
40
+
41
+ def update_data(secret, token, refresh_token, expiration)
42
+ access_key = access_key(secret)
43
+ refresh_key = refresh_key(secret)
44
+ storage.set(access_key, token)
45
+ storage.set(refresh_key, refresh_token)
46
+ storage.expireat(access_key, expiration)
47
+ end
48
+
49
+ def configure_redis_client(redis_url: nil, redis_host: nil, redis_port: nil, redis_db_name: nil)
50
+ if redis_url && (redis_host || redis_port || redis_db_name)
51
+ raise ArgumentError, 'redis_url cannot be passed along with redis_host, redis_port or redis_db_name options'
52
+ end
53
+
54
+ redis_url ||= build_redis_url(
55
+ redis_host: redis_host,
56
+ redis_port: redis_port,
57
+ redis_db_name: redis_db_name
58
+ )
59
+
60
+ Redis.new(url: redis_url)
61
+ end
62
+
63
+ def build_redis_url(redis_host: nil, redis_port: nil, redis_db_name: nil)
64
+ redis_db_name ||= Amorail.config.redis_db_name
65
+ return URI.join(Amorail.config.redis_url, redis_db_name).to_s if Amorail.config.redis_url
66
+
67
+ redis_host ||= Amorail.config.redis_host
68
+ redis_port ||= Amorail.config.redis_port
69
+
70
+ redis_base_url = ENV['REDIS_URL'] || "redis://#{redis_host}:#{redis_port}"
71
+ URI.join(redis_base_url, redis_db_name).to_s
72
+ end
73
+
74
+ def access_key(secret)
75
+ "access_#{secret}"
76
+ end
77
+
78
+ def refresh_key(secret)
79
+ "refresh_#{secret}"
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Amorail version
2
4
  module Amorail
3
- VERSION = "0.4.0".freeze
5
+ VERSION = '0.7.0'
4
6
  end
@@ -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
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Amorail::AccessToken do
6
+ let(:store) { Amorail.token_store }
7
+
8
+ before do
9
+ Amorail::AccessToken.create(
10
+ 'secret',
11
+ 'token',
12
+ 'refresh_token',
13
+ Time.now.to_i + 86_000,
14
+ store
15
+ )
16
+
17
+ Amorail::AccessToken.create(
18
+ 'secret_expired',
19
+ 'token',
20
+ 'refresh_token',
21
+ Time.now.to_i - 92_000,
22
+ store
23
+ )
24
+ end
25
+
26
+ describe '#find' do
27
+ context 'when token is not expired' do
28
+ subject { Amorail::AccessToken.find('secret', store).token }
29
+
30
+ it 'should return token' do
31
+ expect(subject).to eq('token')
32
+ end
33
+ end
34
+
35
+ context 'when token is expired' do
36
+ subject { Amorail::AccessToken.find('secret_expired', store).token }
37
+
38
+ it 'should return nil' do
39
+ expect(subject).to be_nil
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#refresh' do
45
+ it 'updates token data' do
46
+ upd_expiration = Time.now.to_i + 96_000
47
+ access_token = Amorail::AccessToken.refresh('secret',
48
+ 'upd_token',
49
+ 'upd_refresh',
50
+ upd_expiration,
51
+ Amorail.token_store)
52
+ aggregate_failures do
53
+ expect(access_token.token).to eq('upd_token')
54
+ expect(access_token.refresh_token).to eq('upd_refresh')
55
+ expect(access_token.expiration).to eq(upd_expiration)
56
+ end
57
+ end
58
+ end
59
+ end
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
@@ -7,8 +9,10 @@ describe Amorail::Client do
7
9
 
8
10
  context "default client" do
9
11
  it "should create client", :aggregate_failures do
10
- expect(subject.usermail).to eq "amorail@test.com"
11
- expect(subject.api_key).to eq "75742b166417fe32ae132282ce178cf6"
12
+ expect(subject.client_id).to eq "some_id"
13
+ expect(subject.client_secret).to eq "some_secret"
14
+ expect(subject.code).to eq "some_code"
15
+ expect(subject.redirect_uri).to eq "https://example.ru/redirect/uri"
12
16
  expect(subject.api_endpoint).to eq "https://test.amocrm.ru"
13
17
  end
14
18
 
@@ -24,40 +28,48 @@ describe Amorail::Client do
24
28
  end
25
29
 
26
30
  describe "#with_client" do
27
- before { mock_custom_api("https://custom.amo.com", "custom@amo.com", "123") }
31
+ before { mock_custom_api("https://custom.amo.com", "custom_client_id", "custom_client_secret", "custom_code", "https://custom-site.ru/redirecto/uri") }
28
32
 
29
33
  let(:new_client) do
30
34
  described_class.new(
31
35
  api_endpoint: "https://custom.amo.com",
32
- usermail: "custom@amo.com",
33
- api_key: "123"
36
+ client_secret: "custom_client_secret",
37
+ client_id: "custom_client_id",
38
+ code: "custom_code",
39
+ redirect_uri: "https://custom-site.ru/redirecto/uri"
34
40
  )
35
41
  end
36
42
 
37
43
  it "use custom client as instance", :aggregate_failures do
38
- expect(Amorail.client.usermail).to eq "amorail@test.com"
44
+ expect(Amorail.client.client_id).to eq "some_id"
39
45
  Amorail.with_client(new_client) do
40
- expect(Amorail.client.usermail).to eq "custom@amo.com"
46
+ expect(Amorail.client.client_secret).to eq "custom_client_secret"
47
+ expect(Amorail.client.client_id).to eq "custom_client_id"
41
48
  expect(Amorail.client.api_endpoint).to eq "https://custom.amo.com"
42
- expect(Amorail.client.api_key).to eq "123"
49
+ expect(Amorail.client.code).to eq "custom_code"
50
+ expect(Amorail.client.redirect_uri).to eq "https://custom-site.ru/redirecto/uri"
43
51
  end
44
52
 
45
- expect(Amorail.client.usermail).to eq "amorail@test.com"
53
+ expect(Amorail.client.client_id).to eq "some_id"
46
54
  end
47
55
 
48
56
  it "use custom client as options", :aggregate_failures do
49
- expect(Amorail.client.usermail).to eq "amorail@test.com"
57
+ expect(Amorail.client.client_id).to eq "some_id"
50
58
  Amorail.with_client(
51
59
  api_endpoint: "https://custom.amo.com",
52
- usermail: "custom@amo.com",
53
- api_key: "123"
60
+ client_secret: "custom_client_secret",
61
+ client_id: "custom_client_id",
62
+ code: "custom_code",
63
+ redirect_uri: "https://custom-site.ru/redirecto/uri"
54
64
  ) do
55
- expect(Amorail.client.usermail).to eq "custom@amo.com"
65
+ expect(Amorail.client.client_secret).to eq "custom_client_secret"
66
+ expect(Amorail.client.client_id).to eq "custom_client_id"
56
67
  expect(Amorail.client.api_endpoint).to eq "https://custom.amo.com"
57
- expect(Amorail.client.api_key).to eq "123"
68
+ expect(Amorail.client.code).to eq "custom_code"
69
+ expect(Amorail.client.redirect_uri).to eq "https://custom-site.ru/redirecto/uri"
58
70
  end
59
71
 
60
- expect(Amorail.client.usermail).to eq "amorail@test.com"
72
+ expect(Amorail.client.client_id).to eq "some_id"
61
73
  end
62
74
 
63
75
  it "loads custom properties", :aggregate_failures do
@@ -81,10 +93,10 @@ describe Amorail::Client do
81
93
  # only after the second thread enters block
82
94
  threads << Thread.new do
83
95
  q1.pop
84
- Amorail.with_client(usermail: 'test1@amo.com') do
96
+ Amorail.with_client(client_id: 'some_id_1') do
85
97
  q2 << 1
86
98
  q1.pop
87
- results << Amorail.client.usermail
99
+ results << Amorail.client.client_id
88
100
  q2 << 1
89
101
  end
90
102
  q3 << 1
@@ -94,10 +106,10 @@ describe Amorail::Client do
94
106
  # after the first block
95
107
  threads << Thread.new do
96
108
  q2.pop
97
- Amorail.with_client(usermail: 'test2@amo.com') do
109
+ Amorail.with_client(client_id: 'some_id_2') do
98
110
  q1 << 1
99
111
  q2.pop
100
- results << Amorail.client.usermail
112
+ results << Amorail.client.client_id
101
113
  end
102
114
  q3 << 1
103
115
  end
@@ -105,19 +117,19 @@ describe Amorail::Client do
105
117
  # This thread enters block third and commits
106
118
  # after all other threads left blocks
107
119
  threads << Thread.new do
108
- Amorail.with_client(usermail: 'test3@amo.com') do
120
+ Amorail.with_client(client_id: 'some_id_3') do
109
121
  q3.pop
110
122
  q3.pop
111
- results << Amorail.client.usermail
123
+ results << Amorail.client.client_id
112
124
  end
113
125
  end
114
126
 
115
127
  q1 << 1
116
128
  threads.each(&:join)
117
129
 
118
- expect(results[0]).to eq 'test1@amo.com'
119
- expect(results[1]).to eq 'test2@amo.com'
120
- expect(results[2]).to eq 'test3@amo.com'
130
+ expect(results[0]).to eq 'some_id_1'
131
+ expect(results[1]).to eq 'some_id_2'
132
+ expect(results[2]).to eq 'some_id_3'
121
133
  end
122
134
  end
123
135
  end
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
@@ -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
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
@@ -1,3 +1,5 @@
1
- usermail: 'amorail@test.com'
2
- api_key: '75742b166417fe32ae132282ce178cf6'
3
- api_endpoint: 'https://test.amocrm.ru'
1
+ client_id: 'some_id'
2
+ client_secret: 'some_secret'
3
+ code: 'some_code'
4
+ redirect_uri: 'https://example.ru/redirect/uri'
5
+ api_endpoint: 'https://test.amocrm.ru'
@@ -0,0 +1,6 @@
1
+ {
2
+ "token_type": "Bearer",
3
+ "expires_in": 86400,
4
+ "access_token": "eyJ0eXAiOiJKf2QihCJhbGciOiJSUzI1NiIsImp0aSI6IjMxMTY3MGY3ZDVjY2IwODRjYTUyOTc5OGVjMzM0ZGU2ZDIzMmYzZDUyMjE0NTFhMTYzZDFlMTM2ZGY3NjA4MGVmMjViZTMwODQwNzFhY2Y0In0.eyJhdWQiOiIwNDA4M2FjZC1iY2ZmLTRiOWItOTJkYS05OTFiOTc0MDBlNzMiLCJqdGkiOiIzMTE2NzBmN2Q1Y2NiMDg0Y2E1Mjk3OThlYzMzNGRlNmQyMzJmM2Q1MjIxNDUxYTE2M2QxZTEzNmRmNzYwODBlZjI1YmUzMDg0MDcxYWNmNCIsImlhdCI6MTYxMzM4NzQ2MiwibmJmIDoxNjEzMzg3NDYyLCJleHAiOjE2MTM0NzM4NyIsInN1YiI6IjYyNjU1OTEiLCJhY2NvdW50X2lkIjoyOTAxMTIzMSwic2NvcGVzIjpbInB1c2hfbm90aWZpY2F0aW9ucyIsImNybSIsIm5vdGlmaWNhdGlvbnMiXX0.HRnJJXSK5KrlkcxHVBQBvE8TS34Rwru4Ba_lBlgzEtfU6FjaOCuBA0VLKJ24lLHz2w9B3lgMn9-OG9ayXAkDqrNPZByOimJ5cdwQExlNws-gvO9Hj27QiWK5JMTvbDE4EjVGvKuH7uXRsFTcsmuP6MA-5hjZ5h2DmNr5gzfZVS2Onh_9vrX75yh5FjFohfoO8izohtQYzZDVNYzek13EBdEK2BiNgLCoGhyGeMRtmTpwdSueD72qFGL80RMkQAGV8mElkZiXeUuGckTvEdIUodlgH6fk_KYG8OF3jozbEpzFKKfgPMUjE3vyCLVPWCEolQZjZPhSd6KbatK-f0oPWA",
5
+ "refresh_token": "def50200f4151ec4424843abc377eec488c6e8dceeda93b3f0b33d8f02207911533d98b408b97e2b2688acd1d956a44368f51263c7a55253efb543b256b90a2a1dc0ac71bf546374f23ab3d2b07f3ced5ad31e500e16b4d99deb6c735a5001c43c70156feac0a9c94dd24fdc6238ee59603997614ccb28773e4bce14d01e69fa7c04f869088fb1c9c27fea2f68f70E46d615a3982bdcd352Dcd05e3ae70e1d1ba707dcb354e7b611eba6790039a6c4bf2909210a85bdc34a254e9a10f8637aff405938ddcdc8bf88fb4ed8c8f15d7fa1e0e787c624b26c270b43e5877e1b6c87292bd95bb90305f50886b595d5a83c5b9768a8a61c63cdc7b082312ecc32619577253856058e8761c6f1e338e58824d8bed2a227bbe43dd12a69bf347657aa4f41f5d7609b6c5e088a0a0d2b2af9877bf8642c7d44fc6caa3c7dfa342d8b38e37d8a68dd26e814f0bfcdee707bf44ce7ef9e4d57ff5ac6aa52f2259388e5a3b7e5c6689366f43bf9197b2bf0e00470a3031581031b82ade8d8c0f8c01eabb61c312f47a2cfdc2943b10bc1f3d0b7791e1b1487832d3db75908611af90659f721cd3f831dcc76d8da12044611910722c9dc8bc09a5aff82923a2551a5bd5c5c57e4273993e655da7881e3"
6
+ }
@@ -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
+ }
@@ -1,36 +1,73 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # rubocop: disable Metrics/ModuleLength
2
4
  module AmoWebMock
3
5
  def mock_api
4
6
  authorize_stub(
5
7
  Amorail.config.api_endpoint,
6
- Amorail.config.usermail,
7
- Amorail.config.api_key)
8
+ Amorail.config.client_id,
9
+ Amorail.config.client_secret,
10
+ 'authorization_code',
11
+ Amorail.config.code,
12
+ Amorail.config.redirect_uri
13
+ )
14
+
15
+ resresh_token_stub(
16
+ Amorail.config.api_endpoint,
17
+ Amorail.config.client_id,
18
+ Amorail.config.client_secret,
19
+ 'refresh_token',
20
+ 'refresh_token',
21
+ Amorail.config.redirect_uri
22
+ )
8
23
 
9
24
  account_info_stub(Amorail.config.api_endpoint)
10
25
  end
11
26
 
12
- def mock_custom_api(endpoint, usermail, api_key, properties = 'response_2.json')
27
+ def mock_custom_api(endpoint, client_id, client_secret, code, redirect_uri, properties = 'response_2.json')
13
28
  authorize_stub(
14
29
  endpoint,
15
- usermail,
16
- api_key
30
+ client_id,
31
+ client_secret,
32
+ 'authorization_code',
33
+ code,
34
+ redirect_uri
35
+ )
36
+
37
+ resresh_token_stub(
38
+ endpoint,
39
+ client_id,
40
+ client_secret,
41
+ 'refresh_token',
42
+ 'refresh_token',
43
+ redirect_uri
17
44
  )
18
45
 
19
46
  account_info_stub(endpoint, properties)
20
47
  end
21
48
 
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")
49
+ def authorize_stub(endpoint, client_id, client_secret, grant_type, code, redirect_uri)
50
+ stub_request(:post, "#{endpoint}/oauth2/access_token")
25
51
  .with(
26
- body: "{\"USER_LOGIN\":\"#{usermail}\",\"USER_HASH\":\"#{api_key}\"}"
52
+ body: "{\"client_id\":\"#{client_id}\",\"client_secret\":\"#{client_secret}\",\"grant_type\":\"#{grant_type}\",\"code\":\"#{code}\",\"redirect_uri\":\"#{redirect_uri}\"}"
27
53
  )
28
54
  .to_return(
29
55
  status: 200,
30
- body: "",
31
- headers: {
32
- 'Set-Cookie' => cookie
33
- })
56
+ body: File.read('./spec/fixtures/authorize.json'),
57
+ headers: {}
58
+ )
59
+ end
60
+
61
+ def resresh_token_stub(endpoint, client_id, client_secret, grant_type, refresh_token, redirect_uri)
62
+ stub_request(:post, "#{endpoint}/oauth2/access_token")
63
+ .with(
64
+ body: "{\"client_id\":\"#{client_id}\",\"client_secret\":\"#{client_secret}\",\"grant_type\":\"#{grant_type}\",\"refresh_token\":\"#{refresh_token}\",\"redirect_uri\":\"#{redirect_uri}\"}"
65
+ )
66
+ .to_return(
67
+ status: 200,
68
+ body: File.read('./spec/fixtures/authorize.json'),
69
+ headers: {}
70
+ )
34
71
  end
35
72
 
36
73
  def account_info_stub(endpoint, properties = 'response_1.json')
@@ -246,4 +283,34 @@ module AmoWebMock
246
283
  .to_return(status: 204)
247
284
  end
248
285
  end
286
+
287
+ def webhooks_list_stub(endpoint, empty: false)
288
+ body = empty ? '' : File.read('./spec/fixtures/webhooks/list.json')
289
+ stub_request(:get, "#{endpoint}/private/api/v2/json/webhooks/list")
290
+ .to_return(
291
+ body: body,
292
+ headers: { 'Content-Type' => 'application/json' },
293
+ status: 200
294
+ )
295
+ end
296
+
297
+ def webhooks_subscribe_stub(endpoint, webhooks)
298
+ stub_request(:post, "#{endpoint}/private/api/v2/json/webhooks/subscribe")
299
+ .with(body: { request: { webhooks: { subscribe: webhooks } } }.to_json)
300
+ .to_return(
301
+ body: File.read('./spec/fixtures/webhooks/subscribe.json'),
302
+ headers: { 'Content-Type' => 'application/json' },
303
+ status: 200
304
+ )
305
+ end
306
+
307
+ def webhooks_unsubscribe_stub(endpoint, webhooks)
308
+ stub_request(:post, "#{endpoint}/private/api/v2/json/webhooks/unsubscribe")
309
+ .with(body: { request: { webhooks: { unsubscribe: webhooks } } }.to_json)
310
+ .to_return(
311
+ body: File.read('./spec/fixtures/webhooks/unsubscribe.json'),
312
+ headers: { 'Content-Type' => 'application/json' },
313
+ status: 200
314
+ )
315
+ end
249
316
  end