zoho_service 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +6 -0
- data/bin/zoho_service +122 -0
- data/lib/zoho_service.rb +49 -0
- data/lib/zoho_service/Hash.rb +9 -0
- data/lib/zoho_service/api_collection.rb +108 -0
- data/lib/zoho_service/api_connector.rb +90 -0
- data/lib/zoho_service/base.rb +125 -0
- data/lib/zoho_service/version.rb +3 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/zoho_service_spec.rb +9 -0
- data/zoho_service.gemspec +54 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7f5ff3ce5a4d2491f6b4c9cabeb677e976e1470370388bddc5d3195481f877fd
|
4
|
+
data.tar.gz: de8ce4a34eb71e3dba3efc4bc5f59e1db867e4ff181d52499e0e218b21f45e14
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6144f70309bbb7954691626e78016b6d5a661f1a4801bd5b01563699441e65ecd756481f916536556b18d76ff9f733bf69dd11ff85da396f44efcce6a68b1213
|
7
|
+
data.tar.gz: 987c837dee3efc38ca99fd40d33e88d1d5a879b57667cf0478f8a200332b317473da806db4bf67305e608806b1c346986df9ac73a6a8718bd651ac2b8d4d21c2
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2017 chaky222
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
zoho_service gem
|
2
|
+
=============================
|
3
|
+
|
4
|
+
zoho_service gem is a library to read, update and delete data in Zoho Service Desk.
|
5
|
+
|
6
|
+
https://desk.zoho.com/DeskAPIDocument#Introduction
|
7
|
+
|
8
|
+
## Support Modules (see and onn/off at lib/zoho_service.rb)
|
9
|
+
- [x] organizations
|
10
|
+
- [x] tickets [comments threads attachments timeEntries]
|
11
|
+
- [x] contacts
|
12
|
+
- [x] tasks
|
13
|
+
- [x] accounts
|
14
|
+
- [x] tasks
|
15
|
+
- [x] agents
|
16
|
+
- [x] departments
|
17
|
+
### Not ready yet:
|
18
|
+
- [ ] uploads
|
19
|
+
- [ ] search [searchStr sortBy]
|
20
|
+
- [ ] mailReplyAddress
|
21
|
+
- [ ] from & limit
|
22
|
+
- [ ] sortBy
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add this line to your application's Gemfile:
|
27
|
+
|
28
|
+
|
29
|
+
And then execute:
|
30
|
+
|
31
|
+
$ bundle install
|
32
|
+
|
33
|
+
Or install it yourself as:
|
34
|
+
|
35
|
+
$ gem install zoho_service
|
36
|
+
|
37
|
+
## Usage
|
38
|
+
|
39
|
+
### Get the token
|
40
|
+
|
41
|
+
You can get the token read "Zoho Service Desk API documentation" available here:
|
42
|
+
|
43
|
+
https://desk.zoho.com/DeskAPIDocument
|
44
|
+
|
45
|
+
### Setup Token and Host
|
46
|
+
|
47
|
+
Before accessing ZohoService, you must first configure the connector with token.
|
48
|
+
|
49
|
+
require "zoho_service"
|
50
|
+
zoho_service_connector = ZohoService::ApiConnector.new('224d6ade955bbb18f82ebd00f5c6642e')
|
51
|
+
puts zoho_service_connector.organizations.to_json
|
52
|
+
puts zoho_service_connector.tickets.to_json
|
53
|
+
puts zoho_service_connector.tickets.first.comments.to_json
|
54
|
+
|
55
|
+
Example how to use this gem you can find in file 'bin/zoho_service'. Here some lines from it:
|
56
|
+
```ruby
|
57
|
+
require 'zoho_service'
|
58
|
+
zoho_conn = ZohoService::ApiConnector.new('224d6ade955bbb18f82ebd00f5c6642e', {}, true)
|
59
|
+
|
60
|
+
# ticket = c.tickets.first.update(subject: 'zzzz Вот ваш первый талон.')
|
61
|
+
# ticket = c.tickets.first
|
62
|
+
|
63
|
+
ticket = zoho_conn.tickets.new({
|
64
|
+
"subCategory": "Sub General",
|
65
|
+
"contactId": zoho_conn.contacts.first.id,
|
66
|
+
"subject": "100500 started",
|
67
|
+
"dueDate": (Time.now + 300.days).utc,
|
68
|
+
"departmentId": zoho_conn.departments.first.id,
|
69
|
+
"channel": "Email",
|
70
|
+
"description": "Hai This is Description",
|
71
|
+
"assigneeId": zoho_conn.agents.first.id,
|
72
|
+
"phone": "1 888 900 9646",
|
73
|
+
"email": "example@example.com",
|
74
|
+
"status": "Open"
|
75
|
+
}).save!
|
76
|
+
|
77
|
+
puts "\n\n ticket=[#{ticket.to_json}] \n\n"
|
78
|
+
|
79
|
+
comm = ticket.comments.create({
|
80
|
+
"isPublic": "true",
|
81
|
+
"content": "comm 1005002"
|
82
|
+
})
|
83
|
+
|
84
|
+
comm = ticket.comments.new({
|
85
|
+
"isPublic": "true",
|
86
|
+
"content": "comm 1005003"
|
87
|
+
}).save!
|
88
|
+
|
89
|
+
comm = ticket.comments.first
|
90
|
+
comm.delete!
|
91
|
+
|
92
|
+
puts "\n\n comm=[#{comm.to_json}] \n\n"
|
93
|
+
|
94
|
+
ticket.update(description: ticket.description + ' bla-bla-bla ')
|
95
|
+
|
96
|
+
```
|
97
|
+
|
98
|
+
My mail=chaky22222222@gmail.com.
|
data/Rakefile
ADDED
data/bin/zoho_service
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'zoho_service'
|
3
|
+
|
4
|
+
@zoho_conn = ZohoService::ApiConnector.new('80aea8029f7c4648f1a9d118e0e5df8a', { api_url: 'https://desk.zoho.eu/api/v1' }, true)
|
5
|
+
# ticket = zoho_conn.tickets.first
|
6
|
+
|
7
|
+
# puts "\n\n tickets=[#{zoho_conn.tickets.to_json}] \n\n"
|
8
|
+
# puts "\n\n contacts=[#{zoho_conn.contacts.to_json}] \n\n"
|
9
|
+
# puts "\n\n agents=[#{zoho_conn.agents.to_json}] \n\n"
|
10
|
+
|
11
|
+
# contacts = @zoho_conn.contacts
|
12
|
+
|
13
|
+
# puts "\n\n contacts=[#{contacts.to_json}] \n\n"
|
14
|
+
|
15
|
+
phone = '+380681765911'
|
16
|
+
# contact = zoho_conn.contacts.find_or_initialize_by({ phone: phone }, { lastName: 'Client_'+phone })
|
17
|
+
# @zoho_conn.contacts.create(lastName: name, phone: attrs[:phone], ownerId: crm_id)
|
18
|
+
|
19
|
+
# # # arr1 = zoho_conn.tickets.map { |x| x.id }.sort
|
20
|
+
|
21
|
+
|
22
|
+
def get_agent
|
23
|
+
@zoho_conn.agents&.select { |x| x.id == '258000000002-5005' }.first&.id ||
|
24
|
+
@zoho_conn.agents&.select { |x| x.id == 12312 }.first&.id ||
|
25
|
+
@zoho_conn.agents&.first&.id
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_contact(lead_type, attrs)
|
29
|
+
name = attrs[:name] || "#{lead_type} #{attrs[:phone]}"
|
30
|
+
@zoho_conn.contacts.create(lastName: name, phone: attrs[:phone], ownerId: get_agent() )
|
31
|
+
end
|
32
|
+
|
33
|
+
lead_type = 'входящий лид'
|
34
|
+
target_phone = '+380666679921'
|
35
|
+
|
36
|
+
contact = create_contact(lead_type, phone: target_phone)
|
37
|
+
puts "\n\n contact=[#{contact.to_json}] \n\n"
|
38
|
+
# ticket = zoho_conn.tickets.new({
|
39
|
+
# "subCategory": "Sub General",
|
40
|
+
# "contactId": contact.id,
|
41
|
+
# "subject": "100500 started",
|
42
|
+
# # "dueDate": (Time.now + 300.days).utc,
|
43
|
+
# # "departmentId": zoho_conn.departments.first.id,
|
44
|
+
# "channel": "Phone",
|
45
|
+
# "description": "Hai This is Description",
|
46
|
+
# "assigneeId": zoho_conn.agents.first.id,
|
47
|
+
# "phone": phone,
|
48
|
+
# "email": "example@example.com",
|
49
|
+
# "status": "Open"
|
50
|
+
# }).save!
|
51
|
+
|
52
|
+
# # # ticket = zoho_conn.tickets.find({ phone: '1 888 900 9646' })
|
53
|
+
# # # zoho_conn.tickets
|
54
|
+
# # # ticket = zoho_conn.tickets.find({ phone: '1 888 900 9646' })
|
55
|
+
# # # ticket = zoho_conn.tickets.find_or_initialize_by({ productId: '123123', phone: '80681765917' })
|
56
|
+
# puts "\n\n ticket[#{ticket.count}]=[#{ticket.to_json}] \n\n"
|
57
|
+
|
58
|
+
# # # contact = zoho_conn.contacts.find({ phone: '80681765917' })
|
59
|
+
|
60
|
+
|
61
|
+
# # # contact = zoho_conn.contacts.find({ customFields: { custom_id: 123 } })
|
62
|
+
# # # puts "\n\n contact[#{contact.count}]=[#{contact.to_json}] \n\n"
|
63
|
+
|
64
|
+
# task = zoho_conn.tasks.create({
|
65
|
+
# ticketId: ticket.id,
|
66
|
+
# subject: "New Testing Task #{ticket.id}",
|
67
|
+
# # status: "Open",
|
68
|
+
# category: 'Call',
|
69
|
+
# ownerId: zoho_conn.agents.second.id,
|
70
|
+
# creatorId: zoho_conn.agents.second.id,
|
71
|
+
# # ownerId: ticket.assigneeId
|
72
|
+
# status: "In Progress"
|
73
|
+
# })
|
74
|
+
|
75
|
+
# # task = zoho_conn.tasks.by_id("217087000000142001")
|
76
|
+
# # task = zoho_conn.tasks
|
77
|
+
# puts "\n\n task[#{task.count}]=[#{task.to_json}] \n\n"
|
78
|
+
|
79
|
+
# puts "\n\n search client =[#{zoho_conn.tickets.search('eeee').to_json}] \n\n"
|
80
|
+
# puts "\n\n arr1[#{arr1.count}]=[#{arr1.to_json}] \n\n "
|
81
|
+
|
82
|
+
# arr2 = zoho_conn.tickets.all.map { |x| x.id }.sort
|
83
|
+
# puts "\n\n arr1[#{arr2.count}]=[#{arr2.to_json}] \n\n "
|
84
|
+
|
85
|
+
# puts "\n\n ticket1=[#{zoho_conn.tickets.map { |x| x.id }.sort.to_json}] \n\n ticket2=[#{zoho_conn.tickets.all.map { |x| x.id }.sort.to_json}] \n\n"
|
86
|
+
|
87
|
+
# ticket = c.tickets.first.update(subject: 'zzzz Вот ваш первый талон.')
|
88
|
+
# ticket = zoho_conn.tickets.first
|
89
|
+
# comm = ticket.comments
|
90
|
+
|
91
|
+
# ticket = zoho_conn.tickets.new({
|
92
|
+
# "subCategory": "Sub General",
|
93
|
+
# "contactId": zoho_conn.contacts.first.id,
|
94
|
+
# "subject": "100500 started",
|
95
|
+
# "dueDate": (Time.now + 300.days).utc,
|
96
|
+
# "departmentId": zoho_conn.departments.first.id,
|
97
|
+
# "channel": "Email",
|
98
|
+
# "description": "Hai This is Description",
|
99
|
+
# "assigneeId": zoho_conn.agents.first.id,
|
100
|
+
# "phone": "1 888 900 9646",
|
101
|
+
# "email": "example@example.com",
|
102
|
+
# "status": "Open"
|
103
|
+
# }).save!
|
104
|
+
|
105
|
+
|
106
|
+
# puts "\n\n ticketNumber=[#{ticket['ticketNumber']}] ticket=[#{ticket.to_json}] \n\n"
|
107
|
+
# comm = ticket.comments.create({
|
108
|
+
# "isPublic": "true",
|
109
|
+
# "content": "comm 1005002"
|
110
|
+
# })
|
111
|
+
|
112
|
+
# comm = ticket.comments.new({
|
113
|
+
# "isPublic": "true",
|
114
|
+
# "content": "comm 1005003"
|
115
|
+
# }).save!
|
116
|
+
|
117
|
+
# comm = ticket.comments.first
|
118
|
+
# comm.delete!
|
119
|
+
|
120
|
+
# puts "\n\n comm=[#{comm.to_json}] \n\n"
|
121
|
+
|
122
|
+
# ticket.update(description: ticket.description + ' bla-bla-bla ')
|
data/lib/zoho_service.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require "zoho_service/version"
|
2
|
+
require "zoho_service/Hash"
|
3
|
+
require "active_support"
|
4
|
+
require "active_support/core_ext"
|
5
|
+
require "zoho_service/base"
|
6
|
+
require "zoho_service/api_connector"
|
7
|
+
require "zoho_service/api_collection"
|
8
|
+
|
9
|
+
module ZohoService
|
10
|
+
def self.name_to_many(model_name)
|
11
|
+
model_name.to_s.pluralize.underscore
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.many_to_name(models_name)
|
15
|
+
models_name.to_s.singularize.camelize
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.init_models_recursion(recursion, tree, parent_class)
|
19
|
+
raise("Too deep recursion in init_models_recursion in ZohoService gem") unless recursion && recursion > 0
|
20
|
+
raise("Need parent class in init_models_recursion in ZohoService gem") unless parent_class
|
21
|
+
parent_name = parent_class.name.demodulize.underscore
|
22
|
+
models = tree.map { |m| m.kind_of?(Array) ? { name: m.first, childs: m.second, params: m.third } : { name: m } }
|
23
|
+
models.each do |model|
|
24
|
+
# puts "\n try init parent_name2=[#{parent_name}] recursion=[#{recursion}] mod=[#{model.to_json}] \n"
|
25
|
+
current_class = nil
|
26
|
+
if const_defined?(model[:name])
|
27
|
+
current_class = const_get(model[:name])
|
28
|
+
else
|
29
|
+
current_class = Class.new(Base)
|
30
|
+
const_set(model[:name], current_class)
|
31
|
+
current_class.model_params = model[:params]
|
32
|
+
current_class.default_parent_name = parent_name
|
33
|
+
end
|
34
|
+
current_class.send(:define_method, parent_name) { |params = {}| get_parent(__method__, params) }
|
35
|
+
parent_class.send(:define_method, ZohoService::name_to_many(model[:name])) do
|
36
|
+
get_childs(__method__.to_sym, current_class)
|
37
|
+
end
|
38
|
+
init_models_recursion(recursion - 1, model[:childs], current_class) if model[:childs]
|
39
|
+
end
|
40
|
+
parent_class.class.send(:define_method, 'childs_list') { models.map { |x| x[:name] }.sort }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
ZohoService::init_models_recursion(5, ([
|
45
|
+
#[model_name, [childs_array], {params}]
|
46
|
+
['Ticket', %w[Comment Thread Attachment TimeEntry], { queries: %w[from limit departmentId sortBy include] }],
|
47
|
+
['Contact', %w[Ticket], { queries: %w[from limit sortBy include] }],
|
48
|
+
['Task', nil, { queries: %w[from limit departmentId sortBy include] }]
|
49
|
+
] + %w[Organization Account Agent Department]), ZohoService::ApiConnector)
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module ZohoService
|
2
|
+
class ApiCollection < Array
|
3
|
+
attr_reader :parent, :request_params, :loaded
|
4
|
+
|
5
|
+
def initialize(parent, attrs = {})
|
6
|
+
@loaded = false
|
7
|
+
@parent = parent
|
8
|
+
@request_params = attrs # request_params writing only in init proc!
|
9
|
+
super()
|
10
|
+
if accepted_queries.include?('departmentId')
|
11
|
+
@request_params[:query] ||= {}
|
12
|
+
@request_params[:query][:departmentId] ||= parent.connector.client_params[:departmentId]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_request(eval_method)
|
17
|
+
return self if @loaded
|
18
|
+
@loaded = true
|
19
|
+
req_query = @request_params[:query] || {}
|
20
|
+
if accepted_queries.include?('limit') && !(req_query[:from] || req_query[:limit] || request_params[:skip_pages])
|
21
|
+
items_per_page = 50
|
22
|
+
(0..100).each do |page|
|
23
|
+
query = req_query.merge(from: 0 + (items_per_page * page), limit: items_per_page)
|
24
|
+
query[:from] += 1 if query[:from] > 0 # WTF bug with from-limit on zoho server!
|
25
|
+
query.merge!(sortBy: 'createdTime') if accepted_queries.include?('sortBy') && !query[:sortBy]
|
26
|
+
arr = new_collection(query: query).run_request(__method__)
|
27
|
+
arr.each { |x| self.push(x) }
|
28
|
+
break unless arr.count == items_per_page
|
29
|
+
end
|
30
|
+
else
|
31
|
+
parent.connector.load_by_api(collection_url, req_query)&.each do |item_data|
|
32
|
+
raise("ERROR in ZohoService gem. item_data=[#{item_data}]") unless item_data.is_a?(Hash)
|
33
|
+
self.push(request_params[:items_class].new(parent, item_data))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def new(item_params)
|
40
|
+
if accepted_queries.include?('departmentId')
|
41
|
+
item_params[:departmentId] ||= parent.connector.client_params[:departmentId]
|
42
|
+
end
|
43
|
+
request_params[:items_class].new(parent, item_params)
|
44
|
+
end
|
45
|
+
|
46
|
+
def create(item_params)
|
47
|
+
new(item_params).save!
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_or_initialize_by(params, create_params = {})
|
51
|
+
find(params).first || create(params.deep_merge(create_params))
|
52
|
+
end
|
53
|
+
|
54
|
+
def find(params)
|
55
|
+
# this method not normal! It is temporary! Search method not working normal on the desk.zoho.com.
|
56
|
+
# use "search" method if you want search only in texts of a model.
|
57
|
+
params = params ? params.deep_symbolize : {}
|
58
|
+
select { |x| x.to_h.deep_symbolize.deep_include?(params) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_with_str(searchStr, params = {})
|
62
|
+
search(searchStr).find(params)
|
63
|
+
end
|
64
|
+
|
65
|
+
def by_id(id)
|
66
|
+
request_params[:items_class].new_by_id(parent, id)
|
67
|
+
end
|
68
|
+
|
69
|
+
def search(searchStr) # Search method can search only searchStr in texts of a model :( . it`s not good practice :(.
|
70
|
+
new_collection(query: { searchStr: searchStr, 'module': request_params[:items_class].models_name,
|
71
|
+
sortBy: 'relevance' })
|
72
|
+
end
|
73
|
+
|
74
|
+
def all
|
75
|
+
run_request(__method__)
|
76
|
+
end
|
77
|
+
|
78
|
+
def accepted_queries
|
79
|
+
if request_params[:query] && request_params[:searchStr]
|
80
|
+
['from', 'limit', 'sortBy', 'departmentId']
|
81
|
+
else
|
82
|
+
mod = request_params[:items_class]
|
83
|
+
mod.model_params && mod.model_params[:queries] ? mod.model_params[:queries] : []
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def first(*args, &block)
|
88
|
+
if !@loaded && accepted_queries.include?('limit')
|
89
|
+
return new_collection({ query: { limit: 1 } }).run_request(__method__).first(*args, &block)
|
90
|
+
end
|
91
|
+
run_request(__method__)
|
92
|
+
super(*args, &block)
|
93
|
+
end
|
94
|
+
|
95
|
+
def new_collection(more_params)
|
96
|
+
self.class.new(parent, request_params.deep_merge(more_params))
|
97
|
+
end
|
98
|
+
|
99
|
+
def collection_url
|
100
|
+
parent.resource_path + request_params[:items_class].class_path
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
redefine_methods = Array.instance_methods(false) - %i[inspect push] - ApiCollection.instance_methods(false)
|
105
|
+
redefine_methods.sort.each do |method|
|
106
|
+
ApiCollection.send(:define_method, method ) { |*args, &block| run_request(__method__); super(*args, &block) }
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module ZohoService
|
5
|
+
class ApiConnector < Base
|
6
|
+
attr_reader :token, :invalid_token, :client_params, :debug
|
7
|
+
def initialize(token_in = nil, client_params_in = {}, debug_in = false)
|
8
|
+
raise('Need zoho API token in params for ZohoService::ApiConnector.new') unless token_in
|
9
|
+
@token = token_in
|
10
|
+
@debug = debug_in
|
11
|
+
@client_params = client_params_in
|
12
|
+
super()
|
13
|
+
@client_params[:api_url] = 'https://desk.zoho.com/api/v1'.freeze unless @client_params[:api_url]
|
14
|
+
@client_params[:orgId] = organizations.first&.id unless @client_params[:orgId]
|
15
|
+
@client_params[:departmentId] = departments.first&.id unless @client_params[:departmentId]
|
16
|
+
@client_params[:timeout] = @client_params[:timeout] ? @client_params[:timeout].to_i : 5
|
17
|
+
end
|
18
|
+
|
19
|
+
def resource_path
|
20
|
+
@client_params[:api_url]
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_headers(params = {})
|
24
|
+
client_headers = { 'Authorization': 'Zoho-authtoken ' + @token }
|
25
|
+
client_headers[:orgId] = @client_params[:orgId].to_s if @client_params[:orgId]
|
26
|
+
self.class.headers.merge(client_headers)
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_by_api(url, query = nil, params = {})
|
30
|
+
url = resource_path + '/search' if query && query[:searchStr]
|
31
|
+
url = URI.encode(url)
|
32
|
+
raise "Invalid CRMCSRFToken. Check your token in ApiConnector in ZohoService gem!\n" if @invalid_token
|
33
|
+
|
34
|
+
request_params = { headers: get_headers(params), timeout: @client_params[:timeout], no_follow: true, limit: 1,
|
35
|
+
follow_redirects: false, read_timeout: @client_params[:timeout] }
|
36
|
+
response = nil
|
37
|
+
begin
|
38
|
+
response = if params[:method] == :post
|
39
|
+
HTTParty.post(url, request_params.merge(body: query.to_json))
|
40
|
+
elsif params[:method] == :patch
|
41
|
+
HTTParty.patch(url, request_params.merge(body: query.to_json))
|
42
|
+
elsif params[:method] == :delete
|
43
|
+
HTTParty.delete(url, request_params)
|
44
|
+
else
|
45
|
+
url = url + '?' + query.to_query if query
|
46
|
+
HTTParty.get(url, request_params)
|
47
|
+
end
|
48
|
+
rescue HTTParty::RedirectionTooDeep => e
|
49
|
+
raise("Can`t Connect to zohoDesk server. RedirectionTooDeep. Check https or maybe your account blocked.\nurl=[#{url}]\nerror=[#{e}]")
|
50
|
+
rescue => e
|
51
|
+
raise("Can`t Connect to zohoDesk server. Unknown error. Maybe your account blocked.\nurl=[#{url}]\nerror=[#{e}]")
|
52
|
+
end
|
53
|
+
if response
|
54
|
+
$stderr.puts "#{params[:method]} url=[#{url}] length=[#{response.to_json.length}] cnt=[#{response['data']&.count}]\n" if @debug
|
55
|
+
if response.code == 200
|
56
|
+
raise "Error message in ZohoService gem: \n[#{ response['message'] }]\n" if response['message']
|
57
|
+
return response['data'] ? response['data'] : response
|
58
|
+
elsif response.code == 204 # 204 - no content found or from-limit out of range
|
59
|
+
return []
|
60
|
+
elsif response.code == 400 # 400 - Invalid CRMCSRFToken
|
61
|
+
invalid_CRMCSRFToken()
|
62
|
+
else
|
63
|
+
invalid_CRMCSRFToken() if response.body&.include?('Invalid CRMCSRFToken')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
bad_response(response, url, query, get_headers(params), params)
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def invalid_CRMCSRFToken
|
71
|
+
@invalid_token = true
|
72
|
+
raise('Invalid CRMCSRFToken. Check your token in ApiConnector in ZohoService gem!')
|
73
|
+
end
|
74
|
+
|
75
|
+
def bad_response(response, url, query, headers, params)
|
76
|
+
error_str = "ZohoService API bad_response url=[#{url}], query=[#{query&.to_json}]\nparams=[#{params.to_json}]\n"
|
77
|
+
error_str += response ? "code=[#{response.code}] body=[#{response.body}]\n" : "Unknown error in load_by_api.\n"
|
78
|
+
raise error_str
|
79
|
+
end
|
80
|
+
|
81
|
+
class << self
|
82
|
+
def headers
|
83
|
+
{ 'User-Agent' => 'ZohoService-Ruby-On-Rails-gem-by-chaky222/' + ZohoService::VERSION,
|
84
|
+
'Accept' => 'application/json',
|
85
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
86
|
+
'Accept-Charset'=> 'UTF-8' }.freeze
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module ZohoService
|
4
|
+
class Base < OpenStruct
|
5
|
+
attr_reader :parents, :item_id, :table, :full_data, :errors, :childs, :saved
|
6
|
+
|
7
|
+
def initialize(parent = nil, data = nil, params = {})
|
8
|
+
@childs = {}
|
9
|
+
@errors = []
|
10
|
+
@parents = parent ? { parent.class.name.demodulize.underscore.to_sym => parent } : {}
|
11
|
+
@item_id = params[:item_id] || ((data && data['id']) ? data['id'] : nil)
|
12
|
+
super(data)
|
13
|
+
@full_data = params[:full_data]
|
14
|
+
end
|
15
|
+
|
16
|
+
def connector
|
17
|
+
parent ? parent.connector : self
|
18
|
+
end
|
19
|
+
|
20
|
+
def parent
|
21
|
+
@parents[self.class.default_parent_name] || @parents.values.first
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_parent(model, params = {})
|
25
|
+
@parents[model.to_sym]
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_childs(child_model, childs_class)
|
29
|
+
@childs[child_model] ||= ApiCollection.new(self, { items_class: childs_class})
|
30
|
+
@childs[child_model]
|
31
|
+
end
|
32
|
+
|
33
|
+
def full
|
34
|
+
load_full unless @full_data
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_full(data = nil)
|
39
|
+
raise('You must save model before take full data in ZohoService gem.') unless @item_id
|
40
|
+
init_data(data || connector.load_by_api(resource_path))
|
41
|
+
@full_data = true
|
42
|
+
end
|
43
|
+
|
44
|
+
def init_data(data)
|
45
|
+
data.each{ |k, v| @table[k.to_sym] = v; new_ostruct_member(k); }
|
46
|
+
@item_id = id if id && !@item_id
|
47
|
+
end
|
48
|
+
|
49
|
+
def update(params)
|
50
|
+
url = @item_id ? resource_path : parent.resource_path + self.class.class_path
|
51
|
+
response = connector.load_by_api(url, params.to_hash, { method: @item_id ? :patch : :post })
|
52
|
+
if response
|
53
|
+
if response.kind_of?(Array)
|
54
|
+
raise("ERROR! create item response is Array[#{response.count}]. Try change http to https in api_url :)!")
|
55
|
+
elsif response['message']
|
56
|
+
@errors << response['message']
|
57
|
+
else
|
58
|
+
init_data(response.to_hash)
|
59
|
+
@full_data = nil
|
60
|
+
end
|
61
|
+
else
|
62
|
+
@errors << "Error while try update[#{@item_id}] url=[#{url}] params=[#{params&.to_json}]"
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def delete
|
68
|
+
return unless @item_id
|
69
|
+
response = connector.load_by_api(resource_path, nil, { method: :delete })
|
70
|
+
if response && response['message']
|
71
|
+
@errors << response['message']
|
72
|
+
elsif response
|
73
|
+
@item_id = nil
|
74
|
+
@id = nil
|
75
|
+
@full_data = nil
|
76
|
+
else
|
77
|
+
@errors << 'Error while try delete'
|
78
|
+
end
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def delete!
|
83
|
+
delete
|
84
|
+
raise("#{@errors.join("\n")}") if @errors.any?
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
def save
|
89
|
+
update(to_hash)
|
90
|
+
@saved = @errors.any?
|
91
|
+
end
|
92
|
+
|
93
|
+
def save!
|
94
|
+
save
|
95
|
+
raise("#{@errors.join("\n")}") if @errors.any?
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
def resource_path
|
100
|
+
raise('Cant take resource_path for not saved item in ZohoService gem.') unless @item_id
|
101
|
+
parent.resource_path + self.class.class_path(@item_id)
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_hash
|
105
|
+
@table.to_hash(*args, &block)
|
106
|
+
end
|
107
|
+
|
108
|
+
class << self
|
109
|
+
attr_accessor :model_params, :default_parent_name
|
110
|
+
def class_path(id = nil)
|
111
|
+
"/#{models_name}" + (id ? '/'+id : '')
|
112
|
+
end
|
113
|
+
|
114
|
+
def models_name
|
115
|
+
self.name.demodulize.pluralize.underscore
|
116
|
+
end
|
117
|
+
|
118
|
+
def new_by_id(parent, id)
|
119
|
+
raise('Need id in Base::new_by_id of ZohoService gem.') unless id
|
120
|
+
data = parent.connector.load_by_api(parent.resource_path + class_path(id))
|
121
|
+
new(parent, data, { full_data: true })
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter,
|
7
|
+
]
|
8
|
+
SimpleCov.start do
|
9
|
+
add_filter './.bundle'
|
10
|
+
end
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
13
|
+
require 'zoho_service'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: zoho_service 0.0.1 ruby lib
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'zoho_service/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "zoho_service".freeze
|
9
|
+
s.version = ZohoService::VERSION
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib".freeze]
|
13
|
+
s.authors = ["chaky222".freeze]
|
14
|
+
s.date = "2017-09-13"
|
15
|
+
s.description = "Working with data in Zoho Service Desk by using API.".freeze
|
16
|
+
s.email = ["emersoncostin@gmail.com".freeze]
|
17
|
+
s.executables = ["zoho_service".freeze]
|
18
|
+
s.files = [ "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "bin/zoho_service".freeze, "lib/zoho_service.rb".freeze, "lib/zoho_service/Hash.rb".freeze, "lib/zoho_service/base.rb".freeze, "lib/zoho_service/api_connector.rb".freeze, "lib/zoho_service/api_collection.rb".freeze, "lib/zoho_service/version.rb".freeze, "spec/spec_helper.rb".freeze, "spec/zoho_service_spec.rb".freeze, "zoho_service.gemspec".freeze]
|
19
|
+
s.homepage = "".freeze
|
20
|
+
s.licenses = ["MIT".freeze]
|
21
|
+
s.rubygems_version = "2.5.2".freeze
|
22
|
+
s.summary = "Zoho Service Desk gem".freeze
|
23
|
+
s.test_files = ["spec/spec_helper.rb".freeze, "spec/zoho_service_spec.rb".freeze]
|
24
|
+
|
25
|
+
if s.respond_to? :specification_version then
|
26
|
+
s.specification_version = 4
|
27
|
+
|
28
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
29
|
+
s.add_runtime_dependency(%q<httparty>.freeze, ["> 0.16"])
|
30
|
+
s.add_runtime_dependency(%q<activesupport>.freeze, ["> 4.2.7.1"])
|
31
|
+
s.add_development_dependency(%q<bundler>.freeze, ["~> 1.5"])
|
32
|
+
s.add_development_dependency(%q<rake>.freeze, ["< 11.0"])
|
33
|
+
s.add_development_dependency(%q<rspec>.freeze, ["~> 2.14.1"])
|
34
|
+
s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.7.1"])
|
35
|
+
s.add_development_dependency(%q<coveralls>.freeze, ["~> 0.7.0"])
|
36
|
+
else
|
37
|
+
s.add_dependency(%q<httparty>.freeze, ["> 0.16"])
|
38
|
+
s.add_dependency(%q<activesupport>.freeze, ["> 4.2.7.1"])
|
39
|
+
s.add_dependency(%q<bundler>.freeze, ["~> 1.5"])
|
40
|
+
s.add_dependency(%q<rake>.freeze, ["< 11.0"])
|
41
|
+
s.add_dependency(%q<rspec>.freeze, ["~> 2.14.1"])
|
42
|
+
s.add_dependency(%q<simplecov>.freeze, ["~> 0.7.1"])
|
43
|
+
s.add_dependency(%q<coveralls>.freeze, ["~> 0.7.0"])
|
44
|
+
end
|
45
|
+
else
|
46
|
+
s.add_dependency(%q<httparty>.freeze, ["> 0.16.2"])
|
47
|
+
s.add_dependency(%q<activesupport>.freeze, ["> 4.2.7.1"])
|
48
|
+
s.add_dependency(%q<bundler>.freeze, ["~> 1.5"])
|
49
|
+
s.add_dependency(%q<rake>.freeze, ["< 11.0"])
|
50
|
+
s.add_dependency(%q<rspec>.freeze, ["~> 2.14.1"])
|
51
|
+
s.add_dependency(%q<simplecov>.freeze, ["~> 0.7.1"])
|
52
|
+
s.add_dependency(%q<coveralls>.freeze, ["~> 0.7.0"])
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zoho_service
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- chaky222
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.16'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 4.2.7.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.2.7.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "<"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '11.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "<"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '11.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.14.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.14.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.7.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.7.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: coveralls
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.7.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.7.0
|
111
|
+
description: Working with data in Zoho Service Desk by using API.
|
112
|
+
email:
|
113
|
+
- emersoncostin@gmail.com
|
114
|
+
executables:
|
115
|
+
- zoho_service
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- bin/zoho_service
|
124
|
+
- lib/zoho_service.rb
|
125
|
+
- lib/zoho_service/Hash.rb
|
126
|
+
- lib/zoho_service/api_collection.rb
|
127
|
+
- lib/zoho_service/api_connector.rb
|
128
|
+
- lib/zoho_service/base.rb
|
129
|
+
- lib/zoho_service/version.rb
|
130
|
+
- spec/spec_helper.rb
|
131
|
+
- spec/zoho_service_spec.rb
|
132
|
+
- zoho_service.gemspec
|
133
|
+
homepage: ''
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 2.7.6.2
|
154
|
+
signing_key:
|
155
|
+
specification_version: 4
|
156
|
+
summary: Zoho Service Desk gem
|
157
|
+
test_files:
|
158
|
+
- spec/spec_helper.rb
|
159
|
+
- spec/zoho_service_spec.rb
|