booking_automation 0.1.2 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 962b6d00aed91c3195ac3eca6690483ad716eea307f814cc717cc47a4cf0a24d
4
- data.tar.gz: 18639908b04ab01a4a932bec46f24d5e3aebb0bfb522eb22cb57b85aa3fe80d7
3
+ metadata.gz: c3ede7f0ff6fb912ecb43017c225b107aa6080a839b0385a979c60673c446485
4
+ data.tar.gz: 96ef7a0a0ed5d3c8d4c78ab64ef899f1e2e6f3d1585061bb53254d4a5b812ba9
5
5
  SHA512:
6
- metadata.gz: 96c8b7f5a36860ad3a3cbf4835d5e25ade66ada5c57613c33950a2e6d56beadfbb6164bddec7e7efc150c3128a0caef1861b5aaf91d7cb6f6c9edd5f86ea187d
7
- data.tar.gz: 4d9f8228baae4101dd209889d5a1949adbf593ab1d16224f43ebeb067f997d7bed4510634b1ef9829f5b84e29c6c61fd034b4a31a5af5348c19e3e0c311cc913
6
+ metadata.gz: 1793390cd537f4c8be2d3f6c0c5247c1c0128254dc9fb4ccc5373481fdeb24c506d2f744fce2d2fecec724415c3d7201b03f98c631400e5168fb300c9f2d1d64
7
+ data.tar.gz: bee3dbe0ae2e2ec4b66359139bffbf804958374775a1c6efb80ca1bd1cefe37a6474e4868871d938a91000693052b30a692a2f4f3cbb18ebcfea106743b31102
data/.rspec_status CHANGED
@@ -1,12 +1,31 @@
1
- example_id | status | run_time |
2
- ------------------------------------------------- | ------ | --------------- |
3
- ./spec/booking_automation_client_spec.rb[1:1:1] | passed | 0.00062 seconds |
4
- ./spec/booking_automation_client_spec.rb[1:2:1] | passed | 0.00023 seconds |
5
- ./spec/booking_automation_client_spec.rb[1:2:2] | passed | 0.00007 seconds |
6
- ./spec/booking_automation_client_spec.rb[1:3:1:1] | passed | 0.00544 seconds |
7
- ./spec/booking_automation_client_spec.rb[1:3:2:1] | passed | 0.0008 seconds |
8
- ./spec/booking_automation_client_spec.rb[1:4:1:1] | passed | 0.00113 seconds |
9
- ./spec/booking_automation_client_spec.rb[1:4:2:1] | passed | 0.00076 seconds |
10
- ./spec/booking_automation_client_spec.rb[1:5:1:1] | passed | 0.00111 seconds |
11
- ./spec/booking_automation_client_spec.rb[1:5:2:1] | passed | 0.00081 seconds |
12
- ./spec/booking_automation_spec.rb[1:1] | passed | 0.00037 seconds |
1
+ example_id | status | run_time |
2
+ -------------------------------------- | ------ | --------------- |
3
+ ./spec/booking_automation_spec.rb[1:1] | passed | 0.00033 seconds |
4
+ ./spec/hash_spec.rb[1:1:1] | passed | 0.00053 seconds |
5
+ ./spec/hash_spec.rb[1:1:2] | passed | 0.00133 seconds |
6
+ ./spec/hash_spec.rb[1:1:3] | passed | 0.00058 seconds |
7
+ ./spec/hash_spec.rb[1:1:4] | passed | 0.0012 seconds |
8
+ ./spec/hash_spec.rb[1:1:5] | passed | 0.0005 seconds |
9
+ ./spec/hash_spec.rb[1:1:6] | passed | 0.00063 seconds |
10
+ ./spec/json_client_spec.rb[1:1:1] | passed | 0.00007 seconds |
11
+ ./spec/json_client_spec.rb[1:2:1] | passed | 0.00027 seconds |
12
+ ./spec/json_client_spec.rb[1:2:2] | passed | 0.00006 seconds |
13
+ ./spec/json_client_spec.rb[1:3:1:1] | passed | 0.00533 seconds |
14
+ ./spec/json_client_spec.rb[1:3:2:1] | passed | 0.00082 seconds |
15
+ ./spec/json_client_spec.rb[1:4:1:1] | passed | 0.00122 seconds |
16
+ ./spec/json_client_spec.rb[1:4:2:1] | passed | 0.00075 seconds |
17
+ ./spec/json_client_spec.rb[1:5:1:1] | passed | 0.0012 seconds |
18
+ ./spec/json_client_spec.rb[1:5:2:1] | passed | 0.00084 seconds |
19
+ ./spec/xml_client_spec.rb[1:1:1] | passed | 0.00008 seconds |
20
+ ./spec/xml_client_spec.rb[1:2:1:1] | passed | 0.00006 seconds |
21
+ ./spec/xml_client_spec.rb[1:2:1:2] | passed | 0.00006 seconds |
22
+ ./spec/xml_client_spec.rb[1:2:2:1] | passed | 0.00005 seconds |
23
+ ./spec/xml_client_spec.rb[1:2:2:2] | passed | 0.00005 seconds |
24
+ ./spec/xml_client_spec.rb[1:3:1:1:1:1] | passed | 0.00254 seconds |
25
+ ./spec/xml_client_spec.rb[1:3:1:2:1] | passed | 0.00243 seconds |
26
+ ./spec/xml_client_spec.rb[1:3:2:1:1:1] | passed | 0.00176 seconds |
27
+ ./spec/xml_client_spec.rb[1:3:2:2:1] | passed | 0.00143 seconds |
28
+ ./spec/xml_request_spec.rb[1:1:1] | passed | 0.00015 seconds |
29
+ ./spec/xml_request_spec.rb[1:1:2] | passed | 0.00014 seconds |
30
+ ./spec/xml_request_spec.rb[1:2:1] | passed | 0.00015 seconds |
31
+ ./spec/xml_request_spec.rb[1:2:2] | passed | 0.00013 seconds |
data/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2019-08-04
11
+
12
+ ### Added
13
+
14
+ - Added XML client to interact with XML API
15
+ - Added ability to fetch properties through XML API
16
+ - Added ability to fetch bookings through XML API
17
+
18
+ ### Changed
19
+
20
+ - Renamed Client to JSONClient
21
+
10
22
  ## [0.1.0] - 2019-06-30
11
23
 
12
24
  ### Added
data/README.md CHANGED
@@ -24,11 +24,11 @@ To use a gem you should allow API Key through your BookingAutomation settings.
24
24
  Wrapper needs you to supply the account API key (auth_token) set at the menu "Settings > Account"
25
25
  Operations involving a specific property need to supply the property key (propKey) set at the menu "Settings > Properties > Link"
26
26
 
27
- ### Sample Code
27
+ ### Sample Code for JSON API
28
28
 
29
29
  ```ruby
30
30
  auth_token = '<your-key>'
31
- client = BookingAutomation::Client.new auth_token
31
+ client = BookingAutomation::JSONClient.new auth_token
32
32
 
33
33
  client.get_properties # List all account properties
34
34
 
@@ -41,6 +41,46 @@ client.get_bookings(prop_key) # Get all bookings for given property
41
41
  client.get_bookings(prop_key, includeInvoice: true) # Pass parameters as per docs
42
42
  ```
43
43
 
44
+ ### Sample Code for XML API
45
+
46
+ ```ruby
47
+ username = '<your-username>'
48
+ password = '<your-password>'
49
+ client = BookingAutomation::XMLClient.new username, password
50
+
51
+ client.get_properties # List all account properties
52
+
53
+ client.get_properties(propid: 123) # Display individual property data
54
+
55
+ client.get_bookings() # Get all bookings
56
+ client.get_bookings(propid: 123, datefrom: '20190101') # Pass parameters as per docs
57
+ ```
58
+
59
+ Data returned is already parsed in a meaningful way to plain Ruby `Hash`.
60
+ IDs and names are extracted to a top level to avoid hash keys collision.
61
+ Attributes are also preserved.
62
+
63
+ Example:
64
+
65
+ ```xml
66
+ <bookings attr="test">
67
+ <booking id="1"><!-- DATA --></booking>
68
+ <booking id="2"><!-- DATA --></booking>
69
+ </bookings>
70
+ ```
71
+
72
+ will become:
73
+
74
+ ```ruby
75
+ {
76
+ 'bookings' => {
77
+ 'attr' => 'test',
78
+ '1' => {...},
79
+ '2' => {...}
80
+ }
81
+ }
82
+ ```
83
+
44
84
  ## Development
45
85
 
46
86
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -39,9 +39,11 @@ Gem::Specification.new do |spec|
39
39
  spec.add_development_dependency 'bundler', '~> 2.0'
40
40
  spec.add_development_dependency 'rake', '~> 10.0'
41
41
  spec.add_development_dependency 'rspec', '~> 3.0'
42
+ spec.add_development_dependency 'simplecov', '~> 0.17.0'
42
43
  spec.add_development_dependency 'webmock', '~> 3.6'
43
44
 
44
45
  # Dependencies
45
46
  spec.add_dependency 'httparty', '~> 0.17.0'
47
+ spec.add_dependency 'nokogiri', '~> 1.10'
46
48
  spec.add_dependency 'oj', '~> 3.7'
47
49
  end
@@ -1,7 +1,13 @@
1
1
  require 'httparty'
2
2
  require 'oj'
3
+
3
4
  require 'booking_automation/constants'
5
+ require 'booking_automation/json_client'
4
6
  require 'booking_automation/version'
7
+ require 'booking_automation/xml_client'
8
+ require 'booking_automation/xml_request'
9
+
10
+ require 'ext/hash'
5
11
 
6
12
  module BookingAutomation
7
13
  class Error < StandardError; end
@@ -14,76 +20,4 @@ module BookingAutomation
14
20
  @response = response
15
21
  end
16
22
  end
17
-
18
- class Client
19
- include HTTParty
20
- base_uri Constants::API_ENDPOINT
21
-
22
- attr_accessor :auth_token
23
-
24
- def initialize(auth_token)
25
- @auth_token = auth_token
26
- end
27
-
28
- def get_properties
29
- response = self.class.post('/getProperties', body: authentication.to_json)
30
- json = parse! response
31
- json['getProperties']
32
- rescue Oj::ParseError
33
- raise Error, Constants::PARSE_ERROR_MSG
34
- rescue APIError => e
35
- e.response
36
- end
37
-
38
- def get_property(prop_key, options={})
39
- response = self.class.post(
40
- '/getProperty',
41
- body: payload(prop_key, Constants::DEFAULT_PROPERTY_OPTIONS.merge(options))
42
- )
43
- json = parse! response
44
- json['getProperty'].first
45
- rescue Oj::ParseError
46
- raise Error, Constants::PARSE_ERROR_MSG
47
- rescue APIError => e
48
- e.response
49
- end
50
-
51
- def get_bookings(prop_key, options={})
52
- response = self.class.post(
53
- '/getBookings',
54
- body: payload(prop_key, Constants::DEFAULT_BOOKING_OPTIONS.merge(options))
55
- )
56
- parse! response
57
- rescue Oj::ParseError
58
- raise Error, Constants::PARSE_ERROR_MSG
59
- rescue APIError => e
60
- e.response
61
- end
62
-
63
- private
64
-
65
- def authentication(prop_key=nil)
66
- {
67
- authentication: {
68
- apiKey: auth_token,
69
- propKey: prop_key
70
- }
71
- }
72
- end
73
-
74
- def payload(prop_key=nil, options={})
75
- authentication(prop_key)
76
- .merge(options)
77
- .to_json
78
- end
79
-
80
- def parse!(response)
81
- json = Oj.load response.body
82
- raise APIError.new(
83
- "API Error: #{json['errorCode']} #{json['error']}",
84
- json
85
- ) if json.is_a?(Hash) && !json['error'].nil?
86
- json
87
- end
88
- end
89
23
  end
@@ -1,6 +1,8 @@
1
1
  module BookingAutomation
2
2
  module Constants
3
- API_ENDPOINT = 'https://manage.bookingautomation.com/api/json'.freeze
3
+ API_ROOT = 'https://manage.bookingautomation.com/api'.freeze
4
+ JSON_API_ENDPOINT = "#{API_ROOT}/json".freeze
5
+ XML_API_ENDPOINT = "#{API_ROOT}/xml".freeze
4
6
 
5
7
  PARSE_ERROR_MSG = 'Got encoding different from JSON. Please check passed options'.freeze
6
8
 
@@ -14,5 +16,15 @@ module BookingAutomation
14
16
  includeInvoice: false,
15
17
  includeInfoItems: false
16
18
  }.freeze
19
+
20
+ VALID_XML_BOOKING_OPTS = %i[
21
+ modified
22
+ datefrom
23
+ dateto
24
+ propid
25
+ roomid
26
+ masterid
27
+ bookid
28
+ ].freeze
17
29
  end
18
30
  end
@@ -0,0 +1,73 @@
1
+ module BookingAutomation
2
+ class JSONClient
3
+ include HTTParty
4
+ base_uri Constants::JSON_API_ENDPOINT
5
+
6
+ attr_accessor :auth_token
7
+
8
+ def initialize(auth_token)
9
+ @auth_token = auth_token
10
+ end
11
+
12
+ def get_properties
13
+ response = self.class.post('/getProperties', body: authentication.to_json)
14
+ json = parse! response
15
+ json['getProperties']
16
+ rescue Oj::ParseError
17
+ raise Error, Constants::PARSE_ERROR_MSG
18
+ rescue APIError => e
19
+ e.response
20
+ end
21
+
22
+ def get_property(prop_key, options={})
23
+ response = self.class.post(
24
+ '/getProperty',
25
+ body: payload(prop_key, Constants::DEFAULT_PROPERTY_OPTIONS.merge(options))
26
+ )
27
+ json = parse! response
28
+ json['getProperty'].first
29
+ rescue Oj::ParseError
30
+ raise Error, Constants::PARSE_ERROR_MSG
31
+ rescue APIError => e
32
+ e.response
33
+ end
34
+
35
+ def get_bookings(prop_key, options={})
36
+ response = self.class.post(
37
+ '/getBookings',
38
+ body: payload(prop_key, Constants::DEFAULT_BOOKING_OPTIONS.merge(options))
39
+ )
40
+ parse! response
41
+ rescue Oj::ParseError
42
+ raise Error, Constants::PARSE_ERROR_MSG
43
+ rescue APIError => e
44
+ e.response
45
+ end
46
+
47
+ private
48
+
49
+ def authentication(prop_key=nil)
50
+ {
51
+ authentication: {
52
+ apiKey: auth_token,
53
+ propKey: prop_key
54
+ }
55
+ }
56
+ end
57
+
58
+ def payload(prop_key=nil, options={})
59
+ authentication(prop_key)
60
+ .merge(options)
61
+ .to_json
62
+ end
63
+
64
+ def parse!(response)
65
+ json = Oj.load response.body
66
+ raise APIError.new(
67
+ "API Error: #{json['errorCode']} #{json['error']}",
68
+ json
69
+ ) if json.is_a?(Hash) && !json['error'].nil?
70
+ json
71
+ end
72
+ end
73
+ end
@@ -1,3 +1,3 @@
1
1
  module BookingAutomation
2
- VERSION = '0.1.2'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1,48 @@
1
+ module BookingAutomation
2
+ class XMLClient
3
+ include HTTParty
4
+ base_uri Constants::XML_API_ENDPOINT
5
+ headers 'Content-Type' => 'text/xml'
6
+
7
+ attr_accessor :username, :password
8
+
9
+ def initialize(username, password)
10
+ @username = username
11
+ @password = password
12
+ end
13
+
14
+ def get_properties(opts = {})
15
+ response = self.class.post('/getProperties', body: xmlize(opts.slice(:propid)))
16
+ parse! response
17
+ rescue APIError => e
18
+ e.response
19
+ end
20
+
21
+ def get_bookings(opts = {})
22
+ valid_opts = opts.slice(*Constants::VALID_XML_BOOKING_OPTS)
23
+ response = self.class.post('/getBookings', body: xmlize(valid_opts))
24
+ parse! response
25
+ rescue APIError => e
26
+ e.response
27
+ end
28
+
29
+ private
30
+
31
+ def parse!(response)
32
+ hash = Hash.from_xml(response.body)
33
+ raise APIError.new(
34
+ "API Error: #{hash['code']} #{hash['error']}",
35
+ hash
36
+ ) if hash.key?('error')
37
+ hash
38
+ end
39
+
40
+ def auth
41
+ { username: @username, password: @password }
42
+ end
43
+
44
+ def xmlize(opts = {})
45
+ XMLRequest.new(auth, opts).to_xml
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ module BookingAutomation
2
+ class XMLRequest
3
+ def initialize(auth, opts = {})
4
+ @auth = auth
5
+ @opts = opts
6
+ end
7
+
8
+ def to_xml
9
+ data = builder.new do |xml|
10
+ xml.request do
11
+ xml.auth do
12
+ xml.username @auth[:username]
13
+ xml.password @auth[:password]
14
+ end
15
+ @opts.each do |prop, value|
16
+ xml.public_send prop, value
17
+ end
18
+ end
19
+ end
20
+ data.doc.root.to_xml
21
+ end
22
+
23
+ private
24
+
25
+ def builder
26
+ Nokogiri::XML::Builder
27
+ end
28
+ end
29
+ end
data/lib/ext/hash.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'nokogiri'
2
+
3
+ class Hash
4
+ class << self
5
+ def from_xml(xml_io)
6
+ result = Nokogiri::XML(xml_io)
7
+ { result.root.name => xml_node_to_hash(result.root)}
8
+ end
9
+
10
+ def xml_node_to_hash(node)
11
+ if node.element?
12
+ result_hash = {}
13
+ if node.attributes != {}
14
+ attributes = {}
15
+ node.attributes.keys.each do |key|
16
+ if [:id, 'id', :name, 'name'].include?(key)
17
+ node.name = node.attributes[key].value
18
+ node.delete(key.to_s)
19
+ else
20
+ attributes[node.attributes[key].name] = node.attributes[key].value
21
+ end
22
+ end
23
+ end
24
+
25
+ if node.children.size > 0
26
+ node.children.each do |child|
27
+ result = xml_node_to_hash(child)
28
+
29
+ if child.name == 'text'
30
+ unless child.next_sibling || child.previous_sibling
31
+ return result unless attributes
32
+ result_hash[child.name] = result
33
+ end
34
+ elsif result_hash[child.name]
35
+ if result_hash[child.name].is_a?(Array)
36
+ result_hash[child.name] << result
37
+ else
38
+ result_hash[child.name] = [result_hash[child.name]] << result
39
+ end
40
+ else
41
+ result_hash[child.name] = result
42
+ end
43
+ end
44
+ if attributes
45
+ result_hash = attributes.merge(result_hash)
46
+ end
47
+ return result_hash
48
+ else
49
+ return attributes
50
+ end
51
+ else
52
+ node.content.to_s
53
+ end
54
+ end
55
+ end
56
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: booking_automation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Babin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-30 00:00:00.000000000 Z
11
+ date: 2019-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.17.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.17.0
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: webmock
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
96
  version: 0.17.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: nokogiri
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.10'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.10'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: oj
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -115,7 +143,11 @@ files:
115
143
  - booking_automation.gemspec
116
144
  - lib/booking_automation.rb
117
145
  - lib/booking_automation/constants.rb
146
+ - lib/booking_automation/json_client.rb
118
147
  - lib/booking_automation/version.rb
148
+ - lib/booking_automation/xml_client.rb
149
+ - lib/booking_automation/xml_request.rb
150
+ - lib/ext/hash.rb
119
151
  homepage: https://github.com/mihilbabin/booking_automation
120
152
  licenses:
121
153
  - MIT