alma 0.2.8 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|