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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -8
  3. data/README.md +160 -13
  4. data/bin/console +4 -0
  5. data/bin/read +8 -4
  6. data/bin/zoho_hub +29 -48
  7. data/examples/models/campaign.rb +13 -0
  8. data/{lib/zoho_hub/deprecated_and_only_for_reference_records → examples/models}/potential.rb +2 -1
  9. data/{lib/zoho_hub/deprecated_and_only_for_reference_records → examples/models}/quote.rb +5 -9
  10. data/lib/zoho_hub/auth.rb +36 -28
  11. data/lib/zoho_hub/base_record.rb +23 -12
  12. data/lib/zoho_hub/cli/callback_server.rb +94 -0
  13. data/lib/zoho_hub/cli/read_modules.rb +122 -0
  14. data/lib/zoho_hub/connection.rb +7 -0
  15. data/lib/zoho_hub/oauth_callback_server.rb +0 -4
  16. data/lib/zoho_hub/{module_builder.rb → reflection/module_builder.rb} +11 -15
  17. data/lib/zoho_hub/response.rb +1 -5
  18. data/lib/zoho_hub/string_utils.rb +5 -1
  19. data/lib/zoho_hub/validations/base_validation.rb +14 -0
  20. data/lib/zoho_hub/validations/validate_length.rb +19 -0
  21. data/lib/zoho_hub/validations/validate_picklist.rb +22 -0
  22. data/lib/zoho_hub/version.rb +1 -1
  23. data/lib/zoho_hub/views/variables.erb +7 -0
  24. data/lib/zoho_hub/with_connection.rb +8 -0
  25. data/lib/zoho_hub/with_validations.rb +66 -0
  26. data/lib/zoho_hub.rb +2 -1
  27. metadata +12 -10
  28. data/lib/zoho_hub/deprecated_and_only_for_reference_records/account.rb +0 -43
  29. data/lib/zoho_hub/deprecated_and_only_for_reference_records/campaign.rb +0 -14
  30. data/lib/zoho_hub/deprecated_and_only_for_reference_records/contact.rb +0 -45
  31. data/lib/zoho_hub/deprecated_and_only_for_reference_records/funder.rb +0 -9
  32. 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: bb0b0886637feb21a98d0a73f40cb3571a0ec2507dfd45b7eec9fd348b365276
4
- data.tar.gz: 70638084911ec64dc02095d4cf085453ca13ba4ea28a3c983c79e235a1a5911e
3
+ metadata.gz: e1967126d56677efb3373c3a3d8700842f5d03e0f3b0cb922b4ffcf5d113a831
4
+ data.tar.gz: 1cf0f3e67da7d878dd367614c3da7441d0024fe070dae978f72e49575e6be013
5
5
  SHA512:
6
- metadata.gz: c5fc255597ced5c966a59b0db9de72ab6a67defca6c1a62e5e168f37bc70326f2c1cccd5cf3ab44369a94372277ca42c671965e50d742b315b26126882f1af72
7
- data.tar.gz: 89fbe288d53b9ebf9c76f8229981deffcacc9d6fe484b6187f654430eb097c7e1b57719dafcc953cafbfafeec7f1d765c87794697b3d283b168cbd2c9f35ff03
6
+ metadata.gz: 203045fd8b960ae3dd03873106ea7a88a111bbd6618d9942e9c597cdef83ba860792639e13e92b7a32ad0d550b9521795ab8c4043dc8e9e2de44321a5e2a7990
7
+ data.tar.gz: ac2a1e1e7bca5a28196d9cdc68312c1a8774ddc1666266a0a4956587b482bf255da15aa50f9c05cb593a6768103f3b939a91ed692c16641cd26976ce51f63243
data/.rubocop.yml CHANGED
@@ -33,11 +33,3 @@ RSpec/ExampleLength:
33
33
 
34
34
  RSpec/MultipleExpectations:
35
35
  Max: 10
36
-
37
- RSpec/RepeatedExample:
38
- Exclude:
39
- - 'spec/policies/**/*'
40
-
41
- RSpec/RepeatedDescription:
42
- Exclude:
43
- - 'spec/policies/**/*'
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/v2/#OAuth2_0)
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/v2/#oauth-request.
36
+ application as described here: https://www.zoho.com/crm/help/developer/api/register-client.html.
37
37
 
38
- **TODO TODO - explain "Authorized redirect URIs"**
38
+ This will give you a **Client ID** and a **secret**, that you'll use in step 2.
39
39
 
40
- This will give you a **Client ID** and a **secret**, that you'll use in the next step.
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` dir):
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
- **Note:** if you don't know what the `redirect_url` is then **TODO TODO TODO TODO TODO**
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
- #### 2.1 Offline access
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
- By design the access tokens returned by the OAuth flow expire after a period of time (1 hour by
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. Refresh tokens give your
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
- ## 3. Generate Access Token
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/records/base_record'
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
- file_name = File.join(ZohoHub.root, 'cache', 'modules', "#{hash[:api_name]}.json")
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
- file_name = File.join(ZohoHub.root, 'cache', 'fields', "#{hash[:api_name]}.json")
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
- require 'zoho_hub'
7
- require 'zoho_hub/auth'
8
- require 'zoho_hub/oauth_callback_server'
9
-
10
- require 'launchy'
11
- require 'optparse'
6
+ begin
7
+ require 'dotenv'
8
+ Dotenv.load
9
+ rescue LoadError
10
+ end
12
11
 
13
- default_port = ZohoHub::OauthCallbackServer.settings.port
12
+ require 'zoho_hub/cli/callback_server'
13
+ require 'zoho_hub/cli/read_modules'
14
14
 
15
- options = {}
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
- op.on('-c', '--client-id=client_id', 'The Zoho client ID') do |client|
20
- options[:client_id] = client
21
- end
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
- op.on('-s', '--secret=secret', 'The Zoho secret') do |secret|
24
- options[:secret] = secret
25
- end
23
+ largest_name = commands.map(&:first).max_by(&:length)
24
+ left_pad = largest_name.length + 5
26
25
 
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
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
- 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
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
@@ -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
- puts Rainbow(params).bright.red
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
- uri.query_values = {
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 token_url(grant_token)
61
- uri = token_full_uri
58
+ def auth_full_uri
59
+ Addressable::URI.join(api_domain, AUTH_PATH)
60
+ end
62
61
 
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
- }
62
+ def self.refresh_token(refresh_token)
63
+ new.refresh_token(refresh_token)
64
+ end
70
65
 
71
- Addressable::URI.unencode(uri.to_s)
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 self.refresh_token(refresh_token)
88
- new.refresh_token(refresh_token)
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
@@ -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
- response = get(path, params)
44
- data = response[:data]
45
+ body = get(path, params)
46
+ response = build_response(body)
47
+
48
+ data = response.nil? ? [] : response.data
45
49
 
46
- data.map { |info| new(info) }
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(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
+ 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, options)
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
- path = File.join(self.class.request_path, id)
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?