alma 0.2.8 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +10 -2
- data/Guardfile +75 -0
- data/README.md +136 -26
- data/alma.gemspec +9 -4
- data/lib/alma.rb +8 -4
- data/lib/alma/api_defaults.rb +30 -0
- data/lib/alma/availability_response.rb +1 -1
- data/lib/alma/bib.rb +4 -22
- data/lib/alma/bib_item.rb +8 -31
- data/lib/alma/bib_item_set.rb +60 -11
- data/lib/alma/bib_set.rb +7 -21
- data/lib/alma/config.rb +7 -3
- data/lib/alma/electronic.rb +167 -0
- data/lib/alma/electronic/README.md +20 -0
- data/lib/alma/electronic/batch_utils.rb +224 -0
- data/lib/alma/electronic/business.rb +29 -0
- data/lib/alma/error.rb +12 -1
- data/lib/alma/fine.rb +15 -0
- data/lib/alma/fine_set.rb +34 -23
- data/lib/alma/item_request_options.rb +22 -0
- data/lib/alma/loan.rb +18 -0
- data/lib/alma/loan_set.rb +59 -17
- data/lib/alma/renewal_response.rb +7 -3
- data/lib/alma/request.rb +165 -0
- data/lib/alma/request_options.rb +31 -18
- data/lib/alma/request_set.rb +62 -17
- data/lib/alma/response.rb +45 -0
- data/lib/alma/result_set.rb +27 -35
- data/lib/alma/user.rb +65 -57
- data/lib/alma/user_request.rb +17 -0
- data/lib/alma/user_set.rb +5 -6
- data/lib/alma/version.rb +1 -1
- data/log/.gitignore +4 -0
- metadata +75 -8
- data/lib/alma/api.rb +0 -33
data/lib/alma/loan_set.rb
CHANGED
@@ -1,34 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Alma
|
2
|
-
class LoanSet
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
class LoanSet < ResultSet
|
5
|
+
class ResponseError < Alma::StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
alias :total_records :total_record_count
|
9
|
+
|
6
10
|
|
7
|
-
attr_reader :
|
8
|
-
def_delegators :
|
11
|
+
attr_reader :results, :raw_response
|
12
|
+
def_delegators :results, :empty?
|
9
13
|
|
10
|
-
def initialize(
|
11
|
-
@
|
14
|
+
def initialize(raw_response, search_args={})
|
15
|
+
@raw_response = raw_response
|
16
|
+
@response = raw_response.parsed_response
|
17
|
+
@search_args = search_args
|
18
|
+
validate(raw_response)
|
19
|
+
@results = @response.fetch(key, [])
|
20
|
+
.map { |item| single_record_class.new(item) }
|
21
|
+
# args passed to the search that returned this set
|
22
|
+
# such as limit, expand, order_by, etc
|
12
23
|
end
|
13
24
|
|
14
|
-
def
|
15
|
-
@
|
25
|
+
def loggable
|
26
|
+
{ search_args: @search_args,
|
27
|
+
uri: @raw_response&.request&.uri.to_s
|
28
|
+
}.select { |k, v| !(v.nil? || v.empty?) }
|
16
29
|
end
|
17
|
-
alias list each
|
18
30
|
|
19
|
-
def
|
20
|
-
|
31
|
+
def validate(response)
|
32
|
+
if response.code != 200
|
33
|
+
error = "Could not find loans info."
|
34
|
+
log = loggable.merge(response.parsed_response)
|
35
|
+
raise ResponseError.new(error, log)
|
36
|
+
end
|
21
37
|
end
|
22
38
|
|
39
|
+
def all
|
40
|
+
Enumerator.new do |yielder|
|
41
|
+
offset = 0
|
42
|
+
loop do
|
43
|
+
extra_args = @search_args.merge({limit: 100, offset: offset})
|
44
|
+
r = (offset == 0) ? self : single_record_class.where_user(user_id, extra_args)
|
45
|
+
unless r.empty?
|
46
|
+
r.map { |item| yielder << item }
|
47
|
+
offset += 100
|
48
|
+
else
|
49
|
+
raise StopIteration
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def each(&block)
|
56
|
+
@results.each(&block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def success?
|
60
|
+
raw_response.response.code.to_s == "200"
|
61
|
+
end
|
23
62
|
|
24
63
|
def key
|
25
|
-
|
64
|
+
"item_loan"
|
26
65
|
end
|
27
66
|
|
28
|
-
def
|
29
|
-
|
67
|
+
def single_record_class
|
68
|
+
Alma::Loan
|
30
69
|
end
|
31
|
-
alias :total_records :total_record_count
|
32
70
|
|
71
|
+
private
|
72
|
+
def user_id
|
73
|
+
@user_id ||= results.first.user_id
|
74
|
+
end
|
33
75
|
end
|
34
76
|
end
|
@@ -1,13 +1,17 @@
|
|
1
1
|
module Alma
|
2
2
|
class RenewalResponse
|
3
3
|
|
4
|
-
|
5
|
-
|
6
4
|
def initialize(response)
|
7
|
-
@
|
5
|
+
@raw_response = response
|
6
|
+
@response = response.parsed_response
|
8
7
|
@success = response.has_key?('loan_id')
|
9
8
|
end
|
10
9
|
|
10
|
+
def loggable
|
11
|
+
{ uri: @raw_response&.request&.uri.to_s
|
12
|
+
}.select { |k, v| !(v.nil? || v.empty?) }
|
13
|
+
end
|
14
|
+
|
11
15
|
def renewed?
|
12
16
|
@success
|
13
17
|
end
|
data/lib/alma/request.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
module Alma
|
2
|
+
class BibRequest
|
3
|
+
class ItemAlreadyExists < Alma::StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
extend Alma::ApiDefaults
|
7
|
+
|
8
|
+
REQUEST_TYPES = %w[HOLD DIGITIZATION BOOKING]
|
9
|
+
|
10
|
+
def self.submit(args)
|
11
|
+
request = new(args)
|
12
|
+
response = HTTParty.post(
|
13
|
+
"#{bibs_base_path}/#{request.mms_id}/requests",
|
14
|
+
query: {user_id: request.user_id},
|
15
|
+
headers: headers,
|
16
|
+
body: request.body.to_json
|
17
|
+
)
|
18
|
+
Alma::Response.new(response)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :mms_id, :user_id, :body, :request_type
|
22
|
+
def initialize(args)
|
23
|
+
@mms_id = args.delete(:mms_id) { raise ArgumentError.new(":mms_id option must be specified to create request") }
|
24
|
+
@user_id = args.delete(:user_id) { raise ArgumentError.new(":user_id option must be specified to create request") }
|
25
|
+
@request_type = args.fetch(:request_type, "NOT_SPECIFIED")
|
26
|
+
validate!(args)
|
27
|
+
normalize!(args)
|
28
|
+
@body = args
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def normalize!(args)
|
33
|
+
request_type_normalization!(args)
|
34
|
+
additional_normalization!(args)
|
35
|
+
end
|
36
|
+
|
37
|
+
def request_type_normalization!(args)
|
38
|
+
method = "#{@request_type.downcase}_normalization".to_sym
|
39
|
+
send(method, args) if respond_to? method
|
40
|
+
end
|
41
|
+
|
42
|
+
# Intended to be overridden by subclasses, allowing extra normalization logic to be provided
|
43
|
+
def additional_normalization!(args)
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate!(args)
|
47
|
+
unless REQUEST_TYPES.include?(request_type)
|
48
|
+
raise ArgumentError.new(":request_type option must be specified and one of #{REQUEST_TYPES.join(", ")} to submit a request")
|
49
|
+
end
|
50
|
+
request_type_validation!(args)
|
51
|
+
additional_validation!(args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def request_type_validation!(args)
|
55
|
+
method = "#{@request_type.downcase}_validation".to_sym
|
56
|
+
send(method, args) if respond_to? method
|
57
|
+
end
|
58
|
+
|
59
|
+
# Intended to be overridden by subclasses, allowing extra validation logic to be provided
|
60
|
+
def additional_validation!(args)
|
61
|
+
end
|
62
|
+
|
63
|
+
def digitization_normalization(args)
|
64
|
+
if args[:target_destination].is_a? String
|
65
|
+
args[:target_destination] = { value: args[:target_destination] }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def digitization_validation(args)
|
70
|
+
args.fetch(:target_destination) do
|
71
|
+
raise ArgumentError.new(
|
72
|
+
":target_destination option must be specified when request_type is DIGITIZATION"
|
73
|
+
)
|
74
|
+
end
|
75
|
+
pd = args.fetch(:partial_digitization) do
|
76
|
+
raise ArgumentError.new(
|
77
|
+
":partial_digitization option must be specified when request_type is DIGITIZATION"
|
78
|
+
)
|
79
|
+
end
|
80
|
+
if pd == true
|
81
|
+
args.fetch(:comment) do
|
82
|
+
raise ArgumentError.new(
|
83
|
+
":comment option must be specified when :request_type is DIGITIZATION and :partial_digitization is true"
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def booking_normalization(args)
|
90
|
+
if args[:material_type].is_a? String
|
91
|
+
args[:material_type] = { value: args[:material_type] }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def booking_validation(args)
|
96
|
+
args.fetch(:booking_start_date) do
|
97
|
+
raise ArgumentError.new(
|
98
|
+
":booking_start_date option must be specified when request_type is BOOKING"
|
99
|
+
)
|
100
|
+
end
|
101
|
+
args.fetch(:booking_end_date) do
|
102
|
+
raise ArgumentError.new(
|
103
|
+
":booking_end_date option must be specified when request_type is BOOKING"
|
104
|
+
)
|
105
|
+
end
|
106
|
+
args.fetch(:pickup_location_type) do
|
107
|
+
raise ArgumentError.new(
|
108
|
+
":pickup_location_type option must be specified when request_type is BOOKING"
|
109
|
+
)
|
110
|
+
end
|
111
|
+
args.fetch(:pickup_location_library) do
|
112
|
+
raise ArgumentError.new(
|
113
|
+
":pickup_location_library option must be specified when request_type is BOOKING"
|
114
|
+
)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def hold_normalization(args)
|
119
|
+
# if args[:material_type].is_a? String
|
120
|
+
# args[:material_type] = { value: args[:material_type] }
|
121
|
+
# end
|
122
|
+
end
|
123
|
+
|
124
|
+
def hold_validation(args)
|
125
|
+
args.fetch(:pickup_location_type) do
|
126
|
+
raise ArgumentError.new(
|
127
|
+
":pickup_location_type option must be specified when request_type is HOLD"
|
128
|
+
)
|
129
|
+
end
|
130
|
+
args.fetch(:pickup_location_library) do
|
131
|
+
raise ArgumentError.new(
|
132
|
+
":pickup_location_library option must be specified when request_type is HOLD"
|
133
|
+
)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class ItemRequest < BibRequest
|
139
|
+
def self.submit(args)
|
140
|
+
request = new(args)
|
141
|
+
response = HTTParty.post(
|
142
|
+
"#{bibs_base_path}/#{request.mms_id}/holdings/#{request.holding_id}/items/#{request.item_pid}/requests",
|
143
|
+
query: {user_id: request.user_id},
|
144
|
+
headers: headers,
|
145
|
+
body: request.body.to_json
|
146
|
+
)
|
147
|
+
Alma::Response.new(response)
|
148
|
+
end
|
149
|
+
|
150
|
+
attr_reader :holding_id, :item_pid
|
151
|
+
def initialize(args)
|
152
|
+
super(args)
|
153
|
+
@holding_id = args.delete(:holding_id) { raise ArgumentError.new(":holding_id option must be specified to create request") }
|
154
|
+
@item_pid = args.delete(:item_pid) { raise ArgumentError.new(":item_pid option must be specified to create request") }
|
155
|
+
end
|
156
|
+
|
157
|
+
def additional_validation!(args)
|
158
|
+
args.fetch(:description) do
|
159
|
+
raise ArgumentError.new(
|
160
|
+
":description option must be specified when request_type is DIGITIZATION"
|
161
|
+
)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
data/lib/alma/request_options.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Alma
|
2
2
|
class RequestOptions
|
3
|
+
class ResponseError < Alma::StandardError
|
4
|
+
end
|
5
|
+
|
3
6
|
extend Forwardable
|
7
|
+
extend Alma::ApiDefaults
|
4
8
|
|
5
9
|
attr_accessor :request_options, :raw_response
|
6
10
|
def_delegators :raw_response, :response, :request
|
@@ -9,43 +13,52 @@ module Alma
|
|
9
13
|
|
10
14
|
def initialize(response)
|
11
15
|
@raw_response = response
|
12
|
-
|
16
|
+
validate(response)
|
17
|
+
@request_options = response.parsed_response["request_option"]
|
13
18
|
end
|
14
19
|
|
20
|
+
|
15
21
|
def self.get(mms_id, options={})
|
16
22
|
url = "#{bibs_base_path}/#{mms_id}/request-options"
|
17
23
|
options.select! {|k,_| REQUEST_OPTIONS_PERMITTED_ARGS.include? k }
|
18
|
-
response = HTTParty.get(url, headers: headers, query: options)
|
24
|
+
response = HTTParty.get(url, headers: headers, query: options, timeout: timeout)
|
19
25
|
new(response)
|
20
26
|
end
|
21
27
|
|
22
|
-
def
|
23
|
-
|
28
|
+
def loggable
|
29
|
+
{ uri: @raw_response&.request&.uri.to_s
|
30
|
+
}.select { |k, v| !(v.nil? || v.empty?) }
|
24
31
|
end
|
25
32
|
|
26
|
-
def
|
27
|
-
|
33
|
+
def validate(response)
|
34
|
+
if response.code != 200
|
35
|
+
raise ResponseError.new("Could not get request options.", loggable.merge(response.parsed_response))
|
36
|
+
end
|
28
37
|
end
|
29
38
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
Alma.configuration.region
|
39
|
+
def hold_allowed?
|
40
|
+
!request_options.nil? &&
|
41
|
+
!request_options.select {|option| option["type"]["value"] == "HOLD" }.empty?
|
34
42
|
end
|
35
43
|
|
36
|
-
def
|
37
|
-
|
44
|
+
def digitization_allowed?
|
45
|
+
!request_options.nil? &&
|
46
|
+
!request_options.select {|option| option["type"]["value"] == "DIGITIZATION" }.empty?
|
38
47
|
end
|
39
48
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
"Content-Type": "application/json" }
|
49
|
+
def booking_allowed?
|
50
|
+
!request_options.nil? &&
|
51
|
+
!request_options.select {|option| option["type"]["value"] == "BOOKING" }.empty?
|
44
52
|
end
|
45
53
|
|
46
|
-
def
|
47
|
-
|
54
|
+
def resource_sharing_broker_allowed?
|
55
|
+
!request_options.nil? &&
|
56
|
+
!request_options.select {|option| option["type"]["value"] == "RS_BROKER" }.empty?
|
48
57
|
end
|
49
58
|
|
59
|
+
def ez_borrow_link
|
60
|
+
broker = request_options.select {|option| option["type"]["value"] == "RS_BROKER" }
|
61
|
+
broker.collect { |opt| opt["request_url"] }.first
|
62
|
+
end
|
50
63
|
end
|
51
64
|
end
|
data/lib/alma/request_set.rb
CHANGED
@@ -1,33 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Alma
|
2
|
-
class RequestSet
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
class RequestSet < ResultSet
|
5
|
+
class ResponseError < Alma::StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
alias :total_records :total_record_count
|
6
9
|
|
7
|
-
attr_reader :
|
8
|
-
def_delegators :
|
10
|
+
attr_reader :results, :raw_response
|
11
|
+
def_delegators :results, :empty?
|
9
12
|
|
10
|
-
def initialize(
|
11
|
-
@
|
13
|
+
def initialize(raw_response)
|
14
|
+
@raw_response = raw_response
|
15
|
+
@response = raw_response.parsed_response
|
16
|
+
validate(raw_response)
|
17
|
+
@results = @response.fetch(key, [])
|
18
|
+
.map { |item| single_record_class.new(item) }
|
12
19
|
end
|
13
20
|
|
14
|
-
def
|
15
|
-
|
21
|
+
def loggable
|
22
|
+
{ uri: @raw_response&.request&.uri.to_s
|
23
|
+
}.select { |k, v| !(v.nil? || v.empty?) }
|
16
24
|
end
|
17
|
-
alias list each
|
18
25
|
|
19
|
-
def
|
20
|
-
|
26
|
+
def validate(response)
|
27
|
+
if response.code != 200
|
28
|
+
error = "Could not find requests."
|
29
|
+
log = loggable.merge(response.parsed_response)
|
30
|
+
raise ResponseError.new(error, log)
|
31
|
+
end
|
21
32
|
end
|
22
33
|
|
23
|
-
def
|
24
|
-
|
34
|
+
def all
|
35
|
+
Enumerator.new do |yielder|
|
36
|
+
offset = 0
|
37
|
+
loop do
|
38
|
+
r = (offset == 0) ? self : single_record_class.where_user(user_id, {limit: 100, offset: offset})
|
39
|
+
unless r.empty?
|
40
|
+
r.map { |item| yielder << item }
|
41
|
+
offset += 100
|
42
|
+
else
|
43
|
+
raise StopIteration
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def each(&block)
|
50
|
+
@results.each(&block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def success?
|
54
|
+
raw_response.response.code.to_s == "200"
|
25
55
|
end
|
26
|
-
alias :total_records :total_record_count
|
27
56
|
|
28
57
|
def key
|
29
|
-
|
58
|
+
"user_request"
|
30
59
|
end
|
31
60
|
|
61
|
+
def single_record_class
|
62
|
+
Alma::UserRequest
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def user_id
|
67
|
+
@user_id ||= get_user_id_from_path(raw_response.request.uri.path)
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_user_id_from_path(path)
|
71
|
+
# Path in user api calls starts with "/almaws/v1/users/123/maybe_something/else"
|
72
|
+
split_path = path.split("/")
|
73
|
+
# the part immediately following the "users" is going to be the user_id
|
74
|
+
user_id_index = split_path.index("users") + 1
|
75
|
+
split_path[user_id_index]
|
76
|
+
end
|
32
77
|
end
|
33
78
|
end
|