amorail 0.5.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rspec.yml +23 -0
- data/.gitignore +2 -1
- data/CHANGELOG.md +27 -0
- data/README.md +49 -8
- data/RELEASING.md +43 -0
- data/amorail.gemspec +5 -3
- data/lib/amorail/access_token.rb +44 -0
- data/lib/amorail/client.rb +84 -23
- data/lib/amorail/config.rb +14 -8
- data/lib/amorail/entities/company.rb +2 -0
- data/lib/amorail/entities/contact.rb +2 -0
- data/lib/amorail/entities/contact_link.rb +2 -0
- data/lib/amorail/entities/elementable.rb +4 -2
- data/lib/amorail/entities/lead.rb +2 -0
- data/lib/amorail/entities/leadable.rb +2 -0
- data/lib/amorail/entities/note.rb +2 -0
- data/lib/amorail/entities/task.rb +2 -0
- data/lib/amorail/entities/webhook.rb +2 -0
- data/lib/amorail/entity/finders.rb +2 -0
- data/lib/amorail/entity/params.rb +13 -3
- data/lib/amorail/entity/persistence.rb +2 -0
- data/lib/amorail/entity.rb +20 -3
- data/lib/amorail/exceptions.rb +2 -0
- data/lib/amorail/property.rb +5 -3
- data/lib/amorail/railtie.rb +2 -0
- data/lib/amorail/store_adapters/abstract_store_adapter.rb +23 -0
- data/lib/amorail/store_adapters/memory_store_adapter.rb +50 -0
- data/lib/amorail/store_adapters/redis_store_adapter.rb +83 -0
- data/lib/amorail/store_adapters.rb +15 -0
- data/lib/amorail/version.rb +3 -1
- data/lib/amorail.rb +27 -6
- data/lib/tasks/amorail.rake +2 -0
- data/spec/access_token_spec.rb +59 -0
- data/spec/client_spec.rb +36 -24
- data/spec/company_spec.rb +2 -0
- data/spec/contact_link_spec.rb +2 -0
- data/spec/contact_spec.rb +4 -0
- data/spec/entity_spec.rb +2 -0
- data/spec/fixtures/amorail_test.yml +5 -3
- data/spec/fixtures/authorize.json +6 -0
- data/spec/fixtures/contacts/my_contact_find.json +4 -0
- data/spec/helpers/webmock_helpers.rb +50 -13
- data/spec/lead_spec.rb +2 -0
- data/spec/my_contact_spec.rb +5 -2
- data/spec/note_spec.rb +2 -0
- data/spec/property_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/store_adapters/memory_store_adapter_spec.rb +56 -0
- data/spec/store_adapters/redis_store_adapter_spec.rb +67 -0
- data/spec/support/elementable_example.rb +2 -0
- data/spec/support/entity_class_example.rb +2 -0
- data/spec/support/leadable_example.rb +2 -0
- data/spec/support/my_contact.rb +3 -0
- data/spec/support/my_entity.rb +2 -0
- data/spec/task_spec.rb +2 -0
- data/spec/webhook_spec.rb +2 -0
- metadata +39 -17
- data/.travis.yml +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbc85a53892ba746e91fb6b52a9d86dedfa4c2885bc550760797cea6b6c1077a
|
4
|
+
data.tar.gz: ef947d63cdb4556d3d37934bf7ff6a4298c529b3692ee2617b207737f460b9ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92801120cb72d28e30df5d41ee23cf2f89681eec639f6837d75302204ab0b49d0b1bfffdd2ea544fad88a6e57939b2bfc8ddd1305c439ab4ff4c31b8206f998c
|
7
|
+
data.tar.gz: 532f646b965c0f92f7a4e6174932a97e1c0fb023fbfa4d4b2fea1d3d348361e3885ef671fbd0e165c00c274c136fe6d39dc628904e6487cd447375e576782db7
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Build
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
- name: Set up Ruby 2.5
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: 2.5
|
20
|
+
bundler-cache: true
|
21
|
+
bundler: 1.13.6
|
22
|
+
- name: Build and test
|
23
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Change log
|
2
|
+
|
3
|
+
## master (unreleased)
|
4
|
+
|
5
|
+
## 0.7.1 (2021-09-25)
|
6
|
+
|
7
|
+
### Features
|
8
|
+
|
9
|
+
- Adds multiple option to property ([@lHydra][])
|
10
|
+
|
11
|
+
See spec/support/my_contact.rb and spec/my_contact_spec.rb
|
12
|
+
|
13
|
+
## 0.7.0 (2021-07-16)
|
14
|
+
|
15
|
+
### Features
|
16
|
+
|
17
|
+
- Introduce [#53](https://github.com/teachbase/amorail/issues/48) Implement OAuth authentication ([@lHydra][])
|
18
|
+
|
19
|
+
### Changes
|
20
|
+
|
21
|
+
- increased ruby version to >= 2.5.0
|
22
|
+
- updates dependencies versions
|
23
|
+
|
24
|
+
|
25
|
+
[@palkan]: https://github.com/palkan
|
26
|
+
[@AlexanderShvaykin]: https://github.com/AlexanderShvaykin
|
27
|
+
[@lHydra]: https://github.com/lHydra
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[![Gem Version](https://badge.fury.io/rb/amorail.svg)](https://rubygems.org/gems/amorail)
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/amorail.svg)](https://rubygems.org/gems/amorail) ![Build](https://github.com/teachbase/amorail/workflows/Build/badge.svg)
|
2
2
|
|
3
3
|
# Amorail
|
4
4
|
|
@@ -25,12 +25,48 @@ Or install it yourself as:
|
|
25
25
|
With Amorail you can manipulate the following AmoCRM entities: Companies, Contacts, Leads and Tasks.
|
26
26
|
We're triying to build simple AR-like interface.
|
27
27
|
|
28
|
+
### Store configuration
|
29
|
+
|
30
|
+
In order to configure a token store you should set up a store adapter in a following way: `Amorail.token_store = :redis, { redis_url: 'redis://127.0.0.1:6379/0' }` (options can be omitted). Currently supported stores are `:redis` and `:memory`. Memory adapter is used **by default**.
|
31
|
+
|
32
|
+
Here is a default configuration for Redis:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
Amorail.token_store = :redis, {
|
36
|
+
redis_host: "127.0.0.1",
|
37
|
+
redis_port: "6379",
|
38
|
+
redis_db_name: "0"
|
39
|
+
}
|
40
|
+
```
|
41
|
+
|
42
|
+
You can also provide a Redis URL instead:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Amorail.token_store = :redis, { redis_url: "redis://localhost:6397" }
|
46
|
+
```
|
47
|
+
|
48
|
+
**NOTE**: if `REDIS_URL` environment variable is set it is used automatically.
|
49
|
+
|
50
|
+
### Add custom store
|
51
|
+
|
52
|
+
To add custom store you need declare a class that implements the interface `AbstractStoreAdapter`.
|
53
|
+
For example `class FileStoreAdapter < Amorail::StoreAdapters::AbstractStoreAdapter`
|
54
|
+
|
55
|
+
The class must contain constructor `initialize(**options)` and **4 required methods**:
|
56
|
+
|
57
|
+
1. `fetch_access` — method that should return Hash with token data (**required keys:** `token`, `refresh_token` and `expiration`) or empty Hash (`{}`) if no value was received
|
58
|
+
2. `persist_access` — method that stores data in storage
|
59
|
+
3. `update_access` — method that updates existed token data in storage
|
60
|
+
4. `access_expired?` — method that returns `true` if token was expired otherwise `false`
|
61
|
+
|
28
62
|
### Auth configuration
|
29
63
|
|
30
64
|
Amorail uses [anyway_config](https://github.com/palkan/anyway_config) for configuration, so you
|
31
65
|
can provide configuration parameters through env vars, seperate config file (`config/amorail.yml`) or `secrets.yml`.
|
32
66
|
|
33
|
-
Required params: **
|
67
|
+
Required params: **client_id**, **client_secret** **code**, **redirect_uri** and **api_endpoint**.
|
68
|
+
|
69
|
+
An authorization **code** is required for the initial obtaining of a pair of access and refresh tokens. You can see it in the interface or through a Redirect URI if the authorization was run from the modal window for permissions. The lifespan of the code is 20 minutes. [More details](https://www.amocrm.com/developers/content/oauth/oauth/)
|
34
70
|
|
35
71
|
Example:
|
36
72
|
|
@@ -39,9 +75,14 @@ Example:
|
|
39
75
|
development:
|
40
76
|
...
|
41
77
|
amorail:
|
42
|
-
|
43
|
-
|
44
|
-
|
78
|
+
client_id: c0df457d-eacc-47cc-behb-3d8f962g4lbf
|
79
|
+
client_secret: a36b564b64398d3e53004c12e4997eb340e32b18ee185389ddb409292ebc5ebae297a3eab96be4a9d38ecbf274d90bbb54a7e8f282f40d1b29e5c9b2e2e357a6
|
80
|
+
code: a911ff963f58ea6c846901056114d37a14d2efa4d05ffb6ef0a8d60d32e5d6dae785bd317cbc9b0bd04261cb0cf9905af0cc32b5567c1eb84433328d08888f5c613608b822c1928272769ffd284b
|
81
|
+
redirect_uri: https://example.ru
|
82
|
+
api_endpoint: https://test.amocrm.ru
|
83
|
+
redis_host: 127.0.0.1
|
84
|
+
redis_port: 6379
|
85
|
+
redis_db_name: 0
|
45
86
|
```
|
46
87
|
|
47
88
|
### Running from console
|
@@ -50,7 +91,7 @@ You can try amorail in action from console ([PRY](https://github.com/pry/pry) is
|
|
50
91
|
|
51
92
|
```shell
|
52
93
|
# amorail gem directory
|
53
|
-
|
94
|
+
AMORAIL_CLIENT_ID=integration_id AMORAIL_CLIENT_SECRET=secret_key AMORAIL_CODE=my_code AMORAIL_REDIRECT_URI=https://example.com AMORAIL_API_ENDPOINT=https://test.amocrm.ru bundle exec rake console
|
54
95
|
pry> Amorail.properties
|
55
96
|
# ... prints properties (custom_fields) data
|
56
97
|
pry> Amorail::Contact.find_by_query("test_contact")
|
@@ -223,12 +264,12 @@ It is possible to use Amorail with multiple AmoCRM accounts. To do so use `Amora
|
|
223
264
|
which receive client params or client instance and a block to execute within custom context:
|
224
265
|
|
225
266
|
```ruby
|
226
|
-
Amorail.with_client(
|
267
|
+
Amorail.with_client(client_id: "my_id", client_secret: "my_secret", code: "my_code", api_endpoint: "https://my.acmocrm.ru", redirect_uri: "https://example.com") do
|
227
268
|
# Client specific code here
|
228
269
|
end
|
229
270
|
|
230
271
|
# or using client instance
|
231
|
-
my_client = Amorail::Client.new(
|
272
|
+
my_client = Amorail::Client.new(client_id: "my_id", client_secret: "my_secret", code: "my_code", api_endpoint: "https://my.acmocrm.ru", redirect_uri: "https://example.com")
|
232
273
|
|
233
274
|
Amorail.with_client(client) do
|
234
275
|
...
|
data/RELEASING.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# How to release a gem
|
2
|
+
|
3
|
+
This document describes a process of releasing a new version of a gem.
|
4
|
+
|
5
|
+
1. Bump version.
|
6
|
+
|
7
|
+
```sh
|
8
|
+
git commit -m "Bump 1.<x>.<y>"
|
9
|
+
```
|
10
|
+
|
11
|
+
We're (kinda) using semantic versioning:
|
12
|
+
|
13
|
+
- Bugfixes should be released as fast as possible as patch versions.
|
14
|
+
- New features could be combined and released as minor or patch version upgrades (depending on the _size of the feature_—it's up to maintainers to decide).
|
15
|
+
- Breaking API changes should be avoided in minor and patch releases.
|
16
|
+
- Breaking dependencies changes (e.g., dropping older Ruby support) could be released in minor versions.
|
17
|
+
|
18
|
+
How to bump a version:
|
19
|
+
|
20
|
+
- Change the version number in `lib/amorail/version.rb` file.
|
21
|
+
- Update the changelog (add new heading with the version name and date).
|
22
|
+
- Update the installation documentation if necessary (e.g., during minor and major updates).
|
23
|
+
|
24
|
+
2. Push code to GitHub and make sure CI passes.
|
25
|
+
|
26
|
+
```sh
|
27
|
+
git push
|
28
|
+
```
|
29
|
+
|
30
|
+
3. Release a gem.
|
31
|
+
|
32
|
+
```sh
|
33
|
+
gem release -t
|
34
|
+
git push --tags
|
35
|
+
```
|
36
|
+
|
37
|
+
We use [gem-release](https://github.com/svenfuchs/gem-release) for publishing gems with a single command:
|
38
|
+
|
39
|
+
```sh
|
40
|
+
gem release -t
|
41
|
+
```
|
42
|
+
|
43
|
+
Don't forget to push tags and write release notes on GitHub (if necessary).
|
data/amorail.gemspec
CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = %q{Ruby API client for AmoCRM. You can integrate your system with it.}
|
13
13
|
spec.homepage = ""
|
14
14
|
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
15
16
|
|
16
17
|
spec.files = `git ls-files -z`.split("\x0")
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
@@ -25,9 +26,10 @@ Gem::Specification.new do |spec|
|
|
25
26
|
spec.add_development_dependency "pry"
|
26
27
|
spec.add_development_dependency "shoulda-matchers", "~> 2.0"
|
27
28
|
spec.add_development_dependency "rubocop", "~> 0.49"
|
28
|
-
spec.add_dependency "anyway_config", "
|
29
|
+
spec.add_dependency "anyway_config", ">= 1.0"
|
29
30
|
spec.add_dependency "faraday"
|
30
31
|
spec.add_dependency "faraday_middleware"
|
31
|
-
spec.add_dependency
|
32
|
-
spec.add_dependency
|
32
|
+
spec.add_dependency "activemodel"
|
33
|
+
spec.add_dependency "json"
|
34
|
+
spec.add_dependency "redis"
|
33
35
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Amorail
|
4
|
+
class AccessToken
|
5
|
+
attr_reader :token, :secret, :expiration, :refresh_token, :store
|
6
|
+
|
7
|
+
def initialize(secret, token, refresh_token, expiration, store)
|
8
|
+
@secret = secret
|
9
|
+
@token = token
|
10
|
+
@refresh_token = refresh_token
|
11
|
+
@expiration = expiration
|
12
|
+
@store = store
|
13
|
+
end
|
14
|
+
|
15
|
+
def expired?
|
16
|
+
store.access_expired?(secret)
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def create(secret, token, refresh_token, expiration, store)
|
21
|
+
new(secret, token, refresh_token, expiration, store).tap do |access_token|
|
22
|
+
store.persist_access(access_token.secret, access_token.token, access_token.refresh_token, access_token.expiration)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def find(secret, store)
|
27
|
+
token_attrs = store.fetch_access(secret)
|
28
|
+
build_with_token_attrs(store, secret, token_attrs)
|
29
|
+
end
|
30
|
+
|
31
|
+
def refresh(secret, token, refresh_token, expiration, store)
|
32
|
+
new(secret, token, refresh_token, expiration, store).tap do |access_token|
|
33
|
+
store.update_access(access_token.secret, access_token.token, access_token.refresh_token, access_token.expiration)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def build_with_token_attrs(store, secret, token_attrs)
|
40
|
+
new(secret, token_attrs[:token], token_attrs[:refresh_token], token_attrs[:expiration], store)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
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'
|
@@ -8,14 +10,31 @@ module Amorail
|
|
8
10
|
class Client
|
9
11
|
SUCCESS_STATUS_CODES = [200, 204].freeze
|
10
12
|
|
11
|
-
|
13
|
+
attr_accessor :store
|
14
|
+
attr_reader :api_endpoint,
|
15
|
+
:access_token,
|
16
|
+
:refresh_token,
|
17
|
+
:access,
|
18
|
+
:client_id,
|
19
|
+
:client_secret,
|
20
|
+
:code,
|
21
|
+
:redirect_uri
|
12
22
|
|
13
23
|
def initialize(api_endpoint: Amorail.config.api_endpoint,
|
14
|
-
|
15
|
-
|
24
|
+
client_id: Amorail.config.client_id,
|
25
|
+
client_secret: Amorail.config.client_secret,
|
26
|
+
code: Amorail.config.code,
|
27
|
+
redirect_uri: Amorail.config.redirect_uri)
|
28
|
+
@store = Amorail.token_store
|
16
29
|
@api_endpoint = api_endpoint
|
17
|
-
@
|
18
|
-
@
|
30
|
+
@client_id = client_id
|
31
|
+
@client_secret = client_secret
|
32
|
+
@code = code
|
33
|
+
@redirect_uri = redirect_uri
|
34
|
+
@access = AccessToken.find(@client_secret, store)
|
35
|
+
@access_token = @access.token
|
36
|
+
@refresh_token = @access.refresh_token
|
37
|
+
|
19
38
|
@connect = Faraday.new(url: api_endpoint) do |faraday|
|
20
39
|
faraday.response :json, content_type: /\bjson$/
|
21
40
|
faraday.use :instrumentation
|
@@ -32,33 +51,53 @@ module Amorail
|
|
32
51
|
end
|
33
52
|
|
34
53
|
def authorize
|
35
|
-
|
36
|
-
response
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
54
|
+
response = post(Amorail.config.auth_url, auth_params)
|
55
|
+
create_access_token(response)
|
56
|
+
response
|
57
|
+
end
|
58
|
+
|
59
|
+
def refresh_token!
|
60
|
+
response = post(Amorail.config.auth_url, refresh_params)
|
61
|
+
update_access_token(response)
|
42
62
|
response
|
43
63
|
end
|
44
64
|
|
65
|
+
def auth_params
|
66
|
+
{
|
67
|
+
client_id: client_id,
|
68
|
+
client_secret: client_secret,
|
69
|
+
grant_type: 'authorization_code',
|
70
|
+
code: @code,
|
71
|
+
redirect_uri: redirect_uri
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def refresh_params
|
76
|
+
{
|
77
|
+
client_id: client_id,
|
78
|
+
client_secret: client_secret,
|
79
|
+
grant_type: 'refresh_token',
|
80
|
+
refresh_token: refresh_token,
|
81
|
+
redirect_uri: redirect_uri
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
45
85
|
def safe_request(method, url, params = {})
|
46
|
-
|
47
|
-
|
48
|
-
authorize
|
86
|
+
authorize if access_token.blank?
|
87
|
+
refresh_token! if access.expired?
|
49
88
|
public_send(method, url, params)
|
50
89
|
end
|
51
90
|
|
52
91
|
def get(url, params = {})
|
53
92
|
response = connect.get(url, params) do |request|
|
54
|
-
request.headers['
|
93
|
+
request.headers['Authorization'] = "Bearer #{access_token}" if access_token.present?
|
55
94
|
end
|
56
95
|
handle_response(response)
|
57
96
|
end
|
58
97
|
|
59
98
|
def post(url, params = {})
|
60
99
|
response = connect.post(url) do |request|
|
61
|
-
request.headers['
|
100
|
+
request.headers['Authorization'] = "Bearer #{access_token}" if access_token.present?
|
62
101
|
request.headers['Content-Type'] = 'application/json'
|
63
102
|
request.body = params.to_json
|
64
103
|
end
|
@@ -67,12 +106,6 @@ module Amorail
|
|
67
106
|
|
68
107
|
private
|
69
108
|
|
70
|
-
attr_accessor :cookies
|
71
|
-
|
72
|
-
def cookie_handler(response)
|
73
|
-
self.cookies = response.headers['set-cookie'].split('; ')[0]
|
74
|
-
end
|
75
|
-
|
76
109
|
def handle_response(response) # rubocop:disable all
|
77
110
|
return response if SUCCESS_STATUS_CODES.include?(response.status)
|
78
111
|
|
@@ -97,5 +130,33 @@ module Amorail
|
|
97
130
|
fail ::Amorail::AmoUnknownError, response.body
|
98
131
|
end
|
99
132
|
end
|
133
|
+
|
134
|
+
def create_access_token(response)
|
135
|
+
_access = AccessToken.create(
|
136
|
+
client_secret,
|
137
|
+
response.body['access_token'],
|
138
|
+
response.body['refresh_token'],
|
139
|
+
expiration(response.body['expires_in']),
|
140
|
+
store
|
141
|
+
)
|
142
|
+
@access_token = _access.token
|
143
|
+
@refresh_token = _access.refresh_token
|
144
|
+
end
|
145
|
+
|
146
|
+
def update_access_token(response)
|
147
|
+
_access = AccessToken.refresh(
|
148
|
+
client_secret,
|
149
|
+
response.body['access_token'],
|
150
|
+
response.body['refresh_token'],
|
151
|
+
expiration(response.body['expires_in']),
|
152
|
+
store
|
153
|
+
)
|
154
|
+
@access_token = _access.token
|
155
|
+
@refresh_token = _access.refresh_token
|
156
|
+
end
|
157
|
+
|
158
|
+
def expiration(expires_in)
|
159
|
+
Time.now.to_i + expires_in.to_i
|
160
|
+
end
|
100
161
|
end
|
101
162
|
end
|
data/lib/amorail/config.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'anyway'
|
2
4
|
|
3
5
|
module Amorail
|
4
6
|
# Amorail config contains:
|
5
|
-
# - usermail ("user@gmail.com")
|
6
|
-
# - api_key ("13601bbac84727df")
|
7
7
|
# - api_endpoint ("http://you_company.amocrm.com")
|
8
8
|
# - api_path (default: "/private/api/v2/json/")
|
9
|
-
# - auth_url (default: "/
|
9
|
+
# - auth_url (default: "/oauth2/access_token")
|
10
10
|
class Config < Anyway::Config
|
11
|
-
attr_config :
|
12
|
-
:
|
13
|
-
:
|
14
|
-
|
15
|
-
|
11
|
+
attr_config :api_endpoint,
|
12
|
+
:client_id,
|
13
|
+
:client_secret,
|
14
|
+
:code,
|
15
|
+
:redirect_uri,
|
16
|
+
:redis_url,
|
17
|
+
api_path: '/private/api/v2/json/',
|
18
|
+
auth_url: '/oauth2/access_token',
|
19
|
+
redis_host: '127.0.0.1',
|
20
|
+
redis_port: '6379',
|
21
|
+
redis_db_name: '0'
|
16
22
|
end
|
17
23
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Amorail
|
2
4
|
# Provides common functionallity for entities
|
3
5
|
# that can be attached to another objects.
|
@@ -6,9 +8,9 @@ module Amorail
|
|
6
8
|
|
7
9
|
ELEMENT_TYPES = {
|
8
10
|
contact: 1,
|
9
|
-
lead:
|
11
|
+
lead: 2,
|
10
12
|
company: 3,
|
11
|
-
task:
|
13
|
+
task: 4
|
12
14
|
}.freeze
|
13
15
|
|
14
16
|
included do
|
@@ -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
|
@@ -19,11 +21,19 @@ module Amorail # :nodoc: all
|
|
19
21
|
props = properties.send(self.class.amo_name)
|
20
22
|
|
21
23
|
custom_fields = []
|
22
|
-
|
23
24
|
self.class.properties.each do |k, v|
|
24
25
|
prop_id = props.send(k).id
|
25
|
-
|
26
|
-
|
26
|
+
prop_values = send(v.fetch(:method_name, k))
|
27
|
+
|
28
|
+
if prop_values.is_a?(Array)
|
29
|
+
prop_val = prop_values.map do |value|
|
30
|
+
{ value: value }.merge(v)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
prop_val = [{ value: prop_values }.merge(v)]
|
34
|
+
end
|
35
|
+
|
36
|
+
custom_fields << { id: prop_id, values: prop_val }
|
27
37
|
end
|
28
38
|
|
29
39
|
custom_fields
|
data/lib/amorail/entity.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
4
|
+
require 'active_support/core_ext/array'
|
2
5
|
|
3
6
|
module Amorail
|
4
7
|
# Core class for all Amo entities (company, contact, etc)
|
@@ -32,7 +35,12 @@ module Amorail
|
|
32
35
|
|
33
36
|
def amo_property(name, options = {})
|
34
37
|
properties[name] = options
|
35
|
-
|
38
|
+
var_name = options.fetch(:method_name, name)
|
39
|
+
define_method "#{var_name}=" do |value|
|
40
|
+
var_value = options[:multiple] ? Array.wrap(value) : Array.wrap(value).first
|
41
|
+
instance_variable_set("@#{var_name}", var_value)
|
42
|
+
end
|
43
|
+
attr_reader(var_name)
|
36
44
|
end
|
37
45
|
|
38
46
|
def attributes
|
@@ -87,15 +95,24 @@ module Amorail
|
|
87
95
|
return if fields.nil?
|
88
96
|
|
89
97
|
fields.each do |f|
|
90
|
-
fname = f
|
98
|
+
fname = custom_field_name(f)
|
91
99
|
next if fname.nil?
|
92
100
|
|
93
101
|
fname = "#{fname.downcase}="
|
94
|
-
fval = f.fetch('values').
|
102
|
+
fval = f.fetch('values').pluck('value')
|
95
103
|
send(fname, fval) if respond_to?(fname)
|
96
104
|
end
|
97
105
|
end
|
98
106
|
|
107
|
+
def custom_field_name(field)
|
108
|
+
fname = field['code'] || field['name']
|
109
|
+
return if fname.nil?
|
110
|
+
|
111
|
+
fname = self.class.properties
|
112
|
+
.fetch(fname.downcase, {})[:method_name] || fname
|
113
|
+
fname
|
114
|
+
end
|
115
|
+
|
99
116
|
# call safe method <safe_request>. safe_request call authorize
|
100
117
|
# if current session undefined or expires.
|
101
118
|
def push(method)
|
data/lib/amorail/exceptions.rb
CHANGED
data/lib/amorail/property.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Amorail
|
2
4
|
# Return hash key as method call
|
3
5
|
module MethodMissing
|
4
6
|
def method_missing(method_sym, *arguments, &block)
|
5
|
-
if data.key?(method_sym.to_s)
|
6
|
-
data.fetch(method_sym.to_s)
|
7
|
+
if data.key?(method_sym.to_s.downcase)
|
8
|
+
data.fetch(method_sym.to_s.downcase)
|
7
9
|
else
|
8
10
|
super
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
14
|
def respond_to_missing?(method_sym, *args)
|
13
|
-
args.size.zero? && data.key?(method_sym.to_s)
|
15
|
+
args.size.zero? && data.key?(method_sym.to_s.downcase)
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|