hotdogprincess 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e7c35fd12cdfc18cf8f3184c216dc0431aa5b129
4
+ data.tar.gz: 1df368952003b482dd2f857a921964c9e4728b31
5
+ SHA512:
6
+ metadata.gz: 98743b6e01e4ecf64d5cdc3eec8f7df3bff6815ad9e3667a42b24b0db0e7d6756ea435ce6dcd6d1d1167f50adb9f57df02e52406b9b7b2915ef90a166ad8d27c
7
+ data.tar.gz: b9e01d4b3a3401a45b254f048866e5d5610212341e833859d9b3390419f262105c9384de412cc0a9d4a88b15a02557815ad020c86655f1fca79321b43797c3f9
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Matthew Callis
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,315 @@
1
+ # Hot Dog Princess
2
+
3
+ ![Hot Dog Princess](https://raw.githubusercontent.com/MatthewCallis/HotDogPrincess/master/hdp.png)
4
+
5
+ _-- "Their message says, Baby... Us... Trouble... Time."_
6
+
7
+ Integrate with the [Parature](http://www.parature.com/) API. It's gunna be so flippin' awesome!
8
+
9
+ Currently a WIP.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'hotdogprincess'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install hotdogprincess
24
+
25
+ ## Usage
26
+
27
+ ### Setup
28
+
29
+ You will need your host, the account ID, the department ID and your API token.
30
+
31
+ ### Testing
32
+
33
+ You will need to make a copy of `spec/hotdogprincess.sample.yml` as `spec/hotdogprincess.yml` with your own testing credentials.
34
+
35
+ ### Examples
36
+
37
+ You can use the client in two possible way, or more if you're really brave and creative:
38
+
39
+ ```ruby
40
+ client = ::HotDogPrincess::Client.new(host: 'sandbox.parature.com', account_id: 123, department_id: 456, token: 'api_token')
41
+
42
+ OR
43
+
44
+ HotDogPrincess.client
45
+ ```
46
+
47
+ From here you can do all sorts of wonderful things:
48
+
49
+ ```ruby
50
+ # Schema, Status, View
51
+ client.schema 'Customer'
52
+ client.schema 'Ticket'
53
+ client.schema 'Sla'
54
+ => {"?xml"=>{"@version"=>"1.0", "@encoding"=>"utf-8"}, "Customer"=> ...
55
+
56
+ client.status 'Customer'
57
+ client.status 'Ticket'
58
+ client.status 'Sla'
59
+ => {"?xml"=>{"@version"=>"1.0", "@encoding"=>"utf-8"}, "entities"=> ...
60
+
61
+
62
+ # Well that's neat, but XML? What the hell is wrong with you, is it 2001‽
63
+ client.schema_json 'Customer'
64
+ client.schema_json 'Ticket'
65
+ client.schema_json 'Sla'
66
+ => # See below for important details about all JSON returns.
67
+
68
+ client.status_json 'Customer'
69
+ client.status_json 'Ticket'
70
+ client.status_json 'Sla'
71
+ => "[{\"id\":16,\"uid\":\"123/456/Customer/status/10001\",\"href\":"...
72
+
73
+ client.view 'Ticket'
74
+ => {"?xml"=>{"@version"=>"1.0", "@encoding"=>"utf-8"}, "Entities"=> ...
75
+
76
+ client.view_json 'Ticket'
77
+ => "[{\"id\":7,\"uid\":\"123/456/Ticket/view/7\","...
78
+
79
+ # Working with Customers / Tickets / SLAs
80
+ # Raw XML: Page size defaults to 100 records.
81
+ page_size = 50
82
+ customers = client.fetch_customers(page_size)
83
+ tickets = client.fetch_ticket(page_size)
84
+ slas = client.fetch_slas(page_size)
85
+ => {"?xml"=>{"@version"=>"1.0", "@encoding"=>"utf-8"}, "Entities"=> {"@total"=>"12400", "@results"=>"50"...
86
+
87
+ customers = client.fetch_customers
88
+ tickets = client.fetch_ticket
89
+ slas = client.fetch_slas
90
+ => {"?xml"=>{"@version"=>"1.0", "@encoding"=>"utf-8"}, "Entities"=> {"@total"=>"12400", "@results"=>"100"...
91
+
92
+ # We have them cached, so if we need the raw XML again:
93
+ customers = client.customers_raw
94
+ tickets = client.tickets_raw
95
+ slas = client.slas_raw
96
+ => {"?xml"=>{"@version"=>"1.0", "@encoding"=>"utf-8"}, "Entities"=> {"@total"=>"12400", "@results"=>"100"...
97
+
98
+ # Hash: Page size defaults to 100 records, and force update defaults to false.
99
+ customers = client.customers
100
+ tickets = client.tickets
101
+ slas = client.slas
102
+ => [#<Hash id="10002", uid="123/456/Customer/10002", href="https:..."] x 100 of 12400
103
+
104
+ customers = client.customers(50, true)
105
+ tickets = client.tickets(50, true)
106
+ slas = client.slas(50, true)
107
+ => [#<Hash id="10002", uid="123/456/Customer/10002", href="https:..."] x 50 of 12401, we got a new entry since the last call!
108
+
109
+ # Counts: Just for convenience.
110
+ client.customer_count
111
+ client.ticket_count
112
+ client.sla_count
113
+ => 50
114
+
115
+ # Fetch a single item by ID.
116
+ customer = client.customer 10002
117
+ ticket = client.ticket 10001
118
+ sla = client.sla 1
119
+ => #<Hash id="1", uid="123/456/Sla/1", href="https://sandbox.parature.com/api/v1/123/456/Sla/1", name="System Default">
120
+
121
+ # Searching: You search email with either exact match or a substring match.
122
+ client.find_customer_by_email 'joe@exmaple.comz'
123
+ => [#<Hash id="26553", uid="16115/16155/Customer/26553",
124
+
125
+ client.find_customer_by_email 'not_found@brandnewusers.io'
126
+ => []
127
+
128
+ substring = true
129
+ client.find_customer_by_email 'gmail.com', substring
130
+ => [#<Hash id="26553", uid="16115/16155/Customer/26553", x ~50
131
+
132
+ # Creating Customers / Tickets: We are using https://github.com/savonrb/gyoku to create XML from Hashes, so see the docs for in-depth XML constructions.
133
+ customer_hash = {
134
+ "Customer" => {
135
+ "First_Name" => 'Joe',
136
+ "Last_Name" => 'Blow',
137
+ "Email" => 'joe@example.comz',
138
+ "Password" => 'password',
139
+ "Password_Confirm" => 'password',
140
+ "Sla" => {
141
+ "Sla/" => {
142
+ :@id => "1"
143
+ }
144
+ }
145
+ }
146
+ }
147
+ customer = client.create_customer customer_hash
148
+ => #<Hash id="10003", uid="123/456/Customer/10003", ...
149
+
150
+ ticket_hash = {
151
+ "Ticket" => {
152
+ "Ticket_Customer" => {
153
+ "Customer/" => {
154
+ :@id => "10003"
155
+ }
156
+ },
157
+ "Custom_Field" => [
158
+ {
159
+ :@id => 1,
160
+ :content! => "Notes: It's Godzilla, no it's Apptentive!"
161
+ },
162
+ {
163
+ :@id => 2,
164
+ :content! => "Status: Healthy"
165
+ },
166
+ ]
167
+ }
168
+ }
169
+ ticket = client.create_ticket input_xml
170
+ => #<Hash id="10004", uid="123/456/Ticket/10004", ...
171
+
172
+ # Update Customers / Tickets: Typically this returns an ID, but we instead fetch that ID and return the entire updated entity.
173
+ client.update_customer 10003, customer_hash
174
+ => #<Hash id="10003", uid="123/456/Customer/10003", ...
175
+
176
+ client.update_ticket 10004, ticket_hash
177
+ => #<Hash id="10004", uid="123/456/Ticket/10004", ...
178
+
179
+ # For more depth, have a peek at the source code.
180
+ ```
181
+
182
+ #### Schema JSON Output
183
+
184
+ The JSON output has tried to stay readable and match the keys from the XML. Object formats are converted to their native JSON types (Boolean, Integer, Float) when possible. This is particularly useful when you're using this in combination with native forms on a front end.
185
+
186
+ ```json
187
+ {
188
+ "customer_role": {
189
+ "display_name": "Customer Role",
190
+ "required": false,
191
+ "editable": true,
192
+ "data_type": "entity",
193
+ "field_type": "entity",
194
+ "customerrole": {
195
+ "name": {
196
+ "display_name": "Name"
197
+ }
198
+ }
199
+ },
200
+ "date_created": {
201
+ "display_name": "Date Created",
202
+ "required": false,
203
+ "editable": false,
204
+ "field_type": "usdate",
205
+ "data_type": "date"
206
+ },
207
+ "date_updated": {
208
+ "display_name": "Date Updated",
209
+ "required": false,
210
+ "editable": false,
211
+ "field_type": "usdate",
212
+ "data_type": "date"
213
+ },
214
+ "date_visited": {
215
+ "display_name": "Date Visited",
216
+ "required": false,
217
+ "editable": false,
218
+ "field_type": "usdate",
219
+ "data_type": "date"
220
+ },
221
+ "email": {
222
+ "display_name": "Email",
223
+ "required": true,
224
+ "editable": true,
225
+ "field_type": "email",
226
+ "data_type": "string",
227
+ "max_length": 256
228
+ },
229
+ "first_name": {
230
+ "display_name": "First Name",
231
+ "required": true,
232
+ "editable": true,
233
+ "field_type": "text",
234
+ "data_type": "string",
235
+ "max_length": 128
236
+ },
237
+ "full_name": {
238
+ "display_name": "Full Name",
239
+ "required": false,
240
+ "editable": true,
241
+ "field_type": "text",
242
+ "data_type": "string",
243
+ "max_length": 256
244
+ },
245
+ "last_name": {
246
+ "display_name": "Last Name",
247
+ "required": true,
248
+ "editable": true,
249
+ "field_type": "text",
250
+ "data_type": "string",
251
+ "max_length": 128
252
+ },
253
+ "password": {
254
+ "display_name": "Password",
255
+ "required": true,
256
+ "editable": true,
257
+ "field_type": "password",
258
+ "data_type": "string",
259
+ "max_length": 96
260
+ },
261
+ "password_confirm": {
262
+ "display_name": "Password (confirm)",
263
+ "required": true,
264
+ "editable": true,
265
+ "field_type": "password",
266
+ "data_type": "string",
267
+ "max_length": 96
268
+ },
269
+ "sla": {
270
+ "display_name": "Service Level Agreement",
271
+ "required": true,
272
+ "editable": true,
273
+ "field_type": "dropdown",
274
+ "data_type": "entity",
275
+ "sla": {
276
+ "name": {
277
+ "display_name": "Name"
278
+ }
279
+ }
280
+ },
281
+ "status": {
282
+ "display_name": "Status",
283
+ "required": true,
284
+ "editable": true,
285
+ "data_type": "entity",
286
+ "field_type": "dropdown",
287
+ "status": {
288
+ "name": {
289
+ "display_name": "Name"
290
+ }
291
+ }
292
+ }
293
+ }
294
+ ```
295
+
296
+ #### Unimplemented Functionality
297
+
298
+ Another useful thing about Hot Dog Princess is the GET/PUT/POST/DELETE methods are all available on the client, so any unimplemented feature could be constructed as needed, but it'd be awesome if you would just code and open a pull request.
299
+
300
+ ```ruby
301
+ client.get 'Customer', "First_Name_like_" => "joe"
302
+ => {"?xml"=>{"@version"=>"1.0", "@encoding"=>"utf-8"}...
303
+ ```
304
+
305
+
306
+
307
+ ## Contributing
308
+
309
+ 1. Fork it
310
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
311
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
312
+ 4. Push to the branch (`git push origin my-new-feature`)
313
+ 5. Create new Pull Request
314
+
315
+ ![It's gunna be so flippin' awesome!](https://raw.githubusercontent.com/MatthewCallis/HotDogPrincess/master/awesome.gif)
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :test => :spec
8
+ task :default => :spec
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hotdogprincess/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.authors = ['Matthew Callis']
8
+ spec.email = ['matthew.callis@gmail.com']
9
+
10
+ spec.name = 'hotdogprincess'
11
+ spec.description = %q{Integrate with the Parature API.}
12
+ spec.summary = "Integrate with the Parature API. It's gunna be so flippin' awesome!"
13
+ spec.homepage = 'https://github.com/MatthewCallis/hotdogprincess'
14
+
15
+ spec.files = %w(LICENSE.md README.md Rakefile hotdogprincess.gemspec)
16
+ spec.files += Dir.glob("lib/**/*.rb")
17
+ spec.licenses = ['MIT']
18
+
19
+ spec.add_development_dependency 'bundler', '~> 1.0'
20
+
21
+ spec.add_runtime_dependency 'gyoku', '~> 1'
22
+ spec.add_runtime_dependency 'nori', '~> 2'
23
+
24
+ spec.require_paths = ['lib']
25
+ spec.required_ruby_version = '>= 1.9.2'
26
+ spec.required_rubygems_version = '>= 1.3.5'
27
+
28
+ spec.version = HotDogPrincess::VERSION.dup
29
+ end
@@ -0,0 +1,25 @@
1
+ require 'hotdogprincess/client'
2
+ require 'hotdogprincess/core_extensions'
3
+
4
+ module HotDogPrincess
5
+ class << self
6
+
7
+ def client(options = {})
8
+ @client = HotDogPrincess::Client.new(options) unless defined?(@client)
9
+ @client
10
+ end
11
+
12
+ # @private
13
+ def respond_to_missing?(method_name, include_private=false); client.respond_to?(method_name, include_private); end if RUBY_VERSION >= "1.9"
14
+ # @private
15
+ def respond_to?(method_name, include_private=false); client.respond_to?(method_name, include_private) || super; end if RUBY_VERSION < "1.9"
16
+
17
+ private
18
+
19
+ def method_missing(method_name, *args, &block)
20
+ return super unless client.respond_to?(method_name)
21
+ client.send(method_name, *args, &block)
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,207 @@
1
+ require "restclient"
2
+ require "hotdogprincess/version"
3
+ require "hotdogprincess/client/customers"
4
+ require "hotdogprincess/client/tickets"
5
+ require "hotdogprincess/client/slas"
6
+
7
+ module HotDogPrincess
8
+
9
+ class Client
10
+
11
+ include HotDogPrincess::Client::Customers
12
+ include HotDogPrincess::Client::Tickets
13
+ include HotDogPrincess::Client::Slas
14
+
15
+ def initialize(options = {})
16
+ @host = options[:host]
17
+ @token = options[:token]
18
+ @account_id = options[:account_id]
19
+ @department_id = options[:department_id]
20
+ @output_format = :json
21
+ end
22
+
23
+ def get(path, options = {})
24
+ url = "https://#{@host}/api/v1/#{@account_id}/#{@department_id}/#{path.to_s}"
25
+ options = {
26
+ _output_: @output_format,
27
+ _token_: @token
28
+ }.merge(options)
29
+ @last_response = RestClient.get url, { params: options }
30
+ clean_response @last_response
31
+ end
32
+
33
+ def post(path, body, options = {})
34
+ url = "https://#{@host}/api/v1/#{@account_id}/#{@department_id}/#{path.to_s}?_token_=#{@token}"
35
+ options = {
36
+ content_type: :xml
37
+ }.merge(options)
38
+ @last_response = RestClient.post url, body, options
39
+ @last_response
40
+ end
41
+
42
+ def put(path, body, options = {})
43
+ url = "https://#{@host}/api/v1/#{@account_id}/#{@department_id}/#{path.to_s}?_token_=#{@token}&_enforceRequiredFields_=false"
44
+ options = {
45
+ content_type: :xml
46
+ }.merge(options)
47
+ @last_response = RestClient.put url, body, options
48
+ @last_response
49
+ end
50
+
51
+ def delete(path, options = {})
52
+ url = "https://#{@host}/api/v1/#{@account_id}/#{@department_id}/#{path.to_s}"
53
+ options = {
54
+ _output_: @output_format,
55
+ _token_: @token
56
+ }.merge(options)
57
+ @last_response = RestClient.delete url, { params: options }
58
+ @last_response
59
+ end
60
+
61
+ def host=(value)
62
+ @host = value
63
+ end
64
+
65
+ def host
66
+ @host
67
+ end
68
+
69
+ def token=(value)
70
+ @token = value
71
+ end
72
+
73
+ def token
74
+ @token
75
+ end
76
+
77
+ def account_id=(value)
78
+ @account_id = value
79
+ end
80
+
81
+ def account_id
82
+ @account_id
83
+ end
84
+
85
+ def department_id=(value)
86
+ @department_id = value
87
+ end
88
+
89
+ def department_id
90
+ @department_id
91
+ end
92
+
93
+ def last_response
94
+ @last_response if defined? @last_response
95
+ end
96
+
97
+ def clean_response(response)
98
+ return nil unless response and response.class == String
99
+ return nil unless response.length >= 3
100
+ # "\xEF", "\xBB", "\xBF"
101
+ if response[0].ord == 239 and response[1].ord == 187 and response[2].ord == 191
102
+ response_hash = JSON.parse response[3..-1]
103
+ else
104
+ response_hash = JSON.parse response
105
+ end
106
+ response_hash
107
+ end
108
+
109
+ def status(object)
110
+ get "#{object.to_s}/status"
111
+ end
112
+
113
+ def status_json(object)
114
+ status = status(object)
115
+ status_hash = schema_parse(status['entities']['Status'])
116
+
117
+ JSON.generate(status_hash)
118
+ end
119
+
120
+ def view(object)
121
+ get "#{object.to_s}/view"
122
+ end
123
+
124
+ def view_json(object)
125
+ views = view(object)
126
+ views_hash = schema_parse(views['Entities']['View'])
127
+
128
+ JSON.generate(views_hash)
129
+ end
130
+
131
+ def schema(object)
132
+ get "#{object.to_s}/schema"
133
+ end
134
+
135
+ def schema_json(object)
136
+ schema = schema(object)
137
+ schema_hash = schema_parse_hash(schema[object])
138
+
139
+ JSON.generate(schema_hash)
140
+ end
141
+
142
+ def schema_parse(input)
143
+ output = input
144
+ if input.class == Array
145
+ output = schema_parse_array(input)
146
+ elsif input.class == Hash
147
+ output = schema_parse_hash(input)
148
+ elsif input.class == String
149
+ output = schema_parse_string(input)
150
+ end
151
+ output
152
+ end
153
+
154
+ def schema_parse_array(input_array)
155
+ output = []
156
+ input_array.each do |item|
157
+ if item.class == Array
158
+ output.push schema_parse_array(item)
159
+ elsif item.class == Hash
160
+ output.push schema_parse_hash(item)
161
+ elsif value.class == String
162
+ output.push schema_parse_string(item)
163
+ else
164
+ output.push item
165
+ end
166
+ end
167
+ output
168
+ end
169
+
170
+ def schema_parse_hash(input_hash)
171
+ output = {}
172
+ input_hash.each do |key, value|
173
+ if value.class == Array
174
+ output[key.to_s.name_to_key] = schema_parse_array(value)
175
+ elsif value.class == Hash
176
+ output[key.to_s.name_to_key] = schema_parse_hash(value)
177
+ elsif value.class == String
178
+ output[key.to_s.name_to_key] = schema_parse_string(value)
179
+ else
180
+ output[key.to_s.name_to_key] = value
181
+ end
182
+ end
183
+ output
184
+ end
185
+
186
+ def schema_parse_string(input_string)
187
+ case input_string
188
+ when 'true'
189
+ true
190
+ when 'false'
191
+ false
192
+ else
193
+ # Check for Integers / Floats
194
+ if /^-?(?:[0-9]+|[0-9]*\.[0-9]+)$/ =~ input_string
195
+ if input_string.to_i == input_string.to_f
196
+ input_string.to_i
197
+ else
198
+ input_string.to_f
199
+ end
200
+ else
201
+ input_string
202
+ end
203
+ end
204
+ end
205
+
206
+ end
207
+ end
@@ -0,0 +1,189 @@
1
+ require 'gyoku'
2
+ require 'nori'
3
+
4
+ module HotDogPrincess
5
+ class Client
6
+ module Customers
7
+
8
+ @customers = nil
9
+ @customers_raw = nil
10
+
11
+ def fetch_customers(page_size = 100)
12
+ @customers_raw = get 'Customer', _pageSize_: page_size
13
+ @customers_raw
14
+ end
15
+
16
+ def customers(page_size = 100, force_update = false)
17
+ return @customers if @customers and !force_update
18
+ fetch_customers(page_size)
19
+ return nil unless @customers_raw
20
+ @customers ||= []
21
+ @customers_raw["Entities"]["Customer"].each do |customer|
22
+ @customers.push parse_customer customer
23
+ end
24
+ @customers
25
+ end
26
+
27
+ def customers_raw(page_size = 100)
28
+ return @customers_raw if @customers_raw
29
+ fetch_customers(page_size)
30
+ @customers_raw
31
+ end
32
+
33
+ def customer_count
34
+ return @customers.length if @customers
35
+ return @customers["Entities"].length if @customers_raw
36
+ 0
37
+ end
38
+
39
+ def customer(customer_id, history = false)
40
+ customer = get "Customer/#{customer_id}", _history_: history
41
+ parse_customer customer['Customer']
42
+ end
43
+
44
+ def update_customer(customer_id, customer)
45
+ xml = Gyoku.xml(customer)
46
+ customer_xml = put "Customer/#{customer_id}", xml
47
+
48
+ parser = Nori.new
49
+ new_customer_xml = parser.parse customer_xml
50
+
51
+ customer = get "Customer/#{new_customer_xml['Customer']['@id']}", _history_: false
52
+
53
+ parse_customer customer['Customer']
54
+ end
55
+
56
+ def create_customer(customer)
57
+ xml = Gyoku.xml(customer)
58
+ customer_xml = post 'Customer', xml
59
+
60
+ parser = Nori.new
61
+ new_customer_xml = parser.parse customer_xml
62
+
63
+ customer = get "Customer/#{new_customer_xml['Customer']['@id']}", _history_: false
64
+
65
+ parse_customer customer['Customer']
66
+ end
67
+
68
+ def find_customer_by_email(email, substring = false)
69
+ query = 'Email'
70
+ query << '_like_' if substring
71
+ customers = get 'Customer', "#{query}" => email
72
+
73
+ found_customers = []
74
+ if customers and customers["Entities"] and customers["Entities"]["Customer"]
75
+ customers["Entities"]["Customer"].each do |customer|
76
+ found_customers.push parse_customer customer
77
+ end
78
+ end
79
+
80
+ found_customers
81
+ end
82
+
83
+ def parse_customer(customer)
84
+ # Meta
85
+ clean_customer = {}
86
+ clean_customer[:id] = customer['@id'].to_i
87
+ clean_customer[:uid] = customer['@uid']
88
+ clean_customer[:href] = customer['@href']
89
+ clean_customer[:service_desk_uri] = customer['@service-desk-uri']
90
+
91
+ # Basic Info
92
+ clean_customer[:first_name] = customer['First_Name']['#text']
93
+ clean_customer[:last_name] = customer['Last_Name']['#text']
94
+ clean_customer[:email] = customer['Email']['#text']
95
+
96
+ # Dates
97
+ clean_customer[:date_created] = Time.parse(customer['Date_Created']['#text']).utc.to_date if customer['Date_Created']
98
+ clean_customer[:date_updated] = Time.parse(customer['Date_Updated']['#text']).utc.to_date if customer['Date_Updated']
99
+ clean_customer[:date_visited] = Time.parse(customer['Date_Visited']['#text']).utc.to_date if customer['Date_Visited']
100
+
101
+ # Customer Role
102
+ if customer['Customer_Role'] and customer['Customer_Role']['CustomerRole']
103
+ clean_customer[:customer_role] = {}
104
+ clean_customer[:customer_role][:id] = customer['Customer_Role']['CustomerRole']['@id'].to_i
105
+ clean_customer[:customer_role][:uid] = customer['Customer_Role']['CustomerRole']['@uid']
106
+ clean_customer[:customer_role][:href] = customer['Customer_Role']['CustomerRole']['@href']
107
+ clean_customer[:customer_role][:name] = customer['Customer_Role']['CustomerRole']["Name"]['#text']
108
+ end
109
+
110
+ # SLA
111
+ if customer['Sla'] and customer['Sla']['Sla']
112
+ clean_customer[:sla] = {}
113
+ clean_customer[:sla][:id] = customer['Sla']['Sla']['@id'].to_i
114
+ clean_customer[:sla][:uid] = customer['Sla']['Sla']['@uid']
115
+ clean_customer[:sla][:href] = customer['Sla']['Sla']['@href']
116
+ clean_customer[:sla][:name] = customer['Sla']['Sla']["Name"]['#text']
117
+ end
118
+
119
+ # Status
120
+ if customer['Status'] and customer['Status']['Status']
121
+ clean_customer[:status] = {}
122
+ clean_customer[:status][:id] = customer['Status']['Status']['@id'].to_i
123
+ clean_customer[:status][:uid] = customer['Status']['Status']['@uid']
124
+ clean_customer[:status][:href] = customer['Status']['Status']['@href']
125
+ clean_customer[:status][:name] = customer['Status']['Status']["Name"]['#text']
126
+ end
127
+
128
+ # Custom Field
129
+ if customer['Custom_Field']
130
+ clean_customer[:custom_field] = {}
131
+
132
+ # Multple are returned as an Array, single as a Hash.
133
+ if customer['Custom_Field'].class != Array
134
+ customer['Custom_Field'] = [customer['Custom_Field']]
135
+ end
136
+
137
+ customer['Custom_Field'].each do |custom_field|
138
+ field = custom_field['@display-name'].name_to_key
139
+ field_key = field.to_sym
140
+ clean_customer[:custom_field][field_key] = {}
141
+ clean_customer[:custom_field][field_key][:id] = custom_field['@id'].to_i
142
+ clean_customer[:custom_field][field_key][:required] = custom_field['@required'].downcase == 'true' if custom_field['@required']
143
+ clean_customer[:custom_field][field_key][:editable] = custom_field['@editable'].downcase == 'true' if custom_field['@editable']
144
+ clean_customer[:custom_field][field_key][:max_length] = custom_field['@max-length'].to_i if custom_field['@max-length']
145
+ clean_customer[:custom_field][field_key][:field_type] = custom_field['@field-type'] if custom_field['@field-type']
146
+ clean_customer[:custom_field][field_key][:data_type] = custom_field['@data-type'] if custom_field['@data-type']
147
+ clean_customer[:custom_field][field_key][:multi_value] = custom_field['@multi-value'].downcase == 'true' if custom_field['@multi-value']
148
+
149
+ # Get the value or values.
150
+ case custom_field['@data-type']
151
+ when 'string'
152
+ clean_customer[:custom_field][field_key][:value] = custom_field['#text']
153
+ when 'int'
154
+ clean_customer[:custom_field][field_key][:value] = custom_field['#text'].to_i
155
+ when 'date'
156
+ clean_customer[:custom_field][field_key][:value] = Time.parse(custom_field['#text']).utc.to_date
157
+ when 'boolean'
158
+ clean_customer[:custom_field][field_key][:value] = custom_field['#text'] == 'true'
159
+ when 'float'
160
+ clean_customer[:custom_field][field_key][:value] = custom_field['#text'].to_f
161
+ when 'option'
162
+ selected_options = []
163
+ custom_field['Option'].each do |option|
164
+ if option["@selected"] == 'true'
165
+ selected_option = {}
166
+ selected_option[:id] = option["@id"].to_i
167
+ selected_option[:view_order] = option["@viewOrder"]
168
+ selected_option[:value] = option["Value"]
169
+ selected_options.push selected_option
170
+ end
171
+ end
172
+ selected_options = selected_options.first unless clean_customer[:custom_field][field_key][:multi_value]
173
+ clean_customer[:custom_field][field_key][:value] = selected_options
174
+ when 'entity'
175
+ clean_customer[:custom_field][field_key].value = nil
176
+ when 'attachment'
177
+ clean_customer[:custom_field][field_key].value = nil
178
+ else
179
+ clean_customer[:custom_field][field_key].value = nil
180
+ end
181
+ end
182
+ end
183
+
184
+ clean_customer
185
+ end
186
+
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,57 @@
1
+ require 'gyoku'
2
+ require 'nori'
3
+
4
+ module HotDogPrincess
5
+ class Client
6
+ module Slas
7
+
8
+ @slas = nil
9
+ @slas_raw = nil
10
+
11
+ def fetch_slas(page_size = 100)
12
+ @slas_raw = get "Sla", _pageSize_: page_size
13
+ @slas_raw
14
+ end
15
+
16
+ def slas(page_size = 100, force_update = false)
17
+ return @slas if @slas and !force_update
18
+ fetch_slas(page_size)
19
+ return nil unless @slas_raw
20
+ @slas ||= []
21
+ @slas_raw["Entities"]["Sla"].each do |sla|
22
+ @slas.push parse_sla sla
23
+ end
24
+ @slas
25
+ end
26
+
27
+ def slas_raw(page_size = 100)
28
+ return @slas_raw if @slas_raw
29
+ fetch_slas(page_size)
30
+ @slas_raw
31
+ end
32
+
33
+ def sla_count
34
+ return @slas.length if @slas
35
+ return @slas["Entities"].length if @slas_raw
36
+ 0
37
+ end
38
+
39
+ def sla(sla_id, history = false)
40
+ sla = get "Sla/#{sla_id}", _history_: history
41
+ parse_sla sla['Sla']
42
+ end
43
+
44
+ def parse_sla(sla)
45
+ # Meta
46
+ clean_sla = {}
47
+ clean_sla[:id] = sla['@id'].to_i
48
+ clean_sla[:uid] = sla['@uid']
49
+ clean_sla[:href] = sla['@href']
50
+ clean_sla[:name] = sla['Name']['#text']
51
+
52
+ clean_sla
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,219 @@
1
+ require 'gyoku'
2
+ require 'nori'
3
+
4
+ module HotDogPrincess
5
+ class Client
6
+ module Tickets
7
+
8
+ @tickets = nil
9
+ @tickets_raw = nil
10
+
11
+ def fetch_tickets(page_size = 100)
12
+ @tickets_raw = get "Ticket", _pageSize_: page_size
13
+ @tickets_raw
14
+ end
15
+
16
+ def tickets(page_size = 100, force_update = false)
17
+ return @tickets if @tickets and !force_update
18
+ fetch_tickets(page_size)
19
+ return nil unless @tickets_raw
20
+ @tickets ||= []
21
+ @tickets_raw["Entities"]["Ticket"].each do |ticket|
22
+ @tickets.push parse_ticket ticket
23
+ end
24
+ @tickets
25
+ end
26
+
27
+ def tickets_raw(page_size = 100)
28
+ return @tickets_raw if @tickets_raw
29
+ fetch_tickets(page_size)
30
+ @tickets_raw
31
+ end
32
+
33
+ def ticket_count
34
+ return @tickets.length if @tickets
35
+ return @tickets["Entities"].length if @tickets_raw
36
+ 0
37
+ end
38
+
39
+ def ticket(ticket_id, history = false)
40
+ ticket = get "Ticket/#{ticket_id}", _history_: history
41
+ parse_ticket ticket['Ticket']
42
+ end
43
+
44
+ def update_ticket(ticket_id, ticket)
45
+ xml = Gyoku.xml(ticket)
46
+ ticket_xml = put "Ticket/#{ticket_id}", xml
47
+
48
+ parser = Nori.new
49
+ new_ticket_xml = parser.parse ticket_xml
50
+
51
+ ticket = get "Ticket/#{new_ticket_xml['Ticket']['@id']}", _history_: false
52
+
53
+ parse_ticket ticket['Ticket']
54
+ end
55
+
56
+ def create_ticket(ticket)
57
+ xml = Gyoku.xml(ticket)
58
+ ticket_xml = post "Ticket", xml
59
+
60
+ parser = Nori.new
61
+ new_ticket_xml = parser.parse ticket_xml
62
+
63
+ ticket = get "Ticket/#{new_ticket_xml['Ticket']['@id']}", _history_: false
64
+
65
+ parse_ticket ticket['Ticket']
66
+ end
67
+
68
+ def parse_ticket(ticket)
69
+ # Meta
70
+ clean_ticket = {}
71
+ clean_ticket[:id] = ticket['@id'].to_i
72
+ clean_ticket[:uid] = ticket['@uid']
73
+ clean_ticket[:href] = ticket['@href']
74
+ clean_ticket[:service_desk_uri] = ticket['@service-desk-uri']
75
+
76
+ # Dates
77
+ clean_ticket[:date_created] = Time.parse(ticket['Date_Created']['#text']).utc.to_date if ticket['Date_Created']
78
+ clean_ticket[:date_updated] = Time.parse(ticket['Date_Updated']['#text']).utc.to_date if ticket['Date_Updated']
79
+
80
+ # Booleans
81
+ clean_ticket[:dont_overwrite_sla_in_rr] = ticket['Dont_Overwrite_Sla_In_Rr']['#text'].downcase == 'true'
82
+ clean_ticket[:email_notification] = ticket['Email_Notification']['#text'].downcase == 'true'
83
+ clean_ticket[:email_notification_additional_contact] = ticket['Email_Notification_Additional_Contact']['#text'].downcase == 'true'
84
+ clean_ticket[:hide_from_customer] = ticket['Hide_From_Customer']['#text'].downcase == 'true'
85
+
86
+ # Durations
87
+ clean_ticket[:initial_resolution_target_duration] = ticket['Initial_Resolution_Target_Duration']['#text'].to_i
88
+ clean_ticket[:initial_response_target_duration] = ticket['Initial_Response_Target_Duration']['#text'].to_i
89
+
90
+ # Ticket Number
91
+ if ticket['Ticket_Number']
92
+ clean_ticket[:ticket_number] = ticket['Ticket_Number']['#text']
93
+ end
94
+
95
+ # Queue
96
+ if ticket['Ticket_Queue'] and ticket['Ticket_Queue']['Queue']
97
+ clean_ticket[:ticket_queue] = {}
98
+ clean_ticket[:ticket_queue][:id] = ticket['Ticket_Queue']['Queue']['@id'].to_i
99
+ clean_ticket[:ticket_queue][:uid] = ticket['Ticket_Queue']['Queue']['@uid']
100
+ clean_ticket[:ticket_queue][:href] = ticket['Ticket_Queue']['Queue']['@href']
101
+ clean_ticket[:ticket_queue][:name] = ticket['Ticket_Queue']['Queue']["Name"]['#text']
102
+ end
103
+
104
+ # SLA
105
+ if ticket['Ticket_Sla'] and ticket['Ticket_Sla']['Sla']
106
+ clean_ticket[:ticket_sla] = {}
107
+ clean_ticket[:ticket_sla][:id] = ticket['Ticket_Sla']['Sla']['@id'].to_i
108
+ clean_ticket[:ticket_sla][:uid] = ticket['Ticket_Sla']['Sla']['@uid']
109
+ clean_ticket[:ticket_sla][:href] = ticket['Ticket_Sla']['Sla']['@href']
110
+ clean_ticket[:ticket_sla][:name] = ticket['Ticket_Sla']['Sla']["Name"]['#text']
111
+ end
112
+
113
+ # Status
114
+ if ticket['Ticket_Status'] and ticket['Ticket_Status']['Status']
115
+ clean_ticket[:ticket_status] = {}
116
+ clean_ticket[:ticket_status][:id] = ticket['Ticket_Status']['Status']['@id'].to_i
117
+ clean_ticket[:ticket_status][:uid] = ticket['Ticket_Status']['Status']['@uid']
118
+ clean_ticket[:ticket_status][:href] = ticket['Ticket_Status']['Status']['@href']
119
+ clean_ticket[:ticket_status][:name] = ticket['Ticket_Status']['Status']["Name"]['#text']
120
+ end
121
+
122
+ # Department
123
+ if ticket['Department'] and ticket['Department']['Department']
124
+ clean_ticket[:department] = {}
125
+ clean_ticket[:department][:id] = ticket['Department']['Department']["@id"].to_i
126
+ clean_ticket[:department][:uid] = ticket['Department']['Department']["@uid"]
127
+ clean_ticket[:department][:href] = ticket['Department']['Department']["@href"]
128
+ clean_ticket[:department][:name] = ticket['Department']['Department']["Name"]['#text']
129
+ end
130
+
131
+ # Customer Service Represenative
132
+ if ticket['Entered_By'] and ticket['Entered_By']['Csr']
133
+ clean_ticket[:entered_by] = {}
134
+ clean_ticket[:entered_by][:id] = ticket['Entered_By']['Csr']['@id'].to_i
135
+ clean_ticket[:entered_by][:uid] = ticket['Entered_By']['Csr']['@uid']
136
+ clean_ticket[:entered_by][:href] = ticket['Entered_By']['Csr']['@href']
137
+ clean_ticket[:entered_by][:full_name] = ticket['Entered_By']['Csr']["Full_Name"]['#text']
138
+ end
139
+
140
+ # Customer
141
+ if ticket['Ticket_Customer'] and ticket['Ticket_Customer']['Customer']
142
+ clean_ticket[:ticket_customer] = {}
143
+ clean_ticket[:ticket_customer][:id] = ticket['Ticket_Customer']['Customer']['@id'].to_i
144
+ clean_ticket[:ticket_customer][:uid] = ticket['Ticket_Customer']['Customer']['@uid']
145
+ clean_ticket[:ticket_customer][:href] = ticket['Ticket_Customer']['Customer']['@href']
146
+ clean_ticket[:ticket_customer][:full_name] = ticket['Ticket_Customer']['Customer']["Full_Name"]['#text']
147
+ end
148
+
149
+ # Attachements
150
+ if ticket['Ticket_Attachments']
151
+ clean_ticket[:ticket_attachments] = {}
152
+ clean_ticket[:ticket_attachments][:id] = ticket['Ticket_Attachments']['@id'].to_i
153
+ clean_ticket[:ticket_attachments][:uid] = ticket['Ticket_Attachments']['@uid']
154
+ clean_ticket[:ticket_attachments][:href] = ticket['Ticket_Attachments']['@href']
155
+ clean_ticket[:ticket_attachments][:attachments] = ticket['Ticket_Attachments']['Attachments']
156
+ end
157
+
158
+ # Custom Field
159
+ if ticket['Custom_Field']
160
+ clean_ticket[:custom_field] = {}
161
+
162
+ # Multple are returned as an Array, single as a Hash.
163
+ if ticket['Custom_Field'].class != Array
164
+ ticket['Custom_Field'] = [ticket['Custom_Field']]
165
+ end
166
+
167
+ ticket['Custom_Field'].each do |custom_field|
168
+ field = custom_field['@display-name'].name_to_key
169
+ field_key = field.to_sym
170
+ clean_ticket[:custom_field][field_key] = {}
171
+ clean_ticket[:custom_field][field_key][:id] = custom_field['@id'].to_i
172
+ clean_ticket[:custom_field][field_key][:required] = custom_field['@required'].downcase == 'true' if custom_field['@required']
173
+ clean_ticket[:custom_field][field_key][:editable] = custom_field['@editable'].downcase == 'true' if custom_field['@editable']
174
+ clean_ticket[:custom_field][field_key][:max_length] = custom_field['@max-length'].to_i if custom_field['@max-length']
175
+ clean_ticket[:custom_field][field_key][:field_type] = custom_field['@field-type'] if custom_field['@field-type']
176
+ clean_ticket[:custom_field][field_key][:data_type] = custom_field['@data-type'] if custom_field['@data-type']
177
+ clean_ticket[:custom_field][field_key][:multi_value] = custom_field['@multi-value'].downcase == 'true' if custom_field['@multi-value']
178
+
179
+ # Get the value or values.
180
+ case custom_field['@data-type']
181
+ when 'string'
182
+ clean_ticket[:custom_field][field_key][:value] = custom_field['#text']
183
+ when 'int'
184
+ clean_ticket[:custom_field][field_key][:value] = custom_field['#text'].to_i
185
+ when 'date'
186
+ clean_ticket[:custom_field][field_key][:value] = Time.parse(custom_field['#text']).utc.to_date
187
+ when 'boolean'
188
+ clean_ticket[:custom_field][field_key][:value] = custom_field['#text'] == 'true'
189
+ when 'float'
190
+ clean_ticket[:custom_field][field_key][:value] = custom_field['#text'].to_f
191
+ when 'option'
192
+ selected_options = []
193
+ custom_field['Option'].each do |option|
194
+ if option["@selected"] == 'true'
195
+ selected_option = {}
196
+ selected_option[:id] = option["@id"].to_i
197
+ selected_option[:view_order] = option["@viewOrder"]
198
+ selected_option[:value] = option["Value"]
199
+ selected_options.push selected_option
200
+ end
201
+ end
202
+ selected_options = selected_options.first unless clean_ticket[:custom_field][field_key][:multi_value]
203
+ clean_ticket[:custom_field][field_key][:value] = selected_options
204
+ when 'entity'
205
+ clean_ticket[:custom_field][field_key][:value] = nil
206
+ when 'attachment'
207
+ clean_ticket[:custom_field][field_key][:value] = nil
208
+ else
209
+ clean_ticket[:custom_field][field_key][:value] = nil
210
+ end
211
+ end
212
+ end
213
+
214
+ clean_ticket
215
+ end
216
+
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,8 @@
1
+ require "restclient"
2
+ require "hotdogprincess/version"
3
+ require "hotdogprincess/core_extensions/string"
4
+
5
+ module HotDogPrincess
6
+ class CoreExtensions
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ module HotDogPrincess
2
+ class CoreExtensions
3
+ module String
4
+
5
+ def name_to_key_camecase
6
+ self.gsub(/[^a-z _-]/i, '')
7
+ .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
8
+ .gsub(/([a-z\d])([A-Z])/,'\1_\2')
9
+ .tr(' ', '_')
10
+ .tr('-', '_')
11
+ .gsub(/(_)\1+/i, '_')
12
+ .downcase
13
+ end
14
+
15
+ def name_to_key
16
+ self.gsub(/[^a-z _-]/i, '')
17
+ .tr(' ', '_')
18
+ .tr('-', '_')
19
+ .gsub(/(_)\1+/i, '_')
20
+ .downcase
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+
27
+ class String
28
+ include HotDogPrincess::CoreExtensions::String
29
+ end
@@ -0,0 +1,3 @@
1
+ module HotDogPrincess
2
+ VERSION = "0.1.1".freeze
3
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hotdogprincess
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Callis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gyoku
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nori
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2'
55
+ description: Integrate with the Parature API.
56
+ email:
57
+ - matthew.callis@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE.md
63
+ - README.md
64
+ - Rakefile
65
+ - hotdogprincess.gemspec
66
+ - lib/hotdogprincess.rb
67
+ - lib/hotdogprincess/client.rb
68
+ - lib/hotdogprincess/client/customers.rb
69
+ - lib/hotdogprincess/client/slas.rb
70
+ - lib/hotdogprincess/client/tickets.rb
71
+ - lib/hotdogprincess/core_extensions.rb
72
+ - lib/hotdogprincess/core_extensions/string.rb
73
+ - lib/hotdogprincess/version.rb
74
+ homepage: https://github.com/MatthewCallis/hotdogprincess
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 1.9.2
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: 1.3.5
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.4.1
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Integrate with the Parature API. It's gunna be so flippin' awesome!
98
+ test_files: []
99
+ has_rdoc: