zoho_hub 0.2.0 → 0.3.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.
- 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
|
[](https://travis-ci.com/rikas/zoho_hub)
|
4
4
|
[](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
|

|
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?
|