collectionspace-client 0.3.0 → 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.
@@ -1,6 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CollectionSpace
2
4
  # Helper methods for client requests
3
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)
11
+ end
12
+
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
19
+
4
20
  # get ALL records at path by paging through record set
5
21
  def all(path, options = {})
6
22
  list_type, list_item = get_list_types(path)
@@ -9,9 +25,7 @@ module CollectionSpace
9
25
 
10
26
  Enumerator::Lazy.new(0...iterations) do |yielder, i|
11
27
  response = request('GET', path, options.merge(query: { pgNum: i }))
12
- unless response.result.success?
13
- raise CollectionSpace::RequestError, response.result.body
14
- end
28
+ raise CollectionSpace::RequestError, response.result.body unless response.result.success?
15
29
 
16
30
  items_in_page = response.parsed[list_type].fetch('itemsInPage', 0).to_i
17
31
  list_items = items_in_page.positive? ? response.parsed[list_type][list_item] : []
@@ -24,24 +38,131 @@ module CollectionSpace
24
38
  def count(path)
25
39
  list_type, = get_list_types(path)
26
40
  response = request('GET', path, query: { pgNum: 0, pgSz: 1 })
27
- response.parsed[list_type]['totalItems'].to_i if response.result.success?
41
+ raise CollectionSpace::RequestError, response.result.body unless response.result.success?
42
+
43
+ response.parsed[list_type]['totalItems'].to_i
44
+ end
45
+
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
28
86
  end
29
87
 
30
88
  def get_list_types(path)
31
89
  {
32
90
  'accounts' => %w[accounts_common_list account_list_item],
33
- 'relations' => %w[relations_common_list relation_list_item],
91
+ 'relations' => %w[relations_common_list relation_list_item]
34
92
  }.fetch(path, %w[abstract_common_list list_item])
35
93
  end
36
94
 
37
- def prepare_query(query, options = {})
38
- query_string = "#{query.type}:#{query.field} #{query.expression}"
39
- options.merge(query: { as: query_string })
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
+ )
100
+ else
101
+ run_job(
102
+ 'Reindex Full Text', :reindex_full_text, :reindex_by_doctype, { doctype: doctype }
103
+ )
104
+ end
40
105
  end
41
106
 
42
- def search(query, options = {})
43
- options = prepare_query(query, options)
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 })
125
+ end
126
+
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)
44
136
  request 'GET', query.path, options
45
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
144
+
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
46
167
  end
47
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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CollectionSpace
2
4
  # CollectionSpace request
3
5
  class Request
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CollectionSpace
2
4
  # CollectionSpace response
3
5
  class Response
@@ -10,5 +12,14 @@ module CollectionSpace
10
12
  body = result.body
11
13
  @xml = @result.success? && body =~ /<?xml/ ? Nokogiri::XML(body) : nil
12
14
  end
15
+
16
+ def find(list_type, item_type, property, value)
17
+ total = parsed[list_type]['totalItems'].to_i
18
+ return unless total.positive?
19
+
20
+ list = parsed[list_type][item_type]
21
+ list = [list] if total == 1 # wrap if single item
22
+ list.find { |i| i[property] == value }
23
+ end
13
24
  end
14
25
  end
@@ -1,11 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CollectionSpace
2
4
  # CollectionSpace search
3
5
  class Search
4
- attr_accessor :path, :type, :field, :expression
6
+ attr_accessor :path, :namespace, :field, :expression
7
+
8
+ DEFAULT_SORT = 'collectionspace_core:updatedAt DESC'
5
9
 
6
- def initialize(path: nil, type: nil, field: nil, expression: nil)
10
+ def initialize(path: nil, namespace: nil, field: nil, expression: nil)
7
11
  @path = path
8
- @type = type
12
+ @namespace = namespace
9
13
  @field = field
10
14
  @expression = expression
11
15
  end
@@ -0,0 +1,198 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CollectionSpace
4
+ # CollectionSpace service
5
+ class Service
6
+ TERM_SUFFIX = 'TermGroupList/0/termDisplayName'
7
+ def self.get(type:, subtype: '')
8
+ {
9
+ 'acquisitions' => {
10
+ identifier: 'acquisitionReferenceNumber',
11
+ ns_prefix: 'acquisitions',
12
+ path: 'acquisitions',
13
+ term: nil
14
+ },
15
+ 'citationauthorities' => {
16
+ identifier: 'shortIdentifier',
17
+ ns_prefix: 'citations',
18
+ path: "citationauthorities/urn:cspace:name(#{subtype})/items",
19
+ term: "citation#{TERM_SUFFIX}"
20
+ },
21
+ 'claims' => {
22
+ identifier: 'claimNumber',
23
+ ns_prefix: 'claims',
24
+ path: 'claims',
25
+ term: nil
26
+ },
27
+ 'collectionobjects' => {
28
+ identifier: 'objectNumber',
29
+ ns_prefix: 'collectionobjects',
30
+ path: 'collectionobjects',
31
+ term: nil
32
+ },
33
+ 'conceptauthorities' => {
34
+ identifier: 'shortIdentifier',
35
+ ns_prefix: 'concepts',
36
+ path: "conceptauthorities/urn:cspace:name(#{subtype})/items",
37
+ term: "concept#{TERM_SUFFIX}"
38
+ },
39
+ 'conditionchecks' => {
40
+ identifier: 'conditionCheckRefNumber',
41
+ ns_prefix: 'conditionchecks',
42
+ path: 'conditionchecks',
43
+ term: nil
44
+ },
45
+ 'conservation' => {
46
+ identifier: 'conservationNumber',
47
+ ns_prefix: 'conservation',
48
+ path: 'conservation',
49
+ term: nil
50
+ },
51
+ 'exhibitions' => {
52
+ identifier: 'exhibitionNumber',
53
+ ns_prefix: 'exhibitions',
54
+ path: 'exhibitions',
55
+ term: nil
56
+ },
57
+ 'groups' => {
58
+ identifier: 'title',
59
+ ns_prefix: 'groups',
60
+ path: 'groups',
61
+ term: nil
62
+ },
63
+ 'insurances' => {
64
+ identifier: 'insuranceIndemnityReferenceNumber',
65
+ ns_prefix: 'insurances',
66
+ path: 'insurances',
67
+ term: nil
68
+ },
69
+ 'intakes' => {
70
+ identifier: 'entryNumber',
71
+ ns_prefix: 'intakes',
72
+ path: 'intakes',
73
+ term: nil
74
+ },
75
+ 'loansin' => {
76
+ identifier: 'loanInNumber',
77
+ ns_prefix: 'loansin',
78
+ path: 'loansin',
79
+ term: nil
80
+ },
81
+ 'loansout' => {
82
+ identifier: 'loanOutNumber',
83
+ ns_prefix: 'loansout',
84
+ path: 'loansout',
85
+ term: nil
86
+ },
87
+ 'locationauthorities' => {
88
+ identifier: 'shortIdentifier',
89
+ ns_prefix: 'locations',
90
+ path: "locationauthorities/urn:cspace:name(#{subtype})/items",
91
+ term: "loc#{TERM_SUFFIX}"
92
+ },
93
+ 'materialauthorities' => {
94
+ identifier: 'shortIdentifier',
95
+ ns_prefix: 'materials',
96
+ path: "materialauthorities/urn:cspace:name(#{subtype})/items",
97
+ term: "material#{TERM_SUFFIX}"
98
+ },
99
+ 'media' => {
100
+ identifier: 'identificationNumber',
101
+ ns_prefix: 'media',
102
+ path: 'media',
103
+ term: nil
104
+ },
105
+ 'movements' => {
106
+ identifier: 'movementReferenceNumber',
107
+ ns_prefix: 'movements',
108
+ path: 'movements',
109
+ term: nil
110
+ },
111
+ 'objectexit' => {
112
+ identifier: 'exitNumber',
113
+ ns_prefix: 'objectexit',
114
+ path: 'objectexit',
115
+ term: nil
116
+ },
117
+ 'orgauthorities' => {
118
+ identifier: 'shortIdentifier',
119
+ ns_prefix: 'organizations',
120
+ path: "orgauthorities/urn:cspace:name(#{subtype})/items",
121
+ term: "org#{TERM_SUFFIX}"
122
+ },
123
+ 'osteology' => {
124
+ identifier: 'InventoryID',
125
+ ns_prefix: 'osteology',
126
+ path: 'osteology',
127
+ term: nil
128
+ },
129
+ 'personauthorities' => {
130
+ identifier: 'shortIdentifier',
131
+ ns_prefix: 'persons',
132
+ path: "personauthorities/urn:cspace:name(#{subtype})/items",
133
+ term: "person#{TERM_SUFFIX}"
134
+ },
135
+ 'placeauthorities' => {
136
+ identifier: 'shortIdentifier',
137
+ ns_prefix: 'places',
138
+ path: "placeauthorities/urn:cspace:name(#{subtype})/items",
139
+ term: "place#{TERM_SUFFIX}"
140
+ },
141
+ 'pottags' => {
142
+ identifier: 'potTagNumber',
143
+ ns_prefix: 'pottags',
144
+ path: 'pottags',
145
+ term: nil
146
+ },
147
+ 'propagations' => {
148
+ identifier: 'propNumber',
149
+ ns_prefix: 'propagations',
150
+ path: 'propagations',
151
+ term: nil
152
+ },
153
+ 'relations' => {
154
+ identifier: 'csid',
155
+ ns_prefix: 'relations',
156
+ path: 'relations',
157
+ term: nil
158
+ },
159
+ 'taxonomyauthority' => {
160
+ identifier: 'shortIdentifier',
161
+ ns_prefix: 'taxon',
162
+ path: "taxonomyauthority/urn:cspace:name(#{subtype})/items",
163
+ term: "taxon#{TERM_SUFFIX}"
164
+ },
165
+ 'transports' => {
166
+ identifier: 'transportReferenceNumber',
167
+ ns_prefix: 'transports',
168
+ path: 'transports',
169
+ term: nil
170
+ },
171
+ 'uoc' => {
172
+ identifier: 'referenceNumber',
173
+ ns_prefix: 'uoc',
174
+ path: 'uoc',
175
+ term: nil
176
+ },
177
+ 'valuationcontrols' => {
178
+ identifier: 'valuationcontrolRefNumber',
179
+ ns_prefix: 'valuationcontrols',
180
+ path: 'valuationcontrols',
181
+ term: nil
182
+ },
183
+ 'vocabularies' => {
184
+ identifier: 'shortIdentifier',
185
+ ns_prefix: 'vocabularyitems',
186
+ path: "vocabularies/urn:cspace:name(#{subtype})/items",
187
+ term: 'displayName'
188
+ },
189
+ 'workauthorities' => {
190
+ identifier: 'shortIdentifier',
191
+ ns_prefix: 'works',
192
+ path: "workauthorities/urn:cspace:name(#{subtype})/items",
193
+ term: "work#{TERM_SUFFIX}"
194
+ }
195
+ }.fetch(type)
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CollectionSpace
4
+ module Template
5
+ def self.list
6
+ Dir.glob File.join(templates_path, '*.erb')
7
+ end
8
+
9
+ def self.process(template, data)
10
+ t = ERB.new(read(template))
11
+ r = t.result(binding).gsub(/\n+/, "\n")
12
+ Nokogiri::XML.parse(r).to_xml
13
+ end
14
+
15
+ def self.read(file)
16
+ File.read("#{templates_path}/#{file}.xml.erb")
17
+ end
18
+
19
+ def self.templates_path
20
+ ENV.fetch(
21
+ 'COLLECTIONSPACE_CLIENT_TEMPLATES_PATH',
22
+ File.join(File.dirname(File.expand_path(__FILE__)), 'templates')
23
+ )
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8" standalone="yes"?>
2
+ <ns2:invocationContext xmlns:ns2="http://collectionspace.org/services/common/invocable">
3
+ <mode>list</mode>
4
+ <docType><%= data[:doctype] %></docType>
5
+ <listCSIDs>
6
+ <% data[:csids].each do |csid| %>
7
+ <csid><%= csid %></csid>
8
+ <% end %>
9
+ </listCSIDs>
10
+ </ns2:invocationContext>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="utf-8" standalone="yes"?>
2
+ <ns2:invocationContext xmlns:ns2="http://collectionspace.org/services/common/invocable">
3
+ <mode>nocontext</mode>
4
+ <docType><%= data[:doctype] %></docType>
5
+ </ns2:invocationContext>
@@ -0,0 +1,51 @@
1
+ <?xml version="1.0" encoding="utf-8" standalone="yes"?>
2
+ <document name="batch">
3
+ <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4
+ <name>Reindex Full Text</name>
5
+ <notes>Recomputes the indexed full text of all or specified records.</notes>
6
+ <className>org.collectionspace.services.batch.nuxeo.ReindexFullTextBatchJob</className>
7
+ <supportsNoContext>true</supportsNoContext>
8
+ <supportsSingleDoc>true</supportsSingleDoc>
9
+ <supportsDocList>true</supportsDocList>
10
+ <supportsGroup>false</supportsGroup>
11
+ <createsNewFocus>false</createsNewFocus>
12
+ <forDocTypes>
13
+ <forDocType>Acquisition</forDocType>
14
+ <forDocType>Batch</forDocType>
15
+ <forDocType>Blob</forDocType>
16
+ <forDocType>Citation</forDocType>
17
+ <forDocType>Citationauthority</forDocType>
18
+ <forDocType>Claim</forDocType>
19
+ <forDocType>CollectionObject</forDocType>
20
+ <forDocType>Conceptauthority</forDocType>
21
+ <forDocType>Conceptitem</forDocType>
22
+ <forDocType>Contact</forDocType>
23
+ <forDocType>Dimension</forDocType>
24
+ <forDocType>Group</forDocType>
25
+ <forDocType>Intake</forDocType>
26
+ <forDocType>Loanin</forDocType>
27
+ <forDocType>Loanout</forDocType>
28
+ <forDocType>Locationauthority</forDocType>
29
+ <forDocType>Locationitem</forDocType>
30
+ <forDocType>Media</forDocType>
31
+ <forDocType>Movement</forDocType>
32
+ <forDocType>ObjectExit</forDocType>
33
+ <forDocType>Organization</forDocType>
34
+ <forDocType>Orgauthority</forDocType>
35
+ <forDocType>Osteology</forDocType>
36
+ <forDocType>Person</forDocType>
37
+ <forDocType>Personauthority</forDocType>
38
+ <forDocType>Placeauthority</forDocType>
39
+ <forDocType>Placeitem</forDocType>
40
+ <forDocType>PublicItem</forDocType>
41
+ <forDocType>Relation</forDocType>
42
+ <forDocType>Report</forDocType>
43
+ <forDocType>Taxon</forDocType>
44
+ <forDocType>Taxonomyauthority</forDocType>
45
+ <forDocType>Vocabulary</forDocType>
46
+ <forDocType>Vocabularyitem</forDocType>
47
+ <forDocType>Workauthority</forDocType>
48
+ <forDocType>Workitem</forDocType>
49
+ </forDocTypes>
50
+ </ns2:batch_common>
51
+ </document>
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <document name="reports">
3
+ <ns2:reports_common xmlns:ns2="http://collectionspace.org/services/report">
4
+ <name><%= data.fetch(:name) %></name>
5
+ <notes><%= data.fetch(:notes, data[:name]) %></notes>
6
+ <forDocTypes>
7
+ <forDocType><%= data.fetch(:doctype) %></forDocType>
8
+ </forDocTypes>
9
+ <supportsSingleDoc><%= data.fetch(:supports_single_doc, 'true') %></supportsSingleDoc>
10
+ <supportsDocList><%= data.fetch(:supports_doc_list, 'false') %></supportsDocList>
11
+ <supportsGroup><%= data.fetch(:supports_group, 'false') %></supportsGroup>
12
+ <supportsNoContext><%= data.fetch(:supports_no_context, 'true') %></supportsNoContext>
13
+ <filename><%= data.fetch(:filename) %></filename>
14
+ <outputMIME><%= data.fetch(:mimetype, 'application/pdf') %></outputMIME>
15
+ </ns2:reports_common>
16
+ </document>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <document name="media">
3
+ <ns2:media_common xmlns:ns2="http://collectionspace.org/services/media" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4
+ <identificationNumber><%= data[:id] %></identificationNumber>
5
+ </ns2:media_common>
6
+ </document>
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CollectionSpace
2
4
  class Client
3
- VERSION = '0.3.0'.freeze
5
+ VERSION = '0.14.1'
4
6
  end
5
7
  end