koha 0.0.2 → 0.0.3
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.
- data/README.md +6 -1
- data/lib/koha.rb +9 -8
- data/lib/koha/api_methods/biblio.rb +60 -0
- data/lib/koha/api_methods/info.rb +13 -0
- data/lib/koha/api_methods/user.rb +54 -0
- data/lib/koha/client.rb +34 -179
- data/lib/koha/connection.rb +13 -28
- data/lib/koha/error.rb +1 -4
- data/lib/koha/uri.rb +7 -11
- data/lib/koha/version.rb +4 -4
- data/spec/api/client_spec.rb +16 -16
- data/spec/api/connection_spec.rb +15 -22
- data/spec/spec_helper.rb +2 -0
- metadata +7 -4
data/README.md
CHANGED
@@ -32,7 +32,7 @@ Here a quick irb walk-through...
|
|
32
32
|
|
33
33
|
Make a Connection...
|
34
34
|
|
35
|
-
> 1.9.3-p286 :002 > k = Koha.connect(
|
35
|
+
> 1.9.3-p286 :002 > k = Koha.connect(:url => "http://my.library.se/cgi-bin/koha/rest.pl" )
|
36
36
|
> => #<Koha::Client:0x007fbcec9b6fd0 @uri=#<URI::HTTP:0x007fbcec9c3a00 URL:http://my.library.se/cgi-bin/koha/rest.pl/>, @proxy=nil, @connection=#<Koha::Connection:0x007fbcec9b6ff8>, @options={:url=>"http://my.library.se/cgi-bin/koha/rest.pl"}>
|
37
37
|
|
38
38
|
now get branch information...
|
@@ -69,6 +69,11 @@ or get the user's issues
|
|
69
69
|
|
70
70
|
|
71
71
|
|
72
|
+
## TODO
|
73
|
+
|
74
|
+
Change to Farady? Worried about other libraries that some people cannot use?
|
75
|
+
More tests.
|
76
|
+
|
72
77
|
### Development
|
73
78
|
|
74
79
|
Checkout the code. rake will run the tests. rake coverage will generate coverage. rake yard will generate documentation.
|
data/lib/koha.rb
CHANGED
@@ -4,17 +4,18 @@ require 'rubygems'
|
|
4
4
|
|
5
5
|
module Koha
|
6
6
|
|
7
|
-
|
7
|
+
require 'koha/version'
|
8
8
|
|
9
|
-
|
9
|
+
%W(Client Error Connection Uri ).each{|n| autoload n.to_sym, "koha/#{n.downcase}"}
|
10
|
+
%W(Info User Biblio ).each { |n| autoload n.to_sym, "koha/api_methods/#{n.downcase}"}
|
10
11
|
|
11
|
-
|
12
|
+
class << self
|
13
|
+
def version; VERSION end
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def connect *args
|
16
|
+
opts = Hash === args[-1] ? args[-1] : {}
|
17
|
+
Client.new Koha::Connection.new, opts
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
21
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Koha::Biblio
|
2
|
+
### Biblio and Item Methods ###
|
3
|
+
|
4
|
+
# This method will get the biblio record from koha given the biblionumber
|
5
|
+
def find_biblio biblionumber, opts = {}
|
6
|
+
biblionumber = biblionumber.to_s
|
7
|
+
JSON.parse(get "biblio/#{biblionumber}", opts)
|
8
|
+
end
|
9
|
+
|
10
|
+
# This method will get the item records from koha given the biblionumber
|
11
|
+
def find_biblio_items biblionumber, opts = {}
|
12
|
+
biblionumber = biblionumber.to_s
|
13
|
+
JSON.parse(get "biblio/#{biblionumber}/items", opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# wrapper to check if a biblio is holdable
|
18
|
+
# take a koha biblio number and standard client opts
|
19
|
+
def biblio_holdable?(biblionumber, opts = {})
|
20
|
+
is_holdable?(:biblio, biblionumber, opts )
|
21
|
+
end
|
22
|
+
|
23
|
+
# makes a hold on the title.
|
24
|
+
# takes a koha biblionumber and the client opts, which should include either a borrowernumber or user_name param.
|
25
|
+
# returns a hash of the pickup location and hold date.
|
26
|
+
def hold_biblio(biblionumber, opts = {})
|
27
|
+
JSON.parse(post "biblio/#{biblionumber}/hold", opts )
|
28
|
+
end
|
29
|
+
|
30
|
+
# wrapper to check a biblio items holdabale statues.
|
31
|
+
# takes a koha bilionumber and standard client opts
|
32
|
+
# this returns just a hash of the items and their status, no need to evaulate.
|
33
|
+
def biblio_items_holdable?(biblionumber, opts = {} )
|
34
|
+
opts ||= {}
|
35
|
+
opts[:holdable] = "items_holdable_status"
|
36
|
+
opts[:evaluate] ||= false
|
37
|
+
is_holdable?(:biblio, biblionumber, opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
# wrapper to check is an item is holdable
|
41
|
+
def item_holdable?(itemnumber, opts = {})
|
42
|
+
is_holdable?(:item, itemnumber, opts)
|
43
|
+
end
|
44
|
+
|
45
|
+
# makes a hold on the title.
|
46
|
+
# takes a koha biblionumber and the client opts, which should include either a borrowernumber or user_name param.
|
47
|
+
# returns a hash of the pickup location and hold date.
|
48
|
+
def hold_item(itemnumber, opts = {})
|
49
|
+
JSON.parse( post "item/#{itemnumber}/hold", opts )
|
50
|
+
end
|
51
|
+
|
52
|
+
def is_holdable?(koha_type, identifier, opts = {} )
|
53
|
+
opts ||= {}
|
54
|
+
opts[:evaluate] = :is_holdable unless opts[:evaluate] == false
|
55
|
+
holdable = opts[:holdable] ? opts[:holdable] : "holdable"
|
56
|
+
koha_type = koha_type.to_s == "item" ? "item" : "biblio"
|
57
|
+
identifier = identifier.to_s
|
58
|
+
get "#{koha_type}/#{identifier}/#{holdable}", opts
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Koha::User
|
2
|
+
### USER Methods ###
|
3
|
+
|
4
|
+
# get all the users
|
5
|
+
# @param opts [Hash] standard opts hash to pass to http client
|
6
|
+
def all_users opts= {}
|
7
|
+
JSON.parse(get "user/all", opts )
|
8
|
+
end
|
9
|
+
|
10
|
+
# get all today's users
|
11
|
+
# @param opts [Hash] standard opts hash to pass to http client
|
12
|
+
def today_users opts= {}
|
13
|
+
JSON.parse(get "user/today", opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
# get all today's users
|
17
|
+
# @param opts [Hash] standard opts hash to pass to http client
|
18
|
+
def user_holds opts= {}
|
19
|
+
path, opts = build_user_path("holds", opts)
|
20
|
+
JSON.parse(get path, opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete_hold opts= {}
|
24
|
+
opts[:evaluate] ||= "canceled"
|
25
|
+
opts[:prefix] = opts[:biblionumber] ? "biblio" : "item" #delete end-point is like :/user/byid/544/holds/biblio/1
|
26
|
+
path, opts = build_user_path("holds", opts)
|
27
|
+
return delete(path, opts)
|
28
|
+
end
|
29
|
+
|
30
|
+
def user_issues opts= {}
|
31
|
+
path, opts = build_user_path("issues", opts)
|
32
|
+
JSON.parse(get path, opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
def renew_issue opts={}
|
36
|
+
path, opts = build_user_path("issues", opts)
|
37
|
+
JSON.parse(put path, opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def build_user_path koha_method, opts= {}
|
43
|
+
raise ArgumentError unless ( opts[:borrowernumber] or opts[:borrowername] ) #we have to be passed either a name or number
|
44
|
+
borrowernumber, borrowername = opts.delete(:borrowernumber), opts.delete(:borrowername)
|
45
|
+
biblionumber, itemnumber = opts.delete(:biblionumber), opts.delete(:itemnumber)
|
46
|
+
prefix = opts.delete(:prefix)
|
47
|
+
path = borrowernumber ? "user/byid/#{borrowernumber}/#{koha_method}/" : "user/#{borrowername}/#{koha_method}/"
|
48
|
+
path << prefix if prefix
|
49
|
+
path << "/#{itemnumber}/" if itemnumber
|
50
|
+
path << "/#{biblionumber}/" if ( biblionumber && itemnumber.nil?)
|
51
|
+
return path, opts
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/koha/client.rb
CHANGED
@@ -2,6 +2,10 @@ require 'json'
|
|
2
2
|
|
3
3
|
class Koha::Client
|
4
4
|
|
5
|
+
include Koha::Info
|
6
|
+
include Koha::User
|
7
|
+
include Koha::Biblio
|
8
|
+
|
5
9
|
attr_reader :connection, :uri, :proxy, :options
|
6
10
|
|
7
11
|
def initialize connection, options = {}
|
@@ -9,11 +13,9 @@ class Koha::Client
|
|
9
13
|
@connection = connection
|
10
14
|
unless false === options[:url]
|
11
15
|
url = options[:url] ? options[:url].dup : 'http://localhost/cgi-bin/koha/rest.pl/'
|
12
|
-
url << "/" unless url[-1] == ?/
|
13
16
|
@uri = Koha::Uri.create url
|
14
17
|
if options[:proxy]
|
15
18
|
proxy_url = options[:proxy].dup
|
16
|
-
proxy_url << "/" unless proxy_url.nil? or proxy_url[-1] == ?/
|
17
19
|
@proxy = Koha::Uri.create proxy_url if proxy_url
|
18
20
|
end
|
19
21
|
end
|
@@ -30,51 +32,31 @@ class Koha::Client
|
|
30
32
|
%W(get post put delete).each do |meth|
|
31
33
|
class_eval <<-RUBY
|
32
34
|
def #{meth} path, opts = {}, &block
|
33
|
-
|
35
|
+
send_request path, opts.merge(:method => :#{meth}), &block
|
34
36
|
end
|
35
37
|
RUBY
|
36
38
|
end
|
37
39
|
|
38
40
|
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# creates a request context hash,
|
49
|
-
# sends it to the connection's +execute+ method
|
50
|
-
# which returns a simple hash,
|
51
|
-
# then passes the request/response into +adapt_response+.
|
52
|
-
def send_and_receive path, opts
|
41
|
+
# the main request method responsible for sending requests.
|
42
|
+
# @param path [String] the client's API REST method
|
43
|
+
# @param opts [Hash] A hash which can contain the following keys:
|
44
|
+
# [:method] : optional - the http method (:get, :post or :put)
|
45
|
+
# [:params] : optional - the query string params in hash form
|
46
|
+
# All other options are passed to the execute method
|
47
|
+
def send_request path, opts
|
53
48
|
request_context = build_request path, opts
|
54
49
|
[:open_timeout, :read_timeout].each do |k|
|
55
50
|
request_context[k] = @options[k]
|
56
51
|
end
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
# send a request to the connection to be submitted
|
61
|
-
def execute request_context
|
62
|
-
raw_response = connection.execute self, request_context
|
63
|
-
adapt_response(request_context, raw_response) unless raw_response.nil?
|
52
|
+
request request_context
|
64
53
|
end
|
65
|
-
|
66
|
-
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
# :method
|
72
|
-
# :params
|
73
|
-
# :data
|
74
|
-
# :uri
|
75
|
-
# :path
|
76
|
-
# :query
|
77
|
-
|
54
|
+
|
55
|
+
|
56
|
+
# Sets up the uri/query string
|
57
|
+
# @param path [String, Symbol] the request path
|
58
|
+
# @param opts [Hash] The options for the REST call. Can include:
|
59
|
+
# :method, :params, :data, :uri, :path, :query
|
78
60
|
def build_request path, opts
|
79
61
|
raise "path must be a string or symbol, not #{path.inspect}" unless [String,Symbol].include?(path.class)
|
80
62
|
path = path.to_s
|
@@ -91,14 +73,7 @@ class Koha::Client
|
|
91
73
|
opts[:data][:user_name] = opts[:borrowername] if opts[:borrowername]
|
92
74
|
end
|
93
75
|
query = Koha::Uri.to_params(opts[:params]) unless opts[:params].empty?
|
94
|
-
opts[:query] = query
|
95
|
-
|
96
|
-
if opts[:data].is_a? Hash
|
97
|
-
opts[:data] = Koha::Uri.to_params opts[:data]
|
98
|
-
opts[:headers] ||= {}
|
99
|
-
opts[:headers]['Content-Type'] ||= 'application/x-www-form-urlencoded; charset=UTF-8'
|
100
|
-
end
|
101
|
-
|
76
|
+
opts[:query] = query
|
102
77
|
opts[:path] = path
|
103
78
|
if base_uri
|
104
79
|
opts[:uri] = URI.join(base_uri, path.to_s)
|
@@ -106,151 +81,31 @@ class Koha::Client
|
|
106
81
|
end
|
107
82
|
opts
|
108
83
|
end
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
module Context
|
84
|
+
|
85
|
+
# A simple mixin for process_response.
|
86
|
+
module Response
|
113
87
|
attr_accessor :request, :response
|
114
88
|
end
|
115
89
|
|
116
|
-
#
|
117
|
-
|
118
|
-
# the evaluate_json_response, which returns just the node.
|
119
|
-
# this is a convience to simply return "false" or "true" and not a bunch of stupid
|
120
|
-
# json that has nothing that makes any god-damn sense.
|
121
|
-
# ... otherwise, the json is simply returned.
|
122
|
-
def adapt_response request, response
|
90
|
+
# Recieves the request and response from the connection and format it. Returns an object with the response body and @request and @response.
|
91
|
+
def process_response request, response
|
123
92
|
raise "The response does not have the correct keys => :body, :headers, :status" unless
|
124
93
|
%W(body headers status) == response.keys.map{|k|k.to_s}.sort
|
125
94
|
raise Koha::Error::Http.new request, response unless [200,302].include? response[:status]
|
126
95
|
result = request[:evaluate] ? evaluate_json_response( response, request[:evaluate]) : response[:body]
|
127
|
-
result.extend
|
96
|
+
result.extend Response
|
128
97
|
result.request, result.response = request, response
|
129
98
|
result
|
130
99
|
end
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
##### KOHA REST API METHODS #######
|
135
|
-
|
136
|
-
### Info Methods ###
|
137
|
-
|
138
|
-
# returns a hash of [ { :code => "1", :name => "Our Branch Name "}]
|
139
|
-
def branches opts= {}
|
140
|
-
JSON.parse(get "branches", opts)
|
141
|
-
end
|
142
|
-
|
143
|
-
|
144
|
-
### USER Methods ###
|
145
|
-
|
146
|
-
# returns a hash of all the users
|
147
|
-
def all_users opts= {}
|
148
|
-
JSON.parse(get "user/all", opts )
|
149
|
-
end
|
150
|
-
|
151
|
-
# returns a hash of patrons enrolled today
|
152
|
-
def today_users opts= {}
|
153
|
-
JSON.parse(get "user/today", opts)
|
154
|
-
end
|
155
|
-
|
156
|
-
|
157
|
-
def user_holds opts= {}
|
158
|
-
path, opts = build_user_path("holds", opts)
|
159
|
-
JSON.parse(get path, opts)
|
160
|
-
end
|
161
|
-
|
162
|
-
def delete_hold opts= {}
|
163
|
-
opts[:evaluate] ||= "canceled"
|
164
|
-
opts[:prefix] = opts[:biblionumber] ? "biblio" : "item" #delete end-point is like :/user/byid/544/holds/biblio/1
|
165
|
-
path, opts = build_user_path("holds", opts)
|
166
|
-
return delete(path, opts)
|
167
|
-
end
|
168
|
-
|
169
|
-
def user_issues opts= {}
|
170
|
-
path, opts = build_user_path("issues", opts)
|
171
|
-
JSON.parse(get path, opts)
|
172
|
-
end
|
173
|
-
|
174
|
-
def renew_issue opts={}
|
175
|
-
path, opts = build_user_path("issues", opts)
|
176
|
-
JSON.parse(put path, opts)
|
177
|
-
end
|
178
|
-
|
179
|
-
|
180
|
-
def build_user_path koha_method, opts= {}
|
181
|
-
raise ArgumentError unless ( opts[:borrowernumber] or opts[:borrowername] ) #we have to be passed either a name or number
|
182
|
-
borrowernumber, borrowername = opts.delete(:borrowernumber), opts.delete(:borrowername)
|
183
|
-
biblionumber, itemnumber = opts.delete(:biblionumber), opts.delete(:itemnumber)
|
184
|
-
prefix = opts.delete(:prefix)
|
185
|
-
path = borrowernumber ? "user/byid/#{borrowernumber}/#{koha_method}/" : "user/#{borrowername}/#{koha_method}/"
|
186
|
-
path << prefix if prefix
|
187
|
-
path << "/#{itemnumber}/" if itemnumber
|
188
|
-
path << "/#{biblionumber}/" if ( biblionumber && itemnumber.nil?)
|
189
|
-
return path, opts
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
### Biblio and Item Methods ###
|
194
|
-
|
195
|
-
# This method will get the biblio record from koha given the biblionumber
|
196
|
-
def find_biblio biblionumber, opts = {}
|
197
|
-
biblionumber = biblionumber.to_s
|
198
|
-
JSON.parse(get "biblio/#{biblionumber}", opts)
|
199
|
-
end
|
200
|
-
|
201
|
-
# This method will get the item records from koha given the biblionumber
|
202
|
-
def find_biblio_items biblionumber, opts = {}
|
203
|
-
biblionumber = biblionumber.to_s
|
204
|
-
JSON.parse(get "biblio/#{biblionumber}/items", opts)
|
205
|
-
end
|
206
|
-
|
207
|
-
|
208
|
-
# wrapper to check if a biblio is holdable
|
209
|
-
# take a koha biblio number and standard client opts
|
210
|
-
def biblio_holdable?(biblionumber, opts = {})
|
211
|
-
is_holdable?(:biblio, biblionumber, opts )
|
212
|
-
end
|
213
|
-
|
214
|
-
# makes a hold on the title.
|
215
|
-
# takes a koha biblionumber and the client opts, which should include either a borrowernumber or user_name param.
|
216
|
-
# returns a hash of the pickup location and hold date.
|
217
|
-
def hold_biblio(biblionumber, opts = {})
|
218
|
-
JSON.parse(post "biblio/#{biblionumber}/hold", opts )
|
219
|
-
end
|
220
|
-
|
221
|
-
# wrapper to check a biblio items holdabale statues.
|
222
|
-
# takes a koha bilionumber and standard client opts
|
223
|
-
# this returns just a hash of the items and their status, no need to evaulate.
|
224
|
-
def biblio_items_holdable?(biblionumber, opts = {} )
|
225
|
-
opts ||= {}
|
226
|
-
opts[:holdable] = "items_holdable_status"
|
227
|
-
opts[:evaluate] ||= false
|
228
|
-
is_holdable?(:biblio, biblionumber, opts)
|
229
|
-
end
|
230
|
-
|
231
|
-
# wrapper to check is an item is holdable
|
232
|
-
def item_holdable?(itemnumber, opts = {})
|
233
|
-
is_holdable?(:item, itemnumber, opts)
|
234
|
-
end
|
235
|
-
|
236
|
-
# makes a hold on the title.
|
237
|
-
# takes a koha biblionumber and the client opts, which should include either a borrowernumber or user_name param.
|
238
|
-
# returns a hash of the pickup location and hold date.
|
239
|
-
def hold_item(itemnumber, opts = {})
|
240
|
-
JSON.parse( post "item/#{itemnumber}/hold", opts )
|
241
|
-
end
|
242
|
-
|
243
|
-
def is_holdable?(koha_type, identifier, opts = {} )
|
244
|
-
opts ||= {}
|
245
|
-
opts[:evaluate] = :is_holdable unless opts[:evaluate] == false
|
246
|
-
holdable = opts[:holdable] ? opts[:holdable] : "holdable"
|
247
|
-
koha_type = koha_type.to_s == "item" ? "item" : "biblio"
|
248
|
-
identifier = identifier.to_s
|
249
|
-
get "#{koha_type}/#{identifier}/#{holdable}", opts
|
250
|
-
end
|
251
|
-
|
252
|
-
|
100
|
+
|
253
101
|
protected
|
102
|
+
# process the request to the connection to be submitted
|
103
|
+
# @param request_context [Hash] A hash created by the build_request method
|
104
|
+
def request request_context
|
105
|
+
raw_response = connection.request request_context
|
106
|
+
process_response(request_context, raw_response) unless raw_response.nil?
|
107
|
+
end
|
108
|
+
|
254
109
|
|
255
110
|
# this is used to retrun a ruby primitive based on a json node. For example holdable returns { "is_holdable" : true, "reasons" : [] }
|
256
111
|
# and we just want true.
|
data/lib/koha/connection.rb
CHANGED
@@ -1,32 +1,24 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'net/https'
|
3
3
|
|
4
|
-
|
5
|
-
# taken from RSOLR's http client
|
6
4
|
class Koha::Connection
|
7
5
|
|
8
|
-
def
|
9
|
-
|
10
|
-
request =
|
6
|
+
def request request_context
|
7
|
+
hclient = http_client request_context[:uri], request_context[:proxy], request_context[:read_timeout], request_context[:open_timeout]
|
8
|
+
request = request_setup request_context
|
11
9
|
request.body = request_context[:data] if request_context[:method] == :post and request_context[:data]
|
12
10
|
begin
|
13
|
-
response =
|
11
|
+
response = hclient.request request
|
14
12
|
charset = response.type_params["charset"]
|
15
|
-
{:status => response.code.to_i, :headers => response.to_hash, :body =>
|
13
|
+
{:status => response.code.to_i, :headers => response.to_hash, :body => response.body}
|
16
14
|
rescue Errno::ECONNREFUSED => e
|
17
15
|
raise(Errno::ECONNREFUSED.new(request_context.inspect))
|
18
|
-
# catch the undefined closed? exception -- this is a confirmed ruby bug
|
19
|
-
rescue NoMethodError
|
20
|
-
$!.message == "undefined method `closed?' for nil:NilClass" ?
|
21
|
-
raise(Errno::ECONNREFUSED.new) :
|
22
|
-
raise($!)
|
23
16
|
end
|
24
17
|
end
|
25
18
|
|
26
19
|
protected
|
27
|
-
|
28
|
-
|
29
|
-
def http uri, proxy = nil, read_timeout = nil, open_timeout = nil
|
20
|
+
# This returns a singleton of a Net::HTTP or Net::HTTP.Proxy
|
21
|
+
def http_client uri, proxy = nil, read_timeout = nil, open_timeout = nil
|
30
22
|
@http ||= (
|
31
23
|
http = if proxy
|
32
24
|
proxy_user, proxy_pass = proxy.userinfo.split(/:/) if proxy.userinfo
|
@@ -41,8 +33,8 @@ class Koha::Connection
|
|
41
33
|
)
|
42
34
|
end
|
43
35
|
|
44
|
-
#
|
45
|
-
def
|
36
|
+
# takes the hash and sets up the basic params.
|
37
|
+
def request_setup request_context
|
46
38
|
http_method = case request_context[:method]
|
47
39
|
when :get
|
48
40
|
Net::HTTP::Get
|
@@ -56,17 +48,10 @@ class Koha::Connection
|
|
56
48
|
raise "Only :get, :post and :delete http method types are allowed."
|
57
49
|
end
|
58
50
|
headers = request_context[:headers] || {}
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
51
|
+
setup = http_method.new request_context[:uri].request_uri
|
52
|
+
setup.initialize_http_header headers
|
53
|
+
setup.basic_auth(request_context[:uri].user, request_context[:uri].password) if request_context[:uri].user && request_context[:uri].password
|
54
|
+
setup
|
63
55
|
end
|
64
56
|
|
65
|
-
private
|
66
|
-
|
67
|
-
def force_charset body, charset
|
68
|
-
return body unless charset and body.respond_to?(:force_encoding)
|
69
|
-
body.force_encoding(charset)
|
70
|
-
end
|
71
|
-
|
72
57
|
end
|
data/lib/koha/error.rb
CHANGED
@@ -25,10 +25,7 @@ module Koha::Error
|
|
25
25
|
class Http < RuntimeError
|
26
26
|
|
27
27
|
include KohaContext
|
28
|
-
#
|
29
|
-
# Defines the standard HTTP status codes, by integer, with their
|
30
|
-
# corresponding default message texts.
|
31
|
-
# Source: http://www.iana.org/assignments/http-status-codes
|
28
|
+
# stolen from ActionPack
|
32
29
|
STATUS_CODES = {
|
33
30
|
100 => "Continue",
|
34
31
|
101 => "Switching Protocols",
|
data/lib/koha/uri.rb
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
require 'uri'
|
2
2
|
|
3
3
|
module Koha::Uri
|
4
|
+
extend self
|
5
|
+
|
4
6
|
|
5
7
|
def create url
|
6
8
|
::URI.parse url[-1] == ?/ ? url : "#{url}/"
|
7
9
|
end
|
8
10
|
|
9
|
-
#
|
10
|
-
#
|
11
|
+
# takes a key and value and returns it as a query string
|
12
|
+
# @param k [String]
|
13
|
+
# @param v [String]
|
14
|
+
# @param escape [Boolean]
|
11
15
|
def build_param(k,v, escape = true)
|
12
16
|
escape ?
|
13
17
|
"#{escape_query_value(k)}=#{escape_query_value(v)}" :
|
14
18
|
"#{k}=#{v}"
|
15
19
|
end
|
16
20
|
|
17
|
-
#
|
18
|
-
# String#bytesize under 1.9.
|
21
|
+
# issue with ruby 1.8, which uses String#size. ruby 1.9 uses String#bytesize.
|
19
22
|
if ''.respond_to?(:bytesize)
|
20
23
|
def bytesize(string)
|
21
24
|
string.bytesize
|
@@ -27,10 +30,6 @@ module Koha::Uri
|
|
27
30
|
end
|
28
31
|
|
29
32
|
# Creates a ILSDI based query string.
|
30
|
-
# Keys that have arrays values are set multiple times:
|
31
|
-
# params_to_solr(:service => 'foo', :biblionumbers => ['1', '2'])
|
32
|
-
# is converted to:
|
33
|
-
# ?service=foo&biblinumbers=1+2
|
34
33
|
def to_params(params, escape = true)
|
35
34
|
mapped = params.map do |k, v|
|
36
35
|
next if v.to_s.empty?
|
@@ -45,8 +44,6 @@ module Koha::Uri
|
|
45
44
|
|
46
45
|
|
47
46
|
# Performs URI escaping so that you can construct proper
|
48
|
-
# query strings faster. Use this rather than the cgi.rb
|
49
|
-
# version since it's faster.
|
50
47
|
# (Stolen from Rack).
|
51
48
|
def escape_query_value(s)
|
52
49
|
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/u) {
|
@@ -54,6 +51,5 @@ module Koha::Uri
|
|
54
51
|
}.tr(' ', '+')
|
55
52
|
end
|
56
53
|
|
57
|
-
extend self
|
58
54
|
|
59
55
|
end
|
data/lib/koha/version.rb
CHANGED
data/spec/api/client_spec.rb
CHANGED
@@ -18,30 +18,30 @@ describe "Koha::Client" do
|
|
18
18
|
|
19
19
|
end
|
20
20
|
|
21
|
-
context "
|
21
|
+
context "request" do
|
22
22
|
include ClientHelper
|
23
23
|
it "should forward these method calls the #connection object" do
|
24
24
|
[:get, :post, :put].each do |meth|
|
25
|
-
client.connection.should_receive(:
|
25
|
+
client.connection.should_receive(:request).
|
26
26
|
and_return({:status => 200, :body => "{}", :headers => {}})
|
27
|
-
client.
|
27
|
+
client.send_request '', :method => meth, :params => {}, :data => nil, :headers => {}
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should be timeout aware" do
|
32
32
|
[:get, :post, :put].each do |meth|
|
33
|
-
client.connection.should_receive(:
|
34
|
-
client.
|
33
|
+
client.connection.should_receive(:request).with( hash_including(:read_timeout => 42, :open_timeout=>43))
|
34
|
+
client.send_request '', :method => meth, :params => {}, :data => nil, :headers => {}
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
context "post" do
|
40
40
|
include ClientHelper
|
41
|
-
it "should pass the expected params to the connection's #
|
41
|
+
it "should pass the expected params to the connection's #request method" do
|
42
42
|
request_opts = {:data => "the data", :method=>:post, :headers => {"Content-Type" => "text/plain"}}
|
43
|
-
client.connection.should_receive(:
|
44
|
-
with(
|
43
|
+
client.connection.should_receive(:request).
|
44
|
+
with(hash_including(request_opts)).
|
45
45
|
and_return(
|
46
46
|
:body => "",
|
47
47
|
:status => 200,
|
@@ -53,7 +53,7 @@ describe "Koha::Client" do
|
|
53
53
|
|
54
54
|
|
55
55
|
|
56
|
-
context "
|
56
|
+
context "process_respons" do
|
57
57
|
include ClientHelper
|
58
58
|
|
59
59
|
|
@@ -108,35 +108,35 @@ describe "Koha::Client" do
|
|
108
108
|
end
|
109
109
|
|
110
110
|
it "should call the user holds method for #user_holds" do
|
111
|
-
stub_request(:get, "http://localhost/koha/user/byid/1/holds").to_return(:status => 200, :body =>
|
111
|
+
stub_request(:get, "http://localhost/koha/user/byid/1/holds/").to_return(:status => 200, :body =>
|
112
112
|
"[{\"itemnumber\":null,\"branchname\":\"World Maritime University Library\",\"itemcallnumber\":null,\"hold_id\":null,\"reservedate\":\"2013-02-20\",\"barcode\":null,\"found\":null,\"biblionumber\":\"76356\",\"cancellationdate\":null,\"title\":\"Asian approaches to international law and the legacy of colonialism and imperialism :\",\"rank\":\"1\",\"branchcode\":\"WMU\"}]" )
|
113
113
|
client.user_holds(:borrowernumber => "1")
|
114
|
-
WebMock.should have_requested(:get, "http://localhost/koha/user/byid/1/holds")
|
114
|
+
WebMock.should have_requested(:get, "http://localhost/koha/user/byid/1/holds/")
|
115
115
|
end
|
116
116
|
|
117
117
|
|
118
118
|
it "should call the user issues method for #user_issues" do
|
119
|
-
stub_request(:get, "http://localhost/koha/user/cf/issues").to_return(:status => 200, :body =>
|
119
|
+
stub_request(:get, "http://localhost/koha/user/cf/issues/").to_return(:status => 200, :body =>
|
120
120
|
"[{\"itemnumber\":\"42414\",\"itemcallnumber\":\"KD1819 .H54 2003\",\"barcode\":\"022593\",\"date_due\":\"2013-03-11T23:59:00\",\"renewable\":true,\"issuedate\":\"2012-11-21T00:00:00\",\"biblionumber\":\"17454\",\"title\":\"Maritime law\",\"borrowernumber\":\"544\",\"branchcode\":\"WMU\"}]" )
|
121
121
|
client.user_issues(:borrowername => "cf")
|
122
|
-
WebMock.should have_requested(:get, "http://localhost/koha/user/cf/issues")
|
122
|
+
WebMock.should have_requested(:get, "http://localhost/koha/user/cf/issues/")
|
123
123
|
end
|
124
124
|
|
125
125
|
|
126
126
|
# biblio and items
|
127
127
|
|
128
128
|
it "should call the biblio items method for #find_biblio" do
|
129
|
-
stub_request(:get, "http://localhost/koha/biblio/1
|
129
|
+
stub_request(:get, "http://localhost/koha/biblio/1").to_return(:status => 200, :body =>
|
130
130
|
"[{\"withdrawn\":\"0\",\"biblioitemnumber\":\"1\",\"restricted\":null,\"wthdrawn\":\"0\",\"holdingbranchname\":\"World Maritime University Library\",\"notforloan\":\"0\",\"replacementpricedate\":\"2010-02-05\",\"itemnumber\":\"1\",\"ccode\":null,\"itemnotes\":null,\"location\":\"GEN\",\"itemcallnumber\":\"HD30.3 .A32 1989\",\"stack\":null,\"date_due\":\"\",\"barcode\":\"011376\",\"itemlost\":\"0\",\"uri\":null,\"materials\":null,\"datelastseen\":\"2010-02-05\",\"price\":null,\"issues\":null,\"homebranch\":\"WMU\",\"replacementprice\":null,\"more_subfields_xml\":null,\"cn_source\":\"lcc\",\"homebranchname\":\"World Maritime University Library\",\"booksellerid\":null,\"biblionumber\":\"1\",\"renewals\":null,\"holdingbranch\":\"WMU\",\"timestamp\":\"2012-11-28 07:47:23\",\"damaged\":\"0\",\"stocknumber\":null,\"cn_sort\":\"HD_00030_3_A32_1989\",\"reserves\":null,\"dateaccessioned\":\"2010-02-05\",\"datelastborrowed\":null,\"enumchron\":null,\"copynumber\":\"1\",\"permanent_location\":null,\"onloan\":null,\"paidfor\":null,\"itype\":\"BOOK\"}]" )
|
131
131
|
client.find_biblio("1")
|
132
|
-
WebMock.should have_requested(:get, "http://localhost/koha/biblio/1
|
132
|
+
WebMock.should have_requested(:get, "http://localhost/koha/biblio/1")
|
133
133
|
end
|
134
134
|
|
135
135
|
|
136
136
|
it "should call the biblio items method for #find_biblio" do
|
137
137
|
stub_request(:get, "http://localhost/koha/biblio/1/items").to_return(:status => 200, :body =>
|
138
138
|
"[{\"withdrawn\":\"0\",\"biblioitemnumber\":\"1\",\"restricted\":null,\"wthdrawn\":\"0\",\"holdingbranchname\":\"World Maritime University Library\",\"notforloan\":\"0\",\"replacementpricedate\":\"2010-02-05\",\"itemnumber\":\"1\",\"ccode\":null,\"itemnotes\":null,\"location\":\"GEN\",\"itemcallnumber\":\"HD30.3 .A32 1989\",\"stack\":null,\"date_due\":\"\",\"barcode\":\"011376\",\"itemlost\":\"0\",\"uri\":null,\"materials\":null,\"datelastseen\":\"2010-02-05\",\"price\":null,\"issues\":null,\"homebranch\":\"WMU\",\"replacementprice\":null,\"more_subfields_xml\":null,\"cn_source\":\"lcc\",\"homebranchname\":\"World Maritime University Library\",\"booksellerid\":null,\"biblionumber\":\"1\",\"renewals\":null,\"holdingbranch\":\"WMU\",\"timestamp\":\"2012-11-28 07:47:23\",\"damaged\":\"0\",\"stocknumber\":null,\"cn_sort\":\"HD_00030_3_A32_1989\",\"reserves\":null,\"dateaccessioned\":\"2010-02-05\",\"datelastborrowed\":null,\"enumchron\":null,\"copynumber\":\"1\",\"permanent_location\":null,\"onloan\":null,\"paidfor\":null,\"itype\":\"BOOK\"}]" )
|
139
|
-
client.
|
139
|
+
client.find_biblio_items("1")
|
140
140
|
WebMock.should have_requested(:get, "http://localhost/koha/biblio/1/items")
|
141
141
|
end
|
142
142
|
|
data/spec/api/connection_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'base64'
|
|
3
3
|
|
4
4
|
describe "Koha::Connection" do
|
5
5
|
|
6
|
-
context "
|
6
|
+
context "request_setup" do
|
7
7
|
|
8
8
|
before(:each) do
|
9
9
|
@c = Koha::Connection.new
|
@@ -12,15 +12,15 @@ describe "Koha::Connection" do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should set up a get request" do
|
15
|
-
req = @c.send :
|
15
|
+
req = @c.send :request_setup, {:headers => {"content-type" => "application/json"}, :method => :get, :uri => URI.parse(@base_url + "/biblio/1/items?borrowername=cf")}
|
16
16
|
headers = {}
|
17
|
-
req.each_header{|k,v| headers[k] = v}
|
17
|
+
req.each_header { |k,v| headers[k] = v }
|
18
18
|
req.method.should == "GET"
|
19
19
|
headers.should == {"content-type"=>"application/json"}
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should set up a post request" do
|
23
|
-
req = @c.send :
|
23
|
+
req = @c.send :request_setup, {:headers => {"content-type" => "application/json"}, :method => :post, :uri => URI.parse(@base_url + "/biblio/1/items?borrowername=cf")}
|
24
24
|
headers = {}
|
25
25
|
req.each_header{|k,v| headers[k] = v}
|
26
26
|
req.method.should == "POST"
|
@@ -28,7 +28,7 @@ describe "Koha::Connection" do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should set up a post request" do
|
31
|
-
req = @c.send :
|
31
|
+
req = @c.send :request_setup, {:headers => {"content-type" => "application/json"}, :method => :put, :uri => URI.parse(@base_url + "/biblio/1/items?borrowername=cf")}
|
32
32
|
headers = {}
|
33
33
|
req.each_header{|k,v| headers[k] = v}
|
34
34
|
req.method.should == "PUT"
|
@@ -36,7 +36,8 @@ describe "Koha::Connection" do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should raise error if something weird is set as method" do
|
39
|
-
expect { @c.send :
|
39
|
+
expect { @c.send :request_setup, {:headers => {"content-type" => "application/json"}, :method => :head, :uri => URI.parse(@base_url + "/biblio/1/items?borrowername=cf")} }
|
40
|
+
.to raise_error("Only :get, :post and :delete http method types are allowed.")
|
40
41
|
|
41
42
|
end
|
42
43
|
|
@@ -55,12 +56,12 @@ describe "Koha::Connection" do
|
|
55
56
|
|
56
57
|
it "should configure Net:HTTP read_timeout" do
|
57
58
|
http.should_receive(:read_timeout=).with(42)
|
58
|
-
subject.
|
59
|
+
subject.request :uri => URI.parse("http://localhost/some_uri"), :method => :get, :read_timeout => 42
|
59
60
|
end
|
60
61
|
|
61
62
|
it "should use Net:HTTP default read_timeout if not specified" do
|
62
63
|
http.should_not_receive(:read_timeout=)
|
63
|
-
subject.
|
64
|
+
subject.request :uri => URI.parse("http://localhost/some_uri"), :method => :get
|
64
65
|
end
|
65
66
|
end
|
66
67
|
|
@@ -77,12 +78,12 @@ describe "Koha::Connection" do
|
|
77
78
|
|
78
79
|
it "should configure Net:HTTP open_timeout" do
|
79
80
|
http.should_receive(:open_timeout=).with(42)
|
80
|
-
subject.
|
81
|
+
subject.request :uri => URI.parse("http://localhost/some_uri"), :method => :get, :open_timeout => 42
|
81
82
|
end
|
82
83
|
|
83
84
|
it "should use Net:HTTP default open_timeout if not specified" do
|
84
85
|
http.should_not_receive(:open_timeout=)
|
85
|
-
subject.
|
86
|
+
subject.request :uri => URI.parse("http://localhost/some_uri"), :method => :get
|
86
87
|
end
|
87
88
|
end
|
88
89
|
|
@@ -102,7 +103,7 @@ describe "Koha::Connection" do
|
|
102
103
|
it "should configure Net:HTTP open_timeout" do
|
103
104
|
http.should_receive(:request).and_raise(Errno::ECONNREFUSED)
|
104
105
|
lambda {
|
105
|
-
subject.
|
106
|
+
subject.request request_context
|
106
107
|
}.should raise_error(Errno::ECONNREFUSED, /#{request_context}/)
|
107
108
|
end
|
108
109
|
|
@@ -110,18 +111,10 @@ describe "Koha::Connection" do
|
|
110
111
|
it "should raise NoMethodError if a non-method is called" do
|
111
112
|
http.should_receive(:request).and_raise(NoMethodError)
|
112
113
|
lambda {
|
113
|
-
subject.
|
114
|
+
subject.request request_context
|
114
115
|
}.should raise_error(NoMethodError, /NoMethodError/)
|
115
116
|
end
|
116
117
|
|
117
|
-
it "should raise NoMethodError if a non-method is called" do
|
118
|
-
error = NoMethodError.new("undefined method `closed?' for nil:NilClass")
|
119
|
-
http.should_receive(:request).and_raise(error)
|
120
|
-
lambda {
|
121
|
-
subject.execute client, request_context
|
122
|
-
}.should raise_error(Errno::ECONNREFUSED)
|
123
|
-
end
|
124
|
-
|
125
118
|
end
|
126
119
|
|
127
120
|
describe "basic auth support" do
|
@@ -136,7 +129,7 @@ describe "Koha::Connection" do
|
|
136
129
|
request.fetch('authorization').should == "Basic #{Base64.encode64("joe:pass")}".strip
|
137
130
|
mock(Net::HTTPResponse).as_null_object
|
138
131
|
end
|
139
|
-
Koha::Connection.new.
|
132
|
+
Koha::Connection.new.request :uri => URI.parse("http://joe:pass@localhost/koha/rest.pl"), :method => :get
|
140
133
|
end
|
141
134
|
end
|
142
135
|
|
@@ -145,7 +138,7 @@ describe "Koha::Connection" do
|
|
145
138
|
@mock_proxy = mock('Proxy')
|
146
139
|
@mock_proxy.should_receive(:new).with("localhost", 80).and_return( mock(Net::HTTP).as_null_object)
|
147
140
|
Net::HTTP.should_receive(:Proxy).with("proxy", 80, nil, nil).and_return(@mock_proxy)
|
148
|
-
Koha::Connection.new.
|
141
|
+
Koha::Connection.new.request :uri => URI.parse("http://localhost/koha/rest.pl"), :method => :get, :proxy => URI.parse("http://proxy/pass.pl")
|
149
142
|
end
|
150
143
|
end
|
151
144
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: koha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: simplecov
|
@@ -139,6 +139,9 @@ files:
|
|
139
139
|
- Rakefile
|
140
140
|
- koha.gemspec
|
141
141
|
- lib/koha.rb
|
142
|
+
- lib/koha/api_methods/biblio.rb
|
143
|
+
- lib/koha/api_methods/info.rb
|
144
|
+
- lib/koha/api_methods/user.rb
|
142
145
|
- lib/koha/client.rb
|
143
146
|
- lib/koha/connection.rb
|
144
147
|
- lib/koha/error.rb
|
@@ -164,7 +167,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
164
167
|
version: '0'
|
165
168
|
segments:
|
166
169
|
- 0
|
167
|
-
hash: -
|
170
|
+
hash: -1026450662887779631
|
168
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
172
|
none: false
|
170
173
|
requirements:
|
@@ -173,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
176
|
version: '0'
|
174
177
|
segments:
|
175
178
|
- 0
|
176
|
-
hash: -
|
179
|
+
hash: -1026450662887779631
|
177
180
|
requirements: []
|
178
181
|
rubyforge_project:
|
179
182
|
rubygems_version: 1.8.25
|