borrow_direct 0.9.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.
Files changed (76) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +14 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +183 -0
  6. data/Rakefile +11 -0
  7. data/bd_metrics/finditem_measure.rb +61 -0
  8. data/bd_metrics/isbn.txt +1088 -0
  9. data/bd_metrics/lccn.txt +1668 -0
  10. data/bd_metrics/oclc.txt +167 -0
  11. data/borrow_direct.gemspec +30 -0
  12. data/lib/borrow_direct/authentication.rb +55 -0
  13. data/lib/borrow_direct/defaults.rb +38 -0
  14. data/lib/borrow_direct/error.rb +17 -0
  15. data/lib/borrow_direct/find_item.rb +149 -0
  16. data/lib/borrow_direct/generate_query.rb +78 -0
  17. data/lib/borrow_direct/request.rb +185 -0
  18. data/lib/borrow_direct/request_item.rb +119 -0
  19. data/lib/borrow_direct/request_query.rb +124 -0
  20. data/lib/borrow_direct/util.rb +18 -0
  21. data/lib/borrow_direct/version.rb +3 -0
  22. data/lib/borrow_direct.rb +19 -0
  23. data/test/authentication_test.rb +79 -0
  24. data/test/find_item_test.rb +159 -0
  25. data/test/generate_query_test.rb +91 -0
  26. data/test/request_item_test.rb +109 -0
  27. data/test/request_query_test.rb +113 -0
  28. data/test/request_test.rb +141 -0
  29. data/test/support/assertions.rb +23 -0
  30. data/test/support/vcr_filter.rb +45 -0
  31. data/test/test_helper.rb +39 -0
  32. data/test/util_test.rb +32 -0
  33. data/test/vcr_cassettes/Authentication/Makes_a_request_succesfully.yml +52 -0
  34. data/test/vcr_cassettes/Authentication/Raises_for_bad_library_symbol.yml +52 -0
  35. data/test/vcr_cassettes/Authentication/Raises_for_bad_patron_barcode.yml +53 -0
  36. data/test/vcr_cassettes/Authentication/get_auth_id/raises_for_a_bad_library_symbol.yml +52 -0
  37. data/test/vcr_cassettes/Authentication/get_auth_id/raises_for_a_bad_patron_barcode.yml +53 -0
  38. data/test/vcr_cassettes/Authentication/get_auth_id/returns_an_auth_id_for_a_good_request.yml +52 -0
  39. data/test/vcr_cassettes/Authentication/raw_request_to_verify_HTTP_api/.yml +52 -0
  40. data/test/vcr_cassettes/FindItem/_find_item_request/finds_a_locally_available_item.yml +49 -0
  41. data/test/vcr_cassettes/FindItem/_find_item_request/finds_a_requestable_item.yml +49 -0
  42. data/test/vcr_cassettes/FindItem/_find_item_request/finds_an_item_that_does_not_exist_in_BD.yml +50 -0
  43. data/test/vcr_cassettes/FindItem/_find_item_request/with_expected_error_PUBFI002/returns_result.yml +40 -0
  44. data/test/vcr_cassettes/FindItem/_find_item_request/works_with_multiple_values.yml +49 -0
  45. data/test/vcr_cassettes/FindItem/find_with_Response/has_an_auth_id.yml +49 -0
  46. data/test/vcr_cassettes/FindItem/find_with_Response/has_nil_auth_id_when_BD_doesn_t_want_to_give_us_one.yml +40 -0
  47. data/test/vcr_cassettes/FindItem/find_with_Response/has_nil_pickup_locations_when_BD_doesn_t_want_to_give_us_them.yml +40 -0
  48. data/test/vcr_cassettes/FindItem/find_with_Response/has_pickup_locations.yml +49 -0
  49. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_BD_returns_PUBFI002.yml +40 -0
  50. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_does_not_exist_in_BD.yml +50 -0
  51. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_no_libraries_will_lend.yml +50 -0
  52. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_locally_available_item.yml +49 -0
  53. data/test/vcr_cassettes/FindItem/find_with_Response/requestable_for_requestable_item.yml +49 -0
  54. data/test/vcr_cassettes/FindItem/find_with_Response/requestable_with_multiple_items_if_at_least_one_is_requestable.yml +49 -0
  55. data/test/vcr_cassettes/Request/authentication_id/automatically_fetches_one_when_needed.yml +52 -0
  56. data/test/vcr_cassettes/Request/authentication_id/can_refetch_when_instructed.yml +52 -0
  57. data/test/vcr_cassettes/Request/can_make_a_succesful_request.yml +49 -0
  58. data/test/vcr_cassettes/Request/gets_BD_error_info.yml +41 -0
  59. data/test/vcr_cassettes/Request/raises_on_bad_path.yml +53 -0
  60. data/test/vcr_cassettes/Request/raises_on_bad_request_hash.yml +63 -0
  61. data/test/vcr_cassettes/Request/with_expected_errors/still_returns_result.yml +41 -0
  62. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_a_locally_available_item.yml +90 -0
  63. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_a_requestable_item.yml +89 -0
  64. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_an_unrequestable_item.yml +91 -0
  65. data/test/vcr_cassettes/RequestItem/make_request/raises_for_unrequestable.yml +91 -0
  66. data/test/vcr_cassettes/RequestItem/make_request/returns_number_for_succesful_request.yml +89 -0
  67. data/test/vcr_cassettes/RequestItem/make_request/says_no_for_item_that_BD_returns_PUBRI004.yml +89 -0
  68. data/test/vcr_cassettes/RequestItem/raw_requests_an_unrequestable_item.yml +91 -0
  69. data/test/vcr_cassettes/RequestItem/uses_manually_set_auth_id.yml +89 -0
  70. data/test/vcr_cassettes/RequestItem/with_pickup_location_and_requestable_item/still_works.yml +90 -0
  71. data/test/vcr_cassettes/RequestQuery/raw_request_query_request/returns_results.yml +381 -0
  72. data/test/vcr_cassettes/RequestQuery/raw_request_to_verify_the_BD_HTTP_API.yml +381 -0
  73. data/test/vcr_cassettes/RequestQuery/requests/fetches_default_records.yml +384 -0
  74. data/test/vcr_cassettes/RequestQuery/requests/fetches_full_records.yml +481 -0
  75. data/test/vcr_cassettes/top_level_describe/an_inner_describe/.yml +76 -0
  76. metadata +262 -0
@@ -0,0 +1,185 @@
1
+ require 'json'
2
+ require 'httpclient'
3
+ require 'ostruct'
4
+
5
+ require 'borrow_direct'
6
+
7
+ module BorrowDirect
8
+ # Generic abstract BD request, put in a Hash request body, get
9
+ # back a Hash answer.
10
+ #
11
+ # response_hash = Request.new("/path/to/endpoint").request(request_hash)
12
+ #
13
+ # Typically, clients will use various sub-classes of Request implementing
14
+ # calling of individual BD API's
15
+ #
16
+ # ## AuthenticationID's
17
+ #
18
+ # Some API endpoints require an "AId"/"AuthencationID". BorrowDirect::Request
19
+ # provides some facilities for managing obtaining such (using Authentication API),
20
+ # usually will be used under the hood by Request subclasses.
21
+ #
22
+ # # fetch new auth ID using Authentication API, store it
23
+ # # in self.auth_id
24
+ # request.fetch_auth_id!(barcode, library_symbol)
25
+ #
26
+ # # return the existing value in self.auth_id, or if
27
+ # # nil run fetch_auth_id! to fill it out.
28
+ # request.need_auth_id(barcode, library_symbol)
29
+ #
30
+ # request.auth_id # cached or nil
31
+ class Request
32
+ attr_writer :http_client
33
+ attr_accessor :timeout
34
+ attr_accessor :auth_id
35
+ # default :post, but can be set to :get, usually by a subclass
36
+ attr_accessor :http_method
37
+ attr_reader :last_request_uri, :last_request_json, :last_request_response, :last_request_time
38
+
39
+ # Usually an error code from the server will be turned into an exception.
40
+ # But if there are error codes you expect (usually fixed in a subclass of Request),
41
+ # fill them in this array, and the responses will be returned anyway -- warning,
42
+ # REGARDLESS of HTTP response status code, as these are often non-200 but we want
43
+ # to catch em anyway.
44
+ attr_accessor :expected_error_codes
45
+
46
+ def initialize(path)
47
+ @api_base = Defaults.api_base
48
+ @api_path = path
49
+
50
+ @api_uri = @api_base.chomp("/") + @api_path
51
+
52
+ @expected_error_codes = []
53
+
54
+ @timeout = Defaults.timeout
55
+ @http_method = :post
56
+ end
57
+
58
+ def request(hash)
59
+ http = http_client
60
+
61
+
62
+ # Mostly for debugging, store these
63
+ @last_request_uri = @api_uri
64
+
65
+
66
+ start_time = Time.now
67
+
68
+ if self.http_method == :post
69
+ @last_request_json = json_request = JSON.generate(hash)
70
+ http_response = http.post @api_uri, json_request, self.request_headers
71
+ elsif self.http_method == :get
72
+ @last_request_query_params = hash
73
+ http_response = http.get @api_uri, hash, self.request_headers
74
+ else
75
+ raise ArgumentError.new("BorrowDirect::Request only understands http_method :get and :post, not `#{self.http_method}`")
76
+ end
77
+
78
+ @last_request_response = http_response
79
+ @last_request_time = Time.now - start_time
80
+
81
+ response_hash = begin
82
+ JSON.parse(http_response.body)
83
+ rescue JSON::ParserError => json_parse_exception
84
+ nil
85
+ end
86
+
87
+ # will be nil if we have none
88
+ einfo = error_info(response_hash)
89
+ expected_error = (einfo && self.expected_error_codes.include?(einfo.number))
90
+
91
+
92
+ if einfo && (! expected_error)
93
+ raise BorrowDirect::Error.new(einfo.message, einfo.number)
94
+ elsif http_response.code != 200 && (! expected_error)
95
+ raise BorrowDirect::HttpError.new("HTTP Error: #{http_response.code}: #{http_response.body}")
96
+ elsif response_hash.nil?
97
+ raise BorrowDirect::Error.new("Could not parse expected JSON response: #{http_response.code} #{json_parse_exception}: #{http_response.body}")
98
+ end
99
+
100
+
101
+
102
+ return response_hash
103
+ rescue HTTPClient::ReceiveTimeoutError => e
104
+ elapsed = Time.now - start_time
105
+ raise BorrowDirect::HttpTimeoutError.new("Timeout after #{elapsed}s connecting to BorrowDirect server at #{@api_base}")
106
+ end
107
+
108
+ def http_client
109
+ @http_client ||= make_http_client!
110
+ end
111
+
112
+ # For now, we can send same request headers for all requests. May have to
113
+ # make parameterized later.
114
+ # Note SOME but not all BD API endpoints REQUIRE User-Agent and
115
+ # Accept-Language (for no discernable reason)
116
+ #
117
+ # NOTE WELL: API sometimes requires User-Agent _not to change_ when using
118
+ # an AuthorizationID, or it will revoke your authorization. Need to use the
119
+ # same User-Agent when using an auth_id as you used when receiving it.
120
+ def request_headers
121
+ { "Content-Type" => "application/json",
122
+ "User-Agent" => "ruby borrow_direct gem #{BorrowDirect::VERSION} (HTTPClient #{HTTPClient::VERSION}) https://github.com/jrochkind/borrow_direct",
123
+ "Accept-Language" => "en"
124
+ }
125
+ end
126
+
127
+ # Fetches new authID, stores it in self.auth_id, overwriting
128
+ # any previous value there. Will raise BorrowDirect::Error if no auth
129
+ # could be fetched.
130
+ #
131
+ # returns auth_id too.
132
+ def fetch_auth_id!(barcode, library_symbol)
133
+ auth = Authentication.new(barcode, library_symbol)
134
+ # use the same HTTPClient so we use the same HTTP connection, perhaps
135
+ # slightly more performance worth a shot.
136
+ auth.http_client = http_client
137
+ self.auth_id = auth.get_auth_id
138
+ end
139
+
140
+ # Will use value in self.auth_id, or if nil will
141
+ # fetch a value with fetch_auth_id! and return that.
142
+ def need_auth_id(barcode, library_symbol)
143
+ self.auth_id || fetch_auth_id!(barcode, library_symbol)
144
+ end
145
+
146
+ # Can be used to set an already existing AuthID to be used.
147
+ # Beware, we have no facility for rescuing from escpired auth ids
148
+ # at the moment.
149
+ def with_auth_id(aid)
150
+ self.auth_id = aid
151
+ return self
152
+ end
153
+
154
+
155
+
156
+
157
+ protected
158
+
159
+ def make_http_client!
160
+ http = HTTPClient.new
161
+ if self.timeout
162
+ http.send_timeout = self.timeout
163
+ http.connect_timeout = self.timeout
164
+ http.receive_timeout = self.timeout
165
+ end
166
+
167
+ return http
168
+ end
169
+
170
+ # returns an OpenStruct with #message and #number,
171
+ # or nil if error info can not be extracted
172
+ def error_info(hash)
173
+ if hash && (e = hash["Error"]) && (e["ErrorNumber"] || e["ErrorMessage"])
174
+ return OpenStruct.new(:number => e["ErrorNumber"], :message => e["ErrorMessage"])
175
+ end
176
+
177
+ # Or wait! Some API's have a totally different way of reporting errors, great!
178
+ if hash && (e = hash["Authentication"]) && e["Problem"]
179
+ return OpenStruct.new(:number => e["Problem"]["Code"], :message => e["Problem"]["Message"])
180
+ end
181
+
182
+ return nil
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,119 @@
1
+ require 'borrow_direct'
2
+ require 'borrow_direct/request'
3
+
4
+ module BorrowDirect
5
+ # The BorrowDirect RequestItem service, for placing a request
6
+ # http://borrowdirect.pbworks.com/w/file/86126056/RequestItem.docx
7
+ #
8
+ # You can also use #find_item_request to get the raw BD response as a ruby hash
9
+ class RequestItem < Request
10
+ attr_reader :patron_barcode, :patron_library_symbol
11
+ attr_reader :authorization_id
12
+
13
+ @@api_path = "/dws/item/add"
14
+ @@valid_search_types = %w{ISBN ISSN LCCN OCLC Control }
15
+
16
+
17
+
18
+ def initialize(patron_barcode,
19
+ patron_library_symbol = Defaults.library_symbol)
20
+ super(@@api_path)
21
+
22
+ @patron_barcode = patron_barcode
23
+ @patron_library_symbol = patron_library_symbol
24
+
25
+ # BD sometimes unpredictably returns this error when it means
26
+ # "no results", other times it doens't. We don't want to raise on it.
27
+ self.expected_error_codes << "PUBRI004"
28
+ end
29
+
30
+ # need to send a key and value for a valid exact_search type
31
+ # type can be string or symbol, lowercase or uppercase.
32
+ #
33
+ # Also a pickup_location -- can pass in nil, and we'll send no
34
+ # PickupLocation to BD, which it seems to accept, not sure what it
35
+ # does with it.
36
+ #
37
+ # Returns the actual complete BD response hash. You may want
38
+ # #make_request instead
39
+ #
40
+ # finder.request_item_request(pickup_location, :isbn => "12345545456")
41
+ # finder.request_item_request(pickup_location, :lccn => "12345545456")
42
+ # finder.request_item_request(pickup_location, :oclc => "12345545456")
43
+ def request_item_request(pickup_location, options)
44
+ search_type, search_value = nil, nil
45
+ options.each_pair do |key, value|
46
+ if @@valid_search_types.include? key.to_s.upcase
47
+ if search_type || search_value
48
+ raise ArgumentError.new("Only one search criteria at a time is allowed: '#{options}'")
49
+ end
50
+
51
+ search_type, search_value = key, value
52
+ end
53
+ end
54
+ unless search_type && search_value
55
+ raise ArgumentError.new("Missing valid search type and value: '#{options}'")
56
+ end
57
+
58
+ request exact_search_request_hash(pickup_location, search_type, search_value)
59
+ end
60
+
61
+ # Pass in a BD exact search and pickup location eg
62
+ # make_request(pickup_location, :isbn => isbn)
63
+ #
64
+ # Pass in nil for pickup_location if... not sure exactly what
65
+ # BD will do, but it does allow it.
66
+ #
67
+ # Returns the BD RequestNumber, or nil if a request could
68
+ # not be made
69
+ #
70
+ # See also make_request! to raise if request can not be made
71
+ def make_request(pickup_location, options)
72
+ resp = request_item_request(pickup_location, options)
73
+
74
+ return extract_request_number(resp)
75
+ end
76
+
77
+ # Like make_request, but will raise a BorrowDirect::Error if
78
+ # item can't be requested.
79
+ def make_request!(pickup_location, options)
80
+ resp = request_item_request(pickup_location, options)
81
+
82
+ number = extract_request_number(resp)
83
+
84
+ if number.nil?
85
+ raise BorrowDirect::Error.new("Can not request for: #{options.inspect}: #{resp.inspect}")
86
+ end
87
+
88
+ return number
89
+ end
90
+
91
+ protected
92
+
93
+ def extract_request_number(resp)
94
+ return (resp["Request"] && resp["Request"]["RequestNumber"])
95
+ end
96
+
97
+ def exact_search_request_hash(pickup_location, type, value)
98
+ hash = {
99
+ "PartnershipId" => Defaults.partnership_id,
100
+ "AuthorizationId" => need_auth_id(self.patron_barcode, self.patron_library_symbol),
101
+ "PickupLocation" => pickup_location,
102
+ "ExactSearch" => [
103
+ {
104
+ "Type" => type.to_s.upcase,
105
+ "Value" => value
106
+ }
107
+ ]
108
+ }
109
+
110
+ if pickup_location
111
+ hash["PickupLocation"] = pickup_location
112
+ end
113
+
114
+ return hash
115
+ end
116
+
117
+
118
+ end
119
+ end
@@ -0,0 +1,124 @@
1
+ require 'borrow_direct'
2
+ require 'date'
3
+
4
+ module BorrowDirect
5
+ # Info from Relais/BD on type and status:
6
+ #
7
+ # valid 'type' values for requests:
8
+ #
9
+ # xdays: Retrieve requests submitted within the last xdays (for example, one would include two parameters: type=xdays&xdays=7 to retrieve requests submitted within the last 7 days)
10
+ # all: Retrieve all request submitted by the user
11
+ # open: Retrieve all open requests i.e. requests which haven't been fulfilled yet.
12
+ # allposttoweb: BD doesn't use the post-to-web application; you can ignore this.
13
+ # unopenedposttoweb: You can safely ignore this.
14
+ # onloan: Retrieve requests which are on loan
15
+ #
16
+ # possible RequestStatus values in results:
17
+ #
18
+ # ENTERED: Request has been entered and yet to be processed.
19
+ # IN_PROCESS: Request is being processed.
20
+ # CANCELLED: Request has been cancelled.
21
+ # UNFILLED: Request can't be filled.
22
+ # SHIPPED: Item has been shipped.
23
+ # ARTICLE_SENT: A scanned document or an electronic document has been sent (It doesn't apply to BD)
24
+ # ON_LOAN: Request is on loan.
25
+ # OVERDUE: Item is over due.
26
+ # COMPLETE: Item has been returned and request is completed.
27
+ # UNKNOWN: You should never see this; this indicates there is probably an inconsistency with the record somewhere. You probably want to flag and report this.
28
+ class RequestQuery < Request
29
+ attr_reader :patron_barcode, :patron_library_symbol
30
+
31
+ @@api_path = "/portal-service/request/query/my"
32
+
33
+ # I'm not exactly sure what these mean either.
34
+ @@query_types = %w{xdays all open allposttoweb unopenedposttoweb onloan}
35
+
36
+
37
+ def initialize(patron_barcode,
38
+ patron_library_symbol = Defaults.library_symbol)
39
+ super(@@api_path)
40
+
41
+ @patron_barcode = patron_barcode
42
+ @patron_library_symbol = patron_library_symbol
43
+ self.http_method = :get
44
+ end
45
+
46
+ # Returns raw BD response as a hash.
47
+ # * type defaults to 'all', but can be BD values of xdays, all
48
+ # open, allposttoweb, unopenedposttoweb, onloan.
49
+ # xdays not really supported yet, cause no way to pass an xdays param yet
50
+ # * full_record can be true or false, defaults to false.
51
+ def request_query_request(type = "all", full_record = false)
52
+ query_params = {
53
+ "aid" => need_auth_id(patron_barcode, patron_library_symbol),
54
+ "type" => type.to_s,
55
+ "fullRecord" => (full_record ? "1" : "0")
56
+ }
57
+
58
+ request query_params
59
+ end
60
+
61
+ # Returns an array of BorrowDirect::RequestQuery::Item
62
+ # * type defaults to 'all', but can be BD values of xdays, all
63
+ # open, allposttoweb, unopenedposttoweb, onloan.
64
+ # xdays not really supported yet, cause no way to pass an xdays param yet
65
+ # * full_record can be true or false, defaults to false.
66
+ def requests(*args)
67
+ response = request_query_request(*args)
68
+
69
+ results = []
70
+
71
+ response["QueryResult"]["MyRequestRecords"].each do |item_hash|
72
+ results << BorrowDirect::RequestQuery::Item.new(item_hash)
73
+ end
74
+
75
+ return results
76
+ end
77
+
78
+ class Item
79
+ # fullRecord == 0 values
80
+ attr_reader :request_number, :title, :date_submitted, :allow_renew,
81
+ :allow_cancel, :request_status, :request_status_date
82
+ # fullRecord == 1 values, not all are applicable for BorrowDirect,
83
+ # and many may be nil.
84
+ attr_reader :publication_type, :publication_date, :publication_place,
85
+ :volume, :issue, :edition, :issn, :issn2, :isbn, :isbn2,
86
+ :ismn, :pages_requested, :delivery_date
87
+
88
+ def initialize(hash)
89
+ # basic record values
90
+ @request_number = hash["RequestNumber"]
91
+ @title = hash["Title"]
92
+ @date_submitted = DateTime.iso8601 hash["ISO8601DateSubmitted"]
93
+ @allow_renew = hash["AllowRenew"]
94
+ @allow_cancel = hash["AllowCancel"]
95
+ @request_status = hash["RequestStatus"]
96
+ @request_status_date = DateTime.iso8601 hash["ISO8601RequestStatusDate"]
97
+
98
+ # full record values
99
+ @publicaition_type = hash["PublicationType"]
100
+ @publication_date = hash["PublicationDate"] # BD just gives us a string
101
+ @publication_place = hash["PublicationPlace"]
102
+ @volume = hash["Volume"]
103
+ @issue = hash["Issue"]
104
+ @edition = hash["Edition"]
105
+ @issn = hash["Issn"]
106
+ @issn2 = hash["Issn2"]
107
+ @isbn = hash["Isbn"]
108
+ @isbn2 = hash["Isbn2"]
109
+ @ismn = hash["Ismn"]
110
+ @pages_requested = hash["PagesRequested"]
111
+ if hash["ISO8601DeliveryDate"]
112
+ @delivery_date = DateTime.iso8601 hash["ISO8601DeliveryDate"]
113
+ end
114
+ end
115
+ end
116
+
117
+ end
118
+
119
+
120
+
121
+
122
+
123
+
124
+ end
@@ -0,0 +1,18 @@
1
+ module BorrowDirect
2
+ module Util
3
+ # A utility method that lets you access a nested hash,
4
+ # returning nil if any intermediate hashes are unavailable.
5
+ def hash_key_path(hash, *path)
6
+ result = nil
7
+
8
+ path.each do |key|
9
+ return nil unless hash.respond_to? :"[]"
10
+ result = hash = hash[key]
11
+ end
12
+
13
+ return result
14
+ end
15
+ module_function :hash_key_path
16
+
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module BorrowDirect
2
+ VERSION = "0.9.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ require "borrow_direct/version"
2
+
3
+ require 'borrow_direct/defaults'
4
+ require 'borrow_direct/error'
5
+ require 'borrow_direct/util'
6
+
7
+ require 'borrow_direct/authentication'
8
+
9
+ require 'borrow_direct/request'
10
+ require 'borrow_direct/find_item'
11
+ require 'borrow_direct/request_item'
12
+ require 'borrow_direct/request_query'
13
+
14
+ require 'borrow_direct/generate_query'
15
+
16
+
17
+ module BorrowDirect
18
+
19
+ end
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+ require 'json'
3
+ require 'httpclient'
4
+
5
+
6
+ describe "Authentication", :vcr => {:tag => :bd_auth} do
7
+ describe "raw request to verify HTTP api" do
8
+ it "works" do
9
+ uri = BorrowDirect::Defaults.api_base.chomp("/") + "/portal-service/user/authentication/patron"
10
+
11
+
12
+ request_hash = {
13
+ "AuthenticationInformation" => {
14
+ "LibrarySymbol" => VCRFilter[:bd_library_symbol],
15
+ "PatronId" => VCRFilter[:bd_patron]
16
+ }
17
+ }
18
+
19
+ http = HTTPClient.new
20
+ response = http.post uri, JSON.generate(request_hash), {"Content-Type" => "application/json", "User-Agent" => "ruby borrow_direct gem (#{BorrowDirect::VERSION}) https://github.com/jrochkind/borrow_direct", "Accept-Language" => "en"}
21
+
22
+ assert_equal 200, response.code
23
+ assert_present response.body
24
+
25
+ response_hash = JSON.parse response.body
26
+
27
+ assert_present response_hash
28
+
29
+ assert_present response_hash["Authentication"]["AuthnUserInfo"]["AId"]
30
+ end
31
+ end
32
+
33
+ it "Makes a request succesfully" do
34
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol])
35
+ response = bd.authentication_request
36
+
37
+ assert_present response
38
+ assert_present response["Authentication"]["AuthnUserInfo"]["AId"]
39
+ end
40
+
41
+ it "Raises for bad library symbol" do
42
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , "BAD_SYMBOL")
43
+ assert_raises(BorrowDirect::Error) do
44
+ bd.authentication_request
45
+ end
46
+ end
47
+
48
+ it "Raises for bad patron barcode" do
49
+ bd = BorrowDirect::Authentication.new("BAD_BARCODE", VCRFilter[:bd_library_symbol])
50
+ assert_raises(BorrowDirect::Error) do
51
+ bd.authentication_request
52
+ end
53
+ end
54
+
55
+ describe "get_auth_id" do
56
+ it "returns an auth_id for a good request" do
57
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , VCRFilter[:bd_library_symbol])
58
+ assert_present bd.get_auth_id
59
+ end
60
+
61
+ it "raises for a bad library symbol" do
62
+ bd = BorrowDirect::Authentication.new(VCRFilter[:bd_patron] , "BAD_SYMBOL")
63
+ assert_raises(BorrowDirect::Error) do
64
+ bd.get_auth_id
65
+ end
66
+ end
67
+
68
+ it "raises for a bad patron barcode" do
69
+ bd = BorrowDirect::Authentication.new("BAD_BARCODE", VCRFilter[:bd_library_symbol])
70
+ assert_raises(BorrowDirect::Error) do
71
+ bd.get_auth_id
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+
78
+
79
+ end