KayakoClient 0.0.1b

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 (39) hide show
  1. data/lib/kayako_client.rb +36 -0
  2. data/lib/kayako_client/base.rb +98 -0
  3. data/lib/kayako_client/department.rb +31 -0
  4. data/lib/kayako_client/http/http.rb +217 -0
  5. data/lib/kayako_client/http/http_backend.rb +31 -0
  6. data/lib/kayako_client/http/http_client.rb +87 -0
  7. data/lib/kayako_client/http/http_response.rb +61 -0
  8. data/lib/kayako_client/http/net_http.rb +109 -0
  9. data/lib/kayako_client/mixins/api.rb +299 -0
  10. data/lib/kayako_client/mixins/attachment.rb +69 -0
  11. data/lib/kayako_client/mixins/authentication.rb +34 -0
  12. data/lib/kayako_client/mixins/client.rb +308 -0
  13. data/lib/kayako_client/mixins/logger.rb +29 -0
  14. data/lib/kayako_client/mixins/object.rb +456 -0
  15. data/lib/kayako_client/mixins/post_client.rb +42 -0
  16. data/lib/kayako_client/mixins/staff_visibility_api.rb +9 -0
  17. data/lib/kayako_client/mixins/ticket_api.rb +55 -0
  18. data/lib/kayako_client/mixins/ticket_client.rb +135 -0
  19. data/lib/kayako_client/mixins/user_visibility_api.rb +9 -0
  20. data/lib/kayako_client/staff.rb +25 -0
  21. data/lib/kayako_client/staff_group.rb +9 -0
  22. data/lib/kayako_client/ticket.rb +241 -0
  23. data/lib/kayako_client/ticket_attachment.rb +42 -0
  24. data/lib/kayako_client/ticket_count.rb +135 -0
  25. data/lib/kayako_client/ticket_custom_field.rb +110 -0
  26. data/lib/kayako_client/ticket_note.rb +105 -0
  27. data/lib/kayako_client/ticket_post.rb +61 -0
  28. data/lib/kayako_client/ticket_priority.rb +24 -0
  29. data/lib/kayako_client/ticket_status.rb +31 -0
  30. data/lib/kayako_client/ticket_time_track.rb +27 -0
  31. data/lib/kayako_client/ticket_type.rb +26 -0
  32. data/lib/kayako_client/user.rb +61 -0
  33. data/lib/kayako_client/user_group.rb +12 -0
  34. data/lib/kayako_client/user_organization.rb +23 -0
  35. data/lib/kayako_client/xml/lib_xml.rb +86 -0
  36. data/lib/kayako_client/xml/rexml_document.rb +77 -0
  37. data/lib/kayako_client/xml/xml.rb +63 -0
  38. data/lib/kayako_client/xml/xml_backend.rb +42 -0
  39. metadata +105 -0
@@ -0,0 +1,36 @@
1
+ require 'kayako_client/http/http_response'
2
+ require 'kayako_client/http/http_backend'
3
+ require 'kayako_client/http/http'
4
+
5
+ require 'kayako_client/xml/xml_backend'
6
+ require 'kayako_client/xml/xml'
7
+
8
+ require 'kayako_client/mixins/api'
9
+ require 'kayako_client/mixins/object'
10
+ require 'kayako_client/mixins/client'
11
+ require 'kayako_client/mixins/ticket_client'
12
+ require 'kayako_client/mixins/post_client'
13
+ require 'kayako_client/mixins/logger'
14
+ require 'kayako_client/mixins/authentication'
15
+ require 'kayako_client/mixins/attachment'
16
+ require 'kayako_client/mixins/ticket_api'
17
+ require 'kayako_client/mixins/user_visibility_api'
18
+ require 'kayako_client/mixins/staff_visibility_api'
19
+
20
+ require 'kayako_client/base'
21
+ require 'kayako_client/department'
22
+ require 'kayako_client/staff'
23
+ require 'kayako_client/staff_group'
24
+ require 'kayako_client/ticket'
25
+ require 'kayako_client/ticket_attachment'
26
+ require 'kayako_client/ticket_custom_field'
27
+ require 'kayako_client/ticket_note'
28
+ require 'kayako_client/ticket_post'
29
+ require 'kayako_client/ticket_priority'
30
+ require 'kayako_client/ticket_status'
31
+ require 'kayako_client/ticket_time_track'
32
+ require 'kayako_client/ticket_type'
33
+ require 'kayako_client/ticket_count'
34
+ require 'kayako_client/user'
35
+ require 'kayako_client/user_group'
36
+ require 'kayako_client/user_organization'
@@ -0,0 +1,98 @@
1
+ module KayakoClient
2
+
3
+ class Base
4
+ include KayakoClient::API
5
+ include KayakoClient::Logger
6
+ include KayakoClient::Object
7
+ include KayakoClient::Authentication
8
+ include KayakoClient::HTTP
9
+ include KayakoClient::XML
10
+
11
+ def initialize(*args)
12
+ options = args.last.is_a?(Hash) ? args.pop : {}
13
+
14
+ if args[0]
15
+ @api_url = args[0]
16
+ elsif options.has_key?(:api_url)
17
+ @api_url = options.delete(:api_url)
18
+ else
19
+ @api_url = Base.api_url
20
+ end
21
+
22
+ if args[1]
23
+ @api_key = args[1]
24
+ elsif options.has_key?(:api_key)
25
+ @api_key = options.delete(:api_key)
26
+ else
27
+ @api_key = Base.api_key
28
+ end
29
+
30
+ if args[2]
31
+ @secret_key = args[2]
32
+ elsif options.has_key?(:secret_key)
33
+ @secret_key = options.delete(:secret_key)
34
+ else
35
+ @secret_key = Base.secret_key
36
+ end
37
+
38
+ if options.has_key?(:client)
39
+ http = options.delete(:client)
40
+ if http
41
+ if http.class.included_modules.include?(KayakoClient::HTTPBackend)
42
+ @http_backend = http.class
43
+ @client = http
44
+ else
45
+ raise ArgumentError, "invalid HTTP client: #{http.class.name}"
46
+ end
47
+ end
48
+ end
49
+
50
+ if options.has_key?(:logger)
51
+ @logger = options.delete(:logger)
52
+ end
53
+
54
+ if self.instance_of?(KayakoClient::Base)
55
+ unless defined?(@client) && @client
56
+ @client = http_backend.new(proxy.merge(:logger => logger))
57
+ end
58
+ self.extend(KayakoClient::Client)
59
+ end
60
+
61
+ @associated = {}
62
+ import(options)
63
+ end
64
+
65
+ def inherited_options
66
+ inherited = {}
67
+ inherited[:api_url] = @api_url if defined?(@api_url)
68
+ inherited[:api_key] = @api_key if defined?(@api_key)
69
+ inherited[:secret_key] = @secret_key if defined?(@secret_key)
70
+ inherited[:client] = @client if defined?(@client)
71
+ inherited[:logger] = @logger if defined?(@logger)
72
+ inherited
73
+ end
74
+
75
+ class << self
76
+
77
+ def configure(&block)
78
+ instance_eval(&block)
79
+ end
80
+
81
+ def inherited_options(options)
82
+ inherited = {}
83
+ inherited[:api_url] = options[:api_url] if options.has_key?(:api_url)
84
+ inherited[:api_key] = options[:api_key] if options.has_key?(:api_key)
85
+ inherited[:secret_key] = options[:secret_key] if options.has_key?(:secret_key)
86
+ inherited[:client] = options[:client] if options.has_key?(:client)
87
+ inherited[:logger] = options[:logger] if options.has_key?(:logger)
88
+ inherited
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+ class Tickets < Base
96
+ end
97
+
98
+ end
@@ -0,0 +1,31 @@
1
+ require 'kayako_client/mixins/user_visibility_api'
2
+
3
+ require 'kayako_client/user_group'
4
+
5
+ module KayakoClient
6
+ class Department < KayakoClient::Base
7
+ include KayakoClient::UserVisibilityAPI
8
+
9
+ DEPARTMENT_TYPES = [ :public, :private ].freeze
10
+ DEPARTMENT_MODULES = [ :tickets, :livechat ].freeze
11
+
12
+ # NOTE: if :parent_department_id is set :module should have the same value
13
+
14
+ property :id, :integer, :readonly => true
15
+ property :title, :string, :required => [ :put, :post ]
16
+ property :type, :symbol, :in => DEPARTMENT_TYPES, :required => :post
17
+ property :module, :symbol, :in => DEPARTMENT_MODULES, :required => :post, :new => true
18
+ property :display_order, :integer
19
+ property :parent_department_id, :integer
20
+ property :user_visibility_custom, :boolean
21
+ property :user_group_ids, [ :integer ], :get => :usergroups, :set => :usergroupid, :condition => { :user_visibility_custom => true }
22
+
23
+ associate :parent_department, :parent_department_id, Department
24
+ associate :user_groups, :user_group_ids, UserGroup
25
+
26
+ def has_parent_department?
27
+ !parent_department_id.nil? && parent_department_id > 0
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,217 @@
1
+ module KayakoClient
2
+ module HTTP
3
+
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ def proxy=(options = {})
9
+ @proxy = {}
10
+ options.each do |key, value|
11
+ if [ :host, :port, :user, :pass ].include?(key)
12
+ @proxy[key] = value
13
+ else
14
+ raise ArgumentError, "unsupported option: #{key}"
15
+ end
16
+ end
17
+ end
18
+
19
+ def proxy
20
+ @proxy ||= self.class.proxy
21
+ end
22
+
23
+ def http_backend=(backend)
24
+ if backend.is_a?(String)
25
+ raise ArgumentError, "invalid HTTP backend: #{backend}" unless backend =~ /^[A-Za-z_]+$/
26
+ file = backend.gsub(/([a-z])([A-Z])/, '\1_\2').gsub(/([A-Z])([A-Z][a-z])/, '\1_\2').downcase
27
+ require "kayako_client/http/#{file}"
28
+ backend = KayakoClient.const_get(backend)
29
+ end
30
+ if backend.is_a?(Class)
31
+ if backend.included_modules.include?(KayakoClient::HTTPBackend)
32
+ @http_backend = backend
33
+ @client = nil
34
+ else
35
+ raise ArgumentError, "invalid HTTP backend: #{backend.name}"
36
+ end
37
+ else
38
+ if backend.class.included_modules.include?(KayakoClient::HTTPBackend)
39
+ @http_backend = backend.class
40
+ @client = backend
41
+ else
42
+ raise ArgumentError, "invalid HTTP backend: #{backend.class.name}"
43
+ end
44
+ end
45
+ end
46
+
47
+ def http_backend
48
+ @http_backend ||= self.class.http_backend
49
+ end
50
+
51
+ def client
52
+ @client ||= nil
53
+ unless @client
54
+ if !instance_of?(KayakoClient::Base) && http_backend == self.class.http_backend && self.class.client
55
+ @client = self.class.client
56
+ else
57
+ @client = http_backend.new(proxy.merge(:logger => logger))
58
+ end
59
+ end
60
+ @client
61
+ end
62
+
63
+ def put_request(params = {})
64
+ @errors ||= {}
65
+ raise RuntimeError, "undefined ID" unless id
66
+ random = self.class.salt
67
+ e = params.delete(:e) || "#{self.class.path}/#{id}"
68
+ data = self.class.validate(params.merge(:errors => @errors))
69
+ if @errors.empty?
70
+ client.put(api_url, data.merge(:e => e,
71
+ :apikey => api_key,
72
+ :salt => random,
73
+ :signature => self.class.signature(random, secret_key)))
74
+ else
75
+ @errors
76
+ end
77
+ end
78
+
79
+ def post_request(params = {})
80
+ @errors ||= {}
81
+ random = self.class.salt
82
+ e = params.delete(:e) || self.class.path
83
+ data = self.class.validate(params.merge(:errors => @errors))
84
+ if @errors.empty?
85
+ client.post(api_url, data.merge(:e => e,
86
+ :apikey => api_key,
87
+ :salt => random,
88
+ :signature => self.class.signature(random, secret_key)))
89
+ else
90
+ @errors
91
+ end
92
+ end
93
+
94
+ def delete_request(params = {})
95
+ raise RuntimeError, "undefined ID" unless id
96
+ random = self.class.salt
97
+ e = params.delete(:e) || "#{self.class.path}/#{id}"
98
+ client.delete(api_url, :e => e,
99
+ :apikey => api_key,
100
+ :salt => random,
101
+ :signature => self.class.signature(random, secret_key))
102
+ end
103
+
104
+ module ClassMethods
105
+
106
+ def proxy=(options = {})
107
+ @@proxy = {}
108
+ options.each do |key, value|
109
+ if [ :host, :port, :user, :pass ].include?(key)
110
+ @@proxy[key] = value
111
+ else
112
+ raise ArgumentError, "unsupported option: #{key}"
113
+ end
114
+ end
115
+ end
116
+
117
+ def proxy
118
+ @@proxy ||= {}
119
+ end
120
+
121
+ def http_backend=(backend)
122
+ if backend.is_a?(String)
123
+ raise ArgumentError, "invalid HTTP backend: #{backend}" unless backend =~ /^[A-Za-z_]+$/
124
+ file = backend.gsub(/([a-z])([A-Z])/, '\1_\2').gsub(/([A-Z])([A-Z][a-z])/, '\1_\2').downcase
125
+ require "kayako_client/http/#{file}"
126
+ backend = KayakoClient.const_get(backend)
127
+ end
128
+ if backend.is_a?(Class)
129
+ if backend.included_modules.include?(KayakoClient::HTTPBackend)
130
+ @@http_backend = backend
131
+ @@client = nil
132
+ else
133
+ raise ArgumentError, "invalid HTTP backend: #{backend.name}"
134
+ end
135
+ else
136
+ if backend.class.included_modules.include?(KayakoClient::HTTPBackend)
137
+ @@http_backend = backend.class
138
+ @@client = backend
139
+ else
140
+ raise ArgumentError, "invalid HTTP backend: #{backend.class.name}"
141
+ end
142
+ end
143
+ end
144
+
145
+ def http_backend
146
+ begin
147
+ require 'kayako_client/http/http_client'
148
+ @@http_backend ||= KayakoClient::HTTPClient
149
+ rescue LoadError
150
+ require 'kayako_client/http/net_http'
151
+ @@http_backend ||= KayakoClient::NetHTTP
152
+ end
153
+ end
154
+
155
+ def client
156
+ @@client ||= nil
157
+ unless @@client
158
+ @@client = http_backend.new(proxy.merge(:logger => logger))
159
+ end
160
+ @@client
161
+ end
162
+
163
+ def get_request(options = {})
164
+ random = salt
165
+ params = options.dup
166
+
167
+ id = params.delete(:id)
168
+ e = params.delete(:e) || (id.nil? ? path : "#{path}/#{id}")
169
+ http = params.delete(:client) || client
170
+ url = params.delete(:api_url) || api_url
171
+ key = params.delete(:api_key) || api_key
172
+ secret = params.delete(:secret_key) || secret_key
173
+
174
+ http.get(url, params.merge(:e => e,
175
+ :apikey => key,
176
+ :salt => random,
177
+ :signature => signature(random, secret)))
178
+ end
179
+
180
+ def post_request(options = {})
181
+ random = salt
182
+ params = options.dup
183
+
184
+ e = params.delete(:e) || path
185
+ http = params.delete(:client) || client
186
+ url = params.delete(:api_url) || api_url
187
+ key = params.delete(:api_key) || api_key
188
+ secret = params.delete(:secret_key) || secret_key
189
+
190
+ http.post(url, params.merge(:e => e,
191
+ :apikey => key,
192
+ :salt => random,
193
+ :signature => signature(random, secret)))
194
+ end
195
+
196
+ def delete_request(options = {})
197
+ random = salt
198
+ params = options.dup
199
+
200
+ id = params.delete(:id)
201
+ e = params.delete(:e) || "#{path}/#{id}"
202
+ http = params.delete(:client) || client
203
+ url = params.delete(:api_url) || api_url
204
+ key = params.delete(:api_key) || api_key
205
+ secret = params.delete(:secret_key) || secret_key
206
+
207
+ raise ArgumentError, "missing ID" unless id
208
+ http.delete(url, :e => e,
209
+ :apikey => key,
210
+ :salt => random,
211
+ :signature => signature(random, secret))
212
+ end
213
+
214
+ end
215
+
216
+ end
217
+ end
@@ -0,0 +1,31 @@
1
+ require 'uri'
2
+
3
+ module KayakoClient
4
+ module HTTPBackend
5
+
6
+ def initialize(options = {})
7
+ raise NotImplementedError, "not implemented"
8
+ end
9
+
10
+ def get(base, params = {})
11
+ raise NotImplementedError, "not implemented"
12
+ end
13
+
14
+ def put(base, params = {})
15
+ raise NotImplementedError, "not implemented"
16
+ end
17
+
18
+ def post(base, params = {})
19
+ raise NotImplementedError, "not implemented"
20
+ end
21
+
22
+ def delete(base, params = {})
23
+ raise NotImplementedError, "not implemented"
24
+ end
25
+
26
+ def response(resp)
27
+ raise NotImplementedError, "not implemented"
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,87 @@
1
+ require 'httpclient'
2
+
3
+ module KayakoClient
4
+ class HTTPClient
5
+ include KayakoClient::Logger
6
+ include KayakoClient::HTTPBackend
7
+
8
+ def initialize(options = {})
9
+ @client = ::HTTPClient.new
10
+ if options[:host]
11
+ @client.proxy = "http://#{options[:host]}:#{options[:port] || 80}"
12
+ @client.set_proxy_auth(options[:user], options[:pass])
13
+ end
14
+ @logger = options[:logger] if options[:logger]
15
+ end
16
+
17
+ def get(base, params = {})
18
+ log = params.delete(:logger) || logger
19
+ log.debug ":get => #{base} + #{params.inspect}" if log
20
+ resp = @client.request(:get, base, params)
21
+ response(resp)
22
+ end
23
+
24
+ def put(base, params = {})
25
+ query = { :e => params.delete(:e) }
26
+ data = form_data(params)
27
+ log = params.delete(:logger) || logger
28
+ if log
29
+ log.debug ":put => #{base} + #{query.inspect}"
30
+ log.debug "PUT Data: #{data.inspect}"
31
+ end
32
+ resp = @client.request(:put, base, query, data, { 'Content-Type' => 'application/x-www-form-urlencoded' })
33
+ response(resp)
34
+ end
35
+
36
+ def post(base, params = {})
37
+ query = { :e => params.delete(:e) }
38
+ data = form_data(params)
39
+ log = params.delete(:logger) || logger
40
+ if log
41
+ log.debug ":post => #{base} + #{query.inspect}"
42
+ log.debug "POST Data: #{data.inspect}"
43
+ end
44
+ resp = @client.request(:post, base, query, data, { 'Content-Type' => 'application/x-www-form-urlencoded' })
45
+ response(resp)
46
+ end
47
+
48
+ def delete(base, params = {})
49
+ log = params.delete(:logger) || logger
50
+ log.debug ":delete => #{base} + #{params.inspect}" if log
51
+ resp = @client.request(:delete, base, params)
52
+ response(resp)
53
+ end
54
+
55
+ def response(resp)
56
+ case resp.status
57
+ when 200
58
+ KayakoClient::HTTPOK.new(resp.content)
59
+ when 400
60
+ KayakoClient::HTTPBadRequest.new(resp.content)
61
+ when 401
62
+ KayakoClient::HTTPUnauthorized.new(resp.content)
63
+ when 403
64
+ KayakoClient::HTTPForbidden.new(resp.content)
65
+ when 404
66
+ KayakoClient::HTTPNotFound.new(resp.content)
67
+ when 405
68
+ KayakoClient::HTTPNotAllowed.new(resp.content)
69
+ else
70
+ KayakoClient::HTTPResponse.new(resp.status, resp.content)
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def form_data(params = {})
77
+ params.inject([]) do |array, (name, value)|
78
+ if value.is_a?(Array)
79
+ array.concat(value.collect { |item| [ name.to_s + '[]', item.to_s ] })
80
+ else
81
+ array.push([ name.to_s, value.to_s ])
82
+ end
83
+ end
84
+ end
85
+
86
+ end
87
+ end