zoho_hub 0.1.48 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -2
- data/.rspec +1 -0
- data/.rubocop.yml +5 -2
- data/.ruby-version +1 -1
- data/.travis.yml +5 -2
- data/README.md +91 -7
- data/bin/console +6 -7
- data/bin/read +44 -0
- data/bin/setup +0 -2
- data/bin/zoho_hub +62 -0
- data/cache/.git_keep +0 -0
- data/lib/zoho_hub/auth.rb +37 -47
- data/lib/zoho_hub/base_record.rb +122 -0
- data/lib/zoho_hub/configuration.rb +3 -4
- data/lib/zoho_hub/connection.rb +10 -17
- data/lib/zoho_hub/{records → deprecated_and_only_for_reference_records}/account.rb +1 -1
- data/lib/zoho_hub/{records → deprecated_and_only_for_reference_records}/campaign.rb +0 -0
- data/lib/zoho_hub/{records → deprecated_and_only_for_reference_records}/contact.rb +3 -9
- data/lib/zoho_hub/deprecated_and_only_for_reference_records/funder.rb +9 -0
- data/lib/zoho_hub/{records → deprecated_and_only_for_reference_records}/potential.rb +1 -21
- data/lib/zoho_hub/deprecated_and_only_for_reference_records/product.rb +9 -0
- data/lib/zoho_hub/deprecated_and_only_for_reference_records/quote.rb +34 -0
- data/lib/zoho_hub/errors.rb +0 -3
- data/lib/zoho_hub/module_builder.rb +61 -0
- data/lib/zoho_hub/oauth_callback_server.rb +26 -0
- data/lib/zoho_hub/response.rb +1 -4
- data/lib/zoho_hub/settings/field.rb +33 -0
- data/lib/zoho_hub/settings/module.rb +49 -0
- data/lib/zoho_hub/string_utils.rb +34 -0
- data/lib/zoho_hub/version.rb +1 -1
- data/lib/zoho_hub/views/variables.erb +72 -0
- data/lib/zoho_hub/with_attributes.rb +74 -0
- data/lib/zoho_hub/with_connection.rb +36 -0
- data/lib/zoho_hub.rb +21 -23
- data/zoho_hub.gemspec +14 -10
- metadata +80 -57
- data/lib/zoho_hub/records/adverse_criteria.rb +0 -43
- data/lib/zoho_hub/records/attachment.rb +0 -104
- data/lib/zoho_hub/records/base_record.rb +0 -189
- data/lib/zoho_hub/records/credit_score.rb +0 -36
- data/lib/zoho_hub/records/product.rb +0 -33
- data/lib/zoho_hub/records/quote.rb +0 -44
- data/lib/zoho_hub/records/sms_message.rb +0 -32
- data/lib/zoho_hub/records/vendor.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb0b0886637feb21a98d0a73f40cb3571a0ec2507dfd45b7eec9fd348b365276
|
4
|
+
data.tar.gz: 70638084911ec64dc02095d4cf085453ca13ba4ea28a3c983c79e235a1a5911e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5fc255597ced5c966a59b0db9de72ab6a67defca6c1a62e5e168f37bc70326f2c1cccd5cf3ab44369a94372277ca42c671965e50d742b315b26126882f1af72
|
7
|
+
data.tar.gz: 89fbe288d53b9ebf9c76f8229981deffcacc9d6fe484b6187f654430eb097c7e1b57719dafcc953cafbfafeec7f1d765c87794697b3d283b168cbd2c9f35ff03
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
require: rubocop-rspec
|
2
2
|
|
3
3
|
AllCops:
|
4
|
-
TargetRubyVersion:
|
5
|
-
NewCops: enable
|
4
|
+
TargetRubyVersion: 2.5.1
|
6
5
|
|
7
6
|
# Don't force top level comments in every class
|
8
7
|
Style/Documentation:
|
9
8
|
Enabled: false
|
10
9
|
|
10
|
+
# Safe navigation is not available in older ruby versions
|
11
|
+
Style/SafeNavigation:
|
12
|
+
Enabled: false
|
13
|
+
|
11
14
|
# A good line length is 100 chars
|
12
15
|
Metrics/LineLength:
|
13
16
|
Max: 100
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.5.3
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,16 @@
|
|
1
1
|
# ZohoHub
|
2
2
|
|
3
|
-
https://
|
3
|
+
[![Build Status](https://travis-ci.com/rikas/zoho_hub.svg?branch=master)](https://travis-ci.com/rikas/zoho_hub)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/zoho_hub.svg)](https://badge.fury.io/rb/zoho_hub)
|
5
|
+
|
6
|
+
Simple wrapper around Zoho CRM version2, using [OAuth 2.0 protocol](https://www.zoho.com/crm/help/api/v2/#OAuth2_0)
|
7
|
+
for authentication.
|
8
|
+
|
9
|
+
This gem reads your Module configuration and builds the corresponding classes for you, using some
|
10
|
+
reflection mechanisms. You should then be able to use simple classes with an API close to
|
11
|
+
ActiveRecord, to do CRUD operations.
|
12
|
+
|
13
|
+
**NOTE: this gem is WIP, please try to use it and open an issue if you run into limitations / problems**
|
4
14
|
|
5
15
|
## Installation
|
6
16
|
|
@@ -18,9 +28,86 @@ Or install it yourself as:
|
|
18
28
|
|
19
29
|
$ gem install zoho_hub
|
20
30
|
|
21
|
-
##
|
31
|
+
## Setup process
|
32
|
+
|
33
|
+
### 1. Register your application
|
34
|
+
|
35
|
+
If you want to access your Zoho CRM account from your application you first need to create your
|
36
|
+
application as described here: https://www.zoho.com/crm/help/api/v2/#oauth-request.
|
37
|
+
|
38
|
+
**TODO TODO - explain "Authorized redirect URIs"**
|
39
|
+
|
40
|
+
This will give you a **Client ID** and a **secret**, that you'll use in the next step.
|
41
|
+
|
42
|
+
### 2. Configure ZohoHub with your credentials
|
43
|
+
|
44
|
+
You need to have a configuration block like the one below (in rails add a `zoho_hub.rb` in your
|
45
|
+
`config/initializers` dir):
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
ZohoHub.configure do |config|
|
49
|
+
config.client_id = 'YOUR_ZOHO_CLIENT_ID' # obtained in 1.
|
50
|
+
config.secret = 'YOUR_ZOHO_SECRET' # obtained in 1.
|
51
|
+
config.redirect_uri = 'YOUR_ZOHO_OAUTH_REDIRECT_URL'
|
52
|
+
# config.debug = true # this will be VERY verbose, but helps to identify bugs / problems
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
**Note:** if you don't know what the `redirect_url` is then **TODO TODO TODO TODO TODO**
|
57
|
+
|
58
|
+
### 2. Authorization request
|
59
|
+
|
60
|
+
In order to access data in Zoho CRM you need to authorize ZohoHub to access your account. To do so
|
61
|
+
you have to request a specific URL with the right **scope** and **access_type**.
|
62
|
+
|
63
|
+
To get the right URL you can use this simple line of code:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
ZohoHub::Auth.auth_url
|
67
|
+
# => "https://accounts.zoho.eu/oauth/v2/auth?access_type=offline&client_id=&redirect_uri=&response_type=code&scope=ZohoCRM.modules.custom.all,ZohoCRM.settings.all,ZohoCRM.modules.contacts.all,ZohoCRM.modules.all"
|
68
|
+
```
|
69
|
+
|
70
|
+
If you request this generated URL you should see a screen like this one, where you have to click on "Accept":
|
71
|
+
|
72
|
+
![](https://duaw26jehqd4r.cloudfront.net/items/1h1i3C1N0k0i02092F0S/Screen%20Shot%202018-11-25%20at%2019.18.38.png)
|
73
|
+
|
74
|
+
You can change the default scope (what data can be accessed by your application). This is the list
|
75
|
+
provided as the default scope:
|
76
|
+
|
77
|
+
```
|
78
|
+
ZohoCRM.modules.custom.all
|
79
|
+
ZohoCRM.settings.all
|
80
|
+
ZohoCRM.modules.contacts.all
|
81
|
+
ZohoCRM.modules.all
|
82
|
+
```
|
83
|
+
|
84
|
+
To get the URL for a different scope you can provide a `scope` argument:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
ZohoHub::Auth.auth_url(scope: ['ZohoCRM.modules.custom.all', 'ZohoCRM.modules.all'])
|
88
|
+
# => "https://accounts.zoho.eu/oauth/v2/auth?access_type=offline&client_id=&redirect_uri=&response_type=code&scope=ZohoCRM.modules.custom.all,ZohoCRM.modules.all"
|
89
|
+
```
|
90
|
+
|
91
|
+
#### 2.1 Offline access
|
92
|
+
|
93
|
+
By design the access tokens returned by the OAuth flow expire after a period of time (1 hour by
|
94
|
+
default), as a safety mechanism. This means that any application that wants to work with a user's
|
95
|
+
data needs the user to have recently gone through the OAuth flow, aka be online.
|
96
|
+
|
97
|
+
When you request offline access the Zoho API returns a refresh token. Refresh tokens give your
|
98
|
+
application the ability to request data on behalf of the user when the user is not present and in
|
99
|
+
front of your application.
|
100
|
+
|
101
|
+
**By default `ZohoHub::Auth.auth_url` will request offline access**
|
102
|
+
|
103
|
+
You can force "online" access by using `#auth_url` with a `access_type` argument:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
ZohoHub::Auth.auth_url(access_type: 'online')
|
107
|
+
# => "https://accounts.zoho.eu/oauth/v2/auth?access_type=online&client_id=&redirect_uri=&response_type=code&scope=ZohoCRM.modules.custom.all,ZohoCRM.settings.all,ZohoCRM.modules.contacts.all,ZohoCRM.modules.all"
|
108
|
+
```
|
22
109
|
|
23
|
-
|
110
|
+
## 3. Generate Access Token
|
24
111
|
|
25
112
|
## Development
|
26
113
|
|
@@ -28,10 +115,7 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
28
115
|
the tests. You can also run `bin/console` for an interactive prompt that will allow you to
|
29
116
|
experiment.
|
30
117
|
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
32
|
-
version, update the version number in `version.rb`, and then run `bundle exec rake release`, which
|
33
|
-
will create a git tag for the version, push git commits and tags, and push the `.gem` file
|
34
|
-
to [rubygems.org](https://rubygems.org).
|
118
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
35
119
|
|
36
120
|
## Contributing
|
37
121
|
|
data/bin/console
CHANGED
@@ -8,16 +8,15 @@ require 'dotenv'
|
|
8
8
|
Dotenv.load
|
9
9
|
|
10
10
|
ZohoHub.configure do |config|
|
11
|
-
config.client_id
|
12
|
-
config.secret
|
13
|
-
config.
|
14
|
-
config.debug = true
|
11
|
+
config.client_id = ENV['ZOHO_CLIENT_ID']
|
12
|
+
config.secret = ENV['ZOHO_SECRET']
|
13
|
+
config.debug = ENV['ZOHO_DEBUG'] || false
|
15
14
|
end
|
16
15
|
|
17
|
-
|
16
|
+
# We assume that we already have a refresh token, to make things easier here.
|
17
|
+
puts 'Refreshing token...'
|
18
|
+
token_params = ZohoHub::Auth.refresh_token(ENV['ZOHO_REFRESH_TOKEN'])
|
18
19
|
ZohoHub.setup_connection(token_params)
|
19
20
|
|
20
|
-
self.send(:include, ZohoHub)
|
21
|
-
|
22
21
|
require 'pry'
|
23
22
|
Pry.start
|
data/bin/read
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'zoho_hub'
|
6
|
+
require 'zoho_hub/settings/module'
|
7
|
+
require 'zoho_hub/records/base_record'
|
8
|
+
|
9
|
+
require 'dotenv'
|
10
|
+
Dotenv.load
|
11
|
+
|
12
|
+
ZohoHub.configure do |config|
|
13
|
+
config.client_id = ENV['ZOHO_CLIENT_ID']
|
14
|
+
config.secret = ENV['ZOHO_SECRET']
|
15
|
+
config.redirect_uri = ENV['ZOHO_OAUTH_REDIRECT_URL']
|
16
|
+
end
|
17
|
+
|
18
|
+
token_params = ZohoHub::Auth.refresh_token(ENV['ZOHO_REFRESH_TOKEN'])
|
19
|
+
ZohoHub.setup_connection(token_params)
|
20
|
+
|
21
|
+
puts "Reading modules for client ID: #{ENV['ZOHO_CLIENT_ID']}..."
|
22
|
+
|
23
|
+
modules_hashes = ZohoHub::Settings::Module.all_json
|
24
|
+
|
25
|
+
puts "Found #{modules_hashes.size} modules"
|
26
|
+
|
27
|
+
modules_hashes.each do |hash|
|
28
|
+
puts "- Writing configuration for #{hash[:plural_label]}"
|
29
|
+
|
30
|
+
file_name = File.join(ZohoHub.root, 'cache', 'modules', "#{hash[:api_name]}.json")
|
31
|
+
|
32
|
+
File.open(file_name, 'w') do |file|
|
33
|
+
file.write(JSON.pretty_generate(hash))
|
34
|
+
end
|
35
|
+
|
36
|
+
next unless hash[:api_supported]
|
37
|
+
|
38
|
+
fields_array = ZohoHub::Settings::Field.all_json_for(hash[:api_name])
|
39
|
+
file_name = File.join(ZohoHub.root, 'cache', 'fields', "#{hash[:api_name]}.json")
|
40
|
+
|
41
|
+
File.open(file_name, 'w') do |file|
|
42
|
+
file.write(JSON.pretty_generate(fields_array))
|
43
|
+
end
|
44
|
+
end
|
data/bin/setup
CHANGED
data/bin/zoho_hub
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
|
6
|
+
require 'zoho_hub'
|
7
|
+
require 'zoho_hub/auth'
|
8
|
+
require 'zoho_hub/oauth_callback_server'
|
9
|
+
|
10
|
+
require 'launchy'
|
11
|
+
require 'optparse'
|
12
|
+
|
13
|
+
default_port = ZohoHub::OauthCallbackServer.settings.port
|
14
|
+
|
15
|
+
options = {}
|
16
|
+
parser = OptionParser.new do |op|
|
17
|
+
op.banner = 'Usage: zoho_hub -c CLIENT_ID -s SECRET [options]'
|
18
|
+
|
19
|
+
op.on('-c', '--client-id=client_id', 'The Zoho client ID') do |client|
|
20
|
+
options[:client_id] = client
|
21
|
+
end
|
22
|
+
|
23
|
+
op.on('-s', '--secret=secret', 'The Zoho secret') do |secret|
|
24
|
+
options[:secret] = secret
|
25
|
+
end
|
26
|
+
|
27
|
+
op.on('-p', '--port=port', "The port for your callback (default #{default_port})") do |port|
|
28
|
+
options[:port] = port
|
29
|
+
end
|
30
|
+
|
31
|
+
op.on_tail('--version', 'Show version') do
|
32
|
+
puts "ZohoHub #{ZohoHub::VERSION}"
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
parser.parse!
|
38
|
+
|
39
|
+
abort(parser.help) if options[:client_id].nil? || options[:secret].nil?
|
40
|
+
|
41
|
+
callback_path = ZohoHub::OauthCallbackServer::CALLBACK_PATH
|
42
|
+
|
43
|
+
ZohoHub::OauthCallbackServer.set(:port, options[:port]) if options[:port]
|
44
|
+
|
45
|
+
bind_port = ZohoHub::OauthCallbackServer.settings.port
|
46
|
+
bind_address = ZohoHub::OauthCallbackServer.settings.bind
|
47
|
+
|
48
|
+
callback_url = "http://#{bind_address}:#{bind_port}/#{callback_path}"
|
49
|
+
|
50
|
+
puts "Callback URL: #{callback_url}"
|
51
|
+
|
52
|
+
ZohoHub.configure do |config|
|
53
|
+
config.client_id = options[:client_id]
|
54
|
+
config.secret = options[:secret]
|
55
|
+
config.redirect_uri = callback_url
|
56
|
+
config.debug = true
|
57
|
+
end
|
58
|
+
|
59
|
+
# Open the URL in the browser
|
60
|
+
url = ZohoHub::Auth.auth_url
|
61
|
+
puts "REQUESTING: #{url}"
|
62
|
+
Launchy.open(url)
|
data/cache/.git_keep
ADDED
File without changes
|
data/lib/zoho_hub/auth.rb
CHANGED
@@ -6,11 +6,12 @@ require 'faraday_middleware'
|
|
6
6
|
require 'addressable'
|
7
7
|
|
8
8
|
module ZohoHub
|
9
|
+
# Class that takes care of authentication using Oauth2 workflow as described here:
|
10
|
+
# https://www.zoho.com/crm/help/api/v2/#oauth-request.
|
9
11
|
class Auth
|
10
12
|
extend Forwardable
|
11
13
|
|
12
14
|
TOKEN_PATH = '/oauth/v2/token'
|
13
|
-
REVOKE_TOKEN_PATH = '/oauth/v2/token/revoke'
|
14
15
|
AUTH_PATH = '/oauth/v2/auth'
|
15
16
|
|
16
17
|
DEFAULT_SCOPES = %w[
|
@@ -22,22 +23,30 @@ module ZohoHub
|
|
22
23
|
|
23
24
|
DEFAULT_ACCESS_TYPE = 'offline'
|
24
25
|
|
25
|
-
def_delegators :@configuration, :redirect_uri, :client_id, :secret
|
26
|
+
def_delegators :@configuration, :redirect_uri, :client_id, :secret, :api_domain
|
26
27
|
|
27
|
-
def initialize(access_type:
|
28
|
+
def initialize(access_type: DEFAULT_ACCESS_TYPE, scopes: DEFAULT_SCOPES)
|
28
29
|
@configuration = ZohoHub.configuration
|
29
|
-
@access_type = access_type
|
30
|
-
@scopes = scopes
|
30
|
+
@access_type = access_type
|
31
|
+
@scopes = scopes
|
31
32
|
end
|
32
33
|
|
33
|
-
def
|
34
|
-
|
34
|
+
def token_full_uri
|
35
|
+
Addressable::URI.join(api_domain, TOKEN_PATH)
|
36
|
+
end
|
37
|
+
|
38
|
+
def auth_full_uri
|
39
|
+
Addressable::URI.join(api_domain, AUTH_PATH)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.auth_url(access_type: DEFAULT_ACCESS_TYPE, scopes: DEFAULT_SCOPES)
|
43
|
+
new(access_type: access_type, scopes: scopes).auth_url
|
35
44
|
end
|
36
45
|
|
37
46
|
def auth_url
|
38
47
|
uri = auth_full_uri
|
39
48
|
|
40
|
-
|
49
|
+
uri.query_values = {
|
41
50
|
client_id: client_id,
|
42
51
|
scope: @scopes.join(','),
|
43
52
|
access_type: @access_type,
|
@@ -45,27 +54,21 @@ module ZohoHub
|
|
45
54
|
response_type: 'code'
|
46
55
|
}
|
47
56
|
|
48
|
-
# The consent page must be presented otherwise we don't get the refresh token back.
|
49
|
-
query[:prompt] = 'consent' if @access_type == DEFAULT_ACCESS_TYPE
|
50
|
-
|
51
|
-
uri.query_values = query
|
52
|
-
|
53
57
|
Addressable::URI.unencode(uri.to_s)
|
54
58
|
end
|
55
59
|
|
56
|
-
def
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.refresh_token(refresh_token)
|
61
|
-
new.refresh_token(refresh_token)
|
62
|
-
end
|
60
|
+
def token_url(grant_token)
|
61
|
+
uri = token_full_uri
|
63
62
|
|
64
|
-
|
65
|
-
|
63
|
+
uri.query_values = {
|
64
|
+
client_id: client_id,
|
65
|
+
client_secret: secret,
|
66
|
+
code: grant_token,
|
67
|
+
redirect_uri: redirect_uri,
|
68
|
+
grant_type: 'authorization_code'
|
69
|
+
}
|
66
70
|
|
67
|
-
|
68
|
-
json.merge(refresh_token: refresh_token)
|
71
|
+
Addressable::URI.unencode(uri.to_s)
|
69
72
|
end
|
70
73
|
|
71
74
|
def refresh_url(refresh_token)
|
@@ -81,16 +84,19 @@ module ZohoHub
|
|
81
84
|
Addressable::URI.unencode(uri.to_s)
|
82
85
|
end
|
83
86
|
|
84
|
-
def
|
85
|
-
|
87
|
+
def self.refresh_token(refresh_token)
|
88
|
+
new.refresh_token(refresh_token)
|
86
89
|
end
|
87
90
|
|
88
|
-
def
|
89
|
-
|
91
|
+
def refresh_token(refresh_token)
|
92
|
+
result = Faraday.post(refresh_url(refresh_token))
|
93
|
+
|
94
|
+
json = parse(result.body)
|
95
|
+
json.merge(refresh_token: refresh_token)
|
90
96
|
end
|
91
97
|
|
92
98
|
def revoke_refresh_token(refresh_token)
|
93
|
-
uri =
|
99
|
+
uri = token_full_uri
|
94
100
|
|
95
101
|
uri.query_values = { token: refresh_token }
|
96
102
|
|
@@ -101,10 +107,6 @@ module ZohoHub
|
|
101
107
|
parse(result.body)
|
102
108
|
end
|
103
109
|
|
104
|
-
def revoke_token_full_uri
|
105
|
-
Addressable::URI.join(@configuration.base_url, REVOKE_TOKEN_PATH)
|
106
|
-
end
|
107
|
-
|
108
110
|
def self.get_token(grant_token)
|
109
111
|
new.get_token(grant_token)
|
110
112
|
end
|
@@ -115,20 +117,8 @@ module ZohoHub
|
|
115
117
|
parse(result.body)
|
116
118
|
end
|
117
119
|
|
118
|
-
def
|
119
|
-
|
120
|
-
|
121
|
-
query = {
|
122
|
-
client_id: client_id,
|
123
|
-
client_secret: secret,
|
124
|
-
code: grant_token,
|
125
|
-
redirect_uri: redirect_uri,
|
126
|
-
grant_type: 'authorization_code'
|
127
|
-
}
|
128
|
-
|
129
|
-
uri.query_values = query
|
130
|
-
|
131
|
-
Addressable::URI.unencode(uri.to_s)
|
120
|
+
def parse(body)
|
121
|
+
MultiJson.load(body, symbolize_keys: true)
|
132
122
|
end
|
133
123
|
end
|
134
124
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zoho_hub/response'
|
4
|
+
require 'zoho_hub/with_connection'
|
5
|
+
require 'zoho_hub/with_attributes'
|
6
|
+
require 'zoho_hub/string_utils'
|
7
|
+
|
8
|
+
module ZohoHub
|
9
|
+
class BaseRecord
|
10
|
+
include WithConnection
|
11
|
+
include WithAttributes
|
12
|
+
|
13
|
+
# Default nnumber of records when fetching all.
|
14
|
+
DEFAULT_RECORDS_PER_PAGE = 200
|
15
|
+
|
16
|
+
# Default page number when fetching all.
|
17
|
+
DEFAULT_PAGE = 1
|
18
|
+
|
19
|
+
# Minimum number of records to fetch when fetching all.
|
20
|
+
MIN_RECORDS = 2
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def request_path(name = nil)
|
24
|
+
@request_path = name if name
|
25
|
+
@request_path ||= StringUtils.pluralize(StringUtils.demodulize(to_s))
|
26
|
+
@request_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def find(id)
|
30
|
+
body = get(File.join(request_path, id.to_s))
|
31
|
+
response = build_response(body)
|
32
|
+
|
33
|
+
if response.empty?
|
34
|
+
raise RecordNotFound, "Couldn't find #{request_path.singularize} with 'id'=#{id}"
|
35
|
+
end
|
36
|
+
|
37
|
+
new(response.data)
|
38
|
+
end
|
39
|
+
|
40
|
+
def where(params)
|
41
|
+
path = File.join(request_path, 'search')
|
42
|
+
|
43
|
+
response = get(path, params)
|
44
|
+
data = response[:data]
|
45
|
+
|
46
|
+
data.map { |info| new(info) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_by(params)
|
50
|
+
records = where(params)
|
51
|
+
records.first
|
52
|
+
end
|
53
|
+
|
54
|
+
def create(params)
|
55
|
+
new(params).save
|
56
|
+
end
|
57
|
+
|
58
|
+
def all(options = {})
|
59
|
+
options[:page] ||= DEFAULT_PAGE
|
60
|
+
options[:per_page] ||= DEFAULT_RECORDS_PER_PAGE
|
61
|
+
options[:per_page] = MIN_RECORDS if options[:per_page] < MIN_RECORDS
|
62
|
+
|
63
|
+
body = get(request_path, options)
|
64
|
+
response = build_response(body)
|
65
|
+
|
66
|
+
data = response.nil? ? [] : response.data
|
67
|
+
|
68
|
+
data.map { |json| new(json) }
|
69
|
+
end
|
70
|
+
|
71
|
+
def exists?(id)
|
72
|
+
!find(id).nil?
|
73
|
+
rescue RecordNotFound
|
74
|
+
false
|
75
|
+
end
|
76
|
+
|
77
|
+
alias exist? exists?
|
78
|
+
|
79
|
+
def build_response(body)
|
80
|
+
response = Response.new(body)
|
81
|
+
|
82
|
+
raise InvalidTokenError, response.msg if response.invalid_token?
|
83
|
+
raise RecordInvalid, response.msg if response.invalid_data?
|
84
|
+
|
85
|
+
response
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def save
|
90
|
+
body = if new_record? # create new record
|
91
|
+
post(self.class.request_path, data: [to_params])
|
92
|
+
else # update existing record
|
93
|
+
path = File.join(self.class.request_path, id)
|
94
|
+
put(path, data: [to_params])
|
95
|
+
end
|
96
|
+
|
97
|
+
response = build_response(body)
|
98
|
+
|
99
|
+
response.data.dig(:details, :id)
|
100
|
+
end
|
101
|
+
|
102
|
+
def new_record?
|
103
|
+
!id
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_params
|
107
|
+
params = {}
|
108
|
+
|
109
|
+
attributes.each do |attr|
|
110
|
+
key = attr_to_zoho_key(attr)
|
111
|
+
|
112
|
+
params[key] = send(attr)
|
113
|
+
end
|
114
|
+
|
115
|
+
params
|
116
|
+
end
|
117
|
+
|
118
|
+
def build_response(body)
|
119
|
+
self.class.build_response(body)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -2,17 +2,16 @@
|
|
2
2
|
|
3
3
|
module ZohoHub
|
4
4
|
class Configuration
|
5
|
-
attr_accessor :client_id, :secret, :redirect_uri, :
|
5
|
+
attr_accessor :client_id, :secret, :redirect_uri, :api_domain
|
6
6
|
attr_writer :debug
|
7
7
|
|
8
|
-
|
8
|
+
DEFAULT_API_DOMAIN = 'https://accounts.zoho.eu'
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
@client_id = ''
|
12
12
|
@secret = ''
|
13
13
|
@redirect_uri = ''
|
14
|
-
@
|
15
|
-
@access_type = Auth::DEFAULT_ACCESS_TYPE
|
14
|
+
@api_domain = DEFAULT_API_DOMAIN
|
16
15
|
end
|
17
16
|
|
18
17
|
def debug?
|
data/lib/zoho_hub/connection.rb
CHANGED
@@ -22,43 +22,37 @@ module ZohoHub
|
|
22
22
|
def initialize(access_token:, api_domain: DEFAULT_DOMAIN, expires_in: 3600, refresh_token: nil)
|
23
23
|
@access_token = access_token
|
24
24
|
@expires_in = expires_in
|
25
|
-
@api_domain = api_domain
|
25
|
+
@api_domain = api_domain
|
26
26
|
@refresh_token ||= refresh_token # do not overwrite if it's already set
|
27
27
|
end
|
28
28
|
|
29
|
-
def get(path, params = {}
|
29
|
+
def get(path, params = {})
|
30
30
|
log "GET #{path} with #{params}"
|
31
31
|
|
32
|
-
response = with_refresh
|
33
|
-
adapter(&block).get(path, params)
|
34
|
-
end
|
32
|
+
response = with_refresh { adapter.get(path, params) }
|
35
33
|
response.body
|
36
34
|
end
|
37
35
|
|
38
|
-
def post(path, params = {}
|
36
|
+
def post(path, params = {})
|
39
37
|
log "POST #{path} with #{params}"
|
40
38
|
|
41
|
-
response = with_refresh
|
42
|
-
adapter(&block).post(path, params)
|
43
|
-
end
|
39
|
+
response = with_refresh { adapter.post(path, params) }
|
44
40
|
response.body
|
45
41
|
end
|
46
42
|
|
47
|
-
def put(path, params = {}
|
43
|
+
def put(path, params = {})
|
48
44
|
log "PUT #{path} with #{params}"
|
49
45
|
|
50
|
-
response = with_refresh
|
51
|
-
adapter(&block).put(path, params)
|
52
|
-
end
|
46
|
+
response = with_refresh { adapter.put(path, params) }
|
53
47
|
response.body
|
54
48
|
end
|
55
49
|
|
56
50
|
def access_token?
|
57
|
-
@access_token
|
51
|
+
@access_token
|
58
52
|
end
|
59
53
|
|
60
54
|
def refresh_token?
|
61
|
-
@refresh_token
|
55
|
+
@refresh_token
|
62
56
|
end
|
63
57
|
|
64
58
|
def log(text)
|
@@ -79,7 +73,7 @@ module ZohoHub
|
|
79
73
|
log "Refreshing outdated token... #{@access_token}"
|
80
74
|
params = ZohoHub::Auth.refresh_token(@refresh_token)
|
81
75
|
|
82
|
-
@on_refresh_cb.call(params) if @on_refresh_cb
|
76
|
+
@on_refresh_cb.call(params) if @on_refresh_cb
|
83
77
|
|
84
78
|
@access_token = params[:access_token]
|
85
79
|
|
@@ -104,7 +98,6 @@ module ZohoHub
|
|
104
98
|
Faraday.new(url: base_url) do |conn|
|
105
99
|
conn.headers = authorization_header if access_token?
|
106
100
|
conn.use FaradayMiddleware::ParseJson
|
107
|
-
yield conn if block_given?
|
108
101
|
conn.response :json, parser_options: { symbolize_names: true }
|
109
102
|
conn.response :logger if ZohoHub.configuration.debug?
|
110
103
|
conn.adapter Faraday.default_adapter
|