desk_api_v2 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.
Files changed (59) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +0 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +24 -0
  6. data/README.md +27 -0
  7. data/Rakefile +39 -0
  8. data/desk_api_v2.gemspec +27 -0
  9. data/lib/desk.rb +11 -0
  10. data/lib/desk/api/articles.rb +34 -0
  11. data/lib/desk/api/cases.rb +47 -0
  12. data/lib/desk/api/customers.rb +36 -0
  13. data/lib/desk/api/groups.rb +30 -0
  14. data/lib/desk/api/modules/creatable.rb +15 -0
  15. data/lib/desk/api/modules/deletable.rb +11 -0
  16. data/lib/desk/api/modules/listable.rb +16 -0
  17. data/lib/desk/api/modules/searchable.rb +13 -0
  18. data/lib/desk/api/topics.rb +25 -0
  19. data/lib/desk/api/translations.rb +24 -0
  20. data/lib/desk/article.rb +7 -0
  21. data/lib/desk/case.rb +7 -0
  22. data/lib/desk/client.rb +39 -0
  23. data/lib/desk/collection.rb +17 -0
  24. data/lib/desk/connection.rb +71 -0
  25. data/lib/desk/customer.rb +7 -0
  26. data/lib/desk/entity.rb +7 -0
  27. data/lib/desk/error.rb +17 -0
  28. data/lib/desk/filter.rb +7 -0
  29. data/lib/desk/group.rb +7 -0
  30. data/lib/desk/message.rb +7 -0
  31. data/lib/desk/response/error_handling.rb +30 -0
  32. data/lib/desk/topic.rb +7 -0
  33. data/lib/desk/translation.rb +7 -0
  34. data/lib/desk/user.rb +7 -0
  35. data/spec/desk/api/articles_spec.rb +135 -0
  36. data/spec/desk/api/cases_spec.rb +181 -0
  37. data/spec/desk/api/customers_spec.rb +135 -0
  38. data/spec/desk/api/groups_spec.rb +98 -0
  39. data/spec/desk/api/topics_spec.rb +98 -0
  40. data/spec/desk/api/translations_spec.rb +92 -0
  41. data/spec/desk/collection_spec.rb +22 -0
  42. data/spec/desk/connection_spec.rb +95 -0
  43. data/spec/fixtures/article.json +39 -0
  44. data/spec/fixtures/articles.json +101 -0
  45. data/spec/fixtures/case.json +40 -0
  46. data/spec/fixtures/cases.json +105 -0
  47. data/spec/fixtures/customer.json +60 -0
  48. data/spec/fixtures/customers.json +143 -0
  49. data/spec/fixtures/group.json +9 -0
  50. data/spec/fixtures/group_filters.json +53 -0
  51. data/spec/fixtures/group_users.json +71 -0
  52. data/spec/fixtures/groups.json +42 -0
  53. data/spec/fixtures/message.json +26 -0
  54. data/spec/fixtures/topic.json +23 -0
  55. data/spec/fixtures/topics.json +69 -0
  56. data/spec/fixtures/translation.json +28 -0
  57. data/spec/fixtures/translations.json +79 -0
  58. data/spec/spec_helper.rb +17 -0
  59. metadata +200 -0
@@ -0,0 +1,39 @@
1
+ require 'desk/connection'
2
+ require 'desk/api/cases'
3
+ require 'desk/api/articles'
4
+ require 'desk/api/translations'
5
+ require 'desk/api/customers'
6
+ require 'desk/api/topics'
7
+ require 'desk/api/groups'
8
+
9
+ module Desk
10
+ class Client
11
+
12
+ def initialize(opts={})
13
+ @opts = opts
14
+ end
15
+
16
+ def articles
17
+ Desk::Api::Articles.new(connection)
18
+ end
19
+
20
+ def cases
21
+ Desk::Api::Cases.new(connection)
22
+ end
23
+
24
+ def customers
25
+ Desk::Api::Customers.new(connection)
26
+ end
27
+
28
+ def topics
29
+ Desk::Api::Topics.new(connection)
30
+ end
31
+
32
+ private
33
+
34
+ def connection
35
+ @connection ||= Desk::Connection.new(@opts)
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ module Desk
2
+ class Collection < Array
3
+
4
+ def initialize(response, klass)
5
+ @response = response
6
+ super response["_embedded"]["entries"]
7
+ coerce_into klass
8
+ end
9
+
10
+ private
11
+
12
+ def coerce_into(klass)
13
+ self.map! { |obj| klass.new(obj) }
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,71 @@
1
+ require 'faraday_middleware'
2
+ require 'desk/response/error_handling'
3
+
4
+ module Desk
5
+ class Connection
6
+
7
+ def initialize(opts={})
8
+ @site = opts[:site]
9
+ connection
10
+ use_basic_auth(opts) if opts[:email] && opts[:password]
11
+ use_oauth(opts) if opts[:consumer_key] &&
12
+ opts[:consumer_secret] &&
13
+ opts[:token] &&
14
+ opts[:token_secret]
15
+ end
16
+
17
+ def get(*opts)
18
+ @connection.get(*stringify_arrays(*opts)).body
19
+ end
20
+
21
+ def post(*opts)
22
+ @connection.post(*opts).body
23
+ end
24
+
25
+ def patch(*opts)
26
+ @connection.patch(*opts).body
27
+ end
28
+
29
+ def delete(*opts)
30
+ result = @connection.delete(*opts)
31
+
32
+ result.status == 204
33
+ end
34
+
35
+ private
36
+
37
+ def connection
38
+ @connection ||= Faraday.new(base_url, ssl: { verify: true } ) do |conn|
39
+ conn.use Desk::Response::ErrorHandling
40
+ conn.use FaradayMiddleware::ParseJson
41
+ conn.headers = {'Content-Type' => 'application/json', 'Accept' => 'application/json' }
42
+ conn.request :json
43
+ conn.use Faraday::Adapter::NetHttp
44
+ end
45
+ @connection
46
+ end
47
+
48
+ def use_basic_auth(opts)
49
+ @connection.builder.insert(1, Faraday::Request::BasicAuthentication, opts[:email], opts[:password])
50
+ end
51
+
52
+ def use_oauth(opts)
53
+ @connection.builder.insert(1, FaradayMiddleware::OAuth, {
54
+ :consumer_key => opts[:consumer_key],
55
+ :consumer_secret => opts[:consumer_secret],
56
+ :token => opts[:token],
57
+ :token_secret => opts[:token_secret]
58
+ } )
59
+ end
60
+
61
+ def base_url
62
+ "https://#{@site}.desk.com/api/v2/"
63
+ end
64
+
65
+ def stringify_arrays(*opts)
66
+ opts.collect do |opt|
67
+ opt.is_a?(Hash) ? opt.each {|k,v| opt[k] = v.is_a?(Array) ? v.join(",") : v} : opt
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,7 @@
1
+ require 'desk/entity'
2
+
3
+ module Desk
4
+ class Customer < Entity
5
+
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'ostruct'
2
+
3
+ module Desk
4
+ class Entity < OpenStruct
5
+
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ module Desk
2
+ class Error < StandardError
3
+
4
+ end
5
+
6
+ BadRequest = Class.new(Desk::Error)
7
+ Unauthorized = Class.new(Desk::Error)
8
+ NotFound = Class.new(Desk::Error)
9
+ Forbidden = Class.new(Desk::Error)
10
+ MethodNotAllowed = Class.new(Desk::Error)
11
+ NotAcceptable = Class.new(Desk::Error)
12
+ Conflict = Class.new(Desk::Error)
13
+ UnsupportedMediaType = Class.new(Desk::Error)
14
+ UnprocessableEntity = Class.new(Desk::Error)
15
+ TooManyRequests = Class.new(Desk::Error)
16
+ NotImplemented = Class.new(Desk::Error)
17
+ end
@@ -0,0 +1,7 @@
1
+ require 'desk/entity'
2
+
3
+ module Desk
4
+ class Filter < Entity
5
+
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'desk/entity'
2
+
3
+ module Desk
4
+ class Group < Entity
5
+
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'desk/entity'
2
+
3
+ module Desk
4
+ class Message < Entity
5
+
6
+ end
7
+ end
@@ -0,0 +1,30 @@
1
+ require 'desk/error'
2
+
3
+ module Desk
4
+ module Response
5
+ class ErrorHandling < Faraday::Response::Middleware
6
+
7
+ ERROR_TYPE = {
8
+ 400 => BadRequest,
9
+ 401 => Unauthorized,
10
+ 404 => NotFound,
11
+ 403 => Forbidden,
12
+ 405 => MethodNotAllowed,
13
+ 406 => NotAcceptable,
14
+ 409 => Conflict,
15
+ 415 => UnsupportedMediaType,
16
+ 422 => UnprocessableEntity,
17
+ 429 => TooManyRequests,
18
+ 501 => NotImplemented
19
+ }
20
+
21
+ def call(env)
22
+ @app.call(env).on_complete do |finished_env|
23
+ if finished_env[:status] >= 400
24
+ raise ERROR_TYPE[finished_env[:status]], finished_env[:body]["message"] if ERROR_TYPE[finished_env[:status]]
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ require 'desk/entity'
2
+
3
+ module Desk
4
+ class Topic < Entity
5
+
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'desk/entity'
2
+
3
+ module Desk
4
+ class Translation < Entity
5
+
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'desk/entity'
2
+
3
+ module Desk
4
+ class User < Entity
5
+
6
+ end
7
+ end
@@ -0,0 +1,135 @@
1
+ require 'json'
2
+ require_relative '../../spec_helper'
3
+
4
+ describe Desk::Api::Articles do
5
+
6
+ before { @connection = Minitest::Mock.new }
7
+
8
+ subject { Desk::Api::Articles.new(@connection) }
9
+
10
+ describe "#all" do
11
+
12
+ before { @connection.expect(:get, articles_fixture, ["articles"]) }
13
+
14
+ it "will connect to the articles endpoint" do
15
+ subject.all
16
+ end
17
+
18
+ it "will return an array of articles" do
19
+ result = subject.all
20
+
21
+ assert result.is_a? Array
22
+ assert result.first.is_a? Desk::Article
23
+ end
24
+ end
25
+
26
+ describe "#show" do
27
+
28
+ before { @connection.expect(:get, article_fixture, ["articles/1234"]) }
29
+
30
+ it "will connect to the article show endpoint" do
31
+ subject.show(1234)
32
+
33
+ @connection.verify
34
+ end
35
+
36
+ it "will return a single article object" do
37
+ result = subject.show(1234)
38
+
39
+ assert result.is_a? Desk::Article
40
+ end
41
+ end
42
+
43
+ describe "#create" do
44
+
45
+ before do
46
+ @data = {
47
+ subject: "How to make your customers happy",
48
+ body: "<strong>Use Desk.com</strong>",
49
+ body_email: "Custom email body for article",
50
+ body_email_auto: false,
51
+ _links: { topic: { href: "/api/v2/topics/1", class: "topic" } }
52
+ }
53
+
54
+ @connection.expect(:post, article_fixture, ["articles", @data])
55
+ end
56
+
57
+ it "will connect to the article creation endpoint" do
58
+ subject.create(@data)
59
+
60
+ @connection.verify
61
+ end
62
+ end
63
+
64
+ describe "#update" do
65
+ before do
66
+ @data = {
67
+ subject: "How to make your customers happy",
68
+ body: "<strong>Use Desk.com</strong>",
69
+ body_email: "Email just doesn't cut it",
70
+ body_email_auto: false,
71
+ body_twitter: "Use Desk.com in 140 chars or less",
72
+ body_twitter_auto: false,
73
+ _links: {
74
+ topic: {
75
+ href: "/api/v2/topics/2"
76
+ }
77
+ }
78
+ }
79
+
80
+ @connection.expect(:patch, article_fixture, ["articles/1234", @data])
81
+ end
82
+
83
+ it "will connect to the article update endpoint" do
84
+ subject.update(1234, @data)
85
+
86
+ @connection.verify
87
+ end
88
+ end
89
+
90
+ describe "#delete" do
91
+
92
+ before { @connection.expect(:delete, true, ["articles/1234"]) }
93
+
94
+ it "will connect to the article delete endpoint" do
95
+ subject.delete(1234)
96
+
97
+ @connection.verify
98
+ end
99
+ end
100
+
101
+ describe "#search" do
102
+
103
+ it "will connect to the article search endpoint" do
104
+ @connection.expect(:get, articles_fixture, ["articles/search", {text: "foo"}])
105
+
106
+ subject.search(text: "foo")
107
+
108
+ @connection.verify
109
+ end
110
+
111
+ it "will pass topic IDs into the search query" do
112
+ @connection.expect(:get, articles_fixture, ["articles/search", {text: "foo", topic_ids: [1,2,3]}])
113
+
114
+ subject.search(text: "foo", topic_ids: [1,2,3])
115
+
116
+ @connection.verify
117
+ end
118
+
119
+ it "will whitelist hash arguments" do
120
+ @connection.expect(:get, articles_fixture, ["articles/search", {text: "foo", topic_ids: [1,2,3]}])
121
+
122
+ subject.search(text: "foo", topic_ids: [1,2,3], bar: "baz")
123
+
124
+ @connection.verify
125
+ end
126
+ end
127
+
128
+ def articles_fixture
129
+ JSON.load(fixture("articles.json"))
130
+ end
131
+
132
+ def article_fixture
133
+ JSON.load(fixture("article.json"))
134
+ end
135
+ end
@@ -0,0 +1,181 @@
1
+ require 'json'
2
+ require_relative '../../spec_helper'
3
+
4
+ class CasesSpec
5
+ describe Desk::Api::Cases do
6
+
7
+ before { @connection = Minitest::Mock.new }
8
+
9
+ subject { Desk::Api::Cases.new(@connection) }
10
+
11
+ describe "#all" do
12
+
13
+ before { @connection.expect(:get, cases_fixture, ["cases"]) }
14
+
15
+ it "will connect to the cases endpoint" do
16
+ subject.all
17
+
18
+ @connection.verify
19
+ end
20
+
21
+ it "will return an array of cases" do
22
+ result = subject.all
23
+
24
+ assert result.is_a? Array
25
+ assert result.first.is_a? Desk::Case
26
+ end
27
+ end
28
+
29
+ describe "#show" do
30
+
31
+ before { @connection.expect(:get, case_fixture, ["cases/1234"]) }
32
+
33
+ it "will connect to the case show endpoint" do
34
+ subject.show(1234)
35
+
36
+ @connection.verify
37
+ end
38
+
39
+ it "will return a single case object" do
40
+ result = subject.show(1234)
41
+
42
+ assert result.is_a? Desk::Case
43
+ end
44
+ end
45
+
46
+ describe "#create" do
47
+
48
+ before do
49
+ @data = {
50
+ type: "email",
51
+ subject: "Creating a case via the API",
52
+ priority: 4,
53
+ status: "open",
54
+ labels: [
55
+ "Spam",
56
+ "Ignore"
57
+ ],
58
+ language: "fr",
59
+ created_at: "2012-05-01T21:38:48Z",
60
+ _links: {
61
+ customer: {
62
+ href: "/api/v2/customers/1",
63
+ class: "customer"
64
+ },
65
+ assigned_user: {
66
+ href: "/api/v2/users/1",
67
+ class: "user"
68
+ },
69
+ assigned_group: {
70
+ href: "/api/v2/groups/1",
71
+ class: "group"
72
+ },
73
+ locked_by: {
74
+ href: "/api/v2/users/1",
75
+ class: "user"
76
+ }
77
+ },
78
+ message: {
79
+ direction: "in",
80
+ status: "received",
81
+ to: "someone@desk.com",
82
+ from: "someone-else@desk.com",
83
+ cc: "alpha@desk.com",
84
+ bcc: "beta@desk.com",
85
+ subject: "Creating a case via the API",
86
+ body: "Please assist me with this case",
87
+ created_at: "2012-05-02T21:38:48Z"
88
+ }
89
+ }
90
+
91
+ @connection.expect(:post, case_fixture, ["cases", @data])
92
+ end
93
+
94
+ it "will connect to the case creation endpoint" do
95
+ subject.create(@data)
96
+
97
+ @connection.verify
98
+ end
99
+ end
100
+
101
+ describe "#update" do
102
+ before do
103
+ @data = {
104
+ subject: "Updated",
105
+ status: "pending",
106
+ labels: [
107
+ "Spam",
108
+ "Test"
109
+ ],
110
+ custom_fields: {
111
+ level: "super"
112
+ },
113
+ _links: {
114
+ assigned_group: {
115
+ href: "/api/v2/groups/1",
116
+ rel: "group"
117
+ }
118
+ }
119
+ }
120
+
121
+ @connection.expect(:patch, case_fixture, ["cases/1234", @data])
122
+ end
123
+
124
+ it "will connect to the case update endpoint" do
125
+ subject.update(1234, @data)
126
+
127
+ @connection.verify
128
+ end
129
+ end
130
+
131
+ describe "#search" do
132
+
133
+ Desk::Api::Cases::VALID_SEARCH_PARAMS.each do |param|
134
+ it "will pass whitelisted params into the search query" do
135
+ @connection.expect(:get, cases_fixture, ["cases/search", {param => "foo"}])
136
+
137
+ subject.search(param => "foo")
138
+
139
+ @connection.verify
140
+ end
141
+ end
142
+
143
+ it "will whitelist hash arguments" do
144
+ @connection.expect(:get, cases_fixture, ["cases/search", {name: "foo"}])
145
+
146
+ subject.search(name: "foo", bar: "baz")
147
+
148
+ @connection.verify
149
+ end
150
+ end
151
+
152
+ describe "#message" do
153
+
154
+ before { @connection.expect(:get, message_fixture, ["cases/1234/message"]) }
155
+
156
+ it "will connect to the case message endpoint" do
157
+ subject.message(1234)
158
+
159
+ @connection.verify
160
+ end
161
+
162
+ it "will return a single message object" do
163
+ result = subject.message(1234)
164
+
165
+ assert result.is_a? Desk::Message
166
+ end
167
+ end
168
+
169
+ def cases_fixture
170
+ JSON.load(fixture("cases.json"))
171
+ end
172
+
173
+ def case_fixture
174
+ JSON.load(fixture("case.json"))
175
+ end
176
+
177
+ def message_fixture
178
+ JSON.load(fixture("message.json"))
179
+ end
180
+ end
181
+ end