collectionspace-client 0.1.5 → 0.14.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 +4 -4
- data/.github/workflows/publish.yml +42 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +8 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -0
- data/README.md +19 -65
- data/Rakefile +44 -3
- data/bin/console +26 -0
- data/bin/rspec +29 -0
- data/collectionspace-client.gemspec +21 -19
- data/examples/demo.rb +14 -13
- data/examples/media_with_external_file.rb +20 -18
- data/examples/purge_empty_vocabs.rb +22 -0
- data/examples/reports.rb +178 -0
- data/examples/search.rb +25 -58
- data/examples/update_password.rb +3 -0
- data/lib/collectionspace/client/client.rb +19 -14
- data/lib/collectionspace/client/configuration.rb +16 -17
- data/lib/collectionspace/client/helpers.rb +145 -99
- data/lib/collectionspace/client/refname.rb +114 -0
- data/lib/collectionspace/client/request.rb +17 -13
- data/lib/collectionspace/client/response.rb +15 -10
- data/lib/collectionspace/client/search.rb +12 -7
- data/lib/collectionspace/client/service.rb +198 -0
- data/lib/collectionspace/client/template.rb +26 -0
- data/lib/collectionspace/client/templates/reindex_by_csids.xml.erb +10 -0
- data/lib/collectionspace/client/templates/reindex_by_doctype.xml.erb +5 -0
- data/lib/collectionspace/client/templates/reindex_full_text.xml.erb +51 -0
- data/lib/collectionspace/client/templates/report.xml.erb +16 -0
- data/lib/collectionspace/client/templates/reset_media_blob.xml.erb +6 -0
- data/lib/collectionspace/client/version.rb +3 -1
- data/lib/collectionspace/client.rb +20 -11
- metadata +64 -9
- data/examples/export.rb +0 -31
- data/examples/purge-empty-vocabularies.rb +0 -17
data/examples/search.rb
CHANGED
@@ -1,67 +1,34 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __dir__)
|
2
4
|
require 'awesome_print'
|
3
5
|
require 'collectionspace/client'
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
path: "collectionobjects",
|
11
|
-
type: "collectionobjects_common",
|
12
|
-
field: 'titleGroupList/*1/title',
|
13
|
-
expression: "ILIKE '%blue%'",
|
14
|
-
}
|
15
|
-
|
16
|
-
query = CollectionSpace::Search.new.from_hash search_args
|
17
|
-
ap client.search(query).parsed
|
7
|
+
config = CollectionSpace::Configuration.new(
|
8
|
+
base_uri: 'https://core.dev.collectionspace.org/cspace-services',
|
9
|
+
username: 'admin@core.collectionspace.org',
|
10
|
+
password: 'Administrator'
|
11
|
+
)
|
18
12
|
|
19
|
-
|
20
|
-
|
21
|
-
# assume retrieved for collectionobject i.e.: AttributeMap.where(type: 'collectionobject')
|
22
|
-
attribute_map = [
|
23
|
-
{ field: 'title', key: 'collectionobjects_common', nested_key: 'title', with: nil },
|
24
|
-
{ field: 'title_type', key: 'collectionobjects_common', nested_key: 'titleType', with: nil },
|
25
|
-
{ field: 'display_date', key: 'collectionobjects_common', nested_key: 'dateDisplayDate', with: nil },
|
26
|
-
{ field: 'object_production_person_group', key: 'collectionobjects_common', nested_key: 'objectProductionPersonGroup', with: 'objectProductionPerson' },
|
27
|
-
{ field: 'content_persons', key: 'collectionobjects_common', nested_key: 'contentPersons', with: 'contentPerson' },
|
28
|
-
{ field: 'responsible_department', key: 'collectionobjects_common', nested_key: 'responsibleDepartment', with: nil },
|
29
|
-
{ field: 'created_by', key: 'collectionspace_core', nested_key: 'createdBy', with: nil },
|
30
|
-
{ field: 'created_at', key: 'collectionspace_core', nested_key: 'createdAt', with: nil },
|
31
|
-
{ field: 'updated_at', key: 'collectionspace_core', nested_key: 'updatedAt', with: nil },
|
32
|
-
]
|
13
|
+
client = CollectionSpace::Client.new(config)
|
33
14
|
|
34
15
|
search_args = {
|
35
|
-
path:
|
36
|
-
|
37
|
-
field: '
|
38
|
-
expression: "
|
16
|
+
path: 'groups',
|
17
|
+
namespace: 'groups_common',
|
18
|
+
field: 'title',
|
19
|
+
expression: "ILIKE '%D%'"
|
39
20
|
}
|
40
21
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
attributes = {}
|
50
|
-
attribute_map.each do |map|
|
51
|
-
if map[:with]
|
52
|
-
as = client.deep_find(record, map[:key], map[:nested_key])
|
53
|
-
values = []
|
54
|
-
if as.is_a? Array
|
55
|
-
values = as.map { |a| client.strip_refname( client.deep_find(a, map[:with]) ) }
|
56
|
-
elsif as.is_a? Hash and as[ map[:with] ]
|
57
|
-
values = as[ map[:with] ].is_a?(Array) ? as[ map[:with] ].map { |a| client.strip_refname(a) } : [ client.strip_refname(as[ map[:with] ]) ]
|
58
|
-
end
|
59
|
-
attributes[map[:field]] = values
|
60
|
-
else
|
61
|
-
attributes[map[:field]] = client.deep_find(record, map[:key], map[:nested_key])
|
62
|
-
end
|
63
|
-
end
|
64
|
-
# PRINT REFORMATTED RESULTS
|
65
|
-
ap attributes
|
22
|
+
puts 'Search: %D'
|
23
|
+
response = client.search(
|
24
|
+
CollectionSpace::Search.new.from_hash(search_args),
|
25
|
+
{ sortBy: CollectionSpace::Search::DEFAULT_SORT }
|
26
|
+
)
|
27
|
+
if response.result.success?
|
28
|
+
response.parsed['abstract_common_list']['list_item'].map do |i|
|
29
|
+
puts i['uri']
|
66
30
|
end
|
67
|
-
end
|
31
|
+
end
|
32
|
+
|
33
|
+
puts 'Object and authority term searches have been moved to spec.'
|
34
|
+
puts 'See helpers_spec.rb examples describing find'
|
@@ -1,12 +1,16 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CollectionSpace
|
4
|
+
# CollectionSpace client
|
3
5
|
class Client
|
4
|
-
include DeepFind
|
5
6
|
include Helpers
|
6
7
|
attr_reader :config
|
7
8
|
|
8
9
|
def initialize(config = Configuration.new)
|
9
|
-
|
10
|
+
unless config.is_a? CollectionSpace::Configuration
|
11
|
+
raise CollectionSpace::ArgumentError, 'Invalid configuration object'
|
12
|
+
end
|
13
|
+
|
10
14
|
@config = config
|
11
15
|
end
|
12
16
|
|
@@ -14,15 +18,14 @@ module CollectionSpace
|
|
14
18
|
request 'GET', path, options
|
15
19
|
end
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
request 'POST', path, { body: payload }.merge(additional_options)
|
21
|
+
def post(path, payload, options = {})
|
22
|
+
check_payload(payload)
|
23
|
+
request 'POST', path, { body: payload }.merge(options)
|
21
24
|
end
|
22
25
|
|
23
|
-
def put(path, payload)
|
24
|
-
|
25
|
-
request 'PUT', path, { body: payload }
|
26
|
+
def put(path, payload, options = {})
|
27
|
+
check_payload(payload)
|
28
|
+
request 'PUT', path, { body: payload }.merge(options)
|
26
29
|
end
|
27
30
|
|
28
31
|
def delete(path)
|
@@ -31,12 +34,14 @@ module CollectionSpace
|
|
31
34
|
|
32
35
|
private
|
33
36
|
|
37
|
+
def check_payload(payload)
|
38
|
+
errors = Nokogiri::XML(payload).errors
|
39
|
+
raise CollectionSpace::PayloadError, errors if errors.any?
|
40
|
+
end
|
41
|
+
|
34
42
|
def request(method, path, options = {})
|
35
43
|
sleep config.throttle
|
36
|
-
|
37
|
-
Response.new result
|
44
|
+
Response.new(Request.new(config, method, path, options).execute)
|
38
45
|
end
|
39
|
-
|
40
46
|
end
|
41
|
-
|
42
47
|
end
|
@@ -1,28 +1,27 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CollectionSpace
|
4
|
+
# CollectionSpace configuration
|
3
5
|
class Configuration
|
6
|
+
DEFAULTS = {
|
7
|
+
base_uri: nil,
|
8
|
+
username: nil,
|
9
|
+
password: nil,
|
10
|
+
page_size: 25,
|
11
|
+
include_deleted: false,
|
12
|
+
throttle: 0,
|
13
|
+
verify_ssl: true
|
14
|
+
}.freeze
|
4
15
|
|
5
|
-
|
6
|
-
{
|
7
|
-
base_uri: "https://core.collectionspace.org/cspace-services",
|
8
|
-
username: "admin@core.collectionspace.org",
|
9
|
-
password: "Administrator",
|
10
|
-
page_size: 50,
|
11
|
-
include_deleted: false,
|
12
|
-
throttle: 0,
|
13
|
-
verify_ssl: true,
|
14
|
-
}
|
15
|
-
end
|
16
|
+
attr_accessor :base_uri, :username, :password, :page_size, :include_deleted, :throttle, :verify_ssl
|
16
17
|
|
17
18
|
def initialize(settings = {})
|
18
|
-
settings =
|
19
|
+
settings = DEFAULTS.merge(settings)
|
19
20
|
settings.each do |property, value|
|
20
|
-
next unless
|
21
|
+
next unless DEFAULTS.key?(property)
|
22
|
+
|
21
23
|
instance_variable_set("@#{property}", value)
|
22
|
-
self.class.send(:attr_accessor, property)
|
23
24
|
end
|
24
25
|
end
|
25
|
-
|
26
26
|
end
|
27
|
-
|
28
27
|
end
|
@@ -1,122 +1,168 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
deep_find(found, nested_key)
|
12
|
-
else
|
13
|
-
found
|
14
|
-
end
|
15
|
-
end
|
3
|
+
module CollectionSpace
|
4
|
+
# Helper methods for client requests
|
5
|
+
module Helpers
|
6
|
+
# add / update batch job
|
7
|
+
def add_batch_job(name, template, data = {}, params = { pgSz: 100 })
|
8
|
+
payload = Template.process(template, data)
|
9
|
+
response = get('batch', { query: params })
|
10
|
+
create_or_update(response, 'batch', 'name', name, payload)
|
16
11
|
end
|
17
|
-
end
|
18
12
|
|
19
|
-
|
13
|
+
# add / update reports
|
14
|
+
def add_report(data = {}, params = { pgSz: 100 })
|
15
|
+
payload = Template.process('report', data)
|
16
|
+
response = get('reports', { query: params })
|
17
|
+
create_or_update(response, 'reports', 'name', data[:name], payload)
|
18
|
+
end
|
20
19
|
|
21
20
|
# get ALL records at path by paging through record set
|
22
21
|
def all(path, options = {})
|
23
22
|
list_type, list_item = get_list_types(path)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
iterations = (count(path).to_f / config.page_size).ceil
|
24
|
+
return [] unless iterations.positive?
|
25
|
+
|
26
|
+
Enumerator::Lazy.new(0...iterations) do |yielder, i|
|
27
|
+
response = request('GET', path, options.merge(query: { pgNum: i }))
|
28
|
+
raise CollectionSpace::RequestError, response.result.body unless response.result.success?
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
items_in_page = response.parsed[list_type].fetch('itemsInPage', 0).to_i
|
31
|
+
list_items = items_in_page.positive? ? response.parsed[list_type][list_item] : []
|
32
|
+
list_items = [list_items] if items_in_page == 1
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
list_items.each { |item| yielder << item }
|
36
|
-
page += 1
|
37
|
-
end
|
38
|
-
end.lazy
|
34
|
+
yielder << list_items.shift until list_items.empty?
|
35
|
+
end
|
39
36
|
end
|
40
37
|
|
41
38
|
def count(path)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
# create blob record by external url
|
50
|
-
def post_blob_url(url)
|
51
|
-
raise ArgumentError.new("Invalid blob URL #{url}") unless URI.parse(url).scheme =~ /^https?/
|
52
|
-
request 'POST', "blobs", {
|
53
|
-
query: { "blobUri" => url },
|
54
|
-
}
|
55
|
-
end
|
56
|
-
|
57
|
-
def post_relationship(type_a, csid_a, type_b, csid_b)
|
58
|
-
# requires an erb template
|
59
|
-
# request 'POST', "relations", { body: payload }
|
60
|
-
# flip for reciprocal relationship
|
61
|
-
# request 'POST', "relations", { body: payload }
|
62
|
-
end
|
63
|
-
|
64
|
-
def search(query, options = {})
|
65
|
-
options = prepare_query(query, options)
|
66
|
-
request "GET", query.path, options
|
67
|
-
end
|
68
|
-
|
69
|
-
def search_all(query, options = {}, &block)
|
70
|
-
options = prepare_query(query, options)
|
71
|
-
all query.path, options, &block
|
72
|
-
end
|
73
|
-
|
74
|
-
def strip_refname(refname)
|
75
|
-
stripped = refname.match(/('.*')/)[0].delete("'") rescue ''
|
76
|
-
stripped
|
77
|
-
end
|
78
|
-
|
79
|
-
# parsed record and map to get restructured object
|
80
|
-
def to_object(record, attribute_map, stringify_keys = false)
|
81
|
-
attributes = {}
|
82
|
-
attribute_map.each do |map|
|
83
|
-
map = map.inject({}) { |memo,(k,v)| memo[k.to_s] = v; memo} if stringify_keys
|
84
|
-
if map["with"]
|
85
|
-
as = deep_find(record, map["key"], map["nested_key"])
|
86
|
-
values = []
|
87
|
-
if as.is_a? Array
|
88
|
-
values = as.map { |a| strip_refname( deep_find(a, map["with"]) ) }
|
89
|
-
elsif as.is_a? Hash and as[ map["with"] ]
|
90
|
-
values = as[ map["with"] ].is_a?(Array) ? as[ map["with"] ].map { |a| strip_refname(a) } : [ strip_refname(as[ map["with"] ]) ]
|
91
|
-
end
|
92
|
-
attributes[map["field"]] = values
|
93
|
-
else
|
94
|
-
attributes[map["field"]] = deep_find(record, map["key"], map["nested_key"])
|
95
|
-
end
|
96
|
-
end
|
97
|
-
attributes
|
39
|
+
list_type, = get_list_types(path)
|
40
|
+
response = request('GET', path, query: { pgNum: 0, pgSz: 1 })
|
41
|
+
raise CollectionSpace::RequestError, response.result.body unless response.result.success?
|
42
|
+
|
43
|
+
response.parsed[list_type]['totalItems'].to_i
|
98
44
|
end
|
99
45
|
|
100
|
-
|
46
|
+
# get the tenant domain from a system required top level authority (person)
|
47
|
+
def domain
|
48
|
+
path = 'personauthorities'
|
49
|
+
response = request('GET', path, query: { pgNum: 0, pgSz: 1 })
|
50
|
+
raise CollectionSpace::RequestError, response.result.body unless response.result.success?
|
51
|
+
|
52
|
+
refname = response.parsed.dig(*get_list_types(path), 'refName')
|
53
|
+
CollectionSpace::RefName.parse(refname)[:domain]
|
54
|
+
end
|
55
|
+
|
56
|
+
# find procedure or object by type and id
|
57
|
+
# find authority/vocab term by type, subtype, and refname
|
58
|
+
# rubocop:disable Metrics/ParameterLists
|
59
|
+
def find(type:, value:, subtype: nil, field: nil, schema: 'common', sort: nil, operator: '=')
|
60
|
+
service = CollectionSpace::Service.get(type: type, subtype: subtype)
|
61
|
+
field ||= service[:term] # this will be set if it is an authority or vocabulary, otherwise nil
|
62
|
+
field ||= service[:identifier]
|
63
|
+
search_args = CollectionSpace::Search.new.from_hash(
|
64
|
+
path: service[:path],
|
65
|
+
namespace: "#{service[:ns_prefix]}_#{schema}",
|
66
|
+
field: field,
|
67
|
+
expression: "#{operator} '#{value.gsub(/'/, '\\\\\'')}'"
|
68
|
+
)
|
69
|
+
search(search_args, sortBy: CollectionSpace::Search::DEFAULT_SORT)
|
70
|
+
end
|
71
|
+
# rubocop:enable Metrics/ParameterLists
|
72
|
+
|
73
|
+
# @param subject_csid [String] to be searched as `sbj` value
|
74
|
+
# @param object_csid [String] to be searched as `obj` value
|
75
|
+
# @param rel_type [String<'affects', 'hasBroader'>, nil] to be searched as `prd` value
|
76
|
+
def find_relation(subject_csid:, object_csid:, rel_type: nil)
|
77
|
+
if rel_type
|
78
|
+
get('relations', query: { 'sbj' => subject_csid, 'obj' => object_csid, 'prd' => rel_type })
|
79
|
+
else
|
80
|
+
warn(
|
81
|
+
"No rel_type specified, so multiple types of relations between #{subject_csid} and #{object_csid} may be returned",
|
82
|
+
uplevel: 1
|
83
|
+
)
|
84
|
+
get('relations', query: { 'sbj' => subject_csid, 'obj' => object_csid })
|
85
|
+
end
|
86
|
+
end
|
101
87
|
|
102
88
|
def get_list_types(path)
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
89
|
+
{
|
90
|
+
'accounts' => %w[accounts_common_list account_list_item],
|
91
|
+
'relations' => %w[relations_common_list relation_list_item]
|
92
|
+
}.fetch(path, %w[abstract_common_list list_item])
|
93
|
+
end
|
94
|
+
|
95
|
+
def reindex_full_text(doctype, csids = [])
|
96
|
+
if csids.any?
|
97
|
+
run_job(
|
98
|
+
'Reindex Full Text', :reindex_full_text, :reindex_by_csids, { doctype: doctype, csids: csids }
|
99
|
+
)
|
107
100
|
else
|
108
|
-
|
109
|
-
|
101
|
+
run_job(
|
102
|
+
'Reindex Full Text', :reindex_full_text, :reindex_by_doctype, { doctype: doctype }
|
103
|
+
)
|
110
104
|
end
|
111
|
-
return list_type, list_item
|
112
105
|
end
|
113
106
|
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
107
|
+
def reset_media_blob(id, url)
|
108
|
+
raise CollectionSpace::ArgumentError, "Not a valid url #{url}" unless URI.parse(url).instance_of? URI::HTTPS
|
109
|
+
|
110
|
+
response = find(type: 'media', value: id, field: 'identificationNumber')
|
111
|
+
raise CollectionSpace::RequestError, response.result.body unless response.result.success?
|
112
|
+
|
113
|
+
found = response.parsed
|
114
|
+
total = found['abstract_common_list']['totalItems'].to_i
|
115
|
+
raise CollectionSpace::NotFoundError, "Media #{id} not found" if total.zero?
|
116
|
+
raise CollectionSpace::DuplicateIdFound, "Found multiple media records for #{id}" unless total == 1
|
117
|
+
|
118
|
+
media_uri = found['abstract_common_list']['list_item']['uri']
|
119
|
+
blob_csid = found['abstract_common_list']['list_item']['blobCsid']
|
120
|
+
|
121
|
+
delete("/blobs/#{blob_csid}") if blob_csid
|
122
|
+
|
123
|
+
payload = Template.process(:reset_media_blob, { id: id })
|
124
|
+
put(media_uri, payload, query: { 'blobUri' => url })
|
118
125
|
end
|
119
126
|
|
120
|
-
|
127
|
+
def run_job(name, template, invoke_template, data = {})
|
128
|
+
payload = Template.process(invoke_template, data)
|
129
|
+
job = add_batch_job(name, template)
|
130
|
+
path = job.parsed['document']['collectionspace_core']['uri']
|
131
|
+
post(path, payload)
|
132
|
+
end
|
133
|
+
|
134
|
+
def search(query, params = {})
|
135
|
+
options = prepare_query(query, params)
|
136
|
+
request 'GET', query.path, options
|
137
|
+
end
|
138
|
+
|
139
|
+
def keyword_search(type:, value:, subtype: nil, sort: nil)
|
140
|
+
service = CollectionSpace::Service.get(type: type, subtype: subtype)
|
141
|
+
options = prepare_keyword_query(value, { sortBy: CollectionSpace::Search::DEFAULT_SORT })
|
142
|
+
request 'GET', service[:path], options
|
143
|
+
end
|
121
144
|
|
122
|
-
|
145
|
+
def service(type:, subtype: '')
|
146
|
+
CollectionSpace::Service.get(type: type, subtype: subtype)
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def create_or_update(response, path, property, value, payload)
|
152
|
+
list_type, item_type = get_list_types(path)
|
153
|
+
item = response.find(list_type, item_type, property, value)
|
154
|
+
path = item ? "#{path}/#{item['csid']}" : path
|
155
|
+
item ? put(path, payload) : post(path, payload)
|
156
|
+
end
|
157
|
+
|
158
|
+
def prepare_query(query, params = {})
|
159
|
+
query_string = "#{query.namespace}:#{query.field} #{query.expression}"
|
160
|
+
{ query: { as: query_string }.merge(params) }
|
161
|
+
end
|
162
|
+
|
163
|
+
def prepare_keyword_query(query, sort = {})
|
164
|
+
query_string = query.downcase.gsub(' ', '+')
|
165
|
+
{ query: { kw: query_string }.merge(sort) }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
module CollectionSpace
|
6
|
+
# CollectionSpace RefName
|
7
|
+
#
|
8
|
+
# There are four patterns we need to handle:
|
9
|
+
#
|
10
|
+
# - urn:cspace:domain:type:name(subtype)'label' : Top level authority/vocabulary
|
11
|
+
# - urn:cspace:domain:type:name(subtype):item:name(identifier)'label' : Authority/vocabulary term
|
12
|
+
# - urn:cspace:domain:type:id(identifier)'label' : Collectionobject
|
13
|
+
# - urn:cspace:domain:type:id(identifier) : Procedures, relations, blobs
|
14
|
+
class RefName
|
15
|
+
attr_reader :domain, :type, :subtype, :identifier, :label
|
16
|
+
|
17
|
+
def initialize(refname)
|
18
|
+
@refname = refname
|
19
|
+
@domain = nil
|
20
|
+
@type = nil
|
21
|
+
@subtype = nil
|
22
|
+
@identifier = nil
|
23
|
+
@label = nil
|
24
|
+
parse
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse
|
28
|
+
scanner = StringScanner.new(@refname)
|
29
|
+
scanner.skip('urn:cspace:')
|
30
|
+
@domain = to_next_colon(scanner)
|
31
|
+
@type = to_next_colon(scanner)
|
32
|
+
|
33
|
+
case next_segment(scanner)
|
34
|
+
when 'name'
|
35
|
+
set_subtype(scanner)
|
36
|
+
when 'id'
|
37
|
+
set_identifier(scanner)
|
38
|
+
end
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# Convenience class method, so new instance of RefName does not have to be instantiated in order to parse
|
44
|
+
#
|
45
|
+
# As of v0.13.1, return_class is added and defaults to nil for backward compatibility
|
46
|
+
# Eventually this default will be deprecated, and a parsed RefName object will be returned as the default.
|
47
|
+
# Any new code written using this method should set the return_class parameter to :refname_obj
|
48
|
+
def self.parse(refname, return_class = nil)
|
49
|
+
return_class == :refname_obj ? new(refname) : new(refname).to_h
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns a parsed RefName object as a hash.
|
53
|
+
# As of v0.13.1, this is equivalent to calling RefName.parse('refnamevalue', :hash)
|
54
|
+
# This was added to simplify the process of updating existing code that expects a hash when calling RefName.parse
|
55
|
+
def to_h
|
56
|
+
{
|
57
|
+
domain: domain,
|
58
|
+
type: type,
|
59
|
+
subtype: subtype,
|
60
|
+
identifier: identifier,
|
61
|
+
label: label
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def next_segment(scanner)
|
68
|
+
segment = scanner.check_until(/\(/)
|
69
|
+
return nil unless segment
|
70
|
+
|
71
|
+
segment.delete_suffix('(')
|
72
|
+
end
|
73
|
+
|
74
|
+
def set_identifier(scanner)
|
75
|
+
scanner.skip('id(')
|
76
|
+
@identifier = to_end_paren(scanner)
|
77
|
+
return if scanner.eos?
|
78
|
+
|
79
|
+
set_label(scanner)
|
80
|
+
end
|
81
|
+
|
82
|
+
def set_label(scanner)
|
83
|
+
scanner.skip("'")
|
84
|
+
@label = scanner.rest.delete_suffix("'")
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_subtype(scanner)
|
88
|
+
scanner.skip('name(')
|
89
|
+
@subtype = to_end_paren(scanner)
|
90
|
+
|
91
|
+
case next_segment(scanner)
|
92
|
+
when nil
|
93
|
+
set_label(scanner)
|
94
|
+
when ':item:name'
|
95
|
+
set_term_identifier(scanner)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_term_identifier(scanner)
|
100
|
+
scanner.skip(':item:name(')
|
101
|
+
@identifier = to_end_paren(scanner)
|
102
|
+
scanner.skip("'")
|
103
|
+
set_label(scanner)
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_end_paren(scanner)
|
107
|
+
scanner.scan_until(/\)/).delete_suffix(')')
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_next_colon(scanner)
|
111
|
+
scanner.scan_until(/:/).delete_suffix(':')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CollectionSpace
|
4
|
+
# CollectionSpace request
|
3
5
|
class Request
|
4
6
|
include HTTParty
|
5
7
|
attr_reader :config, :headers, :method, :path, :options
|
@@ -9,41 +11,43 @@ module CollectionSpace
|
|
9
11
|
delete: {},
|
10
12
|
get: {},
|
11
13
|
post: {
|
12
|
-
|
13
|
-
|
14
|
+
'Content-Type' => 'application/xml',
|
15
|
+
'Content-Length' => 'nnnn'
|
14
16
|
},
|
15
17
|
put: {
|
16
|
-
|
17
|
-
|
18
|
+
'Content-Type' => 'application/xml',
|
19
|
+
'Content-Length' => 'nnnn'
|
18
20
|
}
|
19
21
|
}
|
20
22
|
headers[method]
|
21
23
|
end
|
22
24
|
|
23
|
-
def initialize(config, method =
|
25
|
+
def initialize(config, method = 'GET', path = '', options = {})
|
24
26
|
@config = config
|
25
27
|
@method = method.downcase.to_sym
|
26
|
-
@path = path.gsub(
|
28
|
+
@path = path.gsub(%r{^/}, '')
|
27
29
|
|
28
30
|
@auth = {
|
29
31
|
username: config.username,
|
30
|
-
password: config.password
|
32
|
+
password: config.password
|
31
33
|
}
|
32
34
|
|
35
|
+
headers = default_headers(@method).merge(options.fetch(:headers, {}))
|
33
36
|
@options = options
|
34
37
|
@options[:basic_auth] = @auth
|
35
|
-
@options[:headers] =
|
38
|
+
@options[:headers] = headers
|
36
39
|
@options[:verify] = config.verify_ssl
|
37
|
-
@options[:query] =
|
40
|
+
@options[:query] = options.fetch(:query, {})
|
38
41
|
|
39
42
|
self.class.base_uri config.base_uri
|
40
|
-
self.class.default_params
|
43
|
+
self.class.default_params(
|
44
|
+
wf_deleted: config.include_deleted,
|
45
|
+
pgSz: config.page_size
|
46
|
+
)
|
41
47
|
end
|
42
48
|
|
43
49
|
def execute
|
44
50
|
self.class.send method, "/#{path}", options
|
45
51
|
end
|
46
|
-
|
47
52
|
end
|
48
|
-
|
49
53
|
end
|