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 CHANGED
@@ -5,3 +5,4 @@ spec/fixtures/cassettes
5
5
  spec/fixtures/credentials.yml
6
6
  coverage
7
7
  .yardoc
8
+ example.rb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zendesk_api (0.0.9)
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.7)
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.3)
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.2)
43
- webmock (1.8.7)
44
- addressable (>= 2.2.7)
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 (>= 2.0.0)
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
- Currently
13
+ The Zendesk API client can be installed using Rubygems or Bundler.
14
14
 
15
- gem install zendesk_api
15
+ ### Rubygems
16
16
 
17
- will not install this version of the API client. To install this client, either clone this repository and run
17
+ ```sh
18
+ gem install zendesk_api
19
+ ```
20
+
21
+ ### Bundler
18
22
 
19
- rake install
23
+ Add it to your Gemfile
20
24
 
21
- or add it to a Gemfile like so:
25
+ gem "zendesk_api"
22
26
 
23
- gem "zendesk_api", :git => "git://github.com/zendesk/zendesk_api_client_rb.git" #, :tag => "vX.X.X"
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
- ZendeskAPI::Client.new do |config|
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 = "test.user"
37
- config.password = "test.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", :description => "This is a test", :submitter_id => client.current_user.id, :priority => "urgent")
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", :description => "This is a test", :submitter_id => client.current_user.id, :priority => "urgent")
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 tickets using either a path or the File class and will
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
- # Revert Rails' overwrite of const_missing
243
- if method_defined?(:const_missing_without_dependencies)
244
- alias :const_missing :const_missing_without_dependencies
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
- if Array.new.respond_to?(name)
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] && env[:body][:file]
10
- file = env[:body].delete(:file)
11
- case file
12
- when File
13
- path = file.path
14
- when String
15
- path = file
16
- else
17
- warn "WARNING: Passed invalid filename #{file} of type #{file.class} to upload"
18
- end
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
- if path
21
- env[:body][:filename] ||= File.basename(path)
22
- mime_type = MIME::Types.type_for(path).first || "application/octet-stream"
23
- env[:body][:uploaded_data] = Faraday::UploadIO.new(path, mime_type)
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
- @app.call(env)
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
@@ -125,7 +125,7 @@ module ZendeskAPI
125
125
  extend Read
126
126
  include Create
127
127
 
128
- include Update
128
+ include Update
129
129
  include Destroy
130
130
  end
131
131
 
@@ -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
- class TicketComment < Data; end
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
@@ -1,3 +1,3 @@
1
1
  module ZendeskAPI
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.1"
3
3
  end
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
- :description => "Indeed it is!",
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
- #ticket.uploads << File.new("spec/fixtures/Argentina.gif") # TODO ZendeskAPI bug: you can only upload 1 picture at a time
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 where set before save
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
@@ -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
@@ -1,4 +1,8 @@
1
1
  class ZendeskAPI::TestResource < ZendeskAPI::Resource
2
+ def self.test(client)
3
+ "hi"
4
+ end
5
+
2
6
  class TestChild < ZendeskAPI::Resource
3
7
  end
4
8
  end
@@ -45,29 +45,61 @@ describe ZendeskAPI::Middleware::Request::Upload do
45
45
  end
46
46
 
47
47
  context "with file instance" do
48
- before(:each) do
49
- @env = subject.call(:body => { :file => File.new(filename) })
50
- end
48
+ context "top-level" do
49
+ before(:each) do
50
+ @env = subject.call(:body => { :file => File.new(filename) })
51
+ end
51
52
 
52
- it "should convert file string to UploadIO" do
53
- @env[:body][:uploaded_data].should be_instance_of(Faraday::UploadIO)
54
- end
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
- it "should remove file string" do
57
- @env[:body][:file].should be_nil
58
- end
57
+ it "should remove file string" do
58
+ @env[:body][:file].should be_nil
59
+ end
59
60
 
60
- it "should add filename if none exist" do
61
- @env[:body][:filename].should == "test.jpg"
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 "with filename" do
65
- before(:each) do
66
- @env = subject.call(:body => { :file => File.new(filename), :filename => "test" })
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
- it "should not change filename" do
70
- @env[:body][:filename].should_not == "test.jpg"
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", ">= 2.0.0"
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.0.9
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-06-29 00:00:00.000000000 Z
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.0.0
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.0.0
29
+ version: 2.10.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: vcr
32
32
  requirement: !ruby/object:Gem::Requirement