exlibris-aleph 0.1.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/README.md +89 -0
  2. data/Rakefile +2 -4
  3. data/lib/exlibris-aleph.rb +8 -21
  4. data/lib/exlibris/aleph.rb +13 -0
  5. data/lib/exlibris/aleph/abstract.rb +28 -0
  6. data/lib/exlibris/aleph/config.rb +78 -0
  7. data/lib/exlibris/aleph/patron.rb +71 -56
  8. data/lib/exlibris/aleph/record.rb +34 -40
  9. data/lib/exlibris/aleph/rest/base.rb +56 -0
  10. data/lib/exlibris/aleph/tab_helper.rb +84 -99
  11. data/lib/exlibris/aleph/{config/config_base.rb → tabs_parser/base.rb} +2 -2
  12. data/lib/exlibris/aleph/{config → tabs_parser}/pc_tab_exp_field_extended.rb +2 -2
  13. data/lib/exlibris/aleph/{config/config_by_sub_library.rb → tabs_parser/sub_library.rb} +2 -2
  14. data/lib/exlibris/aleph/{config → tabs_parser}/tab15_by_item_process_status.rb +2 -2
  15. data/lib/exlibris/aleph/{config → tabs_parser}/tab15_by_item_status.rb +2 -2
  16. data/lib/exlibris/aleph/{config → tabs_parser}/tab31.rb +2 -2
  17. data/lib/exlibris/aleph/{config → tabs_parser}/tab37.rb +2 -2
  18. data/lib/exlibris/aleph/{config → tabs_parser}/tab40.rb +2 -2
  19. data/lib/exlibris/aleph/{config → tabs_parser}/tab_sub_library.rb +2 -2
  20. data/lib/exlibris/aleph/{config → tabs_parser}/tab_www_item_desc.rb +2 -2
  21. data/lib/exlibris/aleph/task_installer.rb +23 -0
  22. data/lib/exlibris/aleph/version.rb +1 -1
  23. data/lib/exlibris/aleph/write_attributes.rb +38 -0
  24. data/lib/exlibris/aleph/xml_util.rb +50 -0
  25. data/lib/exlibris/aleph/xservice/bor_auth.rb +47 -0
  26. data/lib/tasks/exlibris-aleph_tasks.rake +1 -8
  27. data/test/{dummy/config → config}/aleph/alephe/sub_libraries.yml +0 -1
  28. data/test/{dummy/config → config}/aleph/nyu50/collections.yml +0 -1
  29. data/test/{dummy/config → config}/aleph/nyu50/item_permissions_by_item_process_status.yml +0 -1
  30. data/test/{dummy/config → config}/aleph/nyu50/item_permissions_by_item_status.yml +104 -105
  31. data/test/{dummy/config → config}/aleph/nyu50/items.yml +0 -1
  32. data/test/{dummy/config → config}/aleph/nyu50/patron_permissions.yml +27 -28
  33. data/test/{dummy/config → config}/aleph/nyu50/patrons.yml +0 -1
  34. data/test/{dummy/config → config}/aleph/nyu50/pickup_locations.yml +0 -1
  35. data/test/{dummy/config → config}/aleph/nyu51/collections.yml +0 -1
  36. data/test/{dummy/config → config}/aleph/nyu51/item_permissions_by_item_process_status.yml +0 -1
  37. data/test/{dummy/config → config}/aleph/nyu51/item_permissions_by_item_status.yml +6 -7
  38. data/test/{dummy/config → config}/aleph/nyu51/items.yml +0 -1
  39. data/test/{dummy/config → config}/aleph/nyu51/patron_permissions.yml +27 -28
  40. data/test/{dummy/config → config}/aleph/nyu51/patrons.yml +0 -1
  41. data/test/{dummy/config → config}/aleph/nyu51/pickup_locations.yml +0 -1
  42. data/test/config_test.rb +24 -0
  43. data/test/patron_test.rb +98 -0
  44. data/test/{unit/record_benchmarks.rb → record_benchmarks.rb} +0 -0
  45. data/test/record_test.rb +64 -0
  46. data/test/support/config.yml +2 -0
  47. data/test/{unit/tab_helper_benchmarks.rb → tab_helper_benchmarks.rb} +5 -20
  48. data/test/tab_helper_test.rb +178 -0
  49. data/test/test_helper.rb +26 -22
  50. data/test/vcr_cassettes/bor_auth.yml +8 -10
  51. data/test/vcr_cassettes/patron.yml +77 -18
  52. data/test/vcr_cassettes/patron_address.yml +45 -0
  53. data/test/vcr_cassettes/patron_bogus_url.yml +731 -0
  54. data/test/vcr_cassettes/patron_error.yml +93 -0
  55. data/test/vcr_cassettes/record.yml +18 -17
  56. data/test/vcr_cassettes/record_bogus_url.yml +690 -0
  57. data/test/{unit → xservice}/bor_auth_test.rb +4 -4
  58. metadata +160 -150
  59. data/README.rdoc +0 -67
  60. data/lib/exlibris/aleph/bor_auth.rb +0 -45
  61. data/lib/exlibris/aleph/railtie.rb +0 -9
  62. data/lib/exlibris/aleph/rest.rb +0 -43
  63. data/lib/exlibris/aleph/tasks.rb +0 -25
  64. data/test/dummy/README.rdoc +0 -261
  65. data/test/dummy/Rakefile +0 -7
  66. data/test/dummy/app/assets/javascripts/application.js +0 -15
  67. data/test/dummy/app/assets/stylesheets/application.css +0 -13
  68. data/test/dummy/app/controllers/application_controller.rb +0 -3
  69. data/test/dummy/app/helpers/application_helper.rb +0 -2
  70. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  71. data/test/dummy/config.ru +0 -4
  72. data/test/dummy/config/application.rb +0 -56
  73. data/test/dummy/config/boot.rb +0 -10
  74. data/test/dummy/config/database.yml +0 -25
  75. data/test/dummy/config/environment.rb +0 -5
  76. data/test/dummy/config/environments/development.rb +0 -37
  77. data/test/dummy/config/environments/production.rb +0 -67
  78. data/test/dummy/config/environments/test.rb +0 -37
  79. data/test/dummy/config/initializers/aleph.rb +0 -1
  80. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  81. data/test/dummy/config/initializers/inflections.rb +0 -15
  82. data/test/dummy/config/initializers/mime_types.rb +0 -5
  83. data/test/dummy/config/initializers/secret_token.rb +0 -7
  84. data/test/dummy/config/initializers/session_store.rb +0 -8
  85. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  86. data/test/dummy/config/locales/en.yml +0 -5
  87. data/test/dummy/config/routes.rb +0 -58
  88. data/test/dummy/db/README +0 -0
  89. data/test/dummy/db/test.sqlite3 +0 -0
  90. data/test/dummy/log/aleph/aleph_tab_helper.log +0 -1
  91. data/test/dummy/log/aleph/tab_helper.log +0 -109
  92. data/test/dummy/log/tab_helper.log +0 -16
  93. data/test/dummy/log/test.log +0 -5160
  94. data/test/dummy/public/404.html +0 -26
  95. data/test/dummy/public/422.html +0 -26
  96. data/test/dummy/public/500.html +0 -25
  97. data/test/dummy/public/favicon.ico +0 -0
  98. data/test/dummy/script/rails +0 -6
  99. data/test/unit/patron_test.rb +0 -41
  100. data/test/unit/record_test.rb +0 -32
  101. data/test/unit/tab_helper_test.rb +0 -222
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Exlibris::Aleph
2
+ [![Gem Version](https://badge.fury.io/rb/exlibris-aleph.png)](http://badge.fury.io/rb/exlibris-aleph)
3
+ [![Build Status](https://api.travis-ci.org/scotdalton/exlibris-aleph.png?branch=master)](https://travis-ci.org/scotdalton/exlibris-aleph)
4
+ [![Dependency Status](https://gemnasium.com/scotdalton/exlibris-aleph.png)](https://gemnasium.com/scotdalton/exlibris-aleph)
5
+ [![Code Climate](https://codeclimate.com/github/scotdalton/exlibris-aleph.png)](https://codeclimate.com/github/scotdalton/exlibris-aleph)
6
+ [![Coverage Status](https://coveralls.io/repos/scotdalton/exlibris-aleph/badge.png?branch=master)](https://coveralls.io/r/scotdalton/exlibris-aleph)
7
+
8
+ Exlibris::Aleph offers a set of libraries for interacting with the ExLibris Aleph ILS.
9
+
10
+ ## Exlibris::Aleph::Patron
11
+ Exlibris::Aleph::Patron provides access to the Aleph Patron REST API.
12
+
13
+ ### Example of Exlibris::Aleph::Patron in action
14
+ patron =
15
+ Exlibris::Aleph::Patron.
16
+ new(patron_id: "S0M31D", rest_url: "http://aleph.institution.edu")
17
+ patron.address # Returns a Hash of the of patron's address
18
+ patron.loans # Returns an Array of institution Hashes, each containing an Array of the patron's loans for that institution
19
+ patron.renew_loans # Renews all loans
20
+ patron.renew_loans("ADM5000000001") # Renews loan of item 00000001 in ADM50
21
+ patron.place_hold("ADM50", "SBLIB", "00000001", "00000001", {:pickup_location => "SBLIB"}) # Places hold on the specified item for pickup at SBLIB
22
+
23
+ ## Exlibris::Aleph::Record
24
+ Provides access to the Aleph Record REST API.
25
+
26
+ ### Example of Exlibris::Aleph::Record in action
27
+ record =
28
+ Exlibris::Aleph::Record.
29
+ new(bib_library: "ADM50", record_id: "00000001", rest_url: "http://aleph.institution.edu")
30
+ record.bib # Returns a MARC::Record with bibliographic metadata
31
+ record.holdings # Returns and Array of MARC::Records respresenting the record's holdings
32
+ record.items # Returns and Array of Hashes representing the record's items
33
+
34
+ ## Exlibris::Aleph.configure
35
+ Exlibris::Aleph can be configured at startup in an initializer.
36
+
37
+ # Placed this in an initializer.
38
+ Exlibris::Aleph.configure { |c|
39
+ c.base_url = "http://aleph.institution.edu"
40
+ c.tab_path = "/mnt/aleph_tab"
41
+ c.adms = ["ADM50", "ADM51"]
42
+ }
43
+
44
+ It can also read from a yaml file.
45
+
46
+ # Placed this in an initializer.
47
+ Exlibris::Aleph.configure { |c|
48
+ config.load_yaml File.expand_path("#{File.dirname(__FILE__)}/../config/aleph.yml", __FILE__)
49
+ }
50
+
51
+ ## Exlibris::Aleph::TabHelper
52
+ Exlibris::Aleph::TabHelper provides a way to access the various tab settings for patrons, patron\_permissions, items, item_permission (both by item status and by item processing status), collections and pickup locations. It also provides convenience methods for common tasks like getting the pickup location for a given combination of item status, item process status and borrower status or getting an item's web text. Support a
53
+
54
+ ### Example of Exlibris::Aleph::TabHelper in action
55
+ # Placed this in an initializer.
56
+ Exlibris::Aleph.configure { |c|
57
+ c.tab_path = "/mnt/aleph_tab"
58
+ c.adms = ["ADM50", "ADM51"]
59
+ }
60
+
61
+ # Rake task to refresh the config yml files
62
+ rake exlibris:aleph:refresh
63
+
64
+ # Get an instance of TabHelper
65
+ helper = Exlibris::Aleph::TabHelper.instance
66
+ helper.sub_library_text("SBLIB") # Returns display text for the give code
67
+ helper.sub_library_adm("SBLIB") # Returns ADM for the give code
68
+ helper.item_pickup_locations({:adm_library_code => "ADM50", :sub_library_code => "SBLIB", :bor_status => "51"}) # Returns the pickup locations for the given parameters
69
+ helper.collection_text({:adm_library_code => "ADM50", :sub_library_code => "SBLIB", :collection_code => "MAIN"}) # Returns the collection display text for the give parameters
70
+ helper.item_web_text({:adm_library_code => "ADM50", :item_process_status => "Item Process Status"}) # Returns the web text for the given parameters
71
+ helper.item_web_text({:adm_library_code => "ADM50", :sub_library_code => "SBLIB", :item_process_status_code => "DP"}) # Returns the web text for the given parameters
72
+
73
+ ### Configure irrelevant sub libraries for TabHelper
74
+ To configure the gem to ignore sub libraries pulled from Aleph but not relevant to working with permissions call the following setter with an array of sub library Aleph codes.
75
+
76
+ # Place this in an initializer to replace the current irrelevant sub libraries.
77
+ Exlibris::Aleph.configure { |c|
78
+ c.irrelevant_sub_libraries = ["IRRLIB1", "IRRLIB2"]
79
+ }
80
+
81
+ ## Exlibris::Aleph::BorAuth
82
+ Exlibris::Aleph::BorAuth provides access to the BorAuth Aleph XService.
83
+
84
+ ### Example of Exlibris::Aleph::BorAuth in action
85
+ bor_auth =
86
+ Exlibris::Aleph::BorAuth.
87
+ new("http://aleph.institution.edu", "ADM50", "SBLIB", "N", "S0M31D", "V3R1F1C@T10N")
88
+ permissions = bor_auth.permissions # Return a Hash of permissions based on the Exlibris::Aleph::BorAuth instance
89
+
data/Rakefile CHANGED
@@ -20,9 +20,6 @@ RDoc::Task.new(:rdoc) do |rdoc|
20
20
  rdoc.rdoc_files.include('lib/**/*.rb')
21
21
  end
22
22
 
23
-
24
-
25
-
26
23
  Bundler::GemHelper.install_tasks
27
24
 
28
25
  require 'rake/testtask'
@@ -34,5 +31,6 @@ Rake::TestTask.new(:test) do |t|
34
31
  t.verbose = false
35
32
  end
36
33
 
37
-
38
34
  task :default => :test
35
+
36
+ require 'exlibris-aleph'
@@ -1,21 +1,8 @@
1
- PATH = File.dirname(__FILE__) + "/exlibris/aleph/"
2
- [
3
- 'config/config_base',
4
- 'config/config_by_sub_library',
5
- 'config/pc_tab_exp_field_extended',
6
- 'config/tab15_by_item_process_status',
7
- 'config/tab15_by_item_status',
8
- 'config/tab31',
9
- 'config/tab37',
10
- 'config/tab40',
11
- 'config/tab_sub_library',
12
- 'config/tab_www_item_desc',
13
- 'tab_helper',
14
- 'rest',
15
- 'record',
16
- 'patron',
17
- 'bor_auth'
18
- ].each do |library|
19
- require PATH + library
20
- end
21
- require PATH + 'railtie' if defined?(Rails)
1
+ # Leverage ActiveSupport core extensions
2
+ require 'active_support/core_ext'
3
+ require 'active_support/builder'
4
+ require 'marc'
5
+ require "require_all"
6
+ require_all "#{File.dirname(__FILE__)}/exlibris/"
7
+ # Install tasks
8
+ Exlibris::Aleph::TaskInstaller.install_tasks
@@ -0,0 +1,13 @@
1
+ module Exlibris
2
+ module Aleph
3
+ class << self
4
+ def configure
5
+ yield config
6
+ end
7
+
8
+ def config
9
+ @config ||= Config
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module Exlibris
2
+ module Aleph
3
+ #
4
+ # If a class is abstract, it can't be instantiated.
5
+ #
6
+ module Abstract
7
+ def self.included(klass)
8
+ klass.class_eval do
9
+ extend ClassAttributes
10
+ end
11
+ end
12
+
13
+ module ClassAttributes
14
+ def abstract
15
+ @abstract ||= false
16
+ end
17
+ alias :abstract? :abstract
18
+
19
+ attr_writer :abstract
20
+ protected :abstract=
21
+ end
22
+
23
+ def initialize *args
24
+ raise NotImplementedError.new("Cannot instantiate #{self.class.name}. It is abstract") if self.class.abstract?
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,78 @@
1
+ module Exlibris
2
+ module Aleph
3
+
4
+ #
5
+ # Specify global configuration settings for
6
+ #
7
+ module Config
8
+ class << self
9
+ include WriteAttributes
10
+ attr_accessor :base_url, :rest_url, :adms, :refresh_time, :tab_path,
11
+ :yml_path, :logger, :irrelevant_sub_libraries, :load_time
12
+
13
+ def load_yaml file
14
+ write_attributes YAML.load_file(file)
15
+ self.load_time = Time.now
16
+ end
17
+ end
18
+
19
+ #
20
+ # These attributes default to the global config settings if not
21
+ # specified locally.
22
+ #
23
+ module Attributes
24
+ def config
25
+ @config ||= Config
26
+ end
27
+
28
+ # Aleph base url
29
+ def base_url
30
+ @base_url ||= String.new config.base_url.to_s
31
+ end
32
+
33
+ # Aleph rest url
34
+ def rest_url
35
+ @rest_url ||= (config.rest_url) ? String.new(config.rest_url.to_s) : "#{base_url}:1891/rest-dlf"
36
+ end
37
+
38
+ # Refresh time for TabHelper
39
+ def refresh_time
40
+ @refresh_time ||= (config.refresh_time) ? config.refresh_time : lambda{1.day.ago}
41
+ end
42
+
43
+ # Aleph ADMs to parse
44
+ def adms
45
+ @adms ||= (config.adms) ? config.adms.collect{|adm| adm.downcase} : []
46
+ end
47
+
48
+ # Tab path for Aleph tables
49
+ def tab_path
50
+ @tab_path ||= File.join(config.tab_path)
51
+ end
52
+
53
+ # YAML path for persisting Aleph config
54
+ def yml_path
55
+ @yml_path ||= (File.join(config.yml_path) || File.join(tab_path, "..", "config", "aleph"))
56
+ end
57
+
58
+ def logger
59
+ @logger ||= (config.logger) ? config.logger : Logger.new(File.join(yml_path, "..", "..", "log", "exlibris_aleph.log"))
60
+ end
61
+
62
+ def irrelevant_sub_libraries
63
+ @irrelevant_sub_libraries ||=
64
+ (config.irrelevant_sub_libraries) ? config.irrelevant_sub_libraries :
65
+ [ "USR00", "HOME", "BOX", "ILLDT", "NYU51", "ALEPH", "USM50",
66
+ "MED", "HYL", "HIL", "LAM", "LAW", "LIT", "MUS", "WID", "EXL", "CIRC", "HILR", "HIL01",
67
+ "HYL01", "HYL02", "HYL03", "HYL04", "HYL05", "HYL06", "LAM01", "LAM02", "LAM03", "LAW01",
68
+ "LAW02", "LAW03", "LIT01", "LIT02", "MED01", "MED02", "MUS01", "MUS02", "WID01", "WID02",
69
+ "WID03", "WID04", "WID05", "U60WD", "U60HL", "U60LA", "U70WD", "CBAB", "BCU", "MBAZU", "USM51",
70
+ "ELEC5", "GDOC5", "EDUC5", "LINC5", "RRLIN", "OU511", "OR512", "OR513", "OR514", "OR515", "U61ED",
71
+ "U61EL", "U61LN", "S61GD", "USM53", "ELEC7", "GDOC7", "EDUC7", "LINC7", "USM54", "ELEC4", "USM55",
72
+ "CUN50", "CLEC5", "CDOC5", "CDUC5", "CINC5", "UNI50", "NARCV", "NELEC", "NRLEC", "NGDOC", "NRDOC",
73
+ "NEDUC", "NHLTH", "NLINC", "NLAW", "NMUSI", "NSCI", "NUPTN" ]
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -2,84 +2,99 @@ module Exlibris
2
2
  module Aleph
3
3
  # ==Overview
4
4
  # Provides access to the Aleph Patron REST API.
5
- class Patron < Rest
6
- attr_reader :patron_id
7
-
8
- # Creates an instance of Exlibris::Aleph::Patron for the given :patron_id
9
- def initialize(patron_id, uri)
10
- @patron_id = patron_id
11
- raise "Initialization error in #{self.class}. Missing patron id." if @patron_id.nil?
12
- super(uri)
13
- @uri = @uri+ "/patron/#{patron_id}"
14
- end
5
+ class Patron < Rest::Base
6
+ attr_accessor :patron_id
15
7
 
16
8
  # Place a hold on the specificed item.
17
- # Raises an error if there was a problem placing the hold.
18
- # Returns a HTTParty::Response.
9
+ # Returns a Hash, including the "note" returned from the underlying API.
10
+ # Raises an exception if the response is not valid XML or there are errors.
19
11
  def place_hold(adm_library, bib_library, bib_id, item_id, params)
20
- pickup_location = params[:pickup_location]
21
- raise "Error in place hold. Missing pickup location." if pickup_location.nil?
22
- last_interest_date = params.fetch(:last_interest_date, "")
23
- start_interest_date = params.fetch(:start_interest_date, "")
24
- sub_author = params.fetch(:sub_author, "")
25
- sub_title = params.fetch(:sub_title, "")
26
- pages = params.fetch(:pages, "")
27
- note_1 = params.fetch(:note_1, "")
28
- note_2 = params.fetch(:note_2, "")
29
- rush = params.fetch(:rush, "N")
30
- body_str = "<hold-request-parameters>"
31
- body_str << "<pickup-location>#{pickup_location}</pickup-location>"
32
- body_str << "<last-interest-date>#{last_interest_date}</last-interest-date>"
33
- body_str << "<start-interest-date>#{start_interest_date}</start-interest-date>"
34
- body_str << "<sub-author>#{sub_author}</sub-author>"
35
- body_str << "<sub-title>#{sub_title}</sub-title>"
36
- body_str << "<pages>#{pages}</pages>"
37
- body_str << "<note-1>#{note_1}</note-1>"
38
- body_str << "<note-2>#{note_2}</note-2>"
39
- body_str << "<rush>#{rush}</rush>"
40
- body_str << "</hold-request-parameters>"
41
- options = { :body => "post_xml=#{body_str}"}
42
- @response = self.class.put(@uri+ "/record/#{bib_library}#{bib_id}/items/#{item_id}/hold", options)
43
- raise "Error placing hold through Aleph REST APIs. #{error}" unless error.nil?
44
- return @response
12
+ options = { :body => "post_xml=#{place_hold_xml(params)}"}
13
+ self.response = self.class.put("#{patron_url}/record/#{bib_library}#{bib_id}/items/#{item_id}/hold", options)
14
+ raise_error_if("Error placing hold through Aleph REST APIs. #{error}") {
15
+ (response.parsed_response["put_item_hold"].nil? or response.parsed_response["put_item_hold"]["create_hold"].nil?)
16
+ }
17
+ response.parsed_response["put_item_hold"]["create_hold"]
45
18
  end
46
19
 
47
- # Call the patronInformation/address Aleph Patron REST API
48
- # Returns a HTTParty::Response.
49
- def address()
50
- @response = self.class.get(@uri+ "/patronInformation/address")
51
- return "Error getting patron's address through Aleph REST APIs. #{error}" unless error.nil?
52
- return @response
20
+ # Returns a Hash representing the patron's address information.
21
+ # Every method call refreshes the data from the underlying API.
22
+ # Raises an exception if the response is not valid XML or there are errors.
23
+ def address
24
+ self.response = self.class.get("#{patron_url}/patronInformation/address")
25
+ raise_error_if("Error getting patron address through Aleph REST APIs.") {
26
+ (response.parsed_response["get_pat_adrs"].nil? or response.parsed_response["get_pat_adrs"]["address_information"].nil?)
27
+ }
28
+ response.parsed_response["get_pat_adrs"]["address_information"]
53
29
  end
54
30
 
55
- # Call the circulationActions/loans Aleph Patron REST API
56
- # Returns a HTTParty::Response.
57
- def loans()
58
- @response = self.class.get(@uri+ "/circulationActions/loans?view=full")
59
- raise "Error getting loans through Aleph REST APIs. #{error}" unless error.nil?
60
- return @response
31
+ # Returns an Array of institutions.
32
+ # Each institution is a Hash containing an array of loans for that institution.
33
+ # Every method call refreshes the data from the underlying API.
34
+ # Raises an exception if the response is not valid XML or there are errors.
35
+ def loans
36
+ self.response = self.class.get("#{patron_url}/circulationActions/loans?view=full")
37
+ raise_error_if("Error getting loans through Aleph REST APIs.") {
38
+ (response.parsed_response["pat_loan_list"].nil? or response.parsed_response["pat_loan_list"]["loans"].nil?)
39
+ }
40
+ [response.parsed_response["pat_loan_list"]["loans"]["institution"]].flatten
61
41
  end
62
42
 
63
43
  # Renew the specified item.
64
44
  # Will renew all if item not specified.
65
- # Returns a HTTParty::Response.
45
+ # Returns an Array of institutions.
46
+ # Each institution is a Hash containing an array of loan renewals for that institution.
47
+ # Raises an exception if the response is not valid XML or there are errors.
66
48
  def renew_loans(item_id="")
67
- @response = self.class.post(@uri+ "/circulationActions/loans/#{item_id}")
68
- raise "Error renewing loan(s) through Aleph REST APIs. #{error}" unless error.nil?
69
- return @response
49
+ self.response = self.class.post("#{patron_url}/circulationActions/loans/#{item_id}")
50
+ raise_error_if("Error renewing loans through Aleph REST APIs.") {
51
+ (response.parsed_response["renew_loan"].nil? or response.parsed_response["renew_loan"]["renewals"].nil?)
52
+ }
53
+ [response.parsed_response["renew_loan"]["renewals"]["institution"]].flatten
70
54
  end
71
-
55
+
72
56
  # Returns the note associated with the request.
73
57
  def note
74
- return (not @response.first.last.kind_of?(Hash) or @response.first.last["create_hold"].nil?) ? "" : ": #{@response.first.last["create_hold"]["note"]["__content__"]}" if @response.instance_of?(Hash)
58
+ return (not response.first.last.kind_of?(Hash) or response.first.last["create_hold"].nil?) ? "" : ": #{response.first.last["create_hold"]["note"]["__content__"]}" if response.instance_of?(Hash)
75
59
  end
76
-
60
+
77
61
  # Returns the error associated with the request.
78
62
  # Returns nil if no error.
79
63
  def error
80
64
  return nil if reply_code == "0000"
81
65
  return "#{reply_text}#{note}"
82
66
  end
67
+
68
+ def patron_url
69
+ @patron_url ||= "#{rest_url}/patron/#{patron_id}"
70
+ end
71
+ private :patron_url
72
+
73
+ def place_hold_xml(params)
74
+ pickup_location = params[:pickup_location]
75
+ last_interest_date = params.fetch(:last_interest_date, "")
76
+ start_interest_date = params.fetch(:start_interest_date, "")
77
+ sub_author = params.fetch(:sub_author, "")
78
+ sub_title = params.fetch(:sub_title, "")
79
+ pages = params.fetch(:pages, "")
80
+ note_1 = params.fetch(:note_1, "")
81
+ note_2 = params.fetch(:note_2, "")
82
+ rush = params.fetch(:rush, "N")
83
+ build_xml { |xml|
84
+ xml.send(:"hold-request-parameters") {
85
+ xml.send :"pickup-location", pickup_location
86
+ xml.send :"last-interest-date", last_interest_date
87
+ xml.send :"start-interest-date", start_interest_date
88
+ xml.send :"sub-author", sub_author
89
+ xml.send :"sub-title", sub_title
90
+ xml.send :"pages", pages
91
+ xml.send :"note-1", note_1
92
+ xml.send :"note-2", note_2
93
+ xml.send :"rush", rush
94
+ }
95
+ }
96
+ end
97
+ private :place_hold_xml
83
98
  end
84
99
  end
85
100
  end
@@ -1,64 +1,58 @@
1
1
  module Exlibris
2
2
  module Aleph
3
+ require 'marc'
3
4
  # ==Overview
4
5
  # Provides access to the Aleph Record REST API.
5
- class Record < Rest
6
- attr_reader :bib_library, :record_id
6
+ class Record < Rest::Base
7
+ attr_accessor :bib_library, :record_id
7
8
 
8
- # Creates an instance of Exlibris::Aleph::Record for the given :bib_library and :record_id
9
- def initialize(bib_library, record_id, uri)
10
- @record_id = record_id
11
- raise "Initialization error in #{self.class}. Missing record id." if @record_id.nil?
12
- @bib_library = bib_library
13
- raise "Initialization error in #{self.class}. Missing bib library." if @bib_library.nil?
14
- super(uri)
15
- @uri = @uri+ "/record/#{bib_library}#{record_id}"
16
- # Format :xml parses response as a hash.
17
- # Eventually I'd like this to be the default since it raises exceptions for invalid XML.
18
- # self.class.format :xml
19
- # Format :html does no parsing, just passes back raw XML for parsing by client
20
- self.class.format :html
9
+ def initialize(*args)
10
+ super
21
11
  end
22
12
 
23
- # Returns an XML string representation of a bib.
13
+ # Returns a MARC::Record that contains the bib data
24
14
  # Every method call refreshes the data from the underlying API.
25
- # Raises and exception if there are errors.
26
- # Returns a HTTParty::Response.
15
+ # Raises an exception if the response is not valid XML or there are errors.
27
16
  def bib
28
- @response = self.class.get(@uri+ "?view=full")
29
- raise "Error getting bib from Aleph REST APIs. #{error}" unless error.nil?
30
- return @response
17
+ self.response = self.class.get("#{record_url}?view=full")
18
+ raise_error_if("Error getting bib from Aleph REST APIs.") {
19
+ (response.parsed_response["get_record"].nil? or response.parsed_response["get_record"]["record"].nil?)
20
+ }
21
+ MARC::XMLReader.new(StringIO.new(xml(xml: response.body).at_xpath("get-record/record").to_xml(xml_options).strip)).first
31
22
  end
32
23
 
33
- # Returns an array of items. Each item is represented as an HTTParty hash.
24
+ # Returns an array of items. Each item is represented as a Hash.
34
25
  # Every method call refreshes the data from the underlying API.
35
26
  # Raises an exception if the response is not valid XML or there are errors.
36
- # Returns a HTTParty::Response.
37
27
  def items
38
- @items = []
39
- self.class.format :xml
40
28
  # Since we're parsing xml, this will raise an error
41
29
  # if the response isn't xml.
42
- @response = self.class.get(@uri+ "/items?view=full")
43
- self.class.format :html
44
- raise "Error getting items from Aleph REST APIs. #{error}" if not error.nil? or
45
- @response.nil? or @response["get_item_list"].nil? or @response["get_item_list"]["items"].nil?
46
- item_list = @response["get_item_list"]["items"]["item"]
47
- @items.push(item_list) if item_list.instance_of?(Hash)
48
- item_list.each {|item|@items.push(item)} if item_list.instance_of?(Array)
49
- # Rails.logger.warn("No items returned from Aleph in #{self.class}.") if @items.empty?
50
- return @items
30
+ self.response = self.class.get("#{record_url}/items?view=full")
31
+ raise_error_if("Error getting items from Aleph REST APIs.") {
32
+ (response.parsed_response["get_item_list"].nil? or response.parsed_response["get_item_list"]["items"].nil?)
33
+ }
34
+ [response.parsed_response["get_item_list"]["items"]["item"]].flatten
51
35
  end
52
36
 
53
- # Returns an XML string representation of holdings
37
+ # Returns an array of holdings. Each holding is represented as a MARC::Record.
54
38
  # Every method call refreshes the data from the underlying API.
55
- # Raises and exception if there are errors.
56
- # Returns a HTTParty::Response.
39
+ # Raises an exception if there are errors.
57
40
  def holdings
58
- @response = self.class.get(@uri+ "/holdings?view=full")
59
- raise "Error getting holdings from Aleph REST APIs. #{error}" unless error.nil?
60
- return @response
41
+ self.response = self.class.get("#{record_url}/holdings?view=full")
42
+ raise_error_if("Error getting holdings from Aleph REST APIs.") {
43
+ (response.parsed_response["get_hol_list"].nil? or response.parsed_response["get_hol_list"]["holdings"].nil?)
44
+ }
45
+ xml(xml: response.body).xpath("get-hol-list/holdings/holding").collect{ |holding|
46
+ # Change the tag name to record so that the MARC::XMLReader can parse it.
47
+ holding.name = "record"
48
+ MARC::XMLReader.new(StringIO.new(holding.to_xml(xml_options).strip)).first
49
+ }
50
+ end
51
+
52
+ def record_url
53
+ @record_url ||= "#{rest_url}/record/#{bib_library}#{record_id}"
61
54
  end
55
+ private :record_url
62
56
  end
63
57
  end
64
58
  end