ruby-fedora 0.1.2 → 0.9.0
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.
- data/COPYING.LESSER.txt +165 -0
- data/COPYING.txt +674 -0
- data/Manifest.txt +19 -20
- data/README.txt +6 -1
- data/Rakefile +4 -0
- data/config/hoe.rb +2 -2
- data/config/requirements.rb +9 -2
- data/lib/active_fedora.rb +41 -0
- data/lib/active_fedora/base.rb +278 -8
- data/lib/active_fedora/content_model.rb +22 -0
- data/lib/active_fedora/datastream.rb +95 -0
- data/lib/active_fedora/fedora_object.rb +84 -0
- data/lib/active_fedora/metadata_datastream.rb +97 -0
- data/lib/active_fedora/model.rb +94 -0
- data/lib/active_fedora/property.rb +15 -0
- data/lib/active_fedora/qualified_dublin_core_datastream.rb +72 -0
- data/lib/active_fedora/relationship.rb +43 -0
- data/lib/active_fedora/rels_ext_datastream.rb +43 -0
- data/lib/active_fedora/semantic_node.rb +221 -0
- data/lib/active_fedora/solr_service.rb +20 -0
- data/lib/fedora/base.rb +2 -1
- data/lib/fedora/connection.rb +104 -134
- data/lib/fedora/datastream.rb +10 -1
- data/lib/fedora/fedora_object.rb +28 -24
- data/lib/fedora/generic_search.rb +71 -0
- data/lib/fedora/repository.rb +47 -3
- data/lib/ruby-fedora.rb +9 -8
- data/lib/util/class_level_inheritable_attributes.rb +23 -0
- data/solr/config/schema.xml +229 -0
- metadata +37 -24
- data/lib/active-fedora.rb +0 -1
- data/lib/ambition/adapters/active_fedora.rb +0 -10
- data/lib/ambition/adapters/active_fedora/base.rb +0 -14
- data/lib/ambition/adapters/active_fedora/query.rb +0 -48
- data/lib/ambition/adapters/active_fedora/select.rb +0 -104
- data/lib/ambition/adapters/active_fedora/slice.rb +0 -19
- data/lib/ambition/adapters/active_fedora/sort.rb +0 -43
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/script/txt2html +0 -74
- data/tasks/deployment.rake +0 -34
- data/tasks/environment.rake +0 -7
- data/tasks/website.rake +0 -17
- data/website/index.html +0 -93
- data/website/index.txt +0 -39
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -138
- data/website/template.rhtml +0 -48
@@ -0,0 +1,43 @@
|
|
1
|
+
module ActiveFedora
|
2
|
+
|
3
|
+
class Relationship
|
4
|
+
|
5
|
+
attr_accessor :subject, :predicate, :object, :is_literal, :data_type
|
6
|
+
def initialize(attr={})
|
7
|
+
attr.merge!({:is_literal => false})
|
8
|
+
self.subject = attr[:subject]
|
9
|
+
@predicate = attr[:predicate]
|
10
|
+
self.object = attr[:object]
|
11
|
+
@is_literal = attr[:is_literal]
|
12
|
+
@data_type = attr[:data_type]
|
13
|
+
end
|
14
|
+
|
15
|
+
def subject=(subject)
|
16
|
+
@subject = generate_uri(subject)
|
17
|
+
end
|
18
|
+
|
19
|
+
def subject_pid=(pid)
|
20
|
+
@subject = "info:fedora/#{pid}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def object=(object)
|
24
|
+
@object = generate_uri(object)
|
25
|
+
end
|
26
|
+
|
27
|
+
def object_pid=(pid)
|
28
|
+
@object = "info:fedora/#{pid}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate_uri(input)
|
32
|
+
if input.class == Symbol || input == nil
|
33
|
+
return input
|
34
|
+
elsif input.respond_to?(:pid)
|
35
|
+
return "info:fedora/#{input.pid}"
|
36
|
+
else
|
37
|
+
input.include?("info:fedora") ? input : "info:fedora/#{input}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'active_fedora/semantic_node'
|
2
|
+
|
3
|
+
module ActiveFedora
|
4
|
+
class RelsExtDatastream < Datastream
|
5
|
+
|
6
|
+
include ActiveFedora::SemanticNode
|
7
|
+
|
8
|
+
def initialize(attrs=nil)
|
9
|
+
super
|
10
|
+
self.dsid = "RELS-EXT"
|
11
|
+
end
|
12
|
+
|
13
|
+
def save
|
14
|
+
if @dirty == true
|
15
|
+
self.content = to_rels_ext(self.pid)
|
16
|
+
end
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def pid=(pid)
|
21
|
+
super
|
22
|
+
self.blob = <<-EOL
|
23
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
24
|
+
<rdf:Description rdf:about="info:fedora/#{pid}">
|
25
|
+
</rdf:Description>
|
26
|
+
</rdf:RDF>
|
27
|
+
EOL
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_solr(solr_doc = Solr::Document.new)
|
31
|
+
self.relationships.each_pair do |subject, predicates|
|
32
|
+
if subject == :self || subject == "info:fedora/#{self.pid}"
|
33
|
+
predicates.each_pair do |predicate, values|
|
34
|
+
values.each do |val|
|
35
|
+
solr_doc << Solr::Field.new("#{predicate}_field" => val)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return solr_doc
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
module ActiveFedora
|
2
|
+
module SemanticNode
|
3
|
+
include MediaShelfClassLevelInheritableAttributes
|
4
|
+
ms_inheritable_attributes :class_relationships, :internal_uri
|
5
|
+
include Extlib::Assertions
|
6
|
+
|
7
|
+
attr_accessor :internal_uri, :relationships
|
8
|
+
|
9
|
+
PREDICATE_MAPPINGS = Hash[:is_member_of => "isMemberOf",
|
10
|
+
:is_part_of => "isPartOf",
|
11
|
+
:has_part => "hasPart",
|
12
|
+
:conforms_to => "conformsTo"]
|
13
|
+
|
14
|
+
def self.included(klass)
|
15
|
+
klass.extend(ClassMethods)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_relationship(relationship)
|
19
|
+
# Only accept ActiveFedora::Relationships as input arguments
|
20
|
+
assert_kind_of 'relationship', relationship, ActiveFedora::Relationship
|
21
|
+
register_triple(relationship.subject, relationship.predicate, relationship.object)
|
22
|
+
end
|
23
|
+
|
24
|
+
def register_triple(subject, predicate, object)
|
25
|
+
register_subject(subject)
|
26
|
+
register_predicate(subject, predicate)
|
27
|
+
relationships[subject][predicate] << object
|
28
|
+
end
|
29
|
+
|
30
|
+
def register_subject(subject)
|
31
|
+
if !relationships.has_key?(subject)
|
32
|
+
relationships[subject] = {}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def register_predicate(subject, predicate)
|
37
|
+
register_subject(subject)
|
38
|
+
if !relationships[subject].has_key?(predicate)
|
39
|
+
relationships[subject][predicate] = []
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def outbound_relationships()
|
44
|
+
if !internal_uri.nil? && !relationships[internal_uri].nil?
|
45
|
+
return relationships[:self].merge(relationships[internal_uri])
|
46
|
+
else
|
47
|
+
return relationships[:self]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def relationships
|
52
|
+
@relationships ||= relationships_from_class
|
53
|
+
end
|
54
|
+
|
55
|
+
def relationships_from_class
|
56
|
+
rels = {}
|
57
|
+
self.class.relationships.each_pair do |subj, pred|
|
58
|
+
rels[subj] = {}
|
59
|
+
pred.each_key do |pred_key|
|
60
|
+
rels[subj][pred_key] = []
|
61
|
+
end
|
62
|
+
end
|
63
|
+
#puts "rels from class: #{rels.inspect}"
|
64
|
+
return rels
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates a RELS-EXT datastream for insertion into a Fedora Object
|
68
|
+
# @pid
|
69
|
+
# Note: This method is implemented on SemanticNode instead of RelsExtDatastream because SemanticNode contains the relationships array
|
70
|
+
def to_rels_ext(pid, relationships=self.relationships)
|
71
|
+
starter_xml = <<-EOL
|
72
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
73
|
+
<rdf:Description rdf:about="info:fedora/#{pid}">
|
74
|
+
</rdf:Description>
|
75
|
+
</rdf:RDF>
|
76
|
+
EOL
|
77
|
+
xml = REXML::Document.new(starter_xml)
|
78
|
+
|
79
|
+
# Iterate through the hash of predicates, adding an element to the RELS-EXT for each "object" in the predicate's corresponding array.
|
80
|
+
# puts ""
|
81
|
+
# puts "Iterating through a(n) #{self.class}"
|
82
|
+
# puts "=> whose relationships are #{self.relationships.inspect}"
|
83
|
+
# puts "=> and whose outbound relationships are #{self.outbound_relationships.inspect}"
|
84
|
+
self.outbound_relationships.each do |predicate, targets_array|
|
85
|
+
targets_array.each do |target|
|
86
|
+
# puts ". #{predicate} #{target}"
|
87
|
+
xml.root.elements["rdf:Description"].add_element(self.class.predicate_lookup(predicate), {"xmlns" => "info:fedora/fedora-system:def/relations-external#", "rdf:resource"=>target})
|
88
|
+
end
|
89
|
+
end
|
90
|
+
xml.to_s
|
91
|
+
end
|
92
|
+
|
93
|
+
module ClassMethods
|
94
|
+
|
95
|
+
# Anticipates usage of a relationship in classes that include this module
|
96
|
+
# Creates a key in the @relationships array for the predicate provided. Assumes
|
97
|
+
# :self as the subject of the relationship unless :inbound => true, in which case the
|
98
|
+
# predicate is registered under @relationships[:inbound][#{predicate}]
|
99
|
+
#
|
100
|
+
# TODO:
|
101
|
+
# Custom Methods:
|
102
|
+
# A custom finder method will be appended based on the relationship name.
|
103
|
+
# ie.
|
104
|
+
# class Foo
|
105
|
+
# relationship "container", :is_member_of
|
106
|
+
# end
|
107
|
+
# foo = Foo.new
|
108
|
+
# foo.parts
|
109
|
+
#
|
110
|
+
# Special Predicate Short Hand:
|
111
|
+
# These symbols map to the uris of corresponding Fedora RDF predicates
|
112
|
+
# :is_member_of, :has_member, :is_part_of, :has_part
|
113
|
+
def has_relationship(name, predicate, opts = {})
|
114
|
+
opts = {:singular => nil, :inbound => false}.merge(opts)
|
115
|
+
opts[:inbound] == true ? register_predicate(:inbound, predicate) : register_predicate(:self, predicate)
|
116
|
+
|
117
|
+
if opts[:inbound] == true
|
118
|
+
create_inbound_relationship_finders(name, predicate, opts)
|
119
|
+
else
|
120
|
+
create_outbound_relationship_finders(name, predicate, opts)
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
def create_inbound_relationship_finders(name, predicate, opts = {})
|
126
|
+
class_eval <<-END
|
127
|
+
def #{name}
|
128
|
+
escaped_uri = self.internal_uri.gsub(/(:)/, '\\:')
|
129
|
+
hits = SolrService.instance.conn.query("#{predicate}_field:\#{escaped_uri}").hits
|
130
|
+
results = []
|
131
|
+
hits.each do |hit|
|
132
|
+
classname = Kernel.const_get(hit["active_fedora_model_field"].first)
|
133
|
+
results << Fedora::Repository.instance.find_model(hit["id"], classname)
|
134
|
+
end
|
135
|
+
return results
|
136
|
+
end
|
137
|
+
def #{name}_ids
|
138
|
+
escaped_uri = self.internal_uri.gsub(/(:)/, '\\:')
|
139
|
+
SolrService.instance.conn.query("#{predicate}_field:\#{escaped_uri}")
|
140
|
+
end
|
141
|
+
END
|
142
|
+
end
|
143
|
+
|
144
|
+
def create_outbound_relationship_finders(name, predicate, opts = {})
|
145
|
+
class_eval <<-END
|
146
|
+
def #{name}
|
147
|
+
results = []
|
148
|
+
outbound_relationships[#{predicate.inspect}].each do |rel|
|
149
|
+
uri_as_pid = rel.gsub("info:fedora/", "")
|
150
|
+
results << Fedora::Repository.instance.find_model(uri_as_pid, ActiveFedora::Base)
|
151
|
+
end
|
152
|
+
return results
|
153
|
+
end
|
154
|
+
def #{name}_ids
|
155
|
+
results = []
|
156
|
+
outbound_relationships[#{predicate.inspect}].each do |rel|
|
157
|
+
results << rel
|
158
|
+
end
|
159
|
+
end
|
160
|
+
END
|
161
|
+
end
|
162
|
+
|
163
|
+
# relationships are tracked as a hash of structure {subject => {predicate => [object]}}
|
164
|
+
def relationships
|
165
|
+
@class_relationships ||= Hash[:self => {}]
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
def register_subject(subject)
|
170
|
+
if !relationships.has_key?(subject)
|
171
|
+
relationships[subject] = {}
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def register_predicate(subject, predicate)
|
176
|
+
register_subject(subject)
|
177
|
+
if !relationships[subject].has_key?(predicate)
|
178
|
+
relationships[subject][predicate] = []
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
#alias_method :register_target, :register_object
|
183
|
+
|
184
|
+
# Creates a RELS-EXT datastream for insertion into a Fedora Object
|
185
|
+
# @pid
|
186
|
+
# Note: This method is implemented on SemanticNode instead of RelsExtDatastream because SemanticNode contains the relationships array
|
187
|
+
def relationships_to_rels_ext(pid, relationships=self.relationships)
|
188
|
+
starter_xml = <<-EOL
|
189
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
190
|
+
<rdf:Description rdf:about="info:fedora/#{pid}">
|
191
|
+
</rdf:Description>
|
192
|
+
</rdf:RDF>
|
193
|
+
EOL
|
194
|
+
xml = REXML::Document.new(starter_xml)
|
195
|
+
|
196
|
+
# Iterate through the hash of predicates, adding an element to the RELS-EXT for each "object" in the predicate's corresponding array.
|
197
|
+
self.outbound_relationships.each do |predicate, targets_array|
|
198
|
+
targets_array.each do |target|
|
199
|
+
#puts ". #{predicate} #{target}"
|
200
|
+
xml.root.elements["rdf:Description"].add_element(predicate_lookup(predicate), {"xmlns" => "info:fedora/fedora-system:def/relations-external#", "rdf:resource"=>target})
|
201
|
+
end
|
202
|
+
end
|
203
|
+
xml.to_s
|
204
|
+
end
|
205
|
+
|
206
|
+
# If predicate is a symbol, looks up the predicate in the PREDICATE_MAPPINGS
|
207
|
+
# If predicate is not a Symbol, returns the predicate untouched
|
208
|
+
# @throws UnregisteredPredicateError if the predicate is a symbol but is not found in the PREDICATE_MAPPINGS
|
209
|
+
def predicate_lookup(predicate)
|
210
|
+
if predicate.class == Symbol
|
211
|
+
if PREDICATE_MAPPINGS.has_key?(predicate)
|
212
|
+
return PREDICATE_MAPPINGS[predicate]
|
213
|
+
else
|
214
|
+
throw UnregisteredPredicateError
|
215
|
+
end
|
216
|
+
end
|
217
|
+
return predicate
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'solr'
|
2
|
+
module ActiveFedora
|
3
|
+
class SolrService
|
4
|
+
attr_reader :conn
|
5
|
+
def self.register(host=nil, args={})
|
6
|
+
Thread.current[:solr_service]=self.new(host, args)
|
7
|
+
|
8
|
+
end
|
9
|
+
def initialize(host, args)
|
10
|
+
host = 'http://localhost:8080/solr' unless host
|
11
|
+
opts = {:autocommit=>:on}.merge(args)
|
12
|
+
@conn = Solr::Connection.new(host, opts)
|
13
|
+
end
|
14
|
+
def self.instance
|
15
|
+
raise SolrNotInitialized unless Thread.current[:solr_service]
|
16
|
+
Thread.current[:solr_service]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
class SolrNotInitialized < StandardError;end
|
20
|
+
end
|
data/lib/fedora/base.rb
CHANGED
@@ -12,7 +12,7 @@ class Hash
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class Fedora::BaseObject
|
15
|
-
attr_accessor :attributes, :blob, :uri
|
15
|
+
attr_accessor :attributes, :blob, :uri
|
16
16
|
attr_reader :errors, :uri
|
17
17
|
attr_writer :new_object
|
18
18
|
|
@@ -24,6 +24,7 @@ class Fedora::BaseObject
|
|
24
24
|
@attributes = attrs || {}
|
25
25
|
@errors = []
|
26
26
|
@blob = attributes.delete(:blob)
|
27
|
+
@repository = Fedora::Repository.instance
|
27
28
|
end
|
28
29
|
|
29
30
|
def [](key)
|
data/lib/fedora/connection.rb
CHANGED
@@ -1,64 +1,14 @@
|
|
1
1
|
require "base64"
|
2
|
+
gem 'multipart-post'
|
3
|
+
require 'net/http/post/multipart'
|
2
4
|
require 'cgi'
|
3
5
|
require "mime/types"
|
4
6
|
require 'net/http'
|
5
7
|
require 'net/https'
|
6
8
|
|
7
|
-
# Add multipart/form-data support to net/http
|
8
|
-
#
|
9
|
-
# ==== Usage
|
10
|
-
# File.open(File.expand_path('script/test.png'), 'r') do |file|
|
11
|
-
# http = Net::HTTP.new('localhost', 3000)
|
12
|
-
# begin
|
13
|
-
# http.start do |http|
|
14
|
-
# request = Net::HTTP::Post.new('/your/url/here')
|
15
|
-
# request.set_multipart_data(:file => file, :title => 'test.png')
|
16
|
-
# response = http.request(request)
|
17
|
-
# puts response
|
18
|
-
# end
|
19
|
-
# rescue Net::HTTPServerException => e
|
20
|
-
# p e
|
21
|
-
# end
|
22
|
-
# end
|
23
|
-
module Fedora::Multipart
|
24
|
-
def set_multipart_data(param_hash={})
|
25
|
-
mime_type = param_hash.delete(:content_type)
|
26
|
-
boundary_token = [Array.new(8) {rand(256)}].join
|
27
|
-
self.content_type = "multipart/form-data; boundary=#{boundary_token}"
|
28
|
-
boundary_marker = "--#{boundary_token}\r\n"
|
29
|
-
self.body = param_hash.map { |param_name, param_value|
|
30
|
-
boundary_marker + case param_value
|
31
|
-
when File then file_to_multipart(param_name, param_value, mime_type)
|
32
|
-
when String then text_to_multipart(param_name, param_value, mime_type)
|
33
|
-
else ""
|
34
|
-
end
|
35
|
-
}.join('') + "--#{boundary_token}--\r\n"
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
def file_to_multipart(key,file, mime_type = nil)
|
40
|
-
filename = File.basename(file.path)
|
41
|
-
mime_types = MIME::Types.of(filename)
|
42
|
-
mime_type ||= mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
|
43
|
-
part = %Q{Content-Disposition: form-data; name="#{key}"; filename="#{filename}"\r\n}
|
44
|
-
part += "Content-Transfer-Encoding: binary\r\n"
|
45
|
-
part += "Content-Type: #{mime_type}\r\n\r\n#{file.read}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def text_to_multipart(key,value)
|
49
|
-
"Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n#{value}\r\n"
|
50
|
-
end
|
51
|
-
end
|
52
9
|
|
53
|
-
class Net::HTTP::Post
|
54
|
-
include Fedora::Multipart
|
55
|
-
end
|
56
|
-
|
57
|
-
class Net::HTTP::Put
|
58
|
-
include Fedora::Multipart
|
59
|
-
end
|
60
10
|
|
61
|
-
module
|
11
|
+
module Fedora
|
62
12
|
# This class is based on ActiveResource::Connection so MIT license applies.
|
63
13
|
class ConnectionError < StandardError # :nodoc:
|
64
14
|
attr_reader :response
|
@@ -110,7 +60,7 @@ module RubyFedora
|
|
110
60
|
# This class is used by ActiveResource::Base to interface with REST
|
111
61
|
# services.
|
112
62
|
class Connection
|
113
|
-
attr_reader :site
|
63
|
+
attr_reader :site, :surrogate
|
114
64
|
attr_accessor :format
|
115
65
|
|
116
66
|
class << self
|
@@ -121,10 +71,11 @@ module RubyFedora
|
|
121
71
|
|
122
72
|
# The +site+ parameter is required and will set the +site+
|
123
73
|
# attribute to the URI for the remote resource service.
|
124
|
-
def initialize(site, format = ActiveResource::Formats[:xml])
|
74
|
+
def initialize(site, format = ActiveResource::Formats[:xml], surrogate=nil)
|
125
75
|
raise ArgumentError, 'Missing site URI' unless site
|
126
76
|
self.site = site
|
127
77
|
self.format = format
|
78
|
+
@surrogate=surrogate
|
128
79
|
end
|
129
80
|
|
130
81
|
# Set URI for remote service.
|
@@ -144,97 +95,116 @@ module RubyFedora
|
|
144
95
|
request(:delete, path, build_request_headers(headers))
|
145
96
|
end
|
146
97
|
|
147
|
-
|
148
|
-
# Used to update resources.
|
149
|
-
def put(path, body = '', headers = {})
|
150
|
-
if body.is_a?(File)
|
151
|
-
multipart_request(Net::HTTP::Put.new(path, build_request_headers(headers)), body, headers)
|
152
|
-
else
|
153
|
-
request(:put, path, body.to_s, build_request_headers(headers))
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# Execute a POST request.
|
158
|
-
# Used to create new resources.
|
159
|
-
def post(path, body = '', headers = {})
|
160
|
-
if body.is_a?(File)
|
161
|
-
multipart_request(Net::HTTP::Post.new(path, build_request_headers(headers)), body, headers)
|
162
|
-
else
|
163
|
-
request(:post, path, body.to_s, build_request_headers(headers))
|
164
|
-
end
|
165
|
-
end
|
98
|
+
|
166
99
|
|
167
100
|
def raw_get(path, headers = {})
|
168
101
|
request(:get, path, build_request_headers(headers))
|
169
102
|
end
|
103
|
+
def post(path, body='', headers={})
|
104
|
+
do_method(:post, path, body, headers)
|
105
|
+
end
|
106
|
+
def put( path, body='', headers={})
|
107
|
+
do_method(:put, path, body, headers)
|
108
|
+
end
|
170
109
|
|
171
110
|
private
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
111
|
+
def do_method(method, path, body = '', headers = {})
|
112
|
+
meth_map={:put=>Net::HTTP::Put::Multipart, :post=>Net::HTTP::Post::Multipart}
|
113
|
+
raise "undefined method: #{method}" unless meth_map.has_key? method
|
114
|
+
headers = build_request_headers(headers)
|
115
|
+
if body.respond_to?(:read)
|
116
|
+
if body.respond_to?(:original_filename?)
|
117
|
+
filename = File.basename(body.original_filename)
|
118
|
+
io = UploadIO.new(body, mime_type,filename)
|
119
|
+
elsif body.path
|
120
|
+
filename = File.basename(body.path)
|
121
|
+
else
|
122
|
+
filename="NOFILE"
|
177
123
|
end
|
178
|
-
|
124
|
+
mime_types = MIME::Types.of(filename)
|
125
|
+
mime_type ||= mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
|
126
|
+
|
127
|
+
io = nil
|
128
|
+
if body.is_a?(File)
|
129
|
+
io = UploadIO.new(body.path,mime_type)
|
130
|
+
else
|
131
|
+
io =UploadIO.new(body, mime_type, filename)
|
132
|
+
end
|
133
|
+
|
134
|
+
req = meth_map[method].new(path, {:file=>io}, headers)
|
135
|
+
multipart_request(req)
|
136
|
+
else
|
137
|
+
request(method, path, body.to_s, headers)
|
179
138
|
end
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
139
|
+
end
|
140
|
+
def multipart_request(req)
|
141
|
+
result = nil
|
142
|
+
result = http.start do |conn|
|
143
|
+
conn.read_timeout=60600 #these can take a while
|
144
|
+
conn.request(req)
|
185
145
|
end
|
146
|
+
handle_response(result)
|
186
147
|
|
187
|
-
|
188
|
-
def handle_response(response)
|
189
|
-
case response.code.to_i
|
190
|
-
when 301,302
|
191
|
-
raise(Redirection.new(response))
|
192
|
-
when 200...400
|
193
|
-
response
|
194
|
-
when 400
|
195
|
-
raise(BadRequest.new(response))
|
196
|
-
when 401
|
197
|
-
raise(UnauthorizedAccess.new(response))
|
198
|
-
when 403
|
199
|
-
raise(ForbiddenAccess.new(response))
|
200
|
-
when 404
|
201
|
-
raise(ResourceNotFound.new(response))
|
202
|
-
when 405
|
203
|
-
raise(MethodNotAllowed.new(response))
|
204
|
-
when 409
|
205
|
-
raise(ResourceConflict.new(response))
|
206
|
-
when 422
|
207
|
-
raise(ResourceInvalid.new(response))
|
208
|
-
when 401...500
|
209
|
-
raise(ClientError.new(response))
|
210
|
-
when 500...600
|
211
|
-
raise(ServerError.new(response))
|
212
|
-
else
|
213
|
-
raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
|
214
|
-
end
|
215
|
-
end
|
148
|
+
end
|
216
149
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
|
223
|
-
http
|
224
|
-
end
|
150
|
+
# Makes request to remote service.
|
151
|
+
def request(method, path, *arguments)
|
152
|
+
result = http.send(method, path, *arguments)
|
153
|
+
handle_response(result)
|
154
|
+
end
|
225
155
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
156
|
+
# Handles response and error codes from remote service.
|
157
|
+
def handle_response(response)
|
158
|
+
case response.code.to_i
|
159
|
+
when 301,302
|
160
|
+
raise(Redirection.new(response))
|
161
|
+
when 200...400
|
162
|
+
response
|
163
|
+
when 400
|
164
|
+
raise(BadRequest.new(response))
|
165
|
+
when 401
|
166
|
+
raise(UnauthorizedAccess.new(response))
|
167
|
+
when 403
|
168
|
+
raise(ForbiddenAccess.new(response))
|
169
|
+
when 404
|
170
|
+
raise(ResourceNotFound.new(response))
|
171
|
+
when 405
|
172
|
+
raise(MethodNotAllowed.new(response))
|
173
|
+
when 409
|
174
|
+
raise(ResourceConflict.new(response))
|
175
|
+
when 422
|
176
|
+
raise(ResourceInvalid.new(response))
|
177
|
+
when 401...500
|
178
|
+
raise(ClientError.new(response))
|
179
|
+
when 500...600
|
180
|
+
raise(ServerError.new(response))
|
181
|
+
else
|
182
|
+
raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
|
238
183
|
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Creates new Net::HTTP instance for communication with
|
187
|
+
# remote service and resources.
|
188
|
+
def http
|
189
|
+
http = Net::HTTP.new(@site.host, @site.port)
|
190
|
+
http.use_ssl = @site.is_a?(URI::HTTPS)
|
191
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
|
192
|
+
http
|
193
|
+
end
|
194
|
+
|
195
|
+
def default_header
|
196
|
+
@default_header ||= { 'Content-Type' => format.mime_type }
|
197
|
+
end
|
198
|
+
|
199
|
+
# Builds headers for request to remote service.
|
200
|
+
def build_request_headers(headers)
|
201
|
+
headers.merge!({"From"=>surrogate}) if @surrogate
|
202
|
+
authorization_header.update(default_header).update(headers)
|
203
|
+
end
|
204
|
+
|
205
|
+
# Sets authorization header; authentication information is pulled from credentials provided with site URI.
|
206
|
+
def authorization_header
|
207
|
+
(@site.user || @site.password ? { 'Authorization' => 'Basic ' + ["#{@site.user}:#{ @site.password}"].pack('m').delete("\r\n") } : {})
|
208
|
+
end
|
239
209
|
end
|
240
210
|
end
|