koha 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|