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,528 @@
|
|
|
1
|
+
require 'net/http/persistent'
|
|
2
|
+
require 'net/http/post/multipart'
|
|
3
|
+
require 'json'
|
|
4
|
+
require_relative 'exceptions'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
module JSONModel
|
|
8
|
+
|
|
9
|
+
# Set the repository that subsequent operations will apply to.
|
|
10
|
+
def self.set_repository(id)
|
|
11
|
+
Thread.current[:selected_repo_id] = id
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# The currently selected repository (if any)
|
|
16
|
+
def self.repository
|
|
17
|
+
Thread.current[:selected_repo_id]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Grab an array of JSON objects from 'uri' and use the 'type_descriptor'
|
|
22
|
+
# property of each object to cast it into a JSONModel.
|
|
23
|
+
def self.all(uri, type_descriptor)
|
|
24
|
+
JSONModel::HTTP.get_json(uri).map do |obj|
|
|
25
|
+
JSONModel(obj[type_descriptor.to_s]).new(obj)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def self.with_repository(id)
|
|
31
|
+
old_repo = Thread.current[:selected_repo_id]
|
|
32
|
+
begin
|
|
33
|
+
self.set_repository(id)
|
|
34
|
+
yield
|
|
35
|
+
ensure
|
|
36
|
+
self.set_repository(old_repo)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def self.backend_url
|
|
42
|
+
if Module.const_defined?(:BACKEND_SERVICE_URL)
|
|
43
|
+
BACKEND_SERVICE_URL
|
|
44
|
+
else
|
|
45
|
+
init_args[:url]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@@error_handlers = []
|
|
51
|
+
|
|
52
|
+
def self.add_error_handler(&block)
|
|
53
|
+
@@error_handlers << block
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.handle_error(err)
|
|
57
|
+
@@error_handlers.each do |handler|
|
|
58
|
+
handler.call(err)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
module Notification
|
|
64
|
+
@@notification_handlers = []
|
|
65
|
+
|
|
66
|
+
def self.add_notification_handler(code = nil, &block)
|
|
67
|
+
@@notification_handlers << {:code => code, :block => block}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.start_background_thread
|
|
71
|
+
Thread.new do
|
|
72
|
+
sequence = 0
|
|
73
|
+
|
|
74
|
+
while true
|
|
75
|
+
begin
|
|
76
|
+
notifications = JSONModel::HTTP::get_json('/notifications',
|
|
77
|
+
:last_sequence => sequence)
|
|
78
|
+
|
|
79
|
+
notifications.each do |notification|
|
|
80
|
+
@@notification_handlers.each do |handler|
|
|
81
|
+
if handler[:code].nil? or handler[:code] == notification["code"]
|
|
82
|
+
begin
|
|
83
|
+
handler[:block].call(notification["code"], notification["params"])
|
|
84
|
+
rescue
|
|
85
|
+
$stderr.puts("ERROR: Failed to handle notification #{notification.inspect}: #{$!}")
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
sequence = notifications.last['sequence']
|
|
92
|
+
rescue
|
|
93
|
+
sleep 5
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
module HTTP
|
|
104
|
+
|
|
105
|
+
def self.backend_url
|
|
106
|
+
if Module.const_defined?(:BACKEND_SERVICE_URL)
|
|
107
|
+
BACKEND_SERVICE_URL
|
|
108
|
+
else
|
|
109
|
+
JSONModel::init_args[:url]
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# We override this in the backend's spec_helper since Rack::Test::Methods
|
|
115
|
+
# doesn't support multipart requests.
|
|
116
|
+
def self.multipart_request(uri, params)
|
|
117
|
+
Net::HTTP::Post::Multipart.new(uri, params)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def self.form_urlencoded(uri, params)
|
|
122
|
+
request = Net::HTTP::Post.new(uri)
|
|
123
|
+
request.form_data = params
|
|
124
|
+
request
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# Perform a HTTP POST request against the backend with form parameters
|
|
129
|
+
#
|
|
130
|
+
# `encoding' is either :x_www_form_urlencoded or :multipart_form_data. The
|
|
131
|
+
# latter is useful if you're providing a file upload.
|
|
132
|
+
def self.post_form(uri, params = {}, encoding = :x_www_form_urlencoded)
|
|
133
|
+
url = URI("#{backend_url}#{uri}")
|
|
134
|
+
|
|
135
|
+
req = if encoding == :x_www_form_urlencoded
|
|
136
|
+
self.form_urlencoded(url.request_uri, params)
|
|
137
|
+
elsif encoding == :multipart_form_data
|
|
138
|
+
self.multipart_request(url.request_uri, params)
|
|
139
|
+
else
|
|
140
|
+
raise "Unknown form encoding: #{encoding.inspect}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
do_http_request(url, req)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def self.stream(uri, params = {}, &block)
|
|
148
|
+
uri = URI("#{backend_url}#{uri}")
|
|
149
|
+
uri.query = URI.encode_www_form(params)
|
|
150
|
+
|
|
151
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
|
152
|
+
|
|
153
|
+
req['X-ArchivesSpace-Session'] = current_backend_session
|
|
154
|
+
|
|
155
|
+
if high_priority?
|
|
156
|
+
req['X-ArchivesSpace-Priority'] = "high"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
|
160
|
+
http.request(req, nil) do |response|
|
|
161
|
+
if response.code =~ /^4/
|
|
162
|
+
JSONModel::handle_error(ASUtils.json_parse(response.body))
|
|
163
|
+
raise response.body
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
block.call(response)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def self.get_json(uri, params = {})
|
|
173
|
+
uri = URI("#{backend_url}#{uri}")
|
|
174
|
+
uri.query = URI.encode_www_form(params)
|
|
175
|
+
|
|
176
|
+
response = get_response(uri)
|
|
177
|
+
|
|
178
|
+
if response.is_a?(Net::HTTPSuccess) || response.status == 200
|
|
179
|
+
ASUtils.json_parse(response.body)
|
|
180
|
+
else
|
|
181
|
+
nil
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# Returns the session token to be sent to the backend when making
|
|
187
|
+
# requests.
|
|
188
|
+
def self.current_backend_session
|
|
189
|
+
# Set by the ApplicationController
|
|
190
|
+
Thread.current[:backend_session]
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def self.current_backend_session=(val)
|
|
195
|
+
Thread.current[:backend_session] = val
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def self.high_priority?
|
|
200
|
+
if Thread.current[:request_priority]
|
|
201
|
+
Thread.current[:request_priority] == :high
|
|
202
|
+
else
|
|
203
|
+
JSONModel::init_args[:priority] == :high
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def self.http_conn
|
|
209
|
+
@http ||= Net::HTTP::Persistent.new 'jsonmodel_client'
|
|
210
|
+
@http.read_timeout = 1200
|
|
211
|
+
@http
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def self.do_http_request(url, req, &block)
|
|
216
|
+
req['X-ArchivesSpace-Session'] = current_backend_session
|
|
217
|
+
|
|
218
|
+
if high_priority?
|
|
219
|
+
req['X-ArchivesSpace-Priority'] = "high"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
response = http_conn.request(url, req, &block)
|
|
223
|
+
|
|
224
|
+
if response.code =~ /^4/
|
|
225
|
+
JSONModel::handle_error(ASUtils.json_parse(response.body))
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
response
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def self.with_request_priority(priority)
|
|
233
|
+
old = Thread.current[:request_priority]
|
|
234
|
+
Thread.current[:request_priority] = priority
|
|
235
|
+
begin
|
|
236
|
+
yield
|
|
237
|
+
ensure
|
|
238
|
+
Thread.current[:request_priority] = old
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def self.post_json(url, json)
|
|
244
|
+
req = Net::HTTP::Post.new(url.request_uri)
|
|
245
|
+
req['Content-Type'] = 'text/json'
|
|
246
|
+
req.body = json
|
|
247
|
+
|
|
248
|
+
do_http_request(url, req)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def self.post_json_file(url, path, &block)
|
|
253
|
+
File.open(path) do |fh|
|
|
254
|
+
req = Net::HTTP::Post.new(url.request_uri)
|
|
255
|
+
req['Content-Type'] = 'text/json'
|
|
256
|
+
req['Content-Length'] = File.size(path)
|
|
257
|
+
req.body_stream = fh
|
|
258
|
+
|
|
259
|
+
do_http_request(url, req, &block)
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def self.delete_request(url)
|
|
265
|
+
req = Net::HTTP::Delete.new(url.request_uri)
|
|
266
|
+
|
|
267
|
+
do_http_request(url, req)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def self.get_response(url)
|
|
272
|
+
req = Net::HTTP::Get.new(url.request_uri)
|
|
273
|
+
|
|
274
|
+
do_http_request(url, req)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
module Client
|
|
282
|
+
|
|
283
|
+
def self.included(base)
|
|
284
|
+
base.extend(ClassMethods)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# Validate this JSONModel instance, produce a JSON string, and send an
|
|
289
|
+
# update to the backend.
|
|
290
|
+
def save(opts = {}, whole_body = false)
|
|
291
|
+
|
|
292
|
+
clear_errors
|
|
293
|
+
|
|
294
|
+
type = self.class.record_type
|
|
295
|
+
response = JSONModel::HTTP.post_json(self.class.my_url(self.id, opts),
|
|
296
|
+
self.to_json)
|
|
297
|
+
|
|
298
|
+
if response.code == '200'
|
|
299
|
+
response = ASUtils.json_parse(response.body)
|
|
300
|
+
|
|
301
|
+
self.uri = self.class.uri_for(response["id"], opts)
|
|
302
|
+
|
|
303
|
+
# If we were able to save successfully, increment our local version
|
|
304
|
+
# number to match the version on the server.
|
|
305
|
+
self.lock_version = response["lock_version"]
|
|
306
|
+
|
|
307
|
+
# Ensure object is up to date
|
|
308
|
+
if response["stale"]
|
|
309
|
+
self.refetch
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
return whole_body ? response : response["id"]
|
|
313
|
+
|
|
314
|
+
elsif response.code == '403'
|
|
315
|
+
raise AccessDeniedException.new
|
|
316
|
+
|
|
317
|
+
elsif response.code == '409'
|
|
318
|
+
err = ASUtils.json_parse(response.body)
|
|
319
|
+
raise ConflictException.new(err["error"])
|
|
320
|
+
|
|
321
|
+
elsif response.code == '404'
|
|
322
|
+
raise RecordNotFound.new
|
|
323
|
+
|
|
324
|
+
elsif response.code =~ /^4/
|
|
325
|
+
err = ASUtils.json_parse(response.body)
|
|
326
|
+
|
|
327
|
+
if err["error"].is_a?(Hash)
|
|
328
|
+
err["error"].each do |field, errors|
|
|
329
|
+
errors.each do |msg|
|
|
330
|
+
add_error(field, msg)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
raise ValidationException.new(:invalid_object => self,
|
|
336
|
+
:errors => err["error"])
|
|
337
|
+
else
|
|
338
|
+
raise Exception.new("Unknown response: #{response.body} (code: #{response.code})")
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def refetch
|
|
344
|
+
# if a new object, nothing to fetch
|
|
345
|
+
return self if self.id.nil?
|
|
346
|
+
|
|
347
|
+
obj = (self.instance_data.has_key? :find_opts) ?
|
|
348
|
+
self.class.find(self.id, self.instance_data[:find_opts]) : self.class.find(self.id)
|
|
349
|
+
|
|
350
|
+
self.reset_from(obj) if not obj.nil?
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def delete
|
|
355
|
+
response = JSONModel::HTTP.delete_request(self.class.my_url(self.id))
|
|
356
|
+
|
|
357
|
+
if response.code == '200'
|
|
358
|
+
true
|
|
359
|
+
elsif response.code == '403'
|
|
360
|
+
raise AccessDeniedException.new
|
|
361
|
+
elsif response.code == '404'
|
|
362
|
+
nil
|
|
363
|
+
elsif response.code == '409'
|
|
364
|
+
err = ASUtils.json_parse(response.body)
|
|
365
|
+
raise ConflictException.new(err["error"])
|
|
366
|
+
else
|
|
367
|
+
raise Exception.new("Unknown response: #{response}")
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Mark the suppression status of this record
|
|
372
|
+
def set_suppressed(val)
|
|
373
|
+
response = JSONModel::HTTP.post_form("#{self.uri}/suppressed", :suppressed => val)
|
|
374
|
+
|
|
375
|
+
if response.code == '403'
|
|
376
|
+
raise AccessDeniedException.new("Permission denied when setting suppression status")
|
|
377
|
+
elsif response.code != '200'
|
|
378
|
+
raise "Error when setting suppression status for #{self}: #{response.code} -- #{response.body}"
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
self["suppressed"] = ASUtils.json_parse(response.body)["suppressed_state"]
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def suppress
|
|
386
|
+
set_suppressed(true)
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def unsuppress
|
|
391
|
+
set_suppressed(false)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def add_error(field, message)
|
|
396
|
+
@errors ||= {}
|
|
397
|
+
@errors[field.to_s] ||= []
|
|
398
|
+
@errors[field.to_s] << message
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
module ClassMethods
|
|
403
|
+
|
|
404
|
+
def self.extended(base)
|
|
405
|
+
class << base
|
|
406
|
+
alias :_substitute_parameters :substitute_parameters
|
|
407
|
+
|
|
408
|
+
def substitute_parameters(uri, opts = {})
|
|
409
|
+
opts = ASUtils.keys_as_strings(opts)
|
|
410
|
+
if JSONModel::repository
|
|
411
|
+
opts = {'repo_id' => JSONModel::repository}.merge(opts)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
_substitute_parameters(uri, opts)
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
# Given the ID of a JSONModel instance, return its full URL (including the
|
|
421
|
+
# URL of the backend)
|
|
422
|
+
def my_url(id = nil, opts = {})
|
|
423
|
+
uri, remaining_opts = self.uri_and_remaining_options_for(id, opts)
|
|
424
|
+
|
|
425
|
+
url = URI("#{JSONModel::HTTP.backend_url}#{uri}")
|
|
426
|
+
|
|
427
|
+
# Don't need to pass this as a URL parameter if it wasn't picked up by
|
|
428
|
+
# the URI template substitution.
|
|
429
|
+
remaining_opts.delete(:repo_id)
|
|
430
|
+
|
|
431
|
+
if not remaining_opts.empty?
|
|
432
|
+
url.query = URI.encode_www_form(remaining_opts)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
url
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
# Given an ID, retrieve an instance of the current JSONModel from the
|
|
440
|
+
# backend.
|
|
441
|
+
def find(id, opts = {})
|
|
442
|
+
response = JSONModel::HTTP.get_response(my_url(id, opts))
|
|
443
|
+
|
|
444
|
+
if response.code == '200'
|
|
445
|
+
obj = self.new(ASUtils.json_parse(response.body))
|
|
446
|
+
# store find params on instance to support #refetch
|
|
447
|
+
obj.instance_data[:find_opts] = opts
|
|
448
|
+
obj
|
|
449
|
+
elsif response.code == '403'
|
|
450
|
+
raise AccessDeniedException.new
|
|
451
|
+
elsif response.code == '404'
|
|
452
|
+
raise RecordNotFound.new
|
|
453
|
+
else
|
|
454
|
+
raise response.body
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def find_by_uri(uri, opts = {})
|
|
460
|
+
self.find(self.id_for(uri), opts)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
# Return all instances of the current JSONModel's record type.
|
|
465
|
+
def all(params = {}, opts = {})
|
|
466
|
+
uri = my_url(nil, opts)
|
|
467
|
+
|
|
468
|
+
uri.query = URI.encode_www_form(params)
|
|
469
|
+
|
|
470
|
+
response = JSONModel::HTTP.get_response(uri)
|
|
471
|
+
|
|
472
|
+
if response.code == '200'
|
|
473
|
+
json_list = ASUtils.json_parse(response.body)
|
|
474
|
+
|
|
475
|
+
if json_list.is_a?(Hash)
|
|
476
|
+
json_list["results"] = json_list["results"].map {|h| self.new(h)}
|
|
477
|
+
else
|
|
478
|
+
json_list = json_list.map {|h| self.new(h)}
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
json_list
|
|
482
|
+
elsif response.code == '403'
|
|
483
|
+
raise AccessDeniedException.new
|
|
484
|
+
else
|
|
485
|
+
raise response.body
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class EnumSource
|
|
493
|
+
|
|
494
|
+
def self.fetch_enumerations
|
|
495
|
+
enumerations = {}
|
|
496
|
+
enumerations[:defaults] = {}
|
|
497
|
+
JSONModel::JSONModel(:enumeration).all.each do |enumeration|
|
|
498
|
+
enumerations[enumeration.name] = enumeration.values
|
|
499
|
+
enumerations[:defaults][enumeration.name] = enumeration.default_value
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
enumerations
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def initialize
|
|
507
|
+
@enumerations = self.class.fetch_enumerations
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def valid?(name, value)
|
|
512
|
+
values_for(name).include?(value)
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def values_for(name)
|
|
517
|
+
@enumerations.fetch(name)
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def default_value_for
|
|
521
|
+
@enumerations[:defaults].fetch(name)
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
end
|
|
528
|
+
end
|