zoho_hub 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -8
- data/README.md +160 -13
- data/bin/console +4 -0
- data/bin/read +8 -4
- data/bin/zoho_hub +29 -48
- data/examples/models/campaign.rb +13 -0
- data/{lib/zoho_hub/deprecated_and_only_for_reference_records → examples/models}/potential.rb +2 -1
- data/{lib/zoho_hub/deprecated_and_only_for_reference_records → examples/models}/quote.rb +5 -9
- data/lib/zoho_hub/auth.rb +36 -28
- data/lib/zoho_hub/base_record.rb +23 -12
- data/lib/zoho_hub/cli/callback_server.rb +94 -0
- data/lib/zoho_hub/cli/read_modules.rb +122 -0
- data/lib/zoho_hub/connection.rb +7 -0
- data/lib/zoho_hub/oauth_callback_server.rb +0 -4
- data/lib/zoho_hub/{module_builder.rb → reflection/module_builder.rb} +11 -15
- data/lib/zoho_hub/response.rb +1 -5
- data/lib/zoho_hub/string_utils.rb +5 -1
- data/lib/zoho_hub/validations/base_validation.rb +14 -0
- data/lib/zoho_hub/validations/validate_length.rb +19 -0
- data/lib/zoho_hub/validations/validate_picklist.rb +22 -0
- data/lib/zoho_hub/version.rb +1 -1
- data/lib/zoho_hub/views/variables.erb +7 -0
- data/lib/zoho_hub/with_connection.rb +8 -0
- data/lib/zoho_hub/with_validations.rb +66 -0
- data/lib/zoho_hub.rb +2 -1
- metadata +12 -10
- data/lib/zoho_hub/deprecated_and_only_for_reference_records/account.rb +0 -43
- data/lib/zoho_hub/deprecated_and_only_for_reference_records/campaign.rb +0 -14
- data/lib/zoho_hub/deprecated_and_only_for_reference_records/contact.rb +0 -45
- data/lib/zoho_hub/deprecated_and_only_for_reference_records/funder.rb +0 -9
- data/lib/zoho_hub/deprecated_and_only_for_reference_records/product.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1967126d56677efb3373c3a3d8700842f5d03e0f3b0cb922b4ffcf5d113a831
|
4
|
+
data.tar.gz: 1cf0f3e67da7d878dd367614c3da7441d0024fe070dae978f72e49575e6be013
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 203045fd8b960ae3dd03873106ea7a88a111bbd6618d9942e9c597cdef83ba860792639e13e92b7a32ad0d550b9521795ab8c4043dc8e9e2de44321a5e2a7990
|
7
|
+
data.tar.gz: ac2a1e1e7bca5a28196d9cdc68312c1a8774ddc1666266a0a4956587b482bf255da15aa50f9c05cb593a6768103f3b939a91ed692c16641cd26976ce51f63243
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[![Build Status](https://travis-ci.com/rikas/zoho_hub.svg?branch=master)](https://travis-ci.com/rikas/zoho_hub)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/zoho_hub.svg)](https://badge.fury.io/rb/zoho_hub)
|
5
5
|
|
6
|
-
Simple wrapper around Zoho CRM version2, using [OAuth 2.0 protocol](https://www.zoho.com/crm/help/api/
|
6
|
+
Simple wrapper around Zoho CRM version2, using [OAuth 2.0 protocol](https://www.zoho.com/crm/help/developer/api/oauth-overview.html)
|
7
7
|
for authentication.
|
8
8
|
|
9
9
|
This gem reads your Module configuration and builds the corresponding classes for you, using some
|
@@ -33,32 +33,59 @@ Or install it yourself as:
|
|
33
33
|
### 1. Register your application
|
34
34
|
|
35
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/
|
36
|
+
application as described here: https://www.zoho.com/crm/help/developer/api/register-client.html.
|
37
37
|
|
38
|
-
**
|
38
|
+
This will give you a **Client ID** and a **secret**, that you'll use in step 2.
|
39
39
|
|
40
|
-
|
40
|
+
#### 1.1 Zoho Accounts URL
|
41
|
+
|
42
|
+
Registration and authorization requests are made to Zoho's domain-specific Accounts URL which
|
43
|
+
varies depending on your region:
|
44
|
+
|
45
|
+
* EU: https://accounts.zoho.eu
|
46
|
+
* US: https://accounts.zoho.com
|
47
|
+
* China: https://accounts.zoho.com.cn
|
48
|
+
|
49
|
+
ZohoHub uses the EU Account URL by default, but this can be overriden in a `ZohoHub.configure`
|
50
|
+
block via the `api_domain` method (see step 2.)
|
51
|
+
|
52
|
+
#### 1.2 Authorized Redirect URI
|
53
|
+
|
54
|
+
Per Zoho's API documentation, providing a **redirect URI** is optional. Doing so allows a user of
|
55
|
+
your application to be redirected back to your app (to the **redirect URI**) with a **grant token**
|
56
|
+
upon successful authentication.
|
57
|
+
|
58
|
+
If you don't provide a **redirect URI**, you'll need to use the [self-client option](https://www.zoho.com/crm/help/developer/api/auth-request.html#plink2)
|
59
|
+
for authorization (see 3.2 below.)
|
41
60
|
|
42
61
|
### 2. Configure ZohoHub with your credentials
|
43
62
|
|
63
|
+
> **Note:** Treat these credentials like an important password. It is *strongly* recommended to not
|
64
|
+
> paste them anywhere in plain text. Do *not* add them to version control; keep them out of your
|
65
|
+
> code directly by referencing them via environment variables. Use something like the dotenv gem or
|
66
|
+
> encrypted credentials in Rails to keep them as secret and secure as possible.
|
67
|
+
|
44
68
|
You need to have a configuration block like the one below (in rails add a `zoho_hub.rb` in your
|
45
|
-
`config/initializers`
|
69
|
+
`config/initializers` directory):
|
46
70
|
|
47
71
|
```ruby
|
48
72
|
ZohoHub.configure do |config|
|
49
73
|
config.client_id = 'YOUR_ZOHO_CLIENT_ID' # obtained in 1.
|
50
74
|
config.secret = 'YOUR_ZOHO_SECRET' # obtained in 1.
|
51
75
|
config.redirect_uri = 'YOUR_ZOHO_OAUTH_REDIRECT_URL'
|
76
|
+
config.api_domain = 'https://accounts.zoho.com' # can be omitted if in the EU
|
52
77
|
# config.debug = true # this will be VERY verbose, but helps to identify bugs / problems
|
53
78
|
end
|
54
79
|
```
|
55
80
|
|
56
|
-
|
57
|
-
|
58
|
-
### 2. Authorization request
|
81
|
+
### 3. Authorization request
|
59
82
|
|
60
83
|
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**.
|
84
|
+
you have to request a specific URL with the right **scope** and **access_type**. Successful
|
85
|
+
authorization will provide a **grant token** which will be used to generate **access** and
|
86
|
+
**refresh tokens**.
|
87
|
+
|
88
|
+
#### 3.1 Redirection based authentication
|
62
89
|
|
63
90
|
To get the right URL you can use this simple line of code:
|
64
91
|
|
@@ -71,6 +98,22 @@ If you request this generated URL you should see a screen like this one, where y
|
|
71
98
|
|
72
99
|
![](https://duaw26jehqd4r.cloudfront.net/items/1h1i3C1N0k0i02092F0S/Screen%20Shot%202018-11-25%20at%2019.18.38.png)
|
73
100
|
|
101
|
+
You will then be redirected to the **redirect URI** you provided with additional query parameters
|
102
|
+
as follows (the value after `code=` is the **grant token**):
|
103
|
+
|
104
|
+
```
|
105
|
+
{redirect_uri}?code={grant_token}&location=us&accounts-server=https%3A%2F%2Faccounts.zoho.com
|
106
|
+
```
|
107
|
+
|
108
|
+
#### 3.2 Self-Client Authorization
|
109
|
+
|
110
|
+
If you don't have a **redirect URI** or you want your application to be able to authorize with Zoho
|
111
|
+
programmatically (without a user required to be present and click the "Accept" prompt), Zoho
|
112
|
+
provides a [self-client option](https://www.zoho.com/crm/help/developer/api/auth-request.html#plink2)
|
113
|
+
for authentication which will provide a **grant token**.
|
114
|
+
|
115
|
+
#### 3.3 More on scopes
|
116
|
+
|
74
117
|
You can change the default scope (what data can be accessed by your application). This is the list
|
75
118
|
provided as the default scope:
|
76
119
|
|
@@ -88,13 +131,15 @@ ZohoHub::Auth.auth_url(scope: ['ZohoCRM.modules.custom.all', 'ZohoCRM.modules.al
|
|
88
131
|
# => "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
132
|
```
|
90
133
|
|
91
|
-
|
134
|
+
Refer to [Zoho's API documentation on scopes](https://www.zoho.com/crm/help/developer/api/oauth-overview.html#plink5) for detailed information.
|
92
135
|
|
93
|
-
|
136
|
+
#### 3.4 Offline access
|
137
|
+
|
138
|
+
By design the **access tokens** returned by the OAuth flow expire after a period of time (1 hour by
|
94
139
|
default), as a safety mechanism. This means that any application that wants to work with a user's
|
95
140
|
data needs the user to have recently gone through the OAuth flow, aka be online.
|
96
141
|
|
97
|
-
When you request offline access the Zoho API returns a refresh token
|
142
|
+
When you request offline access the Zoho API returns a **refresh token**. **Refresh tokens** give your
|
98
143
|
application the ability to request data on behalf of the user when the user is not present and in
|
99
144
|
front of your application.
|
100
145
|
|
@@ -107,7 +152,109 @@ ZohoHub::Auth.auth_url(access_type: 'online')
|
|
107
152
|
# => "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
153
|
```
|
109
154
|
|
110
|
-
|
155
|
+
### 4. Access token
|
156
|
+
|
157
|
+
See Zoho's API documentation for generating an initial **access token**:
|
158
|
+
https://www.zoho.com/crm/help/developer/api/access-refresh.html
|
159
|
+
|
160
|
+
To use an **access token** in a manual request, include it as a request header as
|
161
|
+
`Authorization: Zoho-oauthtoken {access_token}` (without the braces.)
|
162
|
+
|
163
|
+
To use an **access token** with ZohoHub, pass it to the `ZohoHub.setup_connection` method as the
|
164
|
+
`access_token` parameter.
|
165
|
+
|
166
|
+
|
167
|
+
### 5. Refresh token
|
168
|
+
|
169
|
+
TODO
|
170
|
+
|
171
|
+
### 6. Basic ZohoHub flow
|
172
|
+
|
173
|
+
Once ZohoHub has been configured with your credentials (section 2) and you have a fresh **access
|
174
|
+
token**, setup a ZohoHub connection:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
ZohoHub.setup_connection access_token: 'ACCESS_TOKEN',
|
178
|
+
expires_in: 'EXPIRES_IN_SEC',
|
179
|
+
api_domain: 'API_DOMAIN'
|
180
|
+
```
|
181
|
+
|
182
|
+
Now you can issue requests to Zoho's API with the Connection object, e.g.:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
# request a (paginated) list of all Lead records
|
186
|
+
ZohoHub.connection.get 'Leads'
|
187
|
+
```
|
188
|
+
|
189
|
+
A successful request will receive a response like the sample here: https://www.zoho.com/crm/help/developer/api/get-records.html.
|
190
|
+
|
191
|
+
### 7. BaseRecord and record classes
|
192
|
+
|
193
|
+
At this point, ZohoHub is starting to do some of the heavy lifting, but using `ZohoHub.connection`
|
194
|
+
still gets tedious after just a handful of requests. But we can improve that by allowing ZohoHub
|
195
|
+
to build our record classes or by manually defining them ourselves.
|
196
|
+
|
197
|
+
#### 7.1 Reflection
|
198
|
+
|
199
|
+
TODO
|
200
|
+
|
201
|
+
#### 7.2 Subclassing BaseRecord
|
202
|
+
|
203
|
+
See `lib/zoho_hub/base_record.rb` and any of the classes in `examples/models/` for reference.
|
204
|
+
|
205
|
+
For any Zoho module with which you want to interact via ZohoHub, make a class of the same name that
|
206
|
+
inherits from `ZohoHub::BaseRecord`. For example, to build a class for the Leads module:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
# lead.rb
|
210
|
+
|
211
|
+
class Lead < BaseRecord
|
212
|
+
...
|
213
|
+
end
|
214
|
+
```
|
215
|
+
|
216
|
+
Specify this module's fields as attributes:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
# lead.rb
|
220
|
+
|
221
|
+
class Lead < BaseRecord
|
222
|
+
attributes: :id, :first_name, :last_name, :phone, :email, :source, # etc.
|
223
|
+
end
|
224
|
+
```
|
225
|
+
|
226
|
+
Define an `initialize` method to populate attributes:
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
def initialize(params)
|
230
|
+
attributes.each do |attr|
|
231
|
+
zoho_key = attr_to_zoho_key(attr)
|
232
|
+
|
233
|
+
send("#{attr}=", params[zoho_key] || params[attr] || DEFAULTS[attr])
|
234
|
+
end
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
Now you can issue requests more easily with your record class, e.g.:
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
# request a (paginated) list of all Lead records
|
242
|
+
Lead.all
|
243
|
+
```
|
244
|
+
|
245
|
+
## Tips and suggestions
|
246
|
+
|
247
|
+
* Using a tool such as Postman or curl to issue HTTP requests and verify responses in isolation
|
248
|
+
can be a great sanity check during setup.
|
249
|
+
* Downloading ZohoHub code (as opposed to the gem) and running `bin/console` is a great way to
|
250
|
+
learn how the code works and test aspects of setup and Zoho's API in isolation.
|
251
|
+
* [The Zoho API Documentation](https://www.zoho.com/crm/help/developer/api/overview.html) is your
|
252
|
+
friend - especially the sample HTTP requests and responses in the various sections under "Rest
|
253
|
+
API" on the left.
|
254
|
+
* If you're manually implementing your record classes (rather than using the reflection mechanism),
|
255
|
+
the files in `/lib/zoho_hub/deprecated_and_only_for_reference_records/` can help you get started.
|
256
|
+
* Requests can be issued to Zoho CRM's [Sandbox](https://help.zoho.com/portal/kb/articles/using-sandbox)
|
257
|
+
by configuring `https://crmsandbox.zoho.com/crm` (or regional equivalent) as the `api_domain`.
|
111
258
|
|
112
259
|
## Development
|
113
260
|
|
data/bin/console
CHANGED
@@ -10,6 +10,8 @@ Dotenv.load
|
|
10
10
|
ZohoHub.configure do |config|
|
11
11
|
config.client_id = ENV['ZOHO_CLIENT_ID']
|
12
12
|
config.secret = ENV['ZOHO_SECRET']
|
13
|
+
config.redirect_uri = ENV['ZOHO_REDIRECT_URI']
|
14
|
+
config.api_domain = ENV['ZOHO_API_DOMAIN'] if ENV['ZOHO_API_DOMAIN']
|
13
15
|
config.debug = ENV['ZOHO_DEBUG'] || false
|
14
16
|
end
|
15
17
|
|
@@ -18,5 +20,7 @@ puts 'Refreshing token...'
|
|
18
20
|
token_params = ZohoHub::Auth.refresh_token(ENV['ZOHO_REFRESH_TOKEN'])
|
19
21
|
ZohoHub.setup_connection(token_params)
|
20
22
|
|
23
|
+
self.send(:include, ZohoHub)
|
24
|
+
|
21
25
|
require 'pry'
|
22
26
|
Pry.start
|
data/bin/read
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'fileutils'
|
4
5
|
require 'bundler/setup'
|
5
6
|
require 'zoho_hub'
|
6
7
|
require 'zoho_hub/settings/module'
|
7
|
-
require 'zoho_hub/
|
8
|
+
require 'zoho_hub/base_record'
|
8
9
|
|
9
10
|
require 'dotenv'
|
10
11
|
Dotenv.load
|
@@ -12,7 +13,6 @@ Dotenv.load
|
|
12
13
|
ZohoHub.configure do |config|
|
13
14
|
config.client_id = ENV['ZOHO_CLIENT_ID']
|
14
15
|
config.secret = ENV['ZOHO_SECRET']
|
15
|
-
config.redirect_uri = ENV['ZOHO_OAUTH_REDIRECT_URL']
|
16
16
|
end
|
17
17
|
|
18
18
|
token_params = ZohoHub::Auth.refresh_token(ENV['ZOHO_REFRESH_TOKEN'])
|
@@ -27,7 +27,9 @@ puts "Found #{modules_hashes.size} modules"
|
|
27
27
|
modules_hashes.each do |hash|
|
28
28
|
puts "- Writing configuration for #{hash[:plural_label]}"
|
29
29
|
|
30
|
-
|
30
|
+
modules_path = File.join(ZohoHub.root, 'cache', 'modules')
|
31
|
+
FileUtils.mkdir_p(modules_path)
|
32
|
+
file_name = File.join(modules_path, "#{hash[:api_name]}.json")
|
31
33
|
|
32
34
|
File.open(file_name, 'w') do |file|
|
33
35
|
file.write(JSON.pretty_generate(hash))
|
@@ -36,7 +38,9 @@ modules_hashes.each do |hash|
|
|
36
38
|
next unless hash[:api_supported]
|
37
39
|
|
38
40
|
fields_array = ZohoHub::Settings::Field.all_json_for(hash[:api_name])
|
39
|
-
|
41
|
+
fields_path = File.join(ZohoHub.root, 'cache', 'fields')
|
42
|
+
FileUtils.mkdir_p(fields_path)
|
43
|
+
file_name = File.join(fields_path, "#{hash[:api_name]}.json")
|
40
44
|
|
41
45
|
File.open(file_name, 'w') do |file|
|
42
46
|
file.write(JSON.pretty_generate(fields_array))
|
data/bin/zoho_hub
CHANGED
@@ -3,60 +3,41 @@
|
|
3
3
|
|
4
4
|
require 'bundler/setup'
|
5
5
|
|
6
|
-
|
7
|
-
require '
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
require 'optparse'
|
6
|
+
begin
|
7
|
+
require 'dotenv'
|
8
|
+
Dotenv.load
|
9
|
+
rescue LoadError
|
10
|
+
end
|
12
11
|
|
13
|
-
|
12
|
+
require 'zoho_hub/cli/callback_server'
|
13
|
+
require 'zoho_hub/cli/read_modules'
|
14
14
|
|
15
|
-
|
16
|
-
parser = OptionParser.new do |op|
|
17
|
-
op.banner = 'Usage: zoho_hub -c CLIENT_ID -s SECRET [options]'
|
15
|
+
command = ARGV[0]
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
def print_commands
|
18
|
+
commands = [
|
19
|
+
['callback-server', 'run a http server to serve as oauth callback to get a refresh token'],
|
20
|
+
['read-modules', 'read the configuration from Zoho CRM and save it locally']
|
21
|
+
]
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
23
|
+
largest_name = commands.map(&:first).max_by(&:length)
|
24
|
+
left_pad = largest_name.length + 5
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
op.on_tail('--version', 'Show version') do
|
32
|
-
puts "ZohoHub #{ZohoHub::VERSION}"
|
33
|
-
exit
|
26
|
+
commands.each do |command|
|
27
|
+
$stdout.print " #{command.first}".ljust(left_pad)
|
28
|
+
$stdout.puts command.last
|
34
29
|
end
|
35
30
|
end
|
36
31
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
32
|
+
case command
|
33
|
+
when 'callback-server'
|
34
|
+
ZohoHub::Cli::CallbackServer.new.run(ARGV[1..-1])
|
35
|
+
when 'read-modules'
|
36
|
+
ZohoHub::Cli::ReadModules.new.run(ARGV[1..-1])
|
37
|
+
else
|
38
|
+
$stdout.puts 'Usage:'
|
39
|
+
$stdout.puts " zoho_hub [command] [options]\n"
|
40
|
+
$stdout.puts 'where <command> is one of:'
|
41
|
+
|
42
|
+
print_commands
|
57
43
|
end
|
58
|
-
|
59
|
-
# Open the URL in the browser
|
60
|
-
url = ZohoHub::Auth.auth_url
|
61
|
-
puts "REQUESTING: #{url}"
|
62
|
-
Launchy.open(url)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zoho_hub/records/base_record'
|
4
|
+
|
5
|
+
module ZohoHub
|
6
|
+
# Simple manual Zoho record where we just want to get the name. Something like:
|
7
|
+
# #<ZohoHub::Campaign:0x00007fce2cc22458 @id="78265000003433063", @name="Smith & Williamson">
|
8
|
+
class Campaign < BaseRecord
|
9
|
+
attributes :id, :name
|
10
|
+
|
11
|
+
attribute_translation name: :Campaign_Name
|
12
|
+
end
|
13
|
+
end
|
data/{lib/zoho_hub/deprecated_and_only_for_reference_records → examples/models}/potential.rb
RENAMED
@@ -10,6 +10,7 @@ module ZohoHub
|
|
10
10
|
attributes :review_outcome, :first_created, :last_modified, :preferred_term, :project_notes
|
11
11
|
attributes :campaign_id, :account_id, :contact_id, :campaign_detail, :reviewers_comment
|
12
12
|
|
13
|
+
# List of default values for some of the attributes, used in the initializer.
|
13
14
|
DEFAULTS = {
|
14
15
|
currency: 'GBP',
|
15
16
|
territory: 'UK all',
|
@@ -26,7 +27,7 @@ module ZohoHub
|
|
26
27
|
use_proceeds: :use_proceeds
|
27
28
|
)
|
28
29
|
|
29
|
-
def initialize(params)
|
30
|
+
def initialize(params = {})
|
30
31
|
attributes.each do |attr|
|
31
32
|
zoho_key = attr_to_zoho_key(attr)
|
32
33
|
|
@@ -4,21 +4,17 @@ require 'zoho_hub/records/base_record'
|
|
4
4
|
|
5
5
|
module ZohoHub
|
6
6
|
class Quote < BaseRecord
|
7
|
-
attributes :id, :stage, :subject
|
8
|
-
attributes :potential_id
|
7
|
+
attributes :id, :stage, :subject, :potential_id
|
9
8
|
|
9
|
+
# The translation from attribute name to the JSON field on Zoho. The default behaviour will be
|
10
|
+
# to Camel_Case the attribute so on this list we should only have exceptions to this rule.
|
10
11
|
attribute_translation(
|
11
12
|
id: :id,
|
12
13
|
stage: :Quote_Stage
|
13
14
|
)
|
14
15
|
|
15
|
-
def initialize(params)
|
16
|
-
|
17
|
-
attributes.each do |attr|
|
18
|
-
zoho_key = attr_to_zoho_key(attr)
|
19
|
-
|
20
|
-
send("#{attr}=", params[zoho_key] || params[attr])
|
21
|
-
end
|
16
|
+
def initialize(params = {})
|
17
|
+
super
|
22
18
|
|
23
19
|
@potential_id ||= params.dig(:Deal_Name, :id)
|
24
20
|
@lender_organisation_id ||= params.dig(:Account_Name, :id)
|
data/lib/zoho_hub/auth.rb
CHANGED
@@ -12,6 +12,7 @@ module ZohoHub
|
|
12
12
|
extend Forwardable
|
13
13
|
|
14
14
|
TOKEN_PATH = '/oauth/v2/token'
|
15
|
+
REVOKE_TOKEN_PATH = '/oauth/v2/token/revoke'
|
15
16
|
AUTH_PATH = '/oauth/v2/auth'
|
16
17
|
|
17
18
|
DEFAULT_SCOPES = %w[
|
@@ -31,14 +32,6 @@ module ZohoHub
|
|
31
32
|
@scopes = scopes
|
32
33
|
end
|
33
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
35
|
def self.auth_url(access_type: DEFAULT_ACCESS_TYPE, scopes: DEFAULT_SCOPES)
|
43
36
|
new(access_type: access_type, scopes: scopes).auth_url
|
44
37
|
end
|
@@ -46,7 +39,7 @@ module ZohoHub
|
|
46
39
|
def auth_url
|
47
40
|
uri = auth_full_uri
|
48
41
|
|
49
|
-
|
42
|
+
query = {
|
50
43
|
client_id: client_id,
|
51
44
|
scope: @scopes.join(','),
|
52
45
|
access_type: @access_type,
|
@@ -54,21 +47,27 @@ module ZohoHub
|
|
54
47
|
response_type: 'code'
|
55
48
|
}
|
56
49
|
|
50
|
+
# The consent page must be presented otherwise we don't get the refresh token back.
|
51
|
+
query[:prompt] = 'consent' if @access_type == DEFAULT_ACCESS_TYPE
|
52
|
+
|
53
|
+
uri.query_values = query
|
54
|
+
|
57
55
|
Addressable::URI.unencode(uri.to_s)
|
58
56
|
end
|
59
57
|
|
60
|
-
def
|
61
|
-
|
58
|
+
def auth_full_uri
|
59
|
+
Addressable::URI.join(api_domain, AUTH_PATH)
|
60
|
+
end
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
code: grant_token,
|
67
|
-
redirect_uri: redirect_uri,
|
68
|
-
grant_type: 'authorization_code'
|
69
|
-
}
|
62
|
+
def self.refresh_token(refresh_token)
|
63
|
+
new.refresh_token(refresh_token)
|
64
|
+
end
|
70
65
|
|
71
|
-
|
66
|
+
def refresh_token(refresh_token)
|
67
|
+
result = Faraday.post(refresh_url(refresh_token))
|
68
|
+
|
69
|
+
json = parse(result.body)
|
70
|
+
json.merge(refresh_token: refresh_token)
|
72
71
|
end
|
73
72
|
|
74
73
|
def refresh_url(refresh_token)
|
@@ -84,15 +83,8 @@ module ZohoHub
|
|
84
83
|
Addressable::URI.unencode(uri.to_s)
|
85
84
|
end
|
86
85
|
|
87
|
-
def
|
88
|
-
|
89
|
-
end
|
90
|
-
|
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)
|
86
|
+
def token_full_uri
|
87
|
+
Addressable::URI.join(api_domain, TOKEN_PATH)
|
96
88
|
end
|
97
89
|
|
98
90
|
def revoke_refresh_token(refresh_token)
|
@@ -117,6 +109,22 @@ module ZohoHub
|
|
117
109
|
parse(result.body)
|
118
110
|
end
|
119
111
|
|
112
|
+
def token_url(grant_token)
|
113
|
+
uri = token_full_uri
|
114
|
+
|
115
|
+
uri.query_values = {
|
116
|
+
client_id: client_id,
|
117
|
+
client_secret: secret,
|
118
|
+
code: grant_token,
|
119
|
+
redirect_uri: redirect_uri,
|
120
|
+
grant_type: 'authorization_code'
|
121
|
+
}
|
122
|
+
|
123
|
+
Addressable::URI.unencode(uri.to_s)
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
120
128
|
def parse(body)
|
121
129
|
MultiJson.load(body, symbolize_keys: true)
|
122
130
|
end
|
data/lib/zoho_hub/base_record.rb
CHANGED
@@ -3,12 +3,14 @@
|
|
3
3
|
require 'zoho_hub/response'
|
4
4
|
require 'zoho_hub/with_connection'
|
5
5
|
require 'zoho_hub/with_attributes'
|
6
|
+
require 'zoho_hub/with_validations'
|
6
7
|
require 'zoho_hub/string_utils'
|
7
8
|
|
8
9
|
module ZohoHub
|
9
10
|
class BaseRecord
|
10
11
|
include WithConnection
|
11
12
|
include WithAttributes
|
13
|
+
include WithValidations
|
12
14
|
|
13
15
|
# Default nnumber of records when fetching all.
|
14
16
|
DEFAULT_RECORDS_PER_PAGE = 200
|
@@ -34,16 +36,18 @@ module ZohoHub
|
|
34
36
|
raise RecordNotFound, "Couldn't find #{request_path.singularize} with 'id'=#{id}"
|
35
37
|
end
|
36
38
|
|
37
|
-
new(response.data)
|
39
|
+
new(response.data.first)
|
38
40
|
end
|
39
41
|
|
40
42
|
def where(params)
|
41
43
|
path = File.join(request_path, 'search')
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
+
body = get(path, params)
|
46
|
+
response = build_response(body)
|
47
|
+
|
48
|
+
data = response.nil? ? [] : response.data
|
45
49
|
|
46
|
-
data.map { |
|
50
|
+
data.map { |json| new(json) }
|
47
51
|
end
|
48
52
|
|
49
53
|
def find_by(params)
|
@@ -55,12 +59,12 @@ module ZohoHub
|
|
55
59
|
new(params).save
|
56
60
|
end
|
57
61
|
|
58
|
-
def all(
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
+
def all(params = {})
|
63
|
+
params[:page] ||= DEFAULT_PAGE
|
64
|
+
params[:per_page] ||= DEFAULT_RECORDS_PER_PAGE
|
65
|
+
params[:per_page] = MIN_RECORDS if params[:per_page] < MIN_RECORDS
|
62
66
|
|
63
|
-
body = get(request_path,
|
67
|
+
body = get(request_path, params)
|
64
68
|
response = build_response(body)
|
65
69
|
|
66
70
|
data = response.nil? ? [] : response.data
|
@@ -86,17 +90,24 @@ module ZohoHub
|
|
86
90
|
end
|
87
91
|
end
|
88
92
|
|
93
|
+
def initialize(params = {})
|
94
|
+
attributes.each do |attr|
|
95
|
+
zoho_key = attr_to_zoho_key(attr)
|
96
|
+
|
97
|
+
send("#{attr}=", params[zoho_key] || params[attr])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
89
101
|
def save
|
90
102
|
body = if new_record? # create new record
|
91
103
|
post(self.class.request_path, data: [to_params])
|
92
104
|
else # update existing record
|
93
|
-
|
94
|
-
put(path, data: [to_params])
|
105
|
+
put(File.join(self.class.request_path, id), data: [to_params])
|
95
106
|
end
|
96
107
|
|
97
108
|
response = build_response(body)
|
98
109
|
|
99
|
-
response.data.dig(:details, :id)
|
110
|
+
response.data.first.dig(:details, :id)
|
100
111
|
end
|
101
112
|
|
102
113
|
def new_record?
|