zoho_hub 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +42 -0
- data/.rubocop.yml +13 -0
- data/.ruby-version +1 -1
- data/README.md +128 -18
- data/bin/console +1 -1
- data/examples/models/potential.rb +2 -0
- data/lib/zoho_hub.rb +3 -1
- data/lib/zoho_hub/auth.rb +1 -0
- data/lib/zoho_hub/base_record.rb +64 -4
- data/lib/zoho_hub/cli/callback_server.rb +5 -5
- data/lib/zoho_hub/cli/read_modules.rb +4 -4
- data/lib/zoho_hub/connection.rb +3 -2
- data/lib/zoho_hub/errors.rb +3 -0
- data/lib/zoho_hub/modules/attachment.rb +41 -0
- data/lib/zoho_hub/notifications.rb +54 -0
- data/lib/zoho_hub/response.rb +8 -3
- data/lib/zoho_hub/string_utils.rb +1 -1
- data/lib/zoho_hub/version.rb +1 -1
- data/lib/zoho_hub/with_attributes.rb +14 -11
- data/lib/zoho_hub/with_connection.rb +2 -2
- data/zoho_hub.gemspec +3 -1
- metadata +52 -8
- data/.travis.yml +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f91e364b7e8432a5047a03f6fa2426201c502368c036bc604566de53de2e65fb
|
4
|
+
data.tar.gz: fc574d26b030f7d69025cc6004cb127a8eb7296ed9bba34566ac0c6de2c0b6fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4931bbcc3fcf425eae35d1b5a5eeca9c27112503e0444198504a2ab65667638f0a070808d8299d00ed7cd1ed03f71d63b0d0ad645cd22e0ef9823902b5028b5
|
7
|
+
data.tar.gz: 8898cf446859177ef26d0a73a066e7f5f0f7ede6fc2401833d4900f2524bc0a9d204890c0006ad59d79f822f8a0e1df7b0bd75f8ca9d60126829960aaad4eea5
|
@@ -0,0 +1,42 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
lint:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
steps:
|
9
|
+
- uses: actions/checkout@v2
|
10
|
+
- uses: ruby/setup-ruby@v1
|
11
|
+
with:
|
12
|
+
ruby-version: "2.5"
|
13
|
+
bundler-cache: true
|
14
|
+
- name: rubocop version
|
15
|
+
timeout-minutes: 1
|
16
|
+
run: bundle exec rubocop --version
|
17
|
+
- name: rubocop
|
18
|
+
timeout-minutes: 5
|
19
|
+
run: bundle exec rubocop -c .rubocop.yml
|
20
|
+
|
21
|
+
test:
|
22
|
+
runs-on: ubuntu-latest
|
23
|
+
continue-on-error: ${{ matrix.experimental }}
|
24
|
+
strategy:
|
25
|
+
fail-fast: false
|
26
|
+
matrix:
|
27
|
+
ruby: ["2.5", "2.6", "2.7", "3.0"]
|
28
|
+
experimental: [false]
|
29
|
+
include:
|
30
|
+
- ruby: "jruby"
|
31
|
+
experimental: true
|
32
|
+
- ruby: "truffleruby"
|
33
|
+
experimental: true
|
34
|
+
steps:
|
35
|
+
- uses: actions/checkout@v2
|
36
|
+
- uses: ruby/setup-ruby@v1
|
37
|
+
with:
|
38
|
+
ruby-version: ${{matrix.ruby}}
|
39
|
+
bundler-cache: true
|
40
|
+
- name: Run tests
|
41
|
+
timeout-minutes: 5
|
42
|
+
run: ${{matrix.env}} bundle exec rspec
|
data/.rubocop.yml
CHANGED
@@ -3,6 +3,13 @@ require: rubocop-rspec
|
|
3
3
|
AllCops:
|
4
4
|
TargetRubyVersion: 2.5.1
|
5
5
|
|
6
|
+
Gemspec/RequiredRubyVersion:
|
7
|
+
Enabled: false
|
8
|
+
|
9
|
+
Lint:
|
10
|
+
Exclude:
|
11
|
+
- bin/*
|
12
|
+
|
6
13
|
# Don't force top level comments in every class
|
7
14
|
Style/Documentation:
|
8
15
|
Enabled: false
|
@@ -25,6 +32,12 @@ Metrics/ClassLength:
|
|
25
32
|
Metrics/MethodLength:
|
26
33
|
Max: 20
|
27
34
|
|
35
|
+
Metrics/CyclomaticComplexity:
|
36
|
+
Max: 10
|
37
|
+
|
38
|
+
Metrics/PerceivedComplexity:
|
39
|
+
Max: 10
|
40
|
+
|
28
41
|
Metrics/AbcSize:
|
29
42
|
Max: 30
|
30
43
|
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.5.
|
1
|
+
2.5.8
|
data/README.md
CHANGED
@@ -14,21 +14,35 @@ ActiveRecord, to do CRUD operations.
|
|
14
14
|
|
15
15
|
## Table of Contents
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
17
|
+
- [ZohoHub](#zohohub)
|
18
|
+
- [Table of Contents](#table-of-contents)
|
19
|
+
- [Installation](#installation)
|
20
|
+
- [Setup process](#setup-process)
|
21
|
+
- [1. Register your application](#1-register-your-application)
|
22
|
+
- [1.1 Zoho Accounts URL](#11-zoho-accounts-url)
|
23
|
+
- [1.2 Authorized Redirect URI](#12-authorized-redirect-uri)
|
24
|
+
- [2. Configure ZohoHub with your credentials](#2-configure-zohohub-with-your-credentials)
|
25
|
+
- [3. Authorization request](#3-authorization-request)
|
26
|
+
- [3.1 Redirection based authentication](#31-redirection-based-authentication)
|
27
|
+
- [3.2 Self-Client Authorization](#32-self-client-authorization)
|
28
|
+
- [3.3 More on scopes](#33-more-on-scopes)
|
29
|
+
- [3.4 Offline access](#34-offline-access)
|
30
|
+
- [4. Access token](#4-access-token)
|
31
|
+
- [5. Refresh token](#5-refresh-token)
|
32
|
+
- [6. Basic ZohoHub flow](#6-basic-zohohub-flow)
|
33
|
+
- [7. BaseRecord and record classes](#7-baserecord-and-record-classes)
|
34
|
+
- [7.1 Reflection](#71-reflection)
|
35
|
+
- [7.2 Subclassing BaseRecord](#72-subclassing-baserecord)
|
36
|
+
- [8 Notifications](#8-notifications)
|
37
|
+
- [8.1 Enable notifications](#81-enable-notifications)
|
38
|
+
- [8.2 List notifications](#82-list-notifications)
|
39
|
+
- [8.3 Caveats](#83-caveats)
|
40
|
+
- [Tips and suggestions](#tips-and-suggestions)
|
41
|
+
- [Examples](#examples)
|
42
|
+
- [Setup auth token and request CurrentUser](#setup-auth-token-and-request-currentuser)
|
43
|
+
- [Development](#development)
|
44
|
+
- [Contributing](#contributing)
|
45
|
+
- [License](#license)
|
32
46
|
|
33
47
|
## Installation
|
34
48
|
|
@@ -198,7 +212,9 @@ To use an **access token** with ZohoHub, pass it to the `ZohoHub.setup_connectio
|
|
198
212
|
|
199
213
|
### 5. Refresh token
|
200
214
|
|
201
|
-
|
215
|
+
This gem automatically refresh the access token.
|
216
|
+
|
217
|
+
If you want automatic refresh, use the refresh_token argument as in the next chapter.
|
202
218
|
|
203
219
|
---
|
204
220
|
|
@@ -210,7 +226,8 @@ token**, setup a ZohoHub connection:
|
|
210
226
|
```ruby
|
211
227
|
ZohoHub.setup_connection access_token: 'ACCESS_TOKEN',
|
212
228
|
expires_in: 'EXPIRES_IN_SEC',
|
213
|
-
api_domain: 'API_DOMAIN'
|
229
|
+
api_domain: 'API_DOMAIN',
|
230
|
+
refresh_token: 'REFRESH_TOKEN'
|
214
231
|
```
|
215
232
|
|
216
233
|
Now you can issue requests to Zoho's API with the Connection object, e.g.:
|
@@ -256,7 +273,7 @@ Specify this module's fields as attributes:
|
|
256
273
|
# lead.rb
|
257
274
|
|
258
275
|
class Lead < ZohoHub::BaseRecord
|
259
|
-
attributes
|
276
|
+
attributes :id, :first_name, :last_name, :phone, :email, :source, # etc.
|
260
277
|
end
|
261
278
|
```
|
262
279
|
|
@@ -283,8 +300,101 @@ lead = Lead.new(
|
|
283
300
|
|
284
301
|
# Creates the new lead
|
285
302
|
lead.save
|
303
|
+
|
304
|
+
# Or in one step:
|
305
|
+
lead = Lead.create(first_name: 'First name', ...)
|
306
|
+
```
|
307
|
+
|
308
|
+
Updating records:
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
Lead.update(id: lead.id, first_name: "...", last_name: "...")
|
312
|
+
|
313
|
+
# Or
|
314
|
+
lead.update(first_name: "...", last_name: "...")
|
315
|
+
|
316
|
+
# Or update up to 100 records in one call:
|
317
|
+
leads = [{ id: id1, phone: "123" }, { id: id2, first_name: "..." }]
|
318
|
+
Lead.update_all(leads)
|
319
|
+
```
|
320
|
+
|
321
|
+
Blueprint transition:
|
322
|
+
|
323
|
+
```ruby
|
324
|
+
Lead.blueprint_transition(lead.id, transition_id)
|
325
|
+
|
326
|
+
# Or
|
327
|
+
lead.blueprint_transition(transition_id)
|
328
|
+
```
|
329
|
+
|
330
|
+
Adding notes:
|
331
|
+
|
332
|
+
```ruby
|
333
|
+
Lead.add_note(id: lead.id, title: 'Note title', content: 'Note content')
|
334
|
+
```
|
335
|
+
|
336
|
+
Related records:
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
Product.all_related(parent_module: 'Lead', parent_id: lead.id)
|
340
|
+
Product.add_related(
|
341
|
+
parent_module: 'Lead',
|
342
|
+
parent_id: lead.id,
|
343
|
+
related_id: product.id
|
344
|
+
)
|
345
|
+
Product.remove_related(
|
346
|
+
parent_module: 'Lead',
|
347
|
+
parent_id: lead.id,
|
348
|
+
related_id: product.id
|
349
|
+
)
|
350
|
+
Product.update_related(...)
|
286
351
|
```
|
287
352
|
|
353
|
+
Attachments (`ZohoHub::Attachment` is defined in the gem):
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
Lead.related_attachments(parent_id: lead.id)
|
357
|
+
# -> Array of Attachments
|
358
|
+
|
359
|
+
attachment = Lead.download_attachment(parent_id: lead.id, attachment_id:attachment.id)
|
360
|
+
# -> Attachment (attachment.file contains the file as a Tempfile)
|
361
|
+
|
362
|
+
#NB: Lead.upload_attachment not implemented yet
|
363
|
+
```
|
364
|
+
|
365
|
+
## 8 Notifications
|
366
|
+
Zoho allows you to receive a notification when a record of a module changes. Supported operation types are create, delete, edit, all.
|
367
|
+
|
368
|
+
### 8.1 Enable notifications
|
369
|
+
In order to receive notifications, you have to enable them first.
|
370
|
+
```ruby
|
371
|
+
# Enable notifications for a given channel:
|
372
|
+
notification_url = 'https://example.org/api/notifications' # Zoho will send notifications by POST to this url
|
373
|
+
token = '123abc' # Zoho will send this token back to you, so you can ensure that the notification is from Zoho
|
374
|
+
channel_id = 1 # Choose a channel to handle the response
|
375
|
+
events = %w[Leads.create Deals.edit Contacts.delete Sales_Orders.all] # Which events to receive notifications for
|
376
|
+
channel_expiry = (DateTime.now + 1.day).iso8601 # choose a date when the channel should expire. 24h is the maximum, default is one hour
|
377
|
+
|
378
|
+
ZohoHub::Notifications.enable(notification_url, channel_id, events, channel_expiry, token)
|
379
|
+
```
|
380
|
+
|
381
|
+
After enabling notifications, Zoho will execute a POST request to the provided notification_url every time the requested event occurs.
|
382
|
+
|
383
|
+
For a list of an in-depth description of the response, check the [Zoho documentation](https://www.zoho.com/crm/developer/docs/api/notifications/overview.html)
|
384
|
+
|
385
|
+
### 8.2 List notifications
|
386
|
+
You can also retrieve all notifications that are currently enabled and that you are receiving uppdates for.
|
387
|
+
|
388
|
+
```ruby
|
389
|
+
# Get all enabled notifications
|
390
|
+
ZohoHub::Notifications.all
|
391
|
+
```
|
392
|
+
|
393
|
+
### 8.3 Caveats
|
394
|
+
|
395
|
+
* Zoho does not notify you when records are merged.
|
396
|
+
* Since Zoho does not tell you what changed, you will have to request the record by yourself. Due to this you can miss changes, when they occur quickly after another. This is especially important for status changes, as you might miss state changes.
|
397
|
+
|
288
398
|
## Tips and suggestions
|
289
399
|
|
290
400
|
* Using a tool such as Postman or curl to issue HTTP requests and verify responses in isolation
|
data/bin/console
CHANGED
data/lib/zoho_hub.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'backports/2.3.0/hash' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0')
|
4
|
+
require 'backports/2.5.0/hash' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5.0')
|
4
5
|
|
5
6
|
require 'zoho_hub/version'
|
6
7
|
require 'zoho_hub/auth'
|
@@ -8,6 +9,7 @@ require 'zoho_hub/configuration'
|
|
8
9
|
require 'zoho_hub/connection'
|
9
10
|
require 'zoho_hub/errors'
|
10
11
|
require 'zoho_hub/base_record'
|
12
|
+
require 'zoho_hub/modules/attachment'
|
11
13
|
require 'zoho_hub/settings/module'
|
12
14
|
|
13
15
|
require 'zoho_hub/reflection/module_builder'
|
@@ -39,7 +41,7 @@ module ZohoHub
|
|
39
41
|
|
40
42
|
connection_params = params.dup.slice(:access_token, :expires_in, :api_domain, :refresh_token)
|
41
43
|
|
42
|
-
@connection = Connection.new(connection_params)
|
44
|
+
@connection = Connection.new(**connection_params)
|
43
45
|
end
|
44
46
|
|
45
47
|
def connection
|
data/lib/zoho_hub/auth.rb
CHANGED
data/lib/zoho_hub/base_record.rb
CHANGED
@@ -12,7 +12,7 @@ module ZohoHub
|
|
12
12
|
include WithAttributes
|
13
13
|
include WithValidations
|
14
14
|
|
15
|
-
# Default
|
15
|
+
# Default number of records when fetching all.
|
16
16
|
DEFAULT_RECORDS_PER_PAGE = 200
|
17
17
|
|
18
18
|
# Default page number when fetching all.
|
@@ -49,7 +49,11 @@ module ZohoHub
|
|
49
49
|
# see https://www.zoho.com/crm/help/developer/api/search-records.html
|
50
50
|
params
|
51
51
|
else
|
52
|
-
|
52
|
+
key = attr_to_zoho_key(params.keys.first)
|
53
|
+
|
54
|
+
{
|
55
|
+
criteria: "#{key}:equals:#{params.values.first}"
|
56
|
+
}
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
@@ -78,6 +82,53 @@ module ZohoHub
|
|
78
82
|
new(id: id).blueprint_transition(transition_id, data)
|
79
83
|
end
|
80
84
|
|
85
|
+
def blueprint_transitions(id)
|
86
|
+
new(id: id).blueprint_transitions
|
87
|
+
end
|
88
|
+
|
89
|
+
def add_note(id:, title: '', content: '')
|
90
|
+
path = File.join(request_path, id, 'Notes')
|
91
|
+
post(path, data: [{ Note_Title: title, Note_Content: content }])
|
92
|
+
end
|
93
|
+
|
94
|
+
def all_related(parent_module:, parent_id:)
|
95
|
+
body = get(File.join(parent_module.constantize.request_path, parent_id, request_path))
|
96
|
+
response = build_response(body)
|
97
|
+
|
98
|
+
data = response.nil? ? [] : response.data
|
99
|
+
|
100
|
+
data.map { |json| new(json) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def update_related(parent_module:, parent_id:, related_id:, data:)
|
104
|
+
path = File.join(
|
105
|
+
parent_module.constantize.request_path, parent_id, request_path, related_id
|
106
|
+
)
|
107
|
+
body = put(path, data: data)
|
108
|
+
build_response(body)
|
109
|
+
end
|
110
|
+
|
111
|
+
def add_related(parent_module:, parent_id:, related_id:)
|
112
|
+
update_related(
|
113
|
+
parent_module: parent_module, parent_id: parent_id, related_id: related_id, data: [{}]
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
def remove_related(parent_module:, parent_id:, related_id:)
|
118
|
+
body = delete(
|
119
|
+
File.join(parent_module.constantize.request_path, parent_id, request_path, related_id)
|
120
|
+
)
|
121
|
+
build_response(body)
|
122
|
+
end
|
123
|
+
|
124
|
+
def update_all(records)
|
125
|
+
zoho_params = records.transform_keys { |key| attr_to_zoho_key(key) }
|
126
|
+
|
127
|
+
body = put(File.join(request_path), data: zoho_params)
|
128
|
+
|
129
|
+
build_response(body)
|
130
|
+
end
|
131
|
+
|
81
132
|
def all(params = {})
|
82
133
|
params[:page] ||= DEFAULT_PAGE
|
83
134
|
params[:per_page] ||= DEFAULT_RECORDS_PER_PAGE
|
@@ -103,6 +154,7 @@ module ZohoHub
|
|
103
154
|
response = Response.new(body)
|
104
155
|
|
105
156
|
raise InvalidTokenError, response.msg if response.invalid_token?
|
157
|
+
raise InternalError, response.msg if response.internal_error?
|
106
158
|
raise RecordInvalid, response.msg if response.invalid_data?
|
107
159
|
raise InvalidModule, response.msg if response.invalid_module?
|
108
160
|
raise NoPermission, response.msg if response.no_permission?
|
@@ -116,8 +168,9 @@ module ZohoHub
|
|
116
168
|
def initialize(params = {})
|
117
169
|
attributes.each do |attr|
|
118
170
|
zoho_key = attr_to_zoho_key(attr)
|
171
|
+
value = params[zoho_key].nil? ? params[attr] : params[zoho_key]
|
119
172
|
|
120
|
-
send("#{attr}=",
|
173
|
+
send("#{attr}=", value)
|
121
174
|
end
|
122
175
|
end
|
123
176
|
|
@@ -134,14 +187,21 @@ module ZohoHub
|
|
134
187
|
end
|
135
188
|
|
136
189
|
def update(params)
|
137
|
-
zoho_params =
|
190
|
+
zoho_params = params.transform_keys { |key| attr_to_zoho_key(key) }
|
138
191
|
body = put(File.join(self.class.request_path, id), data: [zoho_params])
|
192
|
+
|
139
193
|
build_response(body)
|
140
194
|
end
|
141
195
|
|
142
196
|
def blueprint_transition(transition_id, data = {})
|
143
197
|
body = put(File.join(self.class.request_path, id, 'actions/blueprint'),
|
144
198
|
blueprint: [{ transition_id: transition_id, data: data }])
|
199
|
+
|
200
|
+
build_response(body)
|
201
|
+
end
|
202
|
+
|
203
|
+
def blueprint_transitions
|
204
|
+
body = get(File.join(self.class.request_path, id, 'actions/blueprint'))
|
145
205
|
build_response(body)
|
146
206
|
end
|
147
207
|
|
@@ -62,7 +62,7 @@ module ZohoHub
|
|
62
62
|
url = ZohoHub::Auth.auth_url
|
63
63
|
Launchy.open(url)
|
64
64
|
|
65
|
-
puts
|
65
|
+
puts 'Running callback server....'
|
66
66
|
ZohoHub::OauthCallbackServer.run!
|
67
67
|
end
|
68
68
|
|
@@ -79,13 +79,13 @@ module ZohoHub
|
|
79
79
|
def parse(argv, _env)
|
80
80
|
parser.parse!(argv)
|
81
81
|
true
|
82
|
-
rescue OptionParser::ParseError =>
|
83
|
-
error_output(
|
82
|
+
rescue OptionParser::ParseError => e
|
83
|
+
error_output(e)
|
84
84
|
end
|
85
85
|
|
86
86
|
def error_output(error)
|
87
|
-
|
88
|
-
|
87
|
+
warn "Error: #{error}"
|
88
|
+
warn "Try `#{parser.program_name} server --help' for more information"
|
89
89
|
|
90
90
|
false
|
91
91
|
end
|
@@ -107,13 +107,13 @@ module ZohoHub
|
|
107
107
|
def parse(argv, _env)
|
108
108
|
parser.parse!(argv)
|
109
109
|
true
|
110
|
-
rescue OptionParser::ParseError =>
|
111
|
-
error_output(
|
110
|
+
rescue OptionParser::ParseError => e
|
111
|
+
error_output(e)
|
112
112
|
end
|
113
113
|
|
114
114
|
def error_output(error)
|
115
|
-
|
116
|
-
|
115
|
+
warn "Error: #{error}"
|
116
|
+
warn "Try `#{parser.program_name} server --help' for more information"
|
117
117
|
|
118
118
|
false
|
119
119
|
end
|
data/lib/zoho_hub/connection.rb
CHANGED
@@ -31,7 +31,7 @@ module ZohoHub
|
|
31
31
|
|
32
32
|
BASE_PATH = '/crm/v2/'
|
33
33
|
|
34
|
-
def initialize(access_token
|
34
|
+
def initialize(access_token: nil, api_domain: nil, expires_in: 3600, refresh_token: nil)
|
35
35
|
@access_token = access_token
|
36
36
|
@expires_in = expires_in
|
37
37
|
@api_domain = api_domain || self.class.infer_api_domain
|
@@ -88,7 +88,7 @@ module ZohoHub
|
|
88
88
|
response = Response.new(http_response.body)
|
89
89
|
|
90
90
|
# Try to refresh the token and try again
|
91
|
-
if response.invalid_token? && refresh_token?
|
91
|
+
if (response.invalid_token? || response.authentication_failure?) && refresh_token?
|
92
92
|
log "Refreshing outdated token... #{@access_token}"
|
93
93
|
params = ZohoHub::Auth.refresh_token(@refresh_token)
|
94
94
|
|
@@ -116,6 +116,7 @@ module ZohoHub
|
|
116
116
|
def adapter
|
117
117
|
Faraday.new(url: base_url) do |conn|
|
118
118
|
conn.headers = authorization_header if access_token?
|
119
|
+
conn.use FaradayMiddleware::EncodeJson
|
119
120
|
conn.use FaradayMiddleware::ParseJson
|
120
121
|
conn.response :json, parser_options: { symbolize_names: true }
|
121
122
|
conn.response :logger if ZohoHub.configuration.debug?
|
data/lib/zoho_hub/errors.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zoho_hub/base_record'
|
4
|
+
|
5
|
+
module ZohoHub
|
6
|
+
class BaseRecord
|
7
|
+
class << self
|
8
|
+
def related_attachments(parent_id:)
|
9
|
+
body = get(File.join(request_path, parent_id, 'Attachments'))
|
10
|
+
response = build_response(body)
|
11
|
+
|
12
|
+
data = response.nil? ? [] : response.data
|
13
|
+
|
14
|
+
data.map { |json| Attachment.new(json) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def download_attachment(parent_id:, attachment_id:)
|
18
|
+
attachment = related_attachments(parent_id: parent_id).find { |a| a.id == attachment_id }
|
19
|
+
uri = File.join(request_path, parent_id, 'Attachments', attachment_id)
|
20
|
+
res = ZohoHub.connection.adapter.get(uri)
|
21
|
+
attachment.content_type = res.headers['content-type']
|
22
|
+
extension = File.extname(attachment.file_name)
|
23
|
+
basename = File.basename(attachment.file_name, extension)
|
24
|
+
file = Tempfile.new([basename, extension])
|
25
|
+
file.binmode
|
26
|
+
file.write(res.body)
|
27
|
+
file.rewind
|
28
|
+
attachment.file = file
|
29
|
+
attachment
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Attachment < BaseRecord
|
35
|
+
attributes :id, :file_name, :created_by, :modified_by, :owner, :parent_id, :created_time,
|
36
|
+
:modified_time, :size
|
37
|
+
|
38
|
+
attribute_translation id: :id
|
39
|
+
attr_accessor :content_type, :file
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zoho_hub/response'
|
4
|
+
require 'zoho_hub/with_connection'
|
5
|
+
|
6
|
+
module ZohoHub
|
7
|
+
class Notifications
|
8
|
+
include WithConnection
|
9
|
+
|
10
|
+
# Default number of records when fetching all.
|
11
|
+
DEFAULT_RECORDS_PER_PAGE = 200
|
12
|
+
|
13
|
+
# Default page number when fetching all.
|
14
|
+
DEFAULT_PAGE = 1
|
15
|
+
|
16
|
+
# Minimum number of records to fetch when fetching all.
|
17
|
+
MIN_RECORDS = 2
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def request_path
|
21
|
+
@request_path = 'actions/watch'
|
22
|
+
end
|
23
|
+
|
24
|
+
def all(params = {})
|
25
|
+
params[:page] ||= DEFAULT_PAGE
|
26
|
+
params[:per_page] ||= DEFAULT_RECORDS_PER_PAGE
|
27
|
+
params[:per_page] = MIN_RECORDS if params[:per_page] < MIN_RECORDS
|
28
|
+
|
29
|
+
body = get(request_path, params)
|
30
|
+
return [] if body.nil?
|
31
|
+
|
32
|
+
build_response(body)
|
33
|
+
end
|
34
|
+
|
35
|
+
def enable(notify_url, channel_id, events, channel_expiry = nil, token = nil)
|
36
|
+
body = post(request_path, watch: [{ notify_url: notify_url,
|
37
|
+
channel_id: channel_id,
|
38
|
+
events: events,
|
39
|
+
channel_expiry: channel_expiry,
|
40
|
+
token: token }])
|
41
|
+
build_response(body)
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_response(body)
|
45
|
+
response = Response.new(body)
|
46
|
+
|
47
|
+
raise RecordInvalid, response.msg if response.invalid_data?
|
48
|
+
raise MandatoryNotFound, response.msg if response.mandatory_not_found?
|
49
|
+
|
50
|
+
response.data
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/zoho_hub/response.rb
CHANGED
@@ -14,6 +14,10 @@ module ZohoHub
|
|
14
14
|
error_code?('INVALID_TOKEN')
|
15
15
|
end
|
16
16
|
|
17
|
+
def internal_error?
|
18
|
+
error_code?('INTERNAL_ERROR')
|
19
|
+
end
|
20
|
+
|
17
21
|
def authentication_failure?
|
18
22
|
error_code?('AUTHENTICATION_FAILURE')
|
19
23
|
end
|
@@ -39,7 +43,7 @@ module ZohoHub
|
|
39
43
|
end
|
40
44
|
|
41
45
|
def data
|
42
|
-
data = @params[:data] if @params
|
46
|
+
data = @params[:data] if @params[:data]
|
43
47
|
data || @params
|
44
48
|
end
|
45
49
|
|
@@ -59,12 +63,13 @@ module ZohoHub
|
|
59
63
|
msg
|
60
64
|
end
|
61
65
|
|
62
|
-
#
|
63
|
-
# {"data":[{"code":"INVALID_DATA","details":{},"message":"the id given
|
66
|
+
# Error response examples:
|
67
|
+
# {"data":[{"code":"INVALID_DATA","details":{},"message":"the id given...","status":"error"}]}
|
64
68
|
# {:code=>"INVALID_TOKEN", :details=>{}, :message=>"invalid oauth token", :status=>"error"}
|
65
69
|
def error_code?(code)
|
66
70
|
if data.is_a?(Array)
|
67
71
|
return false if data.size > 1
|
72
|
+
|
68
73
|
return data.first[:code] == code
|
69
74
|
end
|
70
75
|
|
data/lib/zoho_hub/version.rb
CHANGED
@@ -44,8 +44,11 @@ module ZohoHub
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def attr_to_zoho_key(attr_name)
|
47
|
-
|
48
|
-
|
47
|
+
if attribute_translation.key?(attr_name.to_sym)
|
48
|
+
return attribute_translation[attr_name.to_sym]
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_name.to_s.split('_').map(&:capitalize).join('_').to_sym
|
49
52
|
end
|
50
53
|
|
51
54
|
def zoho_key_translation
|
@@ -62,11 +65,12 @@ module ZohoHub
|
|
62
65
|
# github.com/rails/rails/blob/master/activemodel/lib/active_model/attribute_assignment.rb
|
63
66
|
def assign_attributes(new_attributes)
|
64
67
|
unless new_attributes.is_a?(Hash)
|
65
|
-
raise ArgumentError,
|
68
|
+
raise ArgumentError, 'When assigning attributes, you must pass a hash as an argument'
|
66
69
|
end
|
70
|
+
|
67
71
|
return if new_attributes.empty?
|
68
72
|
|
69
|
-
attributes =
|
73
|
+
attributes = new_attributes.transform_keys(&:to_s)
|
70
74
|
attributes.each do |k, v|
|
71
75
|
assign_attribute(k, v)
|
72
76
|
end
|
@@ -86,13 +90,12 @@ module ZohoHub
|
|
86
90
|
zoho_key.to_sym
|
87
91
|
end
|
88
92
|
|
89
|
-
def assign_attribute(
|
90
|
-
setter = :"#{
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
93
|
+
def assign_attribute(key, value)
|
94
|
+
setter = :"#{key}="
|
95
|
+
|
96
|
+
return public_send(setter, value) if respond_to?(setter)
|
97
|
+
|
98
|
+
raise ArgumentError, "Unknown attribute #{key}"
|
96
99
|
end
|
97
100
|
end
|
98
101
|
end
|
@@ -13,11 +13,11 @@ module ZohoHub
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def post(path, params = {})
|
16
|
-
ZohoHub.connection.post(path, params
|
16
|
+
ZohoHub.connection.post(path, params)
|
17
17
|
end
|
18
18
|
|
19
19
|
def put(path, params = {})
|
20
|
-
ZohoHub.connection.put(path, params
|
20
|
+
ZohoHub.connection.put(path, params)
|
21
21
|
end
|
22
22
|
|
23
23
|
def delete(path, params = {})
|
data/zoho_hub.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.required_ruby_version = '>= 2.1.0'
|
27
27
|
|
28
28
|
spec.add_dependency 'addressable'
|
29
|
-
spec.add_dependency 'backports'
|
29
|
+
spec.add_dependency 'backports'
|
30
30
|
spec.add_dependency 'faraday'
|
31
31
|
spec.add_dependency 'faraday_middleware'
|
32
32
|
spec.add_dependency 'launchy'
|
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_dependency 'rainbow'
|
35
35
|
spec.add_dependency 'sinatra'
|
36
36
|
|
37
|
+
spec.add_development_dependency 'activesupport'
|
37
38
|
spec.add_development_dependency 'bundler'
|
38
39
|
spec.add_development_dependency 'dotenv'
|
39
40
|
spec.add_development_dependency 'pry-byebug'
|
@@ -42,4 +43,5 @@ Gem::Specification.new do |spec|
|
|
42
43
|
spec.add_development_dependency 'rubocop'
|
43
44
|
spec.add_development_dependency 'rubocop-rspec'
|
44
45
|
spec.add_development_dependency 'simplecov'
|
46
|
+
spec.add_development_dependency 'webmock'
|
45
47
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zoho_hub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ricardo Otero
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: backports
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: faraday
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,20 @@ dependencies:
|
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: activesupport
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
111
139
|
- !ruby/object:Gem::Dependency
|
112
140
|
name: bundler
|
113
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -220,6 +248,20 @@ dependencies:
|
|
220
248
|
- - ">="
|
221
249
|
- !ruby/object:Gem::Version
|
222
250
|
version: '0'
|
251
|
+
- !ruby/object:Gem::Dependency
|
252
|
+
name: webmock
|
253
|
+
requirement: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - ">="
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '0'
|
258
|
+
type: :development
|
259
|
+
prerelease: false
|
260
|
+
version_requirements: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - ">="
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '0'
|
223
265
|
description: Simple gem to connect to Zoho CRM API V2
|
224
266
|
email:
|
225
267
|
- oterosantos@gmail.com
|
@@ -228,11 +270,11 @@ executables:
|
|
228
270
|
extensions: []
|
229
271
|
extra_rdoc_files: []
|
230
272
|
files:
|
273
|
+
- ".github/workflows/ci.yml"
|
231
274
|
- ".gitignore"
|
232
275
|
- ".rspec"
|
233
276
|
- ".rubocop.yml"
|
234
277
|
- ".ruby-version"
|
235
|
-
- ".travis.yml"
|
236
278
|
- Gemfile
|
237
279
|
- LICENSE.txt
|
238
280
|
- README.md
|
@@ -253,6 +295,8 @@ files:
|
|
253
295
|
- lib/zoho_hub/configuration.rb
|
254
296
|
- lib/zoho_hub/connection.rb
|
255
297
|
- lib/zoho_hub/errors.rb
|
298
|
+
- lib/zoho_hub/modules/attachment.rb
|
299
|
+
- lib/zoho_hub/notifications.rb
|
256
300
|
- lib/zoho_hub/oauth_callback_server.rb
|
257
301
|
- lib/zoho_hub/reflection/module_builder.rb
|
258
302
|
- lib/zoho_hub/response.rb
|
@@ -272,7 +316,7 @@ homepage: https://github.com/rikas/zoho_hub
|
|
272
316
|
licenses:
|
273
317
|
- MIT
|
274
318
|
metadata: {}
|
275
|
-
post_install_message:
|
319
|
+
post_install_message:
|
276
320
|
rdoc_options: []
|
277
321
|
require_paths:
|
278
322
|
- lib
|
@@ -287,9 +331,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
287
331
|
- !ruby/object:Gem::Version
|
288
332
|
version: '0'
|
289
333
|
requirements: []
|
290
|
-
rubyforge_project:
|
291
|
-
rubygems_version: 2.7.6
|
292
|
-
signing_key:
|
334
|
+
rubyforge_project:
|
335
|
+
rubygems_version: 2.7.6.2
|
336
|
+
signing_key:
|
293
337
|
specification_version: 4
|
294
338
|
summary: Simple gem to connect to Zoho CRM API V2
|
295
339
|
test_files: []
|