voyager 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in voyager.gemspec
4
+ gemspec
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,17 @@
1
+ # ActiveRecord
2
+ require 'active_record'
3
+ require 'voyager/activerecord/base'
4
+ require 'voyager/activerecord/bib/text'
5
+ require 'voyager/activerecord/bib/item'
6
+ require 'voyager/activerecord/circ/transaction'
7
+ require 'voyager/activerecord/item'
8
+ require 'voyager/activerecord/item/barcode'
9
+
10
+ # SIP Client
11
+ require 'socket'
12
+ require 'voyager/sip/basic_client'
13
+ require 'voyager/sip/client'
14
+
15
+ module Voyager
16
+ # Your code goes here...
17
+ end
@@ -0,0 +1,6 @@
1
+ module Voyager
2
+ module AR
3
+ class Base < ActiveRecord::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ module Voyager
2
+ module AR
3
+ module Bib
4
+ class Item < Voyager::AR::Base
5
+ set_table_name 'bib_item'
6
+ set_primary_key 'bib_id'
7
+
8
+ has_one :bib_text, :foreign_key => :bib_id, :class_name => 'Voyager::AR::Bib::Text'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Voyager
2
+ module AR
3
+ module Bib
4
+ class Text < Voyager::AR::Base
5
+ set_table_name 'bib_text'
6
+ set_primary_key 'bib_id'
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module Voyager
2
+ module AR
3
+ module Circ
4
+ class Transaction < Voyager::AR::Base
5
+ # ActiveRecord Configuration
6
+ set_table_name 'circ_transactions'
7
+ set_primary_key 'circ_transactions_id'
8
+
9
+ # AR Associations
10
+ belongs_to :item, :class_name => 'Voyager::AR::Item'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module Voyager
2
+ module AR
3
+ class Item < Voyager::AR::Base
4
+ # ActiveRecord Configuration
5
+ set_table_name 'item'
6
+ set_primary_key 'item_id'
7
+
8
+ # Associations
9
+ has_one :barcode, :foreign_key => 'item_id', :class_name => 'Voyager::AR::Item::Barcode'
10
+ has_one :circ_transaction, :class_name => 'Voyager::AR::Circ::Transaction'
11
+
12
+ has_one :bib_text, :through => :bib_item, :class_name => 'Voyager::AR::Bib::Text'
13
+ has_one :bib_item, :foreign_key => 'item_id', :class_name => 'Voyager::AR::Bib::Item'
14
+
15
+ # Class Methods
16
+ def charged?
17
+ circ_transaction.nil? ? false : true
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ module Voyager
2
+ module AR
3
+ class Item
4
+ class Barcode < Voyager::AR::Base
5
+ set_table_name 'item_barcode'
6
+ set_primary_key 'item_id'
7
+
8
+ belongs_to :item, :class_name => 'Voyager::AR::Item'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,60 @@
1
+ require 'socket'
2
+
3
+ # Rudimentary SIP Client
4
+
5
+ module Voyager
6
+ module SIP
7
+ module BasicSipClient
8
+ VERBOSE = true
9
+ TIMESTAMP_FORMAT = "%Y%m%d %H%M%S"
10
+ @socket
11
+
12
+ def initialize(host, port)
13
+ Rails::logger.info "SIPClient: Connecting with #{host}:#{port}" if VERBOSE
14
+ @socket = TCPSocket::new(host, port)
15
+
16
+ if block_given?
17
+ begin
18
+ yield self
19
+ ensure
20
+ # When given a socket, we automatically close connection
21
+ close
22
+ end
23
+ end
24
+ end
25
+
26
+ def send(msg)
27
+ Rails::logger.info "SIPClient: Sending #{msg}" if VERBOSE
28
+ @socket.write("#{msg.strip}\r")
29
+
30
+ # If a block is given, yield the response
31
+ if block_given?
32
+ yield recv
33
+ end
34
+ end
35
+
36
+ def recv
37
+ msg = ""
38
+ until msg =~ /\r/
39
+ result = IO::select([@socket], nil, nil)
40
+
41
+ for inp in result[0]
42
+ msg << @socket.recv(300);
43
+ end
44
+ end
45
+
46
+ Rails::logger.info "SIPClient: Recieved #{msg.strip}" if VERBOSE
47
+ msg
48
+ end
49
+
50
+ def close
51
+ Rails::logger.info "SIPClient: Connection closed." if VERBOSE
52
+ @socket.close
53
+ end
54
+
55
+ def timestamp
56
+ Time.now.strftime(TIMESTAMP_FORMAT)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,134 @@
1
+ module Voyager
2
+ module SIP
3
+ class Client
4
+ include BasicSipClient
5
+ #--
6
+ # Sends a Login Message
7
+ #
8
+ # Example login request:
9
+ # 9300CNusername|COpassword|CPCIRC|
10
+ # Example login response:
11
+ # 941
12
+ #++
13
+ def login(username, password, location)
14
+ msg = "9300CN#{username}|CO#{password}|CP#{location}|\r"
15
+
16
+ send(msg) do |response|
17
+ response = parse_login(response)
18
+
19
+ raise "Invalid login: #{response[:raw]}" unless response[:ok] == '1'
20
+
21
+ if block_given?
22
+ yield response
23
+ end
24
+
25
+ response
26
+ end
27
+ end
28
+
29
+ def parse_login(msg)
30
+ match = msg.match(/^94(0|1)\r$/)
31
+ if match
32
+ {:raw => msg,
33
+ :id => 94,
34
+ :ok => match[1]}
35
+ end
36
+ end
37
+
38
+ #--
39
+ # Sends a Create Bib Message
40
+ #
41
+ # Example create bib request:
42
+ # 8120100813 133505AO|MFSelfchk|AJThe transformation of learning : / *77087*|AB77087|AC|^M
43
+ # Example create bib response:
44
+ # 821MJ633124|MA630995|AFCreate Bib successful.|^M
45
+ #++
46
+ def create_bib(operator, title, barcode)
47
+ msg = "81#{self.timestamp}|AO|MF#{operator}|AJ#{title}|AB#{barcode}|AC|"
48
+
49
+ send(msg) do |response|
50
+ response = parse_create_bib(response)
51
+
52
+ # Bib/MFHD/Item create failed
53
+ raise "Bib/MFHD/Item create failed: #{response['raw']}" if response[:ok] == '0'
54
+
55
+ # Bib was created, but not the item
56
+ #
57
+ # This is possible if we have a duplicate barcode, however we
58
+ # check for that. Possible race condition, though unlikely.
59
+ #
60
+ # Store the bib_id for troubleshooting
61
+ raise "Duplicate barcode. A bib exists without an item and should be deleted: #{response['raw']}" if response[:item_id].empty?
62
+
63
+
64
+ if block_given?
65
+ yield response
66
+ end
67
+
68
+ response
69
+ end
70
+ end
71
+
72
+ def parse_create_bib(msg)
73
+ # 821MJ640267|MA818432|AFCreate Bib successful.|
74
+ # [2] - OK? 1:yes, 0:no
75
+ # MJ - Item number
76
+ # MA - Bib number
77
+ # AF - Print screen
78
+ match = msg.match(/^82(.)MJ(.*)\|MA(.*)\|AF(.*)\|\r$/)
79
+ if match
80
+ {:raw => msg,
81
+ :id => 82,
82
+ :ok => match[1],
83
+ :item_id => match[2],
84
+ :bib_id => match[3],
85
+ :print_msg => match[4]
86
+ }
87
+ end
88
+ end
89
+
90
+ def item_status(item_identifier)
91
+ msg = "17#{self.timestamp}|AO|AB#{item_identifier}|AC|"
92
+
93
+ send(msg) do |response|
94
+ response = parse_item_status(response)
95
+
96
+ if block_given?
97
+ yield response
98
+ end
99
+
100
+ response
101
+ end
102
+ end
103
+
104
+ def parse_item_status(msg)
105
+ # 1803000120110408 150732CF0|AH|CJ|AB96917|AJBokml - Test for Nostos *96917*|BGHealey_Library|AQCirculation Desk|AFItem Info retrieved successfully.|
106
+ match = msg.match(/^18([0-9]{2})([0-9]{2})([0-9]{2})(.{18})(.*)\r$/)
107
+ # 1 - Circulation Status
108
+ # 2 - Security Marker
109
+ # 3 - Fee Type
110
+ # 4 - Transaction Date
111
+ # 5 - Variable Fields
112
+ var_fields = msg.scan(/([A-Z]{2})([^|]*)\|/)
113
+ if match
114
+ r = {:raw => msg,
115
+ :id => 18,
116
+ :circ_status => match[1],
117
+ :security_marker => match[2],
118
+ :fee_type => match[3],
119
+ :transaction_date => match[4],
120
+ }
121
+ var_fields.each do |field|
122
+ r[field.first.to_sym] = field.last
123
+ end
124
+ r
125
+ end
126
+ end
127
+
128
+ # Utilities
129
+ def timestamp
130
+ Time.now.strftime("%Y%m%d %H%M%S")
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,3 @@
1
+ module Voyager
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "voyager/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "voyager"
7
+ s.version = Voyager::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Brice Stacey"]
10
+ s.email = ["bricestacey@gmail.com"]
11
+ s.homepage = "https://github.com/bricestacey/voyager"
12
+ s.summary = %q{ActiveRecord bindings for Voyager ILS}
13
+ s.description = %q{ActiveRecord bindings for Voyager ILS}
14
+
15
+ s.rubyforge_project = "voyager"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency('activerecord')
23
+ s.add_dependency('activerecord-oracle_enhanced-adapter')
24
+ s.add_dependency('ruby-oci8')
25
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: voyager
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Brice Stacey
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-15 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: activerecord-oracle_enhanced-adapter
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: ruby-oci8
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ description: ActiveRecord bindings for Voyager ILS
49
+ email:
50
+ - bricestacey@gmail.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - .gitignore
59
+ - Gemfile
60
+ - Rakefile
61
+ - lib/voyager.rb
62
+ - lib/voyager/activerecord/base.rb
63
+ - lib/voyager/activerecord/bib/item.rb
64
+ - lib/voyager/activerecord/bib/text.rb
65
+ - lib/voyager/activerecord/circ/transaction.rb
66
+ - lib/voyager/activerecord/item.rb
67
+ - lib/voyager/activerecord/item/barcode.rb
68
+ - lib/voyager/sip/basic_client.rb
69
+ - lib/voyager/sip/client.rb
70
+ - lib/voyager/version.rb
71
+ - voyager.gemspec
72
+ homepage: https://github.com/bricestacey/voyager
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project: voyager
95
+ rubygems_version: 1.7.2
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: ActiveRecord bindings for Voyager ILS
99
+ test_files: []
100
+