median 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +19 -0
  3. data/Gemfile.lock +118 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.rdoc +5 -0
  6. data/Rakefile +38 -0
  7. data/lib/median.rb +33 -0
  8. data/lib/median/aleph.rb +18 -0
  9. data/lib/median/aleph/authentication.rb +64 -0
  10. data/lib/median/aleph/cash.rb +35 -0
  11. data/lib/median/aleph/hold.rb +86 -0
  12. data/lib/median/aleph/item.rb +34 -0
  13. data/lib/median/aleph/loan.rb +59 -0
  14. data/lib/median/aleph/patron.rb +110 -0
  15. data/lib/median/aleph/search.rb +11 -0
  16. data/lib/median/aleph/utils.rb +82 -0
  17. data/lib/median/primo.rb +9 -0
  18. data/lib/median/primo/facet.rb +27 -0
  19. data/lib/median/primo/record.rb +115 -0
  20. data/lib/median/primo/search.rb +32 -0
  21. data/lib/median/primo/search_request.rb +218 -0
  22. data/lib/median/primo/search_result.rb +64 -0
  23. data/lib/median/version.rb +3 -0
  24. data/lib/median/xml_support.rb +91 -0
  25. data/lib/tasks/median_tasks.rake +4 -0
  26. data/median.gemspec +24 -0
  27. data/test/dummy/README.rdoc +261 -0
  28. data/test/dummy/Rakefile +7 -0
  29. data/test/dummy/app/assets/javascripts/application.js +15 -0
  30. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  31. data/test/dummy/app/controllers/application_controller.rb +3 -0
  32. data/test/dummy/app/helpers/application_helper.rb +2 -0
  33. data/test/dummy/app/mailers/.gitkeep +0 -0
  34. data/test/dummy/app/models/.gitkeep +0 -0
  35. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  36. data/test/dummy/config.ru +4 -0
  37. data/test/dummy/config/application.rb +56 -0
  38. data/test/dummy/config/boot.rb +10 -0
  39. data/test/dummy/config/database.yml +25 -0
  40. data/test/dummy/config/environment.rb +5 -0
  41. data/test/dummy/config/environments/development.rb +37 -0
  42. data/test/dummy/config/environments/production.rb +67 -0
  43. data/test/dummy/config/environments/test.rb +37 -0
  44. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/test/dummy/config/initializers/inflections.rb +15 -0
  46. data/test/dummy/config/initializers/mime_types.rb +5 -0
  47. data/test/dummy/config/initializers/secret_token.rb +7 -0
  48. data/test/dummy/config/initializers/session_store.rb +8 -0
  49. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  50. data/test/dummy/config/locales/en.yml +5 -0
  51. data/test/dummy/config/routes.rb +58 -0
  52. data/test/dummy/lib/assets/.gitkeep +0 -0
  53. data/test/dummy/log/.gitkeep +0 -0
  54. data/test/dummy/public/404.html +26 -0
  55. data/test/dummy/public/422.html +26 -0
  56. data/test/dummy/public/500.html +25 -0
  57. data/test/dummy/public/favicon.ico +0 -0
  58. data/test/dummy/script/rails +6 -0
  59. data/test/median_test.rb +7 -0
  60. data/test/test_helper.rb +15 -0
  61. metadata +192 -0
@@ -0,0 +1,7 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/log/*.log
6
+ test/dummy/tmp/
7
+ test/dummy/.sass-cache
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in median.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # jquery-rails is used by the dummy application
9
+ gem "rails", '~> 3.2.3'
10
+ gem "jquery-rails"
11
+ gem "sqlite3"
12
+
13
+ # Declare any dependencies that are still in development here instead of in
14
+ # your gemspec. These might include edge Rails or gems from your path or
15
+ # Git. Remember to move these dependencies to your gemspec before releasing
16
+ # your gem to rubygems.org.
17
+
18
+ # To use debugger
19
+ # gem 'ruby-debug19', :require => 'ruby-debug'
@@ -0,0 +1,118 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ median (0.0.1)
5
+ activesupport (~> 3.2.3)
6
+ nokogiri (~> 1.5.2)
7
+ savon (~> 0.9.9)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ actionmailer (3.2.3)
13
+ actionpack (= 3.2.3)
14
+ mail (~> 2.4.4)
15
+ actionpack (3.2.3)
16
+ activemodel (= 3.2.3)
17
+ activesupport (= 3.2.3)
18
+ builder (~> 3.0.0)
19
+ erubis (~> 2.7.0)
20
+ journey (~> 1.0.1)
21
+ rack (~> 1.4.0)
22
+ rack-cache (~> 1.2)
23
+ rack-test (~> 0.6.1)
24
+ sprockets (~> 2.1.2)
25
+ activemodel (3.2.3)
26
+ activesupport (= 3.2.3)
27
+ builder (~> 3.0.0)
28
+ activerecord (3.2.3)
29
+ activemodel (= 3.2.3)
30
+ activesupport (= 3.2.3)
31
+ arel (~> 3.0.2)
32
+ tzinfo (~> 0.3.29)
33
+ activeresource (3.2.3)
34
+ activemodel (= 3.2.3)
35
+ activesupport (= 3.2.3)
36
+ activesupport (3.2.3)
37
+ i18n (~> 0.6)
38
+ multi_json (~> 1.0)
39
+ akami (1.0.0)
40
+ gyoku (>= 0.4.0)
41
+ arel (3.0.2)
42
+ builder (3.0.0)
43
+ erubis (2.7.0)
44
+ gyoku (0.4.4)
45
+ builder (>= 2.1.2)
46
+ hike (1.2.1)
47
+ httpi (0.9.6)
48
+ rack
49
+ i18n (0.6.0)
50
+ journey (1.0.3)
51
+ jquery-rails (2.0.2)
52
+ railties (>= 3.2.0, < 5.0)
53
+ thor (~> 0.14)
54
+ json (1.7.3)
55
+ mail (2.4.4)
56
+ i18n (>= 0.4.0)
57
+ mime-types (~> 1.16)
58
+ treetop (~> 1.4.8)
59
+ mime-types (1.18)
60
+ multi_json (1.3.5)
61
+ nokogiri (1.5.2)
62
+ nori (1.1.0)
63
+ polyglot (0.3.3)
64
+ rack (1.4.1)
65
+ rack-cache (1.2)
66
+ rack (>= 0.4)
67
+ rack-ssl (1.3.2)
68
+ rack
69
+ rack-test (0.6.1)
70
+ rack (>= 1.0)
71
+ rails (3.2.3)
72
+ actionmailer (= 3.2.3)
73
+ actionpack (= 3.2.3)
74
+ activerecord (= 3.2.3)
75
+ activeresource (= 3.2.3)
76
+ activesupport (= 3.2.3)
77
+ bundler (~> 1.0)
78
+ railties (= 3.2.3)
79
+ railties (3.2.3)
80
+ actionpack (= 3.2.3)
81
+ activesupport (= 3.2.3)
82
+ rack-ssl (~> 1.3.2)
83
+ rake (>= 0.8.7)
84
+ rdoc (~> 3.4)
85
+ thor (~> 0.14.6)
86
+ rake (0.9.2.2)
87
+ rdoc (3.12)
88
+ json (~> 1.4)
89
+ savon (0.9.9)
90
+ akami (~> 1.0)
91
+ builder (>= 2.1.2)
92
+ gyoku (>= 0.4.0)
93
+ httpi (~> 0.9)
94
+ nokogiri (>= 1.4.0)
95
+ nori (~> 1.1)
96
+ wasabi (~> 2.1)
97
+ sprockets (2.1.3)
98
+ hike (~> 1.2)
99
+ rack (~> 1.0)
100
+ tilt (~> 1.1, != 1.3.0)
101
+ sqlite3 (1.3.6)
102
+ thor (0.14.6)
103
+ tilt (1.3.3)
104
+ treetop (1.4.10)
105
+ polyglot
106
+ polyglot (>= 0.3.1)
107
+ tzinfo (0.3.33)
108
+ wasabi (2.1.0)
109
+ nokogiri (>= 1.4.0)
110
+
111
+ PLATFORMS
112
+ ruby
113
+
114
+ DEPENDENCIES
115
+ jquery-rails
116
+ median!
117
+ rails (~> 3.2.3)
118
+ sqlite3
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,5 @@
1
+ = Median
2
+
3
+ Move along. Nothing to see here yet. Under heavy development.
4
+
5
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Median'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,33 @@
1
+ require 'active_support/all'
2
+ require 'nokogiri'
3
+ require 'ostruct'
4
+ require 'open-uri'
5
+ require 'net/http'
6
+ require 'net/https'
7
+
8
+ require 'savon'
9
+
10
+ require 'median/xml_support'
11
+ require 'median/aleph'
12
+ require 'median/primo'
13
+
14
+ module Median
15
+
16
+ def self.config
17
+ @@config ||= OpenStruct.new
18
+ end
19
+
20
+ def self.config=(hash)
21
+ @@config = OpenStruct.new(hash)
22
+ end
23
+
24
+ class ConnectionError < RuntimeError; end
25
+
26
+ # TODO: Move default config to a config file
27
+ self.config.primo_base_url = 'http://vs39.kobv.de:1701'
28
+ self.config.aleph_rest_service_base_url = 'http://ubtesa.uni-paderborn.de:1891/rest-dlf'
29
+ self.config.aleph_x_service_base_url = 'https://ubtesa.uni-paderborn.de/X'
30
+ self.config.aleph_user_library = 'PAD50'
31
+ self.config.aleph_bib_library = 'PAD01'
32
+
33
+ end
@@ -0,0 +1,18 @@
1
+ require 'median/aleph/utils'
2
+ require 'median/aleph/authentication'
3
+ require 'median/aleph/search'
4
+ require 'median/aleph/patron'
5
+ require 'median/aleph/loan'
6
+ require 'median/aleph/hold'
7
+ require 'median/aleph/cash'
8
+ require 'median/aleph/item'
9
+
10
+ module Median::Aleph
11
+ extend Utils
12
+ extend Search
13
+ extend Authentication
14
+ extend Patron
15
+ extend Loan
16
+ extend Hold
17
+ extend Cash
18
+ end
@@ -0,0 +1,64 @@
1
+ module Median::Aleph
2
+ module Authentication
3
+
4
+ def authenticate(username, password)
5
+ return false if username.blank? or password.blank?
6
+
7
+ username.gsub!(/\s/, '')
8
+ username.upcase!
9
+
10
+ auth_info = post_url(Median.config.aleph_x_service_base_url,
11
+ op: 'bor-auth',
12
+ bor_id: username,
13
+ verification: password,
14
+ library: Median.config.aleph_user_library
15
+ )
16
+ puts auth_info
17
+
18
+ user_info = get_url(
19
+ Median.config.aleph_x_service_base_url,
20
+ op: 'bor-info',
21
+ bor_id: username,
22
+ verification: password,
23
+ loans: 'N',
24
+ cash: 'B',
25
+ hold: 'N',
26
+ library: Median.config.aleph_user_library
27
+ )
28
+
29
+ unless auth_info.at_xpath('/bor-auth/error') or user_info.at_xpath('/bor-info/error')
30
+ options = {}
31
+ # user id in the ILS Alpeh
32
+ options[:ilsid] = auth_info.at_xpath('//z303-id').try(:content)
33
+ # name of the user
34
+ name = auth_info.at_xpath('//z303-name').try(:content)
35
+ options[:lastname], options[:firstname] = name.split(',').map(&:strip) if name.present?
36
+ # email
37
+ options[:email] = auth_info.at_xpath('//z304-email-address').try(:content)
38
+ # map bor-status to roles
39
+ options[:role] = 'g' # guest by default
40
+ status = auth_info.at_xpath('//z305-bor-status').try(:content)
41
+ case status
42
+ when /PS/ then options[:role] = 's'
43
+ when /PA/ then options[:role] = 'a'
44
+ when /PE/ then options[:role] = 'e'
45
+ when /PZ/ then options[:role] = 'z'
46
+ end
47
+ # exiry date
48
+ expiry_date = auth_info.at_xpath('//z305-expiry-date').try(:content)
49
+ options[:expiry_date] = Date.strptime(expiry_date, '%d/%m/%Y') if expiry_date.present?
50
+ # cash balance
51
+ balance = user_info.at_xpath('//balance').try(:content).to_f
52
+ balance = balance * -1 if balance != 0 and user_info.at_xpath('//sign').try(:content).try(:strip).try(:downcase) == 'd'
53
+ options[:cash_balance] = balance
54
+
55
+ # TODO: What about banned users?
56
+
57
+ return options
58
+ end
59
+
60
+ false
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,35 @@
1
+ module Median::Aleph
2
+ module Cash
3
+
4
+ def get_cash(patron_id)
5
+ xml = get_url("#{Median.config.aleph_rest_service_base_url}/patron/#{patron_id}/circulationActions/cash",
6
+ view: 'brief'
7
+ )
8
+
9
+ cash = OpenStruct.new
10
+ cash.balance = 0.0
11
+ cash.charges = []
12
+
13
+ # balance
14
+ cash.balance = xml.at_xpath('//open-sum').try(:content).gsub!(/\s/, '').to_f
15
+ # charges
16
+ xml.xpath('//cash').each do |charge_xml|
17
+ charge = OpenStruct.new
18
+ sum = charge_xml.at_xpath('z31-sum').try(:content).try(:gsub, '(', '').try(:gsub, ')', '').to_f
19
+ sum = sum * -1 if sum != 0 and charge_xml.at_xpath('z31-credit-debit').try(:content).try(:strip).try(:downcase) == 'debit'
20
+ charge.sum = sum
21
+ date = charge_xml.at_xpath('z31-date').try(:content)
22
+ charge.date = date.present? ? Date.strptime(date, '%Y%m%d') : nil
23
+ charge.author = charge_xml.at_xpath('z13-author').try(:content)
24
+ charge.title = charge_xml.at_xpath('z13-title').try(:content)
25
+ charge.year = charge_xml.at_xpath('z13-year').try(:content)
26
+ description = charge_xml.at_xpath('z31-description').try(:content)
27
+ charge.description = description if description.present? and description.downcase.strip != 'alle'
28
+ cash.charges << charge
29
+ end
30
+
31
+ return cash
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,86 @@
1
+ module Median::Aleph
2
+ module Hold
3
+
4
+ def get_holds(patron_id)
5
+ # patron_id = 'COPA99001517'
6
+
7
+ holds = []
8
+
9
+ # load holds
10
+ url = "#{Median.config.aleph_rest_service_base_url}/patron/#{patron_id}/circulationActions/requests/holds"
11
+ xml = get_url(url, view: 'full')
12
+
13
+ # Rails.logger.info xml
14
+
15
+ # parse holds
16
+ holds = xml.xpath('//hold-request').collect do |hold_xml|
17
+ hold = OpenStruct.new()
18
+ hold.id = hold_xml.attribute('href').try(:content).try(:split, '/').try(:last)
19
+ hold.can_cancel = (hold_xml.attribute('delete').try(:content).try(:upcase) == 'Y') ? true : false
20
+ open_date = hold_xml.at_xpath('./z37/z37-open-date').try(:content)
21
+ hold.open_date = open_date.present? ? Date.strptime(open_date, '%Y%m%d') : nil
22
+ queue_pos = hold_xml.at_xpath('./status').try(:content).try(:match, /position ([0-9]+)/i).try(:[], 1).to_i
23
+ hold.queue_pos = queue_pos
24
+ due_date = hold_xml.at_xpath('./status').try(:content).try(:match, /due date ([0-9]+\/[0-9]+\/[0-9]+)/i).try(:[], 1)
25
+ hold.due_date = due_date.present? ? Date.strptime(due_date, '%d/%m/%y') : nil
26
+ hold.doc_id = hold_xml.at_xpath('./z13/z13-doc-number').try(:content)
27
+ hold.author = hold_xml.at_xpath('./z13/z13-author').try(:content)
28
+ hold.title = hold_xml.at_xpath('./z13/z13-title').try(:content)
29
+ hold.year = hold_xml.at_xpath('./z13/z13-year').try(:content)
30
+ hold.signature = hold_xml.at_xpath('./z13/z13-call-no').try(:content)
31
+
32
+ hold
33
+ end
34
+
35
+ return holds
36
+ end
37
+
38
+ def create_hold(patron_id, record_id)
39
+ # First, get the group list and fetch the ID for group 0
40
+ group0_id = get_hold_group0_id(patron_id, record_id)
41
+ if group0_id.present?
42
+ url = "#{Median.config.aleph_rest_service_base_url}/patron/#{patron_id}/record/#{record_id}/holds/#{group0_id}"
43
+
44
+ data = <<-XML
45
+ <hold-request-parameters>
46
+ <pickup-location>P0001</pickup-location>
47
+ <start-interest-date>#{Date.today.strftime('%Y%m%d')}</start-interest-date>
48
+ <last-interest-date>#{(Date.today + 1.year).strftime('%Y%m%d')}</last-interest-date>
49
+ <rush>N</rush>
50
+ </hold-request-parameters>
51
+ XML
52
+
53
+ # Optional XML Fields for the hold request.
54
+ # <sub-author>Additional Author Information</sub-author>
55
+ # <sub-title>Additional Title Information</sub-title>
56
+ # <pages>Addtional Pages Information</pages>
57
+ # <note-1>Additional Note</note-1>
58
+ # <note-2>Addtional Note</note-2>
59
+
60
+ xml = put_url(url, post_xml: data)
61
+ result = xml.at_xpath('//reply-text').try(:content).try(:downcase)
62
+ return result == 'ok'
63
+ end
64
+ false
65
+ end
66
+
67
+ def cancel_hold(patron_id, hold_id)
68
+ url = "#{Median.config.aleph_rest_service_base_url}/patron/#{patron_id}/circulationActions/requests/holds/#{hold_id}"
69
+ xml = delete_url(url)
70
+ result = xml.at_xpath('//reply-text').try(:content).try(:downcase)
71
+ return result == 'ok'
72
+ end
73
+
74
+ protected
75
+
76
+ def get_hold_group0_id(patron_id, record_id)
77
+ url = "#{Median.config.aleph_rest_service_base_url}/patron/#{patron_id}/record/#{record_id}/holds"
78
+ puts url
79
+ xml = get_url(url, view: 'full')
80
+ puts xml
81
+ group0 = xml.at_xpath('//group')
82
+ return group0.attribute('href').try(:content).try(:split, '/').try(:last) if group0
83
+ end
84
+
85
+ end
86
+ end