zoho_hub 0.3.0 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1967126d56677efb3373c3a3d8700842f5d03e0f3b0cb922b4ffcf5d113a831
4
- data.tar.gz: 1cf0f3e67da7d878dd367614c3da7441d0024fe070dae978f72e49575e6be013
3
+ metadata.gz: d69358949e8262ad9da808101b0bbb2da5d0eae262d2d34ab032e5097d58f5ba
4
+ data.tar.gz: a0b64a4714925fa5a6392e43ecd991aaf71e9b3991e4505a5d2703bca22f8269
5
5
  SHA512:
6
- metadata.gz: 203045fd8b960ae3dd03873106ea7a88a111bbd6618d9942e9c597cdef83ba860792639e13e92b7a32ad0d550b9521795ab8c4043dc8e9e2de44321a5e2a7990
7
- data.tar.gz: ac2a1e1e7bca5a28196d9cdc68312c1a8774ddc1666266a0a4956587b482bf255da15aa50f9c05cb593a6768103f3b939a91ed692c16641cd26976ce51f63243
6
+ metadata.gz: d02305e21aae61e11f09a010b8f22dab327af638b036ca075abb47e0943eaad1870355e976c208b00c9a5dfa87f05ff82f60754fd50f1eccee97e37a7e3c8967
7
+ data.tar.gz: 756fb2bd03d39e70f46fdc04eb34bea1310701b72ba363a3b6c79fab033ccf5defa2b615edcae9af6c86cae45dacf24bcefd59c3c17ff2a4c3b7456f0595b0ed
@@ -0,0 +1,37 @@
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
+ steps:
30
+ - uses: actions/checkout@v2
31
+ - uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: ${{matrix.ruby}}
34
+ bundler-cache: true
35
+ - name: Run tests
36
+ timeout-minutes: 5
37
+ 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.3
1
+ 2.7.6
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # ZohoHub
2
2
 
3
- [![Build Status](https://travis-ci.com/rikas/zoho_hub.svg?branch=master)](https://travis-ci.com/rikas/zoho_hub)
4
3
  [![Gem Version](https://badge.fury.io/rb/zoho_hub.svg)](https://badge.fury.io/rb/zoho_hub)
5
4
 
6
- Simple wrapper around Zoho CRM version2, using [OAuth 2.0 protocol](https://www.zoho.com/crm/help/developer/api/oauth-overview.html)
7
- for authentication.
5
+ Simple wrapper around Zoho CRM version2, using
6
+ [OAuth 2.0 protocol](https://www.zoho.com/crm/help/developer/api/oauth-overview.html) for authentication.
8
7
 
9
8
  This gem reads your Module configuration and builds the corresponding classes for you, using some
10
9
  reflection mechanisms. You should then be able to use simple classes with an API close to
@@ -12,6 +11,38 @@ ActiveRecord, to do CRUD operations.
12
11
 
13
12
  **NOTE: this gem is WIP, please try to use it and open an issue if you run into limitations / problems**
14
13
 
14
+ ## Table of Contents
15
+
16
+ - [ZohoHub](#zohohub)
17
+ - [Table of Contents](#table-of-contents)
18
+ - [Installation](#installation)
19
+ - [Setup process](#setup-process)
20
+ - [1. Register your application](#1-register-your-application)
21
+ - [1.1 Zoho Accounts URL](#11-zoho-accounts-url)
22
+ - [1.2 Authorized Redirect URI](#12-authorized-redirect-uri)
23
+ - [2. Configure ZohoHub with your credentials](#2-configure-zohohub-with-your-credentials)
24
+ - [3. Authorization request](#3-authorization-request)
25
+ - [3.1 Redirection based authentication](#31-redirection-based-authentication)
26
+ - [3.2 Self-Client Authorization](#32-self-client-authorization)
27
+ - [3.3 More on scopes](#33-more-on-scopes)
28
+ - [3.4 Offline access](#34-offline-access)
29
+ - [4. Access token](#4-access-token)
30
+ - [5. Refresh token](#5-refresh-token)
31
+ - [6. Basic ZohoHub flow](#6-basic-zohohub-flow)
32
+ - [7. BaseRecord and record classes](#7-baserecord-and-record-classes)
33
+ - [7.1 Reflection](#71-reflection)
34
+ - [7.2 Subclassing BaseRecord](#72-subclassing-baserecord)
35
+ - [8 Notifications](#8-notifications)
36
+ - [8.1 Enable notifications](#81-enable-notifications)
37
+ - [8.2 List notifications](#82-list-notifications)
38
+ - [8.3 Caveats](#83-caveats)
39
+ - [Tips and suggestions](#tips-and-suggestions)
40
+ - [Examples](#examples)
41
+ - [Setup auth token and request CurrentUser](#setup-auth-token-and-request-currentuser)
42
+ - [Development](#development)
43
+ - [Contributing](#contributing)
44
+ - [License](#license)
45
+
15
46
  ## Installation
16
47
 
17
48
  Add this line to your application's Gemfile:
@@ -35,19 +66,21 @@ Or install it yourself as:
35
66
  If you want to access your Zoho CRM account from your application you first need to create your
36
67
  application as described here: https://www.zoho.com/crm/help/developer/api/register-client.html.
37
68
 
38
- This will give you a **Client ID** and a **secret**, that you'll use in step 2.
69
+ This will give you a **Client ID** and a **secret**, that you'll use in
70
+ [step 2](#2-configure-zohohub-with-your-credentials).
39
71
 
40
72
  #### 1.1 Zoho Accounts URL
41
73
 
42
74
  Registration and authorization requests are made to Zoho's domain-specific Accounts URL which
43
75
  varies depending on your region:
44
76
 
45
- * EU: https://accounts.zoho.eu
46
- * US: https://accounts.zoho.com
47
- * China: https://accounts.zoho.com.cn
77
+ - China: https://accounts.zoho.com.cn
78
+ - EU: https://accounts.zoho.eu
79
+ - India: https://accounts.zoho.in
80
+ - US: https://accounts.zoho.com
48
81
 
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.)
82
+ ZohoHub uses the EU Account URL by default, but this can be overriden in a `ZohoHub.configure` block
83
+ via the `api_domain` method ([step 2](#2-configure-zohohub-with-your-credentials).)
51
84
 
52
85
  #### 1.2 Authorized Redirect URI
53
86
 
@@ -55,17 +88,20 @@ Per Zoho's API documentation, providing a **redirect URI** is optional. Doing so
55
88
  your application to be redirected back to your app (to the **redirect URI**) with a **grant token**
56
89
  upon successful authentication.
57
90
 
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.)
91
+ If you don't provide a **redirect URI**, you'll need to use the
92
+ [self-client option](https://www.zoho.com/crm/help/developer/api/auth-request.html#self-client) for
93
+ authorization (see [3.2](#32-self-client-authorization).)
94
+
95
+ ---
60
96
 
61
97
  ### 2. Configure ZohoHub with your credentials
62
98
 
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
99
+ > **Note:** Treat these credentials like an important password. It is _strongly_ recommended to not
100
+ > paste them anywhere in plain text. Do _not_ add them to version control; keep them out of your
65
101
  > code directly by referencing them via environment variables. Use something like the dotenv gem or
66
102
  > encrypted credentials in Rails to keep them as secret and secure as possible.
67
103
 
68
- You need to have a configuration block like the one below (in rails add a `zoho_hub.rb` in your
104
+ You need to have a configuration block like the one below (in Rails add a `zoho_hub.rb` in your
69
105
  `config/initializers` directory):
70
106
 
71
107
  ```ruby
@@ -78,6 +114,8 @@ ZohoHub.configure do |config|
78
114
  end
79
115
  ```
80
116
 
117
+ ---
118
+
81
119
  ### 3. Authorization request
82
120
 
83
121
  In order to access data in Zoho CRM you need to authorize ZohoHub to access your account. To do so
@@ -94,7 +132,8 @@ ZohoHub::Auth.auth_url
94
132
  # => "https://accounts.zoho.eu/oauth/v2/auth?access_type=offline&client_id=&redirect_uri=&response_type=code&scope=ZohoCRM.modules.custom.all,ZohoCRM.settings.all,ZohoCRM.modules.contacts.all,ZohoCRM.modules.all"
95
133
  ```
96
134
 
97
- If you request this generated URL you should see a screen like this one, where you have to click on "Accept":
135
+ If you request this generated URL you should see a screen like this one, where you have to click on
136
+ "Accept":
98
137
 
99
138
  ![](https://duaw26jehqd4r.cloudfront.net/items/1h1i3C1N0k0i02092F0S/Screen%20Shot%202018-11-25%20at%2019.18.38.png)
100
139
 
@@ -109,7 +148,8 @@ as follows (the value after `code=` is the **grant token**):
109
148
 
110
149
  If you don't have a **redirect URI** or you want your application to be able to authorize with Zoho
111
150
  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)
151
+ provides a
152
+ [self-client option](https://www.zoho.com/crm/help/developer/api/auth-request.html#self-client)
113
153
  for authentication which will provide a **grant token**.
114
154
 
115
155
  #### 3.3 More on scopes
@@ -127,11 +167,13 @@ ZohoCRM.modules.all
127
167
  To get the URL for a different scope you can provide a `scope` argument:
128
168
 
129
169
  ```ruby
130
- ZohoHub::Auth.auth_url(scope: ['ZohoCRM.modules.custom.all', 'ZohoCRM.modules.all'])
170
+ ZohoHub::Auth.auth_url(scopes: ['ZohoCRM.modules.custom.all', 'ZohoCRM.modules.all'])
131
171
  # => "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"
132
172
  ```
133
173
 
134
- Refer to [Zoho's API documentation on scopes](https://www.zoho.com/crm/help/developer/api/oauth-overview.html#plink5) for detailed information.
174
+ Refer to
175
+ [Zoho's API documentation on scopes](https://www.zoho.com/crm/help/developer/api/oauth-overview.html#scopes)
176
+ for detailed information.
135
177
 
136
178
  #### 3.4 Offline access
137
179
 
@@ -139,9 +181,9 @@ By design the **access tokens** returned by the OAuth flow expire after a period
139
181
  default), as a safety mechanism. This means that any application that wants to work with a user's
140
182
  data needs the user to have recently gone through the OAuth flow, aka be online.
141
183
 
142
- When you request offline access the Zoho API returns a **refresh token**. **Refresh tokens** give your
143
- application the ability to request data on behalf of the user when the user is not present and in
144
- front of your application.
184
+ When you request offline access the Zoho API returns a **refresh token**. **Refresh tokens** give
185
+ your application the ability to request data on behalf of the user when the user is not present and
186
+ in front of your application.
145
187
 
146
188
  **By default `ZohoHub::Auth.auth_url` will request offline access**
147
189
 
@@ -152,6 +194,8 @@ ZohoHub::Auth.auth_url(access_type: 'online')
152
194
  # => "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"
153
195
  ```
154
196
 
197
+ ---
198
+
155
199
  ### 4. Access token
156
200
 
157
201
  See Zoho's API documentation for generating an initial **access token**:
@@ -163,10 +207,15 @@ To use an **access token** in a manual request, include it as a request header a
163
207
  To use an **access token** with ZohoHub, pass it to the `ZohoHub.setup_connection` method as the
164
208
  `access_token` parameter.
165
209
 
210
+ ---
166
211
 
167
212
  ### 5. Refresh token
168
213
 
169
- TODO
214
+ This gem automatically refresh the access token.
215
+
216
+ If you want automatic refresh, use the `refresh_token` argument as in the next chapter.
217
+
218
+ ---
170
219
 
171
220
  ### 6. Basic ZohoHub flow
172
221
 
@@ -176,7 +225,8 @@ token**, setup a ZohoHub connection:
176
225
  ```ruby
177
226
  ZohoHub.setup_connection access_token: 'ACCESS_TOKEN',
178
227
  expires_in: 'EXPIRES_IN_SEC',
179
- api_domain: 'API_DOMAIN'
228
+ api_domain: 'API_DOMAIN',
229
+ refresh_token: 'REFRESH_TOKEN'
180
230
  ```
181
231
 
182
232
  Now you can issue requests to Zoho's API with the Connection object, e.g.:
@@ -186,7 +236,10 @@ Now you can issue requests to Zoho's API with the Connection object, e.g.:
186
236
  ZohoHub.connection.get 'Leads'
187
237
  ```
188
238
 
189
- A successful request will receive a response like the sample here: https://www.zoho.com/crm/help/developer/api/get-records.html.
239
+ A successful request will receive a response like the sample here:
240
+ https://www.zoho.com/crm/help/developer/api/get-records.html.
241
+
242
+ ---
190
243
 
191
244
  ### 7. BaseRecord and record classes
192
245
 
@@ -208,7 +261,7 @@ inherits from `ZohoHub::BaseRecord`. For example, to build a class for the Leads
208
261
  ```ruby
209
262
  # lead.rb
210
263
 
211
- class Lead < BaseRecord
264
+ class Lead < ZohoHub::BaseRecord
212
265
  ...
213
266
  end
214
267
  ```
@@ -218,44 +271,231 @@ Specify this module's fields as attributes:
218
271
  ```ruby
219
272
  # lead.rb
220
273
 
221
- class Lead < BaseRecord
222
- attributes: :id, :first_name, :last_name, :phone, :email, :source, # etc.
274
+ class Lead < ZohoHub::BaseRecord
275
+ attributes :id, :first_name, :last_name, :phone, :email, :source, # etc.
223
276
  end
224
277
  ```
225
278
 
226
- Define an `initialize` method to populate attributes:
279
+ Now you can issue requests more easily with your record class, e.g.:
227
280
 
228
281
  ```ruby
229
- def initialize(params)
230
- attributes.each do |attr|
231
- zoho_key = attr_to_zoho_key(attr)
282
+ # Request a (paginated) list of all Lead records
283
+ Lead.all
232
284
 
233
- send("#{attr}=", params[zoho_key] || params[attr] || DEFAULTS[attr])
234
- end
235
- end
285
+ # Get the Lead instance with a specific ID
286
+ Lead.find('78265000003433063')
236
287
  ```
237
288
 
238
- Now you can issue requests more easily with your record class, e.g.:
289
+ And even create new Lead entries in Zoho:
239
290
 
240
291
  ```ruby
241
- # request a (paginated) list of all Lead records
242
- Lead.all
292
+ lead = Lead.new(
293
+ first_name: 'First name',
294
+ last_name: 'Last name',
295
+ phone: '+35197736281',
296
+ email: 'myemail@gmail.com',
297
+ source: 'Homepage'
298
+ )
299
+
300
+ # Creates the new lead
301
+ lead.save
302
+
303
+ # Or in one step:
304
+ lead = Lead.create(first_name: 'First name', ...)
305
+ ```
306
+
307
+ Updating records:
308
+
309
+ ```ruby
310
+ Lead.update(id: lead.id, first_name: "...", last_name: "...")
311
+
312
+ # Or
313
+ lead.update(first_name: "...", last_name: "...")
314
+
315
+ # Or update up to 100 records in one call:
316
+ leads = [{ id: id1, phone: "123" }, { id: id2, first_name: "..." }]
317
+ Lead.update_all(leads)
318
+ ```
319
+
320
+ Blueprint transition:
321
+
322
+ ```ruby
323
+ Lead.blueprint_transition(lead.id, transition_id)
324
+
325
+ # Or
326
+ lead.blueprint_transition(transition_id)
327
+ ```
328
+
329
+ Adding notes:
330
+
331
+ ```ruby
332
+ Lead.add_note(id: lead.id, title: 'Note title', content: 'Note content')
333
+ ```
334
+
335
+ Related records:
336
+
337
+ ```ruby
338
+ Product.all_related(parent_module: 'Lead', parent_id: lead.id)
339
+ Product.add_related(
340
+ parent_module: 'Lead',
341
+ parent_id: lead.id,
342
+ related_id: product.id
343
+ )
344
+ Product.remove_related(
345
+ parent_module: 'Lead',
346
+ parent_id: lead.id,
347
+ related_id: product.id
348
+ )
349
+ Product.update_related(...)
350
+ ```
351
+
352
+ Attachments (`ZohoHub::Attachment` is defined in the gem):
353
+
354
+ ```ruby
355
+ Lead.related_attachments(parent_id: lead.id)
356
+ # -> Array of Attachments
357
+
358
+ attachment = Lead.download_attachment(parent_id: lead.id, attachment_id:attachment.id)
359
+ # -> Attachment (attachment.file contains the file as a Tempfile)
360
+
361
+ #NB: Lead.upload_attachment not implemented yet
362
+ ```
363
+
364
+ ## 8 Notifications
365
+
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
+
370
+ In order to receive notifications, you have to enable them first.
371
+
372
+ ```ruby
373
+ # Enable notifications for a given channel:
374
+ notification_url = 'https://example.org/api/notifications' # Zoho will send notifications by POST to this url
375
+ token = '123abc' # Zoho will send this token back to you, so you can ensure that the notification is from Zoho
376
+ channel_id = 1 # Choose a channel to handle the response
377
+ events = %w[Leads.create Deals.edit Contacts.delete Sales_Orders.all] # Which events to receive notifications for
378
+ channel_expiry = (DateTime.now + 1.day).iso8601 # choose a date when the channel should expire. 24h is the maximum, default is one hour
379
+
380
+ ZohoHub::Notifications.enable(notification_url, channel_id, events, channel_expiry, token)
381
+ ```
382
+
383
+ After enabling notifications, Zoho will execute a POST request to the provided notification_url every time the requested event occurs.
384
+
385
+ 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)
386
+
387
+ ### 8.2 List notifications
388
+
389
+ You can also retrieve all notifications that are currently enabled and that you are receiving uppdates for.
390
+
391
+ ```ruby
392
+ # Get all enabled notifications
393
+ ZohoHub::Notifications.all
243
394
  ```
244
395
 
396
+ ### 8.3 Caveats
397
+
398
+ - Zoho does not notify you when records are merged.
399
+ - 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.
400
+
245
401
  ## Tips and suggestions
246
402
 
247
- * Using a tool such as Postman or curl to issue HTTP requests and verify responses in isolation
403
+ - Using a tool such as Postman or curl to issue HTTP requests and verify responses in isolation
248
404
  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
405
+ - Downloading ZohoHub code (as opposed to the gem) and running `bin/console` is a great way to
250
406
  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
407
+ - [The Zoho API Documentation](https://www.zoho.com/crm/help/developer/api/overview.html) is your
252
408
  friend - especially the sample HTTP requests and responses in the various sections under "Rest
253
409
  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)
410
+ - If you're manually implementing your record classes (rather than using the reflection mechanism),
411
+ the files in `/examples/models/` can help you get started.
412
+ - Requests can be issued to Zoho CRM's
413
+ [Sandbox](https://help.zoho.com/portal/kb/articles/using-sandbox)
257
414
  by configuring `https://crmsandbox.zoho.com/crm` (or regional equivalent) as the `api_domain`.
258
415
 
416
+ ## Examples
417
+
418
+ ### Setup auth token and request CurrentUser
419
+
420
+ > This example assumes use of the dotenv gem and is written directly into
421
+ > ZohoHub's root directory (rather than using ZohoHub as a gem) for simplicity.
422
+
423
+ 1. Edit `bin/console` to comment out refreshing the token and setting up the connection:
424
+
425
+ ```ruby
426
+ # bin/console
427
+
428
+ ...
429
+ # puts 'Refreshing token...'
430
+ # token_params = ZohoHub::Auth.refresh_token(ENV['ZOHO_REFRESH_TOKEN'])
431
+ # ZohoHub.setup_connection(token_params)
432
+ ...
433
+ ```
434
+
435
+ 2. [Register your application](#1-register-your-application) to obtain a **client ID** and
436
+ **secret**. (Leave the [Zoho API Credentials page](https://accounts.zoho.com/developerconsole) open;
437
+ you'll need it in step 5.)
438
+ 3. Determine your [Zoho Accounts URL](#11-zoho-accounts-url).
439
+ 4. Add your registration and account URL information to a `.env` file:
440
+
441
+ ```
442
+ # .env
443
+
444
+ ZOHO_CLIENT_ID=YOUR_CLIENT_ID
445
+ ZOHO_SECRET=YOUR_SECRET
446
+ ZOHO_API_DOMAIN=YOUR_ZOHO_ACCOUNTS_URL
447
+ ```
448
+
449
+ 5. On the [Zoho API Credentials page](https://accounts.zoho.com/developerconsole) from step 1, click
450
+ the three vertical dots and select `Self client`.
451
+ 6. Paste this into the `Scope` field: `ZohoCRM.users.ALL`, choose an expiration time, and click
452
+ `View Code`; this is your **Grant token**.
453
+ 7. Run the ZohoHub console from your terminal: `bin/console`
454
+ 8. Issue a token request with the **grant token** (notice the quotes around the token value):
455
+
456
+ ```ruby
457
+ ZohoHub::Auth.get_token('paste_your_grant_token_here')
458
+ ```
459
+
460
+ This should return a response with an **access token**, e.g.:
461
+
462
+ ```ruby
463
+ => {:access_token=>"ACCESS_TOKEN_VALUE",
464
+ :expires_in_sec=>3600,
465
+ :api_domain=>"https://www.zohoapis.com",
466
+ :token_type=>"Bearer"
467
+ }
468
+ ```
469
+
470
+ exit the console with `exit`.
471
+
472
+ 9. Add the access token to your `.env` file:
473
+
474
+ ```
475
+ # .env
476
+
477
+ ZOHO_CLIENT_ID=YOUR_CLIENT_ID
478
+ ZOHO_SECRET=YOUR_SECRET
479
+ ZOHO_API_DOMAIN=YOUR_ZOHO_ACCOUNTS_URL
480
+ ZOHO_ACCESS_TOKEN=YOUR_ACCESS_TOKEN
481
+ ```
482
+
483
+ 10. Edit `bin/console` to add a new `setup_connection` after the previously commented out one:
484
+
485
+ ```ruby
486
+ # bin/console
487
+
488
+ ...
489
+ # ZohoHub.setup_connection(token_params)
490
+
491
+ ZohoHub.setup_connection(access_token: ENV['ZOHO_ACCESS_TOKEN'])
492
+ ...
493
+ ```
494
+
495
+ 11. Start the console again: `bin/console`.
496
+
497
+ 12. Issue a request for the current user: `ZohoHub.connection.get 'users?type=CurrentUser'`
498
+
259
499
  ## Development
260
500
 
261
501
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run
@@ -270,4 +510,5 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/rikas/
270
510
 
271
511
  ## License
272
512
 
273
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
513
+ The gem is available as open source under the terms of the
514
+ [MIT License](https://opensource.org/licenses/MIT).
data/bin/console CHANGED
@@ -20,7 +20,7 @@ puts 'Refreshing token...'
20
20
  token_params = ZohoHub::Auth.refresh_token(ENV['ZOHO_REFRESH_TOKEN'])
21
21
  ZohoHub.setup_connection(token_params)
22
22
 
23
- self.send(:include, ZohoHub)
23
+ send(:include, ZohoHub)
24
24
 
25
25
  require 'pry'
26
26
  Pry.start
@@ -28,6 +28,8 @@ module ZohoHub
28
28
  )
29
29
 
30
30
  def initialize(params = {})
31
+ super
32
+
31
33
  attributes.each do |attr|
32
34
  zoho_key = attr_to_zoho_key(attr)
33
35
 
data/lib/zoho_hub/auth.rb CHANGED
@@ -20,6 +20,7 @@ module ZohoHub
20
20
  ZohoCRM.settings.all
21
21
  ZohoCRM.modules.contacts.all
22
22
  ZohoCRM.modules.all
23
+ ZohoCRM.notifications.all
23
24
  ].freeze
24
25
 
25
26
  DEFAULT_ACCESS_TYPE = 'offline'
@@ -12,7 +12,7 @@ module ZohoHub
12
12
  include WithAttributes
13
13
  include WithValidations
14
14
 
15
- # Default nnumber of records when fetching all.
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.
@@ -42,6 +42,21 @@ module ZohoHub
42
42
  def where(params)
43
43
  path = File.join(request_path, 'search')
44
44
 
45
+ if params.size == 1
46
+ params = case params.keys.first
47
+ when :criteria, :email, :phone, :word
48
+ # these attributes are directly handled by Zoho
49
+ # see https://www.zoho.com/crm/help/developer/api/search-records.html
50
+ params
51
+ else
52
+ key = attr_to_zoho_key(params.keys.first)
53
+
54
+ {
55
+ criteria: "#{key}:equals:#{params.values.first}"
56
+ }
57
+ end
58
+ end
59
+
45
60
  body = get(path, params)
46
61
  response = build_response(body)
47
62
 
@@ -59,6 +74,61 @@ module ZohoHub
59
74
  new(params).save
60
75
  end
61
76
 
77
+ def update(id, params)
78
+ new(id: id).update(params)
79
+ end
80
+
81
+ def blueprint_transition(id, transition_id, data = {})
82
+ new(id: id).blueprint_transition(transition_id, data)
83
+ end
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.map { |record| record.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
+
62
132
  def all(params = {})
63
133
  params[:page] ||= DEFAULT_PAGE
64
134
  params[:per_page] ||= DEFAULT_RECORDS_PER_PAGE
@@ -84,7 +154,12 @@ module ZohoHub
84
154
  response = Response.new(body)
85
155
 
86
156
  raise InvalidTokenError, response.msg if response.invalid_token?
157
+ raise InternalError, response.msg if response.internal_error?
87
158
  raise RecordInvalid, response.msg if response.invalid_data?
159
+ raise InvalidModule, response.msg if response.invalid_module?
160
+ raise NoPermission, response.msg if response.no_permission?
161
+ raise MandatoryNotFound, response.msg if response.mandatory_not_found?
162
+ raise RecordInBlueprint, response.msg if response.record_in_blueprint?
88
163
 
89
164
  response
90
165
  end
@@ -93,8 +168,9 @@ module ZohoHub
93
168
  def initialize(params = {})
94
169
  attributes.each do |attr|
95
170
  zoho_key = attr_to_zoho_key(attr)
171
+ value = params[zoho_key].nil? ? params[attr] : params[zoho_key]
96
172
 
97
- send("#{attr}=", params[zoho_key] || params[attr])
173
+ send("#{attr}=", value)
98
174
  end
99
175
  end
100
176
 
@@ -110,6 +186,25 @@ module ZohoHub
110
186
  response.data.first.dig(:details, :id)
111
187
  end
112
188
 
189
+ def update(params)
190
+ zoho_params = params.transform_keys { |key| attr_to_zoho_key(key) }
191
+ body = put(File.join(self.class.request_path, id), data: [zoho_params])
192
+
193
+ build_response(body)
194
+ end
195
+
196
+ def blueprint_transition(transition_id, data = {})
197
+ body = put(File.join(self.class.request_path, id, 'actions/blueprint'),
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'))
205
+ build_response(body)
206
+ end
207
+
113
208
  def new_record?
114
209
  !id
115
210
  end
@@ -62,7 +62,7 @@ module ZohoHub
62
62
  url = ZohoHub::Auth.auth_url
63
63
  Launchy.open(url)
64
64
 
65
- puts "Running callback server...."
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 => error
83
- error_output(error)
82
+ rescue OptionParser::ParseError => e
83
+ error_output(e)
84
84
  end
85
85
 
86
86
  def error_output(error)
87
- $stderr.puts "Error: #{error}"
88
- $stderr.puts "Try `#{parser.program_name} server --help' for more information"
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 => error
111
- error_output(error)
110
+ rescue OptionParser::ParseError => e
111
+ error_output(e)
112
112
  end
113
113
 
114
114
  def error_output(error)
115
- $stderr.puts "Error: #{error}"
116
- $stderr.puts "Try `#{parser.program_name} server --help' for more information"
115
+ warn "Error: #{error}"
116
+ warn "Try `#{parser.program_name} server --help' for more information"
117
117
 
118
118
  false
119
119
  end
@@ -9,6 +9,18 @@ require 'zoho_hub/response'
9
9
 
10
10
  module ZohoHub
11
11
  class Connection
12
+ class << self
13
+ def infer_api_domain
14
+ case ZohoHub.configuration.api_domain
15
+ when 'https://accounts.zoho.com' then 'https://www.zohoapis.com'
16
+ when 'https://accounts.zoho.com.cn' then 'https://www.zohoapis.com.cn'
17
+ when 'https://accounts.zoho.in' then 'https://www.zohoapis.in'
18
+ when 'https://accounts.zoho.eu' then 'https://www.zohoapis.eu'
19
+ else DEFAULT_DOMAIN
20
+ end
21
+ end
22
+ end
23
+
12
24
  attr_accessor :debug, :access_token, :expires_in, :api_domain, :refresh_token
13
25
 
14
26
  # This is a block to be run when the token is refreshed. This way you can do whatever you want
@@ -19,10 +31,10 @@ module ZohoHub
19
31
 
20
32
  BASE_PATH = '/crm/v2/'
21
33
 
22
- def initialize(access_token:, api_domain: DEFAULT_DOMAIN, expires_in: 3600, refresh_token: nil)
34
+ def initialize(access_token: nil, api_domain: nil, expires_in: 3600, refresh_token: nil)
23
35
  @access_token = access_token
24
36
  @expires_in = expires_in
25
- @api_domain = api_domain
37
+ @api_domain = api_domain || self.class.infer_api_domain
26
38
  @refresh_token ||= refresh_token # do not overwrite if it's already set
27
39
  end
28
40
 
@@ -76,7 +88,7 @@ module ZohoHub
76
88
  response = Response.new(http_response.body)
77
89
 
78
90
  # Try to refresh the token and try again
79
- if response.invalid_token? && refresh_token?
91
+ if (response.invalid_token? || response.authentication_failure?) && refresh_token?
80
92
  log "Refreshing outdated token... #{@access_token}"
81
93
  params = ZohoHub::Auth.refresh_token(@refresh_token)
82
94
 
@@ -104,6 +116,7 @@ module ZohoHub
104
116
  def adapter
105
117
  Faraday.new(url: base_url) do |conn|
106
118
  conn.headers = authorization_header if access_token?
119
+ conn.use FaradayMiddleware::EncodeJson
107
120
  conn.use FaradayMiddleware::ParseJson
108
121
  conn.response :json, parser_options: { symbolize_names: true }
109
122
  conn.response :logger if ZohoHub.configuration.debug?
@@ -10,6 +10,21 @@ module ZohoHub
10
10
  class InvalidTokenError < StandardError
11
11
  end
12
12
 
13
+ class InternalError < StandardError
14
+ end
15
+
16
+ class InvalidModule < StandardError
17
+ end
18
+
19
+ class NoPermission < StandardError
20
+ end
21
+
22
+ class MandatoryNotFound < StandardError
23
+ end
24
+
25
+ class RecordInBlueprint < StandardError
26
+ end
27
+
13
28
  class ZohoAPIError < StandardError
14
29
  end
15
30
  end
@@ -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
@@ -7,22 +7,35 @@ module ZohoHub
7
7
  end
8
8
 
9
9
  def invalid_data?
10
- return false if data.is_a?(Array)
11
-
12
- data[:code] == 'INVALID_DATA'
10
+ error_code?('INVALID_DATA')
13
11
  end
14
12
 
15
- # {:code=>"INVALID_TOKEN", :details=>{}, :message=>"invalid oauth token", :status=>"error"}
16
13
  def invalid_token?
17
- return false if data.is_a?(Array)
14
+ error_code?('INVALID_TOKEN')
15
+ end
18
16
 
19
- data[:code] == 'INVALID_TOKEN'
17
+ def internal_error?
18
+ error_code?('INTERNAL_ERROR')
20
19
  end
21
20
 
22
21
  def authentication_failure?
23
- return false if data.is_a?(Array)
22
+ error_code?('AUTHENTICATION_FAILURE')
23
+ end
24
+
25
+ def invalid_module?
26
+ error_code?('INVALID_MODULE')
27
+ end
28
+
29
+ def no_permission?
30
+ error_code?('NO_PERMISSION')
31
+ end
24
32
 
25
- data[:code] == 'AUTHENTICATION_FAILURE'
33
+ def mandatory_not_found?
34
+ error_code?('MANDATORY_NOT_FOUND')
35
+ end
36
+
37
+ def record_in_blueprint?
38
+ error_code?('RECORD_IN_BLUEPRINT')
26
39
  end
27
40
 
28
41
  def empty?
@@ -30,17 +43,18 @@ module ZohoHub
30
43
  end
31
44
 
32
45
  def data
33
- data = @params[:data] if @params.dig(:data)
46
+ data = @params[:data] if @params[:data]
34
47
  data || @params
35
48
  end
36
49
 
37
50
  def msg
38
- msg = data[:message]
51
+ first_data = data.is_a?(Array) ? data.first : data
52
+ msg = first_data[:message]
39
53
 
40
- if data.dig(:details, :expected_data_type)
41
- expected = data.dig(:details, :expected_data_type)
42
- field = data.dig(:details, :api_name)
43
- parent_api_name = data.dig(:details, :parent_api_name)
54
+ if first_data.dig(:details, :expected_data_type)
55
+ expected = first_data.dig(:details, :expected_data_type)
56
+ field = first_data.dig(:details, :api_name)
57
+ parent_api_name = first_data.dig(:details, :parent_api_name)
44
58
 
45
59
  msg << ", expected #{expected} for '#{field}'"
46
60
  msg << " in #{parent_api_name}" if parent_api_name
@@ -48,5 +62,18 @@ module ZohoHub
48
62
 
49
63
  msg
50
64
  end
65
+
66
+ # Error response examples:
67
+ # {"data":[{"code":"INVALID_DATA","details":{},"message":"the id given...","status":"error"}]}
68
+ # {:code=>"INVALID_TOKEN", :details=>{}, :message=>"invalid oauth token", :status=>"error"}
69
+ def error_code?(code)
70
+ if data.is_a?(Array)
71
+ return false if data.size > 1
72
+
73
+ return data.first[:code] == code
74
+ end
75
+
76
+ data[:code] == code
77
+ end
51
78
  end
52
79
  end
@@ -8,7 +8,7 @@ module ZohoHub
8
8
  end
9
9
 
10
10
  def pluralize(text)
11
- if ENV.key?('RAILS_ENV')
11
+ if defined?(ActiveSupport::Inflector)
12
12
  ActiveSupport::Inflector.pluralize(text)
13
13
  else
14
14
  "#{text}s"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZohoHub
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.2'
5
5
  end
@@ -43,6 +43,14 @@ module ZohoHub
43
43
  @attribute_translation = translation
44
44
  end
45
45
 
46
+ def attr_to_zoho_key(attr_name)
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
52
+ end
53
+
46
54
  def zoho_key_translation
47
55
  @attribute_translation.to_a.map(&:rotate).to_h
48
56
  end
@@ -53,14 +61,25 @@ module ZohoHub
53
61
  self.class.attributes
54
62
  end
55
63
 
56
- private
64
+ # This method and the correponding private methods are inspired from Rails ActiveModel
65
+ # github.com/rails/rails/blob/master/activemodel/lib/active_model/attribute_assignment.rb
66
+ def assign_attributes(new_attributes)
67
+ unless new_attributes.is_a?(Hash)
68
+ raise ArgumentError, 'When assigning attributes, you must pass a hash as an argument'
69
+ end
57
70
 
58
- def attr_to_zoho_key(attr_name)
59
- translations = self.class.attribute_translation
71
+ return if new_attributes.empty?
60
72
 
61
- return translations[attr_name.to_sym] if translations.key?(attr_name.to_sym)
73
+ attributes = new_attributes.transform_keys(&:to_s)
74
+ attributes.each do |k, v|
75
+ assign_attribute(k, v)
76
+ end
77
+ end
62
78
 
63
- attr_name.to_s.split('_').map(&:capitalize).join('_').to_sym
79
+ private
80
+
81
+ def attr_to_zoho_key(attr_name)
82
+ self.class.attr_to_zoho_key(attr_name)
64
83
  end
65
84
 
66
85
  def zoho_key_to_attr(zoho_key)
@@ -70,5 +89,13 @@ module ZohoHub
70
89
 
71
90
  zoho_key.to_sym
72
91
  end
92
+
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}"
99
+ end
73
100
  end
74
101
  end
@@ -13,15 +13,15 @@ module ZohoHub
13
13
  end
14
14
 
15
15
  def post(path, params = {})
16
- ZohoHub.connection.post(path, params.to_json)
16
+ ZohoHub.connection.post(path, params)
17
17
  end
18
18
 
19
19
  def put(path, params = {})
20
- ZohoHub.connection.put(path, params.to_json)
20
+ ZohoHub.connection.put(path, params)
21
21
  end
22
22
 
23
23
  def delete(path, params = {})
24
- ZohoHub.connection.delete(path, params.to_json)
24
+ ZohoHub.connection.delete(path, params)
25
25
  end
26
26
  end
27
27
 
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/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' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0')
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.3.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ricardo Otero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-05 00:00:00.000000000 Z
11
+ date: 2022-05-30 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
@@ -287,8 +331,7 @@ 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
334
+ rubygems_version: 3.1.6
292
335
  signing_key:
293
336
  specification_version: 4
294
337
  summary: Simple gem to connect to Zoho CRM API V2
data/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.1.10
5
- - 2.2.10
6
- - 2.3.7
7
- - 2.4.4
8
- - 2.5.3