aspace_client 0.0.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 +7 -0
- data/lib/aspace_client.rb +15 -0
- data/lib/aspace_client/archivesspace_json_schema.rb +210 -0
- data/lib/aspace_client/asutils.rb +142 -0
- data/lib/aspace_client/client_enum_source.rb +30 -0
- data/lib/aspace_client/exceptions.rb +15 -0
- data/lib/aspace_client/helpers.rb +0 -0
- data/lib/aspace_client/json_schema_concurrency_fix.rb +52 -0
- data/lib/aspace_client/json_schema_utils.rb +414 -0
- data/lib/aspace_client/jsonmodel.rb +342 -0
- data/lib/aspace_client/jsonmodel_client.rb +528 -0
- data/lib/aspace_client/jsonmodel_i18n_mixin.rb +77 -0
- data/lib/aspace_client/jsonmodel_type.rb +478 -0
- data/lib/aspace_client/memoryleak.rb +59 -0
- data/lib/aspace_client/schemas/abstract_agent.rb +51 -0
- data/lib/aspace_client/schemas/abstract_agent_relationship.rb +12 -0
- data/lib/aspace_client/schemas/abstract_archival_object.rb +96 -0
- data/lib/aspace_client/schemas/abstract_classification.rb +44 -0
- data/lib/aspace_client/schemas/abstract_name.rb +23 -0
- data/lib/aspace_client/schemas/abstract_note.rb +13 -0
- data/lib/aspace_client/schemas/accession.rb +174 -0
- data/lib/aspace_client/schemas/accession_parts_relationship.rb +31 -0
- data/lib/aspace_client/schemas/accession_sibling_relationship.rb +31 -0
- data/lib/aspace_client/schemas/active_edits.rb +23 -0
- data/lib/aspace_client/schemas/advanced_query.rb +12 -0
- data/lib/aspace_client/schemas/agent_contact.rb +25 -0
- data/lib/aspace_client/schemas/agent_corporate_entity.rb +32 -0
- data/lib/aspace_client/schemas/agent_family.rb +29 -0
- data/lib/aspace_client/schemas/agent_person.rb +31 -0
- data/lib/aspace_client/schemas/agent_relationship_associative.rb +28 -0
- data/lib/aspace_client/schemas/agent_relationship_earlierlater.rb +28 -0
- data/lib/aspace_client/schemas/agent_relationship_parentchild.rb +26 -0
- data/lib/aspace_client/schemas/agent_relationship_subordinatesuperior.rb +26 -0
- data/lib/aspace_client/schemas/agent_software.rb +22 -0
- data/lib/aspace_client/schemas/archival_object.rb +60 -0
- data/lib/aspace_client/schemas/archival_record_children.rb +15 -0
- data/lib/aspace_client/schemas/boolean_field_query.rb +13 -0
- data/lib/aspace_client/schemas/boolean_query.rb +13 -0
- data/lib/aspace_client/schemas/classification.rb +10 -0
- data/lib/aspace_client/schemas/classification_term.rb +38 -0
- data/lib/aspace_client/schemas/classification_tree.rb +17 -0
- data/lib/aspace_client/schemas/collection_management.rb +27 -0
- data/lib/aspace_client/schemas/container.rb +29 -0
- data/lib/aspace_client/schemas/container_location.rb +19 -0
- data/lib/aspace_client/schemas/date.rb +19 -0
- data/lib/aspace_client/schemas/date_field_query.rb +14 -0
- data/lib/aspace_client/schemas/deaccession.rb +20 -0
- data/lib/aspace_client/schemas/defaults.rb +104 -0
- data/lib/aspace_client/schemas/digital_object.rb +64 -0
- data/lib/aspace_client/schemas/digital_object_component.rb +53 -0
- data/lib/aspace_client/schemas/digital_object_tree.rb +19 -0
- data/lib/aspace_client/schemas/digital_record_children.rb +15 -0
- data/lib/aspace_client/schemas/enumeration.rb +29 -0
- data/lib/aspace_client/schemas/enumeration_migration.rb +14 -0
- data/lib/aspace_client/schemas/event.rb +88 -0
- data/lib/aspace_client/schemas/extent.rb +17 -0
- data/lib/aspace_client/schemas/external_document.rb +12 -0
- data/lib/aspace_client/schemas/external_id.rb +11 -0
- data/lib/aspace_client/schemas/field_query.rb +15 -0
- data/lib/aspace_client/schemas/file_version.rb +26 -0
- data/lib/aspace_client/schemas/group.rb +17 -0
- data/lib/aspace_client/schemas/instance.rb +27 -0
- data/lib/aspace_client/schemas/job.rb +57 -0
- data/lib/aspace_client/schemas/location.rb +36 -0
- data/lib/aspace_client/schemas/location_batch.rb +45 -0
- data/lib/aspace_client/schemas/merge_request.rb +48 -0
- data/lib/aspace_client/schemas/name_corporate_entity.rb +15 -0
- data/lib/aspace_client/schemas/name_family.rb +13 -0
- data/lib/aspace_client/schemas/name_form.rb +15 -0
- data/lib/aspace_client/schemas/name_person.rb +19 -0
- data/lib/aspace_client/schemas/name_software.rb +14 -0
- data/lib/aspace_client/schemas/note_abstract.rb +17 -0
- data/lib/aspace_client/schemas/note_bibliography.rb +29 -0
- data/lib/aspace_client/schemas/note_bioghist.rb +22 -0
- data/lib/aspace_client/schemas/note_chronology.rb +28 -0
- data/lib/aspace_client/schemas/note_citation.rb +32 -0
- data/lib/aspace_client/schemas/note_definedlist.rb +25 -0
- data/lib/aspace_client/schemas/note_digital_object.rb +23 -0
- data/lib/aspace_client/schemas/note_index.rb +29 -0
- data/lib/aspace_client/schemas/note_index_item.rb +25 -0
- data/lib/aspace_client/schemas/note_multipart.rb +25 -0
- data/lib/aspace_client/schemas/note_orderedlist.rb +27 -0
- data/lib/aspace_client/schemas/note_outline.rb +20 -0
- data/lib/aspace_client/schemas/note_outline_level.rb +21 -0
- data/lib/aspace_client/schemas/note_singlepart.rb +24 -0
- data/lib/aspace_client/schemas/note_text.rb +17 -0
- data/lib/aspace_client/schemas/permission.rb +15 -0
- data/lib/aspace_client/schemas/preference.rb +16 -0
- data/lib/aspace_client/schemas/record_tree.rb +17 -0
- data/lib/aspace_client/schemas/repository.rb +32 -0
- data/lib/aspace_client/schemas/repository_with_agent.rb +14 -0
- data/lib/aspace_client/schemas/resource.rb +112 -0
- data/lib/aspace_client/schemas/resource_tree.rb +20 -0
- data/lib/aspace_client/schemas/rights_statement.rb +35 -0
- data/lib/aspace_client/schemas/subject.rb +30 -0
- data/lib/aspace_client/schemas/term.rb +16 -0
- data/lib/aspace_client/schemas/user.rb +56 -0
- data/lib/aspace_client/schemas/user_defined.rb +42 -0
- data/lib/aspace_client/schemas/vocabulary.rb +15 -0
- data/lib/aspace_client/validations.rb +434 -0
- data/lib/aspace_client/validator_cache.rb +47 -0
- data/lib/aspace_client/version.rb +3 -0
- metadata +244 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
require 'time'
|
|
3
|
+
|
|
4
|
+
module JSONModel::Validations
|
|
5
|
+
extend JSONModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def self.check_identifier(hash)
|
|
9
|
+
ids = (0...4).map {|i| hash["id_#{i}"]}
|
|
10
|
+
|
|
11
|
+
errors = []
|
|
12
|
+
|
|
13
|
+
if ids.reverse.drop_while {|elt| elt.to_s.empty?}.any?{|elt| elt.to_s.empty?}
|
|
14
|
+
errors << ["identifier", "must not contain blank entries"]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
errors
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
[:archival_object, :accession, :resource].each do |type|
|
|
22
|
+
if JSONModel(type)
|
|
23
|
+
JSONModel(type).add_validation("#{type}_check_identifier") do |hash|
|
|
24
|
+
check_identifier(hash)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Specification:
|
|
30
|
+
# https://www.pivotaltracker.com/story/show/41430143
|
|
31
|
+
# See also: https://www.pivotaltracker.com/story/show/51373893
|
|
32
|
+
def self.check_source(hash)
|
|
33
|
+
errors = []
|
|
34
|
+
|
|
35
|
+
# non-authorized forms don't need source or rules
|
|
36
|
+
return errors if !hash['authorized']
|
|
37
|
+
|
|
38
|
+
if hash["source"].nil?
|
|
39
|
+
if hash["rules"].nil?
|
|
40
|
+
errors << ["rules", "is required when 'source' is blank"]
|
|
41
|
+
errors << ["source", "is required when 'rules' is blank"]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
errors
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# https://www.pivotaltracker.com/story/show/51373893
|
|
49
|
+
def self.check_authority_id(hash)
|
|
50
|
+
warnings = []
|
|
51
|
+
if hash["source"].nil? && hash["authority_id"]
|
|
52
|
+
warnings << ["source", "is required if there is an authority id"]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
warnings
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.check_name(hash)
|
|
59
|
+
errors = []
|
|
60
|
+
errors << ["sort_name", "Property is required but was missing"] if hash["sort_name"].nil? and !hash["sort_name_auto_generate"]
|
|
61
|
+
errors
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
[:name_person, :name_family, :name_corporate_entity, :name_software].each do |type|
|
|
65
|
+
if JSONModel(type)
|
|
66
|
+
JSONModel(type).add_validation("#{type}_check_source") do |hash|
|
|
67
|
+
check_source(hash)
|
|
68
|
+
end
|
|
69
|
+
JSONModel(type).add_validation("#{type}_check_name") do |hash|
|
|
70
|
+
check_name(hash)
|
|
71
|
+
end
|
|
72
|
+
JSONModel(type).add_validation("#{type}_check_authority_id", :warning) do |hash|
|
|
73
|
+
check_authority_id(hash)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# Take a date like YYYY or YYYY-MM and pad to YYYY-MM-DD
|
|
80
|
+
#
|
|
81
|
+
# Note: this might not yield a valid date. The only goal is that something
|
|
82
|
+
# valid on the way in remains valid on the way out.
|
|
83
|
+
#
|
|
84
|
+
def self.normalise_date(date)
|
|
85
|
+
negated = date.start_with?("-")
|
|
86
|
+
|
|
87
|
+
parts = date.gsub(/^-/, '').split(/-/)
|
|
88
|
+
|
|
89
|
+
# Pad out to the right length
|
|
90
|
+
padded = (parts + ['01', '01']).take(3)
|
|
91
|
+
|
|
92
|
+
(negated ? "-" : "") + padded.join("-")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Returns a valid date or throws if the input is invalid.
|
|
97
|
+
def self.parse_sloppy_date(s)
|
|
98
|
+
begin
|
|
99
|
+
Date.strptime(normalise_date(s), '%Y-%m-%d')
|
|
100
|
+
rescue
|
|
101
|
+
raise ArgumentError.new($!)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def self.check_date(hash)
|
|
107
|
+
errors = []
|
|
108
|
+
|
|
109
|
+
begin
|
|
110
|
+
begin_date = parse_sloppy_date(hash['begin']) if hash['begin']
|
|
111
|
+
rescue ArgumentError => e
|
|
112
|
+
errors << ["begin", "not a valid date"]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
begin
|
|
116
|
+
if hash['end']
|
|
117
|
+
# If padding our end date with months/days would cause it to fall before
|
|
118
|
+
# the start date (e.g. if the start date was '2000-05' and the end date
|
|
119
|
+
# just '2000'), use the start date in place of end.
|
|
120
|
+
end_s = if begin_date && hash['begin'] && hash['begin'].start_with?(hash['end'])
|
|
121
|
+
hash['begin']
|
|
122
|
+
else
|
|
123
|
+
hash['end']
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end_date = parse_sloppy_date(end_s)
|
|
127
|
+
end
|
|
128
|
+
rescue ArgumentError
|
|
129
|
+
errors << ["end", "not a valid date"]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if begin_date && end_date && end_date < begin_date
|
|
133
|
+
errors << ["end", "must not be before begin"]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
if hash["expression"].nil? && hash["begin"].nil? && hash["end"].nil?
|
|
137
|
+
errors << ["expression", "is required unless a begin or end date is given"]
|
|
138
|
+
errors << ["begin", "is required unless an expression or an end date is given"]
|
|
139
|
+
errors << ["end", "is required unless an expression or a begin date is given"]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
errors
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
if JSONModel(:date)
|
|
147
|
+
JSONModel(:date).add_validation("check_date") do |hash|
|
|
148
|
+
check_date(hash)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def self.check_rights_statement(hash)
|
|
154
|
+
errors = []
|
|
155
|
+
|
|
156
|
+
if hash["rights_type"] == "intellectual_property"
|
|
157
|
+
errors << ["ip_status", "missing required property"] if hash["ip_status"].nil?
|
|
158
|
+
errors << ["jurisdiction", "missing required property"] if hash["jurisdiction"].nil?
|
|
159
|
+
elsif hash["rights_type"] == "license"
|
|
160
|
+
errors << ["license_identifier_terms", "missing required property"] if hash["license_identifier_terms"].nil?
|
|
161
|
+
elsif hash["rights_type"] == "statute"
|
|
162
|
+
errors << ["statute_citation", "missing required property"] if hash["statute_citation"].nil?
|
|
163
|
+
errors << ["jurisdiction", "missing required property"] if hash["jurisdiction"].nil?
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
errors
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if JSONModel(:rights_statement)
|
|
171
|
+
JSONModel(:rights_statement).add_validation("check_rights_statement") do |hash|
|
|
172
|
+
check_rights_statement(hash)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def self.check_location(hash)
|
|
178
|
+
errors = []
|
|
179
|
+
|
|
180
|
+
# When creating a location, a minimum of one of the following is required:
|
|
181
|
+
# * Barcode
|
|
182
|
+
# * Classification
|
|
183
|
+
# * Coordinate 1 Label AND Coordinate 1 Indicator
|
|
184
|
+
required_location_fields = [["barcode"],
|
|
185
|
+
["classification"],
|
|
186
|
+
["coordinate_1_indicator", "coordinate_1_label"]]
|
|
187
|
+
|
|
188
|
+
if !required_location_fields.any? { |fieldset| fieldset.all? {|field| hash[field]} }
|
|
189
|
+
errors << :location_fields_error
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
errors
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
if JSONModel(:location)
|
|
197
|
+
JSONModel(:location).add_validation("check_location") do |hash|
|
|
198
|
+
check_location(hash)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def self.check_container_location(hash)
|
|
204
|
+
errors = []
|
|
205
|
+
|
|
206
|
+
errors << ["end_date", "is required"] if hash["end_date"].nil? and hash["status"] == "previous"
|
|
207
|
+
|
|
208
|
+
errors
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
if JSONModel(:container_location)
|
|
213
|
+
JSONModel(:container_location).add_validation("check_container_location") do |hash|
|
|
214
|
+
check_container_location(hash)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def self.check_container(hash)
|
|
220
|
+
errors = []
|
|
221
|
+
got_current = false
|
|
222
|
+
|
|
223
|
+
required_container_fields = [["barcode_1"],
|
|
224
|
+
["type_1", "indicator_1"]]
|
|
225
|
+
|
|
226
|
+
if !required_container_fields.any? { |fieldset| fieldset.all? {|field| hash[field]} }
|
|
227
|
+
errors << [ :type_1, "either type_1 or barcode is required" ]
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
if !hash["container_extent_number"].nil? and hash["container_extent_number"] !~ /^\-?\d{0,9}(\.\d{1,5})?$/
|
|
231
|
+
errors << ["container_extent", "must be a number with no more than nine digits and five decimal places"]
|
|
232
|
+
elsif !hash["container_extent"].nil? and hash["container_extent_type"].nil?
|
|
233
|
+
errors << ["container_extent_type", "is required if container extent is specified "]
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
Array(hash["container_locations"]).each do |loc|
|
|
237
|
+
if loc["status"] == "current"
|
|
238
|
+
if got_current
|
|
239
|
+
errors << ["container_locations", "only one location can be current"]
|
|
240
|
+
break
|
|
241
|
+
else
|
|
242
|
+
got_current = true
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
errors
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
if JSONModel(:container)
|
|
252
|
+
JSONModel(:container).add_validation("check_container") do |hash|
|
|
253
|
+
check_container(hash)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def self.check_instance(hash)
|
|
259
|
+
errors = []
|
|
260
|
+
|
|
261
|
+
if hash["instance_type"] == "digital_object"
|
|
262
|
+
errors << ["digital_object", "Can't be empty"] if hash["digital_object"].nil?
|
|
263
|
+
|
|
264
|
+
elsif hash["instance_type"]
|
|
265
|
+
errors << ["container", "Can't be empty"] if hash["container"].nil?
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
errors
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
if JSONModel(:instance)
|
|
273
|
+
JSONModel(:instance).add_validation("check_instance") do |hash|
|
|
274
|
+
check_instance(hash)
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def self.check_collection_management(hash)
|
|
280
|
+
errors = []
|
|
281
|
+
|
|
282
|
+
if !hash["processing_total_extent"].nil? and hash["processing_total_extent_type"].nil?
|
|
283
|
+
errors << ["processing_total_extent_type", "is required if total extent is specified"]
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
errors
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
if JSONModel(:collection_management)
|
|
291
|
+
JSONModel(:collection_management).add_validation("check_collection_management") do |hash|
|
|
292
|
+
check_collection_management(hash)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def self.check_user_defined(hash)
|
|
298
|
+
errors = []
|
|
299
|
+
|
|
300
|
+
["integer_1", "integer_2", "integer_3"].each do |k|
|
|
301
|
+
if !hash[k].nil? and hash[k] !~ /^\-?\d+$/
|
|
302
|
+
errors << [k, "must be an integer"]
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
["real_1", "real_2", "real_3"].each do |k|
|
|
307
|
+
if !hash[k].nil? and hash[k] !~ /^\-?\d{0,9}(\.\d{1,5})?$/
|
|
308
|
+
errors << [k, "must be a number with no more than nine digits and five decimal places"]
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
errors
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
if JSONModel(:user_defined)
|
|
317
|
+
JSONModel(:user_defined).add_validation("check_user-defined") do |hash|
|
|
318
|
+
check_user_defined(hash)
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
if JSONModel(:resource)
|
|
324
|
+
JSONModel(:resource).add_validation("check_resource_otherlevel", :warning) do |hash|
|
|
325
|
+
check_otherlevel(hash)
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def self.check_otherlevel(hash)
|
|
331
|
+
warnings = []
|
|
332
|
+
|
|
333
|
+
if hash["level"] == "otherlevel"
|
|
334
|
+
warnings << ["other_level", "is required"] if hash["other_level"].nil?
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
warnings
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def self.check_archival_object(hash)
|
|
341
|
+
errors = []
|
|
342
|
+
|
|
343
|
+
if (!hash.has_key?("dates") || hash["dates"].empty?) && (!hash.has_key?("title") || hash["title"].empty?)
|
|
344
|
+
errors << ["dates", "one or more required (or enter a Title)"]
|
|
345
|
+
errors << ["title", "must not be an empty string (or enter a Date)"]
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
errors
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
if JSONModel(:archival_object)
|
|
353
|
+
JSONModel(:archival_object).add_validation("check_archival_object") do |hash|
|
|
354
|
+
check_archival_object(hash)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
JSONModel(:archival_object).add_validation("check_archival_object_otherlevel", :warning) do |hash|
|
|
358
|
+
check_otherlevel(hash);
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def self.check_digital_object_component(hash)
|
|
365
|
+
errors = []
|
|
366
|
+
|
|
367
|
+
fields = ["dates", "title", "label"]
|
|
368
|
+
|
|
369
|
+
if fields.all? {|field| !hash.has_key?(field) || hash[field].empty?}
|
|
370
|
+
fields.each do |field|
|
|
371
|
+
errors << [field, "you must provide a label, title or date"]
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
errors
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
JSONModel(:digital_object_component).add_validation("check_digital_object_component") do |hash|
|
|
380
|
+
check_digital_object_component(hash)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
JSONModel(:event).add_validation("check_event") do |hash|
|
|
385
|
+
errors = []
|
|
386
|
+
|
|
387
|
+
if hash.has_key?("date") && hash.has_key?("timestamp")
|
|
388
|
+
errors << ["date", "Can't specify both a date and a timestamp"]
|
|
389
|
+
errors << ["timestamp", "Can't specify both a date and a timestamp"]
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
if !hash.has_key?("date") && !hash.has_key?("timestamp")
|
|
393
|
+
errors << ["date", "Must specify either a date or a timestamp"]
|
|
394
|
+
errors << ["timestamp", "Must specify either a date or a timestamp"]
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
if hash["timestamp"]
|
|
398
|
+
# Make sure we can parse it
|
|
399
|
+
begin
|
|
400
|
+
Time.parse(hash["timestamp"])
|
|
401
|
+
rescue ArgumentError
|
|
402
|
+
errors << ["timestamp", "Must be an ISO8601-formatted string"]
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
errors
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
[:agent_person, :agent_family, :agent_software, :agent_corporate_entity].each do |agent_type|
|
|
411
|
+
|
|
412
|
+
JSONModel(agent_type).add_validation("check_#{agent_type.to_s}") do |hash|
|
|
413
|
+
errors = []
|
|
414
|
+
|
|
415
|
+
if hash.has_key?("dates_of_existence") && hash["dates_of_existence"].find {|d| d['label'] != 'existence' }
|
|
416
|
+
errors << ["dates_of_existence", "Label must be 'existence' in this context"]
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
errors
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
[:note_multipart, :note_bioghist].each do |schema|
|
|
425
|
+
JSONModel(schema).add_validation("#{schema}_check_at_least_one_subnote") do |hash|
|
|
426
|
+
if Array(hash['subnotes']).empty?
|
|
427
|
+
[["subnotes", "Must contain at least one subnote"]]
|
|
428
|
+
else
|
|
429
|
+
[]
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
class ValidatorCache
|
|
2
|
+
|
|
3
|
+
def self.create_validator(jsonmodel, data)
|
|
4
|
+
JSON::Validator.new(jsonmodel.schema,
|
|
5
|
+
data,
|
|
6
|
+
:errors_as_objects => true,
|
|
7
|
+
:record_errors => true)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.with_validator_for(jsonmodel, data)
|
|
11
|
+
Thread.current[:validator_cache] ||= {}
|
|
12
|
+
|
|
13
|
+
created = false
|
|
14
|
+
if Thread.current[:validator_cache][jsonmodel]
|
|
15
|
+
|
|
16
|
+
# If we have a cache entry but it's in use, just return a newly allocated
|
|
17
|
+
# validator.
|
|
18
|
+
if Thread.current[:validator_cache][jsonmodel][:in_use]
|
|
19
|
+
return self.create_validator(jsonmodel, data)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
else
|
|
23
|
+
# If there's no entry, add one
|
|
24
|
+
Thread.current[:validator_cache][jsonmodel] = {}
|
|
25
|
+
Thread.current[:validator_cache][jsonmodel][:validator] = self.create_validator(jsonmodel, data)
|
|
26
|
+
created = true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
validator = Thread.current[:validator_cache][jsonmodel][:validator]
|
|
30
|
+
|
|
31
|
+
# Reuse this existing validator by setting its data
|
|
32
|
+
if !created
|
|
33
|
+
validator.instance_eval do
|
|
34
|
+
@data = data
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Thread.current[:validator_cache][jsonmodel][:in_use] = true
|
|
39
|
+
|
|
40
|
+
begin
|
|
41
|
+
yield(validator)
|
|
42
|
+
ensure
|
|
43
|
+
Thread.current[:validator_cache][jsonmodel][:in_use] = false
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|