zendesk_api 0.0.9 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile.lock +7 -7
- data/Readme.md +34 -28
- data/lib/zendesk_api/association.rb +3 -3
- data/lib/zendesk_api/collection.rb +5 -1
- data/lib/zendesk_api/middleware/request/upload.rb +54 -15
- data/lib/zendesk_api/resource.rb +1 -1
- data/lib/zendesk_api/resources/misc.rb +2 -2
- data/lib/zendesk_api/resources/ticket.rb +14 -4
- data/lib/zendesk_api/version.rb +1 -1
- data/live/ticket_spec.rb +5 -5
- data/live/user_spec.rb +6 -0
- data/spec/collection_spec.rb +6 -0
- data/spec/fixtures/test_resources.rb +4 -0
- data/spec/middleware/request/upload_spec.rb +48 -16
- data/zendesk_api.gemspec +1 -1
- metadata +6 -6
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
zendesk_api (0.0
|
4
|
+
zendesk_api (0.1.0)
|
5
5
|
faraday (>= 0.8.0)
|
6
6
|
faraday_middleware (>= 0.8.7)
|
7
7
|
hashie
|
@@ -18,11 +18,11 @@ GEM
|
|
18
18
|
diff-lcs (1.1.3)
|
19
19
|
faraday (0.8.1)
|
20
20
|
multipart-post (~> 1.1)
|
21
|
-
faraday_middleware (0.8.
|
21
|
+
faraday_middleware (0.8.8)
|
22
22
|
faraday (>= 0.7.4, < 0.9)
|
23
23
|
hashie (1.2.0)
|
24
24
|
inflection (1.0.0)
|
25
|
-
json (1.7.
|
25
|
+
json (1.7.4)
|
26
26
|
mime-types (1.19)
|
27
27
|
multi_json (1.3.6)
|
28
28
|
multipart-post (1.1.5)
|
@@ -39,9 +39,9 @@ GEM
|
|
39
39
|
multi_json (~> 1.0)
|
40
40
|
simplecov-html (~> 0.5.3)
|
41
41
|
simplecov-html (0.5.3)
|
42
|
-
vcr (2.2.
|
43
|
-
webmock (1.8.
|
44
|
-
addressable (
|
42
|
+
vcr (2.2.4)
|
43
|
+
webmock (1.8.8)
|
44
|
+
addressable (~> 2.2.8)
|
45
45
|
crack (>= 0.1.7)
|
46
46
|
yard (0.8.2.1)
|
47
47
|
|
@@ -51,7 +51,7 @@ PLATFORMS
|
|
51
51
|
DEPENDENCIES
|
52
52
|
jruby-openssl
|
53
53
|
rake
|
54
|
-
rspec (
|
54
|
+
rspec (~> 2.10.0)
|
55
55
|
simplecov
|
56
56
|
vcr
|
57
57
|
webmock
|
data/Readme.md
CHANGED
@@ -10,31 +10,37 @@ Version 0.0.5 brings with it a change to the top-level namespace. All references
|
|
10
10
|
|
11
11
|
## Installation
|
12
12
|
|
13
|
-
|
13
|
+
The Zendesk API client can be installed using Rubygems or Bundler.
|
14
14
|
|
15
|
-
|
15
|
+
### Rubygems
|
16
16
|
|
17
|
-
|
17
|
+
```sh
|
18
|
+
gem install zendesk_api
|
19
|
+
```
|
20
|
+
|
21
|
+
### Bundler
|
18
22
|
|
19
|
-
|
23
|
+
Add it to your Gemfile
|
20
24
|
|
21
|
-
|
25
|
+
gem "zendesk_api"
|
22
26
|
|
23
|
-
|
27
|
+
and follow normal [Bundler](http://gembundler.com/) installation and execution procedures.
|
24
28
|
|
25
29
|
## Configuration
|
26
30
|
|
27
31
|
Configuration is done through a block returning an instance of ZendeskAPI::Client.
|
28
32
|
The block is mandatory and if not passed, an ArgumentError will be thrown.
|
29
33
|
|
30
|
-
```
|
31
|
-
|
34
|
+
```ruby
|
35
|
+
require 'zendesk_api'
|
36
|
+
|
37
|
+
client = ZendeskAPI::Client.new do |config|
|
32
38
|
# Mandatory:
|
33
39
|
|
34
|
-
config.url = "https://mydesk.zendesk.com/api/v2
|
40
|
+
config.url = "<- your-zendesk-url ->" # e.g. https://mydesk.zendesk.com/api/v2
|
35
41
|
|
36
|
-
config.username = "
|
37
|
-
config.password = "
|
42
|
+
config.username = "login.email@zendesk.com"
|
43
|
+
config.password = "your zendesk password or token"
|
38
44
|
|
39
45
|
# Optional:
|
40
46
|
|
@@ -48,12 +54,12 @@ ZendeskAPI::Client.new do |config|
|
|
48
54
|
config.logger = Logger.new(STDOUT)
|
49
55
|
|
50
56
|
# Changes Faraday adapter
|
51
|
-
config.adapter = :patron
|
57
|
+
# config.adapter = :patron
|
52
58
|
|
53
59
|
# Merged with the default client options hash
|
54
|
-
config.client_options = { :ssl => false }
|
60
|
+
# config.client_options = { :ssl => false }
|
55
61
|
|
56
|
-
# When getting the error 'hostname does not match the server certificate'
|
62
|
+
# When getting the error 'hostname does not match the server certificate'
|
57
63
|
# use the API at https://yoursubdomain.zendesk.com/api/v2
|
58
64
|
end
|
59
65
|
```
|
@@ -66,19 +72,19 @@ The result of configuration is an instance of ZendeskAPI::Client which can then
|
|
66
72
|
|
67
73
|
One way to use the client is to pass it in as an argument to individual classes.
|
68
74
|
|
69
|
-
```
|
75
|
+
```ruby
|
70
76
|
ZendeskAPI::Ticket.new(client, :id => 1, :priority => "urgent") # doesn't actually send a request, must explicitly call #save
|
71
|
-
ZendeskAPI::Ticket.create(client, :subject => "Test Ticket", :
|
77
|
+
ZendeskAPI::Ticket.create(client, :subject => "Test Ticket", :comment => { :value => "This is a test" }, :submitter_id => client.current_user.id, :priority => "urgent")
|
72
78
|
ZendeskAPI::Ticket.find(client, :id => 1)
|
73
79
|
ZendeskAPI::Ticket.delete(client, :id => 1)
|
74
80
|
```
|
75
81
|
|
76
82
|
Another way is to use the instance methods under client.
|
77
83
|
|
78
|
-
```
|
84
|
+
```ruby
|
79
85
|
client.tickets.first
|
80
86
|
client.tickets.find(:id => 1)
|
81
|
-
client.tickets.create(:subject => "Test Ticket", :
|
87
|
+
client.tickets.create(:subject => "Test Ticket", :comment => { :value => "This is a test" }, :submitter_id => client.current_user.id, :priority => "urgent")
|
82
88
|
client.tickets.delete(:id => 1)
|
83
89
|
```
|
84
90
|
|
@@ -90,7 +96,7 @@ as #each.
|
|
90
96
|
|
91
97
|
ZendeskAPI::Collections can be paginated:
|
92
98
|
|
93
|
-
```
|
99
|
+
```ruby
|
94
100
|
tickets = client.tickets.page(2).per_page(3)
|
95
101
|
next_page = tickets.next
|
96
102
|
previous_page = tickets.prev
|
@@ -100,7 +106,7 @@ previous_page = tickets.prev
|
|
100
106
|
|
101
107
|
Callbacks can be added to the ZendeskAPI::Client instance and will be called (with the response env) after all response middleware on a successful request.
|
102
108
|
|
103
|
-
```
|
109
|
+
```ruby
|
104
110
|
client.insert_callback do |env|
|
105
111
|
puts env[:response_headers]
|
106
112
|
end
|
@@ -110,7 +116,7 @@ end
|
|
110
116
|
|
111
117
|
Individual resources can be created, modified, saved, and destroyed.
|
112
118
|
|
113
|
-
```
|
119
|
+
```ruby
|
114
120
|
ticket = client.tickets[0] # ZendeskAPI::Ticket.find(client, :id => 1)
|
115
121
|
ticket.priority = "urgent"
|
116
122
|
ticket.attributes # => { "priority" => "urgent" }
|
@@ -127,7 +133,7 @@ ticket.save # Will POST
|
|
127
133
|
API endpoints such as tickets/recent or topics/show_many can be accessed through chaining.
|
128
134
|
They will too return an instance of ZendeskAPI::Collection.
|
129
135
|
|
130
|
-
```
|
136
|
+
```ruby
|
131
137
|
client.tickets.recent
|
132
138
|
client.topics.show_many(:verb => :post, :ids => [1, 2, 3])
|
133
139
|
```
|
@@ -136,20 +142,20 @@ client.topics.show_many(:verb => :post, :ids => [1, 2, 3])
|
|
136
142
|
|
137
143
|
Use either of the following to obtain the current user instance:
|
138
144
|
|
139
|
-
```
|
145
|
+
```ruby
|
140
146
|
client.users.find(:id => 'me')
|
141
147
|
client.current_user
|
142
148
|
```
|
143
149
|
|
144
150
|
### Attaching files
|
145
151
|
|
146
|
-
Files can be attached to
|
152
|
+
Files can be attached to ticket comments using either a path or the File class and will
|
147
153
|
be automatically uploaded and attached.
|
148
154
|
|
149
|
-
```
|
150
|
-
ticket = Ticket.new(
|
151
|
-
ticket.uploads << "img.jpg"
|
152
|
-
ticket.uploads << File.new("img.jpg")
|
155
|
+
```ruby
|
156
|
+
ticket = ZendeskAPI::Ticket.new(client, :comment => { :value => "attachments" })
|
157
|
+
ticket.comment.uploads << "img.jpg"
|
158
|
+
ticket.comment.uploads << File.new("img.jpg")
|
153
159
|
ticket.save
|
154
160
|
```
|
155
161
|
|
@@ -239,9 +239,9 @@ module ZendeskAPI
|
|
239
239
|
end
|
240
240
|
|
241
241
|
class << self
|
242
|
-
#
|
243
|
-
|
244
|
-
|
242
|
+
# Make sure Rails' overwriting of const_missing doesn't cause trouble
|
243
|
+
def const_missing(*args)
|
244
|
+
Object.const_missing(*args)
|
245
245
|
end
|
246
246
|
|
247
247
|
# Allows using has and has_many without having class defined yet
|
@@ -212,7 +212,11 @@ module ZendeskAPI
|
|
212
212
|
|
213
213
|
# Sends methods to underlying array of resources.
|
214
214
|
def method_missing(name, *args, &block)
|
215
|
-
|
215
|
+
methods = @resource_class.singleton_methods(false).map(&:to_sym)
|
216
|
+
|
217
|
+
if methods.include?(name)
|
218
|
+
@resource_class.send(name, @client, *args, &block)
|
219
|
+
elsif Array.new.respond_to?(name)
|
216
220
|
to_a.send(name, *args, &block)
|
217
221
|
else
|
218
222
|
opts = args.last.is_a?(Hash) ? args.last : {}
|
@@ -6,25 +6,64 @@ module ZendeskAPI
|
|
6
6
|
module Request
|
7
7
|
class Upload < Faraday::Middleware
|
8
8
|
def call(env)
|
9
|
-
if env[:body]
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
9
|
+
if env[:body]
|
10
|
+
set_file(env[:body], :file, true)
|
11
|
+
traverse_hash(env[:body])
|
12
|
+
end
|
13
|
+
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Sets the proper file parameters :uploaded_data and :filename
|
20
|
+
# If top_level, then it removes key and and sets the parameters directly on hash,
|
21
|
+
# otherwise it adds the parameters to hash[key]
|
22
|
+
def set_file(hash, key, top_level)
|
23
|
+
return unless hash.key?(key)
|
24
|
+
|
25
|
+
file = if hash[key].is_a?(Hash) && hash[key].key?(:file)
|
26
|
+
hash[key].delete(:file)
|
27
|
+
else
|
28
|
+
hash.delete(key)
|
29
|
+
end
|
19
30
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
31
|
+
case file
|
32
|
+
when File
|
33
|
+
path = file.path
|
34
|
+
when String
|
35
|
+
path = file
|
36
|
+
else
|
37
|
+
warn "WARNING: Passed invalid filename #{file} of type #{file.class} to upload"
|
38
|
+
end
|
39
|
+
|
40
|
+
if path
|
41
|
+
if !top_level
|
42
|
+
hash[key] ||= {}
|
43
|
+
hash = hash[key]
|
24
44
|
end
|
45
|
+
|
46
|
+
mime_type = MIME::Types.type_for(path).first || "application/octet-stream"
|
47
|
+
|
48
|
+
hash[:filename] ||= File.basename(path)
|
49
|
+
hash[:uploaded_data] = Faraday::UploadIO.new(path, mime_type)
|
25
50
|
end
|
51
|
+
end
|
26
52
|
|
27
|
-
|
53
|
+
# Calls #set_file on File instances or Hashes
|
54
|
+
# of the format { :file => File (, :filename => ...) }
|
55
|
+
def traverse_hash(hash)
|
56
|
+
hash.keys.each do |key|
|
57
|
+
if hash[key].is_a?(File)
|
58
|
+
set_file(hash, key, false)
|
59
|
+
elsif hash[key].is_a?(Hash)
|
60
|
+
if hash[key].key?(:file)
|
61
|
+
set_file(hash, key, false)
|
62
|
+
else
|
63
|
+
traverse_hash(hash[key])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
28
67
|
end
|
29
68
|
end
|
30
69
|
end
|
data/lib/zendesk_api/resource.rb
CHANGED
@@ -23,7 +23,7 @@ module ZendeskAPI
|
|
23
23
|
has :ticket
|
24
24
|
has :group
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
class Attachment < Data
|
28
28
|
def initialize(client, attributes)
|
29
29
|
if attributes.is_a?(Hash)
|
@@ -34,7 +34,7 @@ module ZendeskAPI
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def save
|
37
|
-
upload = Upload.create!(client, :file => file)
|
37
|
+
upload = Upload.create!(@client, :file => file)
|
38
38
|
self.token = upload.token
|
39
39
|
end
|
40
40
|
|
@@ -1,6 +1,19 @@
|
|
1
1
|
module ZendeskAPI
|
2
2
|
class TicketField < Resource; end
|
3
|
-
|
3
|
+
|
4
|
+
class TicketComment < Data
|
5
|
+
include Save
|
6
|
+
|
7
|
+
has_many :uploads, :class => :attachment, :inline => true
|
8
|
+
|
9
|
+
def save
|
10
|
+
save_associations
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
alias :save! :save
|
15
|
+
end
|
16
|
+
|
4
17
|
class TicketMetric < ReadResource; end
|
5
18
|
|
6
19
|
class Ticket < Resource
|
@@ -17,7 +30,6 @@ module ZendeskAPI
|
|
17
30
|
has :forum_topic, :class => :topic
|
18
31
|
has :organization
|
19
32
|
|
20
|
-
has_many :uploads, :class => :attachment, :inline => true
|
21
33
|
has :comment, :class => :ticket_comment, :inline => true
|
22
34
|
|
23
35
|
# Gets a incremental export of tickets from the start_time until now.
|
@@ -71,6 +83,4 @@ module ZendeskAPI
|
|
71
83
|
Zendesk::Collection.new(client, ViewRow, options.merge(:path => "views/preview"))
|
72
84
|
end
|
73
85
|
end
|
74
|
-
|
75
|
-
|
76
86
|
end
|
data/lib/zendesk_api/version.rb
CHANGED
data/live/ticket_spec.rb
CHANGED
@@ -5,7 +5,7 @@ describe ZendeskAPI::Ticket do
|
|
5
5
|
{
|
6
6
|
:type => "question",
|
7
7
|
:subject => "This is a question?",
|
8
|
-
:
|
8
|
+
:comment => { :value => "Indeed it is!" },
|
9
9
|
:priority => "normal",
|
10
10
|
:requester_id => user.id,
|
11
11
|
:submitter_id => user.id
|
@@ -66,12 +66,12 @@ describe ZendeskAPI::Ticket do
|
|
66
66
|
it "can upload while creating" do
|
67
67
|
VCR.use_cassette("ticket_inline_uploads") do
|
68
68
|
ticket = ZendeskAPI::Ticket.new(client, valid_attributes.merge(default_options))
|
69
|
-
ticket.uploads << "spec/fixtures/Argentina.gif"
|
70
|
-
|
69
|
+
ticket.comment.uploads << "spec/fixtures/Argentina.gif"
|
70
|
+
ticket.comment.uploads << File.new("spec/fixtures/Argentina.gif")
|
71
71
|
|
72
72
|
ticket.save!
|
73
|
-
ticket.changes.should == {} # uploads
|
74
|
-
ticket.attributes[:uploads].map(&:class).should == [String] # upload was sent as tokens
|
73
|
+
ticket.changes.should == {} # uploads were set before save
|
74
|
+
ticket.comment.attributes[:uploads].map(&:class).should == [String, String] # upload was sent as tokens
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
data/live/user_spec.rb
CHANGED
@@ -10,4 +10,10 @@ describe ZendeskAPI::User, :delete_after do
|
|
10
10
|
it_should_be_deletable :find => [:active?, false]
|
11
11
|
it_should_be_readable :users
|
12
12
|
it_should_be_readable organization, :users
|
13
|
+
|
14
|
+
it "should be able to find by email" do
|
15
|
+
VCR.use_cassette("user_find_by_email") do
|
16
|
+
client.users.search(:query => current_user.email).to_a.should == [current_user]
|
17
|
+
end
|
18
|
+
end
|
13
19
|
end
|
data/spec/collection_spec.rb
CHANGED
@@ -266,6 +266,12 @@ describe ZendeskAPI::Collection do
|
|
266
266
|
context "method missing" do
|
267
267
|
before(:each) { subject.stub(:fetch).and_return([1, 2, nil, 3]) }
|
268
268
|
|
269
|
+
context "with an class method on the resource class" do
|
270
|
+
it "should pass methods to class if defined" do
|
271
|
+
subject.test.should == "hi"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
269
275
|
it "should pass all methods not defined to resources" do
|
270
276
|
subject.compact.should == [1, 2, 3]
|
271
277
|
end
|
@@ -45,29 +45,61 @@ describe ZendeskAPI::Middleware::Request::Upload do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
context "with file instance" do
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
context "top-level" do
|
49
|
+
before(:each) do
|
50
|
+
@env = subject.call(:body => { :file => File.new(filename) })
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
it "should convert file string to UploadIO" do
|
54
|
+
@env[:body][:uploaded_data].should be_instance_of(Faraday::UploadIO)
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
57
|
+
it "should remove file string" do
|
58
|
+
@env[:body][:file].should be_nil
|
59
|
+
end
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
it "should add filename if none exist" do
|
62
|
+
@env[:body][:filename].should == "test.jpg"
|
63
|
+
end
|
64
|
+
|
65
|
+
context "with filename" do
|
66
|
+
before(:each) do
|
67
|
+
@env = subject.call(:body => { :file => File.new(filename), :filename => "test" })
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should not change filename" do
|
71
|
+
@env[:body][:filename].should_not == "test.jpg"
|
72
|
+
end
|
73
|
+
end
|
62
74
|
end
|
63
75
|
|
64
|
-
context "
|
65
|
-
|
66
|
-
|
76
|
+
context "underneath a key" do
|
77
|
+
context "only a file" do
|
78
|
+
before(:each) do
|
79
|
+
@env = subject.call(:body => { :user => { :photo => File.new(filename) } })
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should convert file string to UploadIO" do
|
83
|
+
@env[:body][:user][:photo][:uploaded_data].should be_instance_of(Faraday::UploadIO)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should add filename if none exist" do
|
87
|
+
@env[:body][:user][:photo][:filename].should == "test.jpg"
|
88
|
+
end
|
67
89
|
end
|
68
90
|
|
69
|
-
|
70
|
-
|
91
|
+
context "with filename" do
|
92
|
+
before(:each) do
|
93
|
+
@env = subject.call(:body => { :user => { :photo => { :file => File.new(filename), :filename => "test" } } })
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should convert file string to UploadIO" do
|
97
|
+
@env[:body][:user][:photo][:uploaded_data].should be_instance_of(Faraday::UploadIO)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should not change filename" do
|
101
|
+
@env[:body][:user][:photo][:filename].should_not == "test.jpg"
|
102
|
+
end
|
71
103
|
end
|
72
104
|
end
|
73
105
|
end
|
data/zendesk_api.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.required_ruby_version = ">= 1.8.7"
|
19
19
|
s.required_rubygems_version = ">= 1.3.6"
|
20
20
|
|
21
|
-
s.add_development_dependency "rspec", "
|
21
|
+
s.add_development_dependency "rspec", "~> 2.10.0"
|
22
22
|
s.add_development_dependency "vcr"
|
23
23
|
s.add_development_dependency "webmock"
|
24
24
|
s.add_development_dependency "rake"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zendesk_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 2.
|
21
|
+
version: 2.10.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 2.
|
29
|
+
version: 2.10.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: vcr
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|