desk_api 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -1
- data/lib/desk_api/action/embeddable.rb +47 -0
- data/lib/desk_api/action/update.rb +5 -0
- data/lib/desk_api/error/not_embeddable.rb +8 -0
- data/lib/desk_api/error/not_updateable.rb +10 -0
- data/lib/desk_api/error/unprocessable_entity.rb +1 -0
- data/lib/desk_api/error.rb +7 -9
- data/lib/desk_api/resource/case.rb +2 -0
- data/lib/desk_api/resource/filter.rb +7 -0
- data/lib/desk_api/resource/inbound_mailbox.rb +7 -0
- data/lib/desk_api/resource/job.rb +2 -0
- data/lib/desk_api/resource/page.rb +10 -27
- data/lib/desk_api/resource/reply.rb +2 -0
- data/lib/desk_api/resource.rb +28 -3
- data/lib/desk_api/version.rb +1 -1
- data/spec/cassettes/DeskApi_Error/on_validation_error/allows_access_to_error_hash.yml +54 -0
- data/spec/cassettes/DeskApi_Resource_Case/once_closed/can_not_be_updated.yml +124 -0
- data/spec/cassettes/DeskApi_Resource_Page/{_by_id/loads_the_requested_resource.yml → _find/has_an_alias_by_id.yml} +6 -6
- data/spec/cassettes/DeskApi_Resource_Page/_find/loads_the_requested_resource.yml +54 -0
- data/spec/desk_api/error_spec.rb +11 -0
- data/spec/desk_api/request/retry_spec.rb +9 -3
- data/spec/desk_api/resource/case_spec.rb +28 -0
- data/spec/desk_api/{resources → resource}/page_spec.rb +9 -5
- data/spec/desk_api/resource_spec.rb +68 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/stubs/case_embed_customer.json +115 -0
- data/spec/stubs/cases_embed_assigned_user.json +105 -0
- metadata +23 -7
- data/lib/desk_api/action/embedded.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e26e977b6cb1ed65a5dee9ccd93a3f4617fb71e0
|
4
|
+
data.tar.gz: 46a9845c1399f0a4644cde8f614c9ea38bcfc1e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c2e40fa8dbff7ac13c88e43233c155123efe5d4cd4c87c173e6b4428f725d76e4da01d49481c9d7ddfc6039f2aa25ad328da34d8c3ba19a664bed74c35309d5
|
7
|
+
data.tar.gz: 146cccebb60d61ce7c779a9fe35fe0f26284922270ffe97efbbe4f6c927db15d1bd54fc00844187a8d7ebfad4a0647f6c44ca068c93899c736899868a9a6fa50
|
data/README.md
CHANGED
@@ -54,6 +54,8 @@ The API supports RESTful resources and so does this wrapper. Those resources are
|
|
54
54
|
found_case = DeskApi.users.first.by_url '/api/v2/cases/1'
|
55
55
|
|
56
56
|
# find a case by case number
|
57
|
+
found_case = DeskApi.cases.find 1
|
58
|
+
# the old #by_id still works
|
57
59
|
found_case = DeskApi.cases.by_id 1
|
58
60
|
```
|
59
61
|
|
@@ -108,6 +110,27 @@ end
|
|
108
110
|
DeskApi.cases.page == 1
|
109
111
|
```
|
110
112
|
|
113
|
+
### Side loading
|
114
|
+
|
115
|
+
APIv2 has a lot of great new features but the one I'm most excited about is side loading or embedding resources. You basically request one resource and tell the API to embed sub resources, eg. you need cases but also want to have the `assigned_user` - instead of requesting all cases and the `assigned_user` for each of those cases (30 cases = 31 API requests) you can now embed `assigned_user` into your cases list view (1 API REQUEST!!!!).
|
116
|
+
|
117
|
+
Of course we had to bring this awesomeness into the API wrapper as soon as possible, so here you go:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
# fetch cases with their respective customers
|
121
|
+
cases = DeskApi.cases.embed(:customer)
|
122
|
+
customer = cases.first.customer
|
123
|
+
|
124
|
+
# you can use this feature in finders too
|
125
|
+
my_case = DeskApi.cases.find(1, embed: :customer)
|
126
|
+
# OR
|
127
|
+
my_case = DeskApi.cases.find(1, embed: [:customer, :assigned_user, :assigned_group])
|
128
|
+
|
129
|
+
customer = my_case.customer
|
130
|
+
assigned_user = my_case.assigned_user
|
131
|
+
assigned_group = my_case.assigned_group
|
132
|
+
```
|
133
|
+
|
111
134
|
### Create, Update and Delete
|
112
135
|
|
113
136
|
Of course we support creating, updating and deleting resources but not all resources can be deleted or updated or created, if that's the case for the resource you're trying to update, it'll throw a `DeskApi::Error::MethodNotSupported` error. The specific method won't be defined on the resource either `DeskApi.cases.first.respond_to?(:delete) == false`.
|
@@ -191,7 +214,7 @@ Please also have a look at all [desk.com API errors](http://dev.desk.com/API/usi
|
|
191
214
|
|
192
215
|
(The MIT License)
|
193
216
|
|
194
|
-
Copyright (c) 2013 Thomas Stachl <
|
217
|
+
Copyright (c) 2013 Thomas Stachl <thomas@desk.com>
|
195
218
|
|
196
219
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
197
220
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'desk_api/error/not_embeddable'
|
2
|
+
|
3
|
+
module DeskApi
|
4
|
+
module Action
|
5
|
+
module Embeddable
|
6
|
+
attr_reader :embedded
|
7
|
+
|
8
|
+
def embed(*embedds)
|
9
|
+
# make sure we don't try to embed anything that's not defined
|
10
|
+
# add it to the query
|
11
|
+
self.query_params = { embed: embedds.each{ |embed|
|
12
|
+
unless self.base_class.embeddable?(embed)
|
13
|
+
raise DeskApi::Error::NotEmbeddable.new("`#{embed.to_s}' can not be embedded.")
|
14
|
+
end
|
15
|
+
}.join(',') }
|
16
|
+
# return self
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup_embedded(embedds)
|
21
|
+
if embedds.entries?
|
22
|
+
@records = embedds['entries'].map do |record|
|
23
|
+
resource(record._links.self['class']).new(client, record, true)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
embedds.each_pair do |key, definition|
|
27
|
+
@_links[key]['resource'] = resource(definition['class']).new @client, definition, true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
def embeddable(*embeddables)
|
34
|
+
@embeddables = embeddables
|
35
|
+
end
|
36
|
+
|
37
|
+
def embeddable?(key)
|
38
|
+
(@embeddables || []).include?(key.to_sym)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.included(base)
|
43
|
+
base.extend(ClassMethods)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -2,9 +2,14 @@ module DeskApi
|
|
2
2
|
module Action
|
3
3
|
module Update
|
4
4
|
def update(params = {})
|
5
|
+
if kind_of?(resource('case')) and status == 'closed'
|
6
|
+
raise DeskApi::Error::NotUpdateable
|
7
|
+
end
|
8
|
+
|
5
9
|
params.each_pair do |key, value|
|
6
10
|
send("#{key}=", value) if respond_to?("#{key}=")
|
7
11
|
end
|
12
|
+
|
8
13
|
setup(client.patch(@_links.self.href, @_changed).body)
|
9
14
|
end
|
10
15
|
end
|
data/lib/desk_api/error.rb
CHANGED
@@ -11,10 +11,9 @@ module DeskApi
|
|
11
11
|
# @param response_headers [Hash]
|
12
12
|
# @param code [Integer]
|
13
13
|
# @return [DeskApi::Error]
|
14
|
-
def initialize(exception=$!, response_headers={}, code = nil)
|
14
|
+
def initialize(exception=$!, response_headers={}, code = nil, err_hash = nil)
|
15
15
|
@rate_limit = DeskApi::RateLimit.new(response_headers)
|
16
|
-
@wrapped_exception = exception
|
17
|
-
@code = code
|
16
|
+
@wrapped_exception, @code, @errors = exception, code, err_hash
|
18
17
|
exception.respond_to?(:backtrace) ? super(exception.message) : super(exception.to_s)
|
19
18
|
end
|
20
19
|
|
@@ -28,8 +27,8 @@ module DeskApi
|
|
28
27
|
# @param response [Hash]
|
29
28
|
# @return [DeskApi::Error]
|
30
29
|
def from_response(response = {})
|
31
|
-
error, code =
|
32
|
-
new(error, response[:response_headers], code)
|
30
|
+
err_hash, error, code = parse_body(response[:body]).push(response[:status])
|
31
|
+
new(error, response[:response_headers], code, err_hash)
|
33
32
|
end
|
34
33
|
|
35
34
|
# @return [Hash]
|
@@ -51,11 +50,10 @@ module DeskApi
|
|
51
50
|
|
52
51
|
private
|
53
52
|
|
54
|
-
def
|
55
|
-
|
56
|
-
body['message']
|
57
|
-
end
|
53
|
+
def parse_body(body = {})
|
54
|
+
[body['errors'] || nil, body['message'] || nil]
|
58
55
|
end
|
56
|
+
|
59
57
|
end
|
60
58
|
end
|
61
59
|
end
|
@@ -2,7 +2,6 @@ module DeskApi
|
|
2
2
|
class Resource
|
3
3
|
class Page < DeskApi::Resource
|
4
4
|
include Enumerable
|
5
|
-
include DeskApi::Action::Embedded
|
6
5
|
|
7
6
|
[
|
8
7
|
:all?, :any?,
|
@@ -31,44 +30,28 @@ module DeskApi
|
|
31
30
|
[:page, :per_page].each do |method|
|
32
31
|
define_method(method) do |value = nil|
|
33
32
|
if not value
|
34
|
-
self.exec! if self.
|
35
|
-
return self.
|
33
|
+
self.exec! if self.query_params_include?(method.to_s) == nil
|
34
|
+
return self.query_params_include?(method.to_s).to_i
|
36
35
|
end
|
37
36
|
self.query_params = Hash[method.to_s, value.to_s]
|
38
37
|
self
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
|
-
def
|
43
|
-
|
41
|
+
def find(id, options = {})
|
42
|
+
res = base_class.new(client, Hashie::Mash.new({ _links: { self: { href: "#{clean_base_url}/#{id}" }}}))
|
43
|
+
if options[:embed]
|
44
|
+
options[:embed] = [options[:embed]] unless options[:embed].kind_of?(Array)
|
45
|
+
res.embed(*options[:embed])
|
46
|
+
end
|
47
|
+
res.exec!
|
44
48
|
end
|
49
|
+
alias_method :by_id, :find
|
45
50
|
|
46
51
|
protected
|
47
52
|
|
48
53
|
attr_reader :records
|
49
54
|
|
50
|
-
def setup(definition)
|
51
|
-
setup_embedded(definition._embedded['entries']) if definition._embedded?
|
52
|
-
super(definition)
|
53
|
-
end
|
54
|
-
|
55
|
-
def query_params(param)
|
56
|
-
params = Addressable::URI.parse(@_links.self.href).query_values || {}
|
57
|
-
params.include?(param) ? params[param] : nil
|
58
|
-
end
|
59
|
-
|
60
|
-
def query_params=(params = {})
|
61
|
-
return @_links.self.href if params.empty?
|
62
|
-
|
63
|
-
uri = Addressable::URI.parse(@_links.self.href)
|
64
|
-
params = (uri.query_values || {}).merge(params)
|
65
|
-
|
66
|
-
@loaded = false unless params == uri.query_values
|
67
|
-
|
68
|
-
uri.query_values = params
|
69
|
-
@_links.self.href = uri.to_s
|
70
|
-
end
|
71
|
-
|
72
55
|
def clean_base_url
|
73
56
|
Addressable::URI.parse(@_links.self.href).path.gsub(/\/search$/, '')
|
74
57
|
end
|
data/lib/desk_api/resource.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'desk_api/action/create'
|
2
2
|
require 'desk_api/action/delete'
|
3
|
-
require 'desk_api/action/
|
3
|
+
require 'desk_api/action/embeddable'
|
4
4
|
require 'desk_api/action/field'
|
5
5
|
require 'desk_api/action/link'
|
6
6
|
require 'desk_api/action/resource'
|
@@ -14,6 +14,7 @@ module DeskApi
|
|
14
14
|
include DeskApi::Action::Resource
|
15
15
|
include DeskApi::Action::Link
|
16
16
|
include DeskApi::Action::Field
|
17
|
+
include DeskApi::Action::Embeddable
|
17
18
|
|
18
19
|
def initialize(client, definition = {}, loaded = false)
|
19
20
|
@client, @loaded, @_changed = client, loaded, {}
|
@@ -37,16 +38,41 @@ module DeskApi
|
|
37
38
|
|
38
39
|
def exec!(reload = false)
|
39
40
|
return self if loaded and !reload
|
40
|
-
definition, @loaded = client.get(
|
41
|
+
definition, @loaded = client.get(get_href).body, true
|
41
42
|
setup(definition)
|
42
43
|
end
|
43
44
|
|
45
|
+
def query_params
|
46
|
+
Addressable::URI.parse(@_links.self.href).query_values || {}
|
47
|
+
end
|
48
|
+
|
49
|
+
def query_params_include?(param)
|
50
|
+
query_params.include?(param) ? query_params[param] : nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def query_params=(params = {})
|
54
|
+
return @_links.self.href if params.empty?
|
55
|
+
|
56
|
+
uri = Addressable::URI.parse(@_links.self.href)
|
57
|
+
params = (uri.query_values || {}).merge(params)
|
58
|
+
|
59
|
+
@loaded = false unless params == uri.query_values
|
60
|
+
|
61
|
+
uri.query_values = params
|
62
|
+
@_links.self.href = uri.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def base_class
|
66
|
+
self.class
|
67
|
+
end
|
68
|
+
|
44
69
|
private
|
45
70
|
|
46
71
|
attr_accessor :client, :loaded, :_changed
|
47
72
|
|
48
73
|
def setup(definition)
|
49
74
|
setup_links(definition._links) if definition._links?
|
75
|
+
setup_embedded(definition._embedded) if definition._embedded?
|
50
76
|
setup_fields(definition)
|
51
77
|
self
|
52
78
|
end
|
@@ -56,6 +82,5 @@ module DeskApi
|
|
56
82
|
raise DeskApi::Error::MethodNotSupported unless self.respond_to?(method.to_sym)
|
57
83
|
self.send(method, *args, &block)
|
58
84
|
end
|
59
|
-
|
60
85
|
end
|
61
86
|
end
|
data/lib/desk_api/version.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://devel.desk.com/api/v2/articles
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"subject":"Testing","body":"Testing"}'
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- application/json
|
12
|
+
User-Agent:
|
13
|
+
- desk.com Ruby Gem v0.1.2
|
14
|
+
Content-Type:
|
15
|
+
- application/json
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 422
|
19
|
+
message:
|
20
|
+
headers:
|
21
|
+
Accept-Ranges:
|
22
|
+
- bytes
|
23
|
+
Cache-Control:
|
24
|
+
- no-cache
|
25
|
+
Content-Type:
|
26
|
+
- application/json; charset=utf-8
|
27
|
+
Date:
|
28
|
+
- Wed, 04 Sep 2013 23:57:05 GMT
|
29
|
+
Status:
|
30
|
+
- 422 Unprocessable Entity
|
31
|
+
Vary:
|
32
|
+
- X-AppVersion
|
33
|
+
X-AppVersion:
|
34
|
+
- '9.7'
|
35
|
+
X-Frame-Options:
|
36
|
+
- SAMEORIGIN
|
37
|
+
X-Rate-Limit-Limit:
|
38
|
+
- '60'
|
39
|
+
X-Rate-Limit-Remaining:
|
40
|
+
- '59'
|
41
|
+
X-Rate-Limit-Reset:
|
42
|
+
- '55'
|
43
|
+
X-Request-Id:
|
44
|
+
- a902613e4a179503f1a94b35421449ec
|
45
|
+
Content-Length:
|
46
|
+
- '71'
|
47
|
+
Connection:
|
48
|
+
- keep-alive
|
49
|
+
body:
|
50
|
+
encoding: UTF-8
|
51
|
+
string: '{"message":"Validation Failed","errors":{"_links":{"topic":["blank"]}}}'
|
52
|
+
http_version:
|
53
|
+
recorded_at: Wed, 04 Sep 2013 23:57:05 GMT
|
54
|
+
recorded_with: VCR 2.5.0
|