atlas_rb 1.25.0 → 1.26.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.
- checksums.yaml +4 -4
- data/.version +1 -1
- data/CHANGELOG.md +28 -0
- data/Gemfile.lock +7 -3
- data/README.md +31 -0
- data/lib/atlas_rb/resource.rb +56 -11
- data/lib/atlas_rb/resource_writes.rb +52 -1
- data/lib/atlas_rb/work.rb +33 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74f74d6af596e2f817ba6991018efd21cb158f897efa39ffc572367a27a3c968
|
|
4
|
+
data.tar.gz: 26b52d5a67e30cac921695e31aba127338fe77095218a1277f6c04049c1dde5e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 692f82797f41797a10b06b1c6fb79624a03437711c1781afd3e7a0d1f8711eb5964c42197dd6b411e4c1b0df84115a609c7f26091d736f02faacb72a40dc22f3
|
|
7
|
+
data.tar.gz: fffef87ace94444d2f9b82f5347ad342e8a908f05541fd4c4b4feced02b63cc6ecc5eff57ca2c0824439fb5c133fa3a4389655c157e8809aafc472236fc9eb60
|
data/.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.26.0
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.26.0
|
|
4
|
+
|
|
5
|
+
These bindings need Atlas 0.6.221 or later.
|
|
6
|
+
|
|
7
|
+
### Added — Darwin Core records
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
AtlasRb::Work.dwc(id, kind = "xml") # "xml", "json" or "html"; nil on 404
|
|
11
|
+
AtlasRb::Resource.put_dwc(id, xml_path, origin: nil)
|
|
12
|
+
AtlasRb::Resource.delete_dwc(id) # true; raises NotFoundError on 404
|
|
13
|
+
AtlasRb::Resource.dwc_versions(id)
|
|
14
|
+
AtlasRb::Resource.dwc_version(id, version_id)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
A Work can hold one Simple Darwin Core record. `Work.dwc` returns the stored
|
|
18
|
+
XML by default, the display block for `"html"`, and the Work unwrapped from
|
|
19
|
+
`"work"` for `"json"`, with the terms under `"dwc"`. `put_dwc` replaces the
|
|
20
|
+
whole record and raises `ResourceError` on Atlas's `422` when the document
|
|
21
|
+
breaks a shape rule. `delete_dwc` withdraws the record without purging it, so
|
|
22
|
+
the next `put_dwc` restores it. The version calls mirror `mods_versions` and
|
|
23
|
+
`mods_version`.
|
|
24
|
+
|
|
25
|
+
### Documented — `metadata_formats` on the Work
|
|
26
|
+
|
|
27
|
+
`Work.find` results now carry `metadata_formats`, the additional records the
|
|
28
|
+
Work holds, such as `["dwc"]`. No code changed: the gem passes the whole Work
|
|
29
|
+
through.
|
|
30
|
+
|
|
3
31
|
## 1.25.0
|
|
4
32
|
|
|
5
33
|
These bindings need Atlas 0.6.214 or later.
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
atlas_rb (1.
|
|
4
|
+
atlas_rb (1.26.0)
|
|
5
5
|
faraday (~> 2.7)
|
|
6
6
|
faraday-follow_redirects (~> 0.3.0)
|
|
7
7
|
faraday-multipart (~> 1)
|
|
@@ -38,10 +38,13 @@ GEM
|
|
|
38
38
|
base64
|
|
39
39
|
logger (1.7.0)
|
|
40
40
|
multipart-post (2.4.1)
|
|
41
|
-
net-http (0.
|
|
41
|
+
net-http (0.10.0)
|
|
42
|
+
net-protocol (>= 0.3.0)
|
|
42
43
|
uri (>= 0.11.1)
|
|
43
44
|
net-http-persistent (4.0.8)
|
|
44
45
|
connection_pool (>= 2.2.4, < 4)
|
|
46
|
+
net-protocol (0.4.0)
|
|
47
|
+
timeout
|
|
45
48
|
rake (13.2.1)
|
|
46
49
|
rspec (3.13.0)
|
|
47
50
|
rspec-core (~> 3.13.0)
|
|
@@ -56,7 +59,8 @@ GEM
|
|
|
56
59
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
57
60
|
rspec-support (~> 3.13.0)
|
|
58
61
|
rspec-support (3.13.3)
|
|
59
|
-
|
|
62
|
+
timeout (0.6.1)
|
|
63
|
+
uri (1.1.2)
|
|
60
64
|
yard (0.9.43)
|
|
61
65
|
|
|
62
66
|
PLATFORMS
|
data/README.md
CHANGED
|
@@ -527,6 +527,35 @@ array (mirroring `Collection.children`); the two mutations return the list
|
|
|
527
527
|
Resolving those Collections' full contents is a Cerberus/Solr concern —
|
|
528
528
|
this gem never queries the index.
|
|
529
529
|
|
|
530
|
+
### Darwin Core records
|
|
531
|
+
|
|
532
|
+
A Work can hold one Simple Darwin Core record beside its MODS. The Work's
|
|
533
|
+
`metadata_formats` says whether it does, so check that before reading:
|
|
534
|
+
|
|
535
|
+
```ruby
|
|
536
|
+
work = AtlasRb::Work.find("w-789")
|
|
537
|
+
if work["metadata_formats"].include?("dwc")
|
|
538
|
+
AtlasRb::Work.dwc("w-789", "html") # the display block
|
|
539
|
+
AtlasRb::Work.dwc("w-789", "json")["dwc"]["catalogNumber"] # => "S27880"
|
|
540
|
+
AtlasRb::Work.dwc("w-789") # the stored XML
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
AtlasRb::Resource.put_dwc("w-789", "/tmp/dwc.xml", origin: "xml_loader")
|
|
544
|
+
AtlasRb::Resource.delete_dwc("w-789") # withdraws; the next put_dwc restores
|
|
545
|
+
|
|
546
|
+
history = AtlasRb::Resource.dwc_versions("w-789")
|
|
547
|
+
AtlasRb::Resource.dwc_version("w-789", history["versions"].last["version_id"])
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
`Work.dwc` answers `nil` when the Work holds no record. `put_dwc` raises
|
|
551
|
+
`ResourceError` on a refused document; its body's `error` names the rule
|
|
552
|
+
(`malformed_xml`, `invalid_root`, `record_count` or `duplicate_term`). Atlas
|
|
553
|
+
checks shape only, so validate against `tdwg_dwc_simple.xsd` before you call.
|
|
554
|
+
`delete_dwc` purges nothing: Atlas keeps the document and its history.
|
|
555
|
+
|
|
556
|
+
The two version calls behave as `mods_versions` and `mods_version` do, under
|
|
557
|
+
the same admin gate.
|
|
558
|
+
|
|
530
559
|
The two mutations raise the same way `reparent` does — `LinkedMemberError`
|
|
531
560
|
on a structural `422` (carrying the envelope's `error` code as `#code`) and
|
|
532
561
|
`ForbiddenError` on a `403` — instead of swallowing the envelope.
|
|
@@ -540,6 +569,8 @@ write. The whole surface:
|
|
|
540
569
|
| Call | Endpoint |
|
|
541
570
|
|---|---|
|
|
542
571
|
| `Resource.put_mods(id, xml_path, origin:)` | `PUT /resources/{id}/mods` |
|
|
572
|
+
| `Resource.put_dwc(id, xml_path, origin:)` | `PUT /resources/{id}/dwc` (Works only) |
|
|
573
|
+
| `Resource.delete_dwc(id)` | `DELETE /resources/{id}/dwc` (Works only) |
|
|
543
574
|
| `Resource.set_permissions(id, acl)` | `PATCH /resources/{id}/permissions` |
|
|
544
575
|
| `Resource.set_thumbnails(id, thumbnail:, thumbnail_2x:, preview:)` | `PATCH /resources/{id}/thumbnails` |
|
|
545
576
|
| `Resource.reparent(id, parent_id)` | `PATCH /resources/{id}/parent` |
|
data/lib/atlas_rb/resource.rb
CHANGED
|
@@ -419,6 +419,47 @@ module AtlasRb
|
|
|
419
419
|
))
|
|
420
420
|
end
|
|
421
421
|
|
|
422
|
+
# List the retained versions of a Work's Darwin Core record.
|
|
423
|
+
#
|
|
424
|
+
# The same envelope as {mods_versions}, under the same admin gate, with
|
|
425
|
+
# attribution drawn from the Darwin Core edits only. A Work with no record,
|
|
426
|
+
# or an id that is not a Work, comes back as `{ "versions" => [] }`.
|
|
427
|
+
#
|
|
428
|
+
# @param id [String] the Work's NOID.
|
|
429
|
+
# @param nuid [String, nil] optional acting user's NUID.
|
|
430
|
+
# @param on_behalf_of [String, nil] optional NUID for the `On-Behalf-Of`
|
|
431
|
+
# header.
|
|
432
|
+
# @return [AtlasRb::Mash, nil] the envelope, with `"resource_id"` and a
|
|
433
|
+
# newest-first `"versions"` array; `nil` on a `404`.
|
|
434
|
+
# @raise [AtlasRb::ResourceError] on any non-2xx other than `404` / `410`,
|
|
435
|
+
# including the `403` a non-admin caller gets.
|
|
436
|
+
# @example
|
|
437
|
+
# AtlasRb::Resource.dwc_versions("w-789")["versions"].first["source"] # => "dwc"
|
|
438
|
+
def self.dwc_versions(id, nuid: nil, on_behalf_of: nil)
|
|
439
|
+
read_body(connection({}, nuid, on_behalf_of: on_behalf_of)
|
|
440
|
+
.get('/resources/' + id + '/dwc/versions')) { |body| AtlasRb::Mash.new(body) }
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# Fetch a Work's Darwin Core document as of a specific version.
|
|
444
|
+
#
|
|
445
|
+
# XML only, because Atlas overwrites the JSON access copy in place. Pass a
|
|
446
|
+
# `version_id` from {dwc_versions}.
|
|
447
|
+
#
|
|
448
|
+
# @param id [String] the Work's NOID.
|
|
449
|
+
# @param version_id [String] an OCFL version label, e.g. `"v3"`.
|
|
450
|
+
# @param nuid [String, nil] optional acting user's NUID.
|
|
451
|
+
# @param on_behalf_of [String, nil] optional NUID for the `On-Behalf-Of`
|
|
452
|
+
# header.
|
|
453
|
+
# @return [String, nil] the raw XML; `nil` on a `404` (unknown version, or
|
|
454
|
+
# no record ever written).
|
|
455
|
+
# @raise [AtlasRb::ResourceError] on any non-2xx other than `404` / `410`.
|
|
456
|
+
# @example
|
|
457
|
+
# AtlasRb::Resource.dwc_version("w-789", "v3")
|
|
458
|
+
def self.dwc_version(id, version_id, nuid: nil, on_behalf_of: nil)
|
|
459
|
+
read_raw(connection({}, nuid, on_behalf_of: on_behalf_of)
|
|
460
|
+
.get('/resources/' + id + '/dwc/versions/' + version_id))
|
|
461
|
+
end
|
|
462
|
+
|
|
422
463
|
# Shared read path behind every typed `find`: perform a single-resource
|
|
423
464
|
# `GET` and hand the response to {AtlasRb::FaradayHelper#read_body}, which
|
|
424
465
|
# owns the status mapping (`404` → `nil`, `410` → the tombstone body, any
|
|
@@ -485,21 +526,25 @@ module AtlasRb
|
|
|
485
526
|
# @raise [AtlasRb::ResourceError] on any other non-2xx except `410`.
|
|
486
527
|
# @api private
|
|
487
528
|
def self.write_resource(resp)
|
|
529
|
+
guard_write(resp)
|
|
530
|
+
JSON.parse(resp.body)
|
|
531
|
+
end
|
|
532
|
+
private_class_method :write_resource
|
|
533
|
+
|
|
534
|
+
# The status half of {write_resource}, for a write that answers with no
|
|
535
|
+
# body, such as a `204`.
|
|
536
|
+
def self.guard_write(resp)
|
|
488
537
|
if resp.status == 404
|
|
489
538
|
raise AtlasRb::NotFoundError.new("#{request_target(resp)} → 404 (no such resource)", response: resp)
|
|
490
539
|
end
|
|
540
|
+
return if resp.success? || resp.status == 410
|
|
491
541
|
|
|
492
|
-
|
|
493
|
-
raise AtlasRb::ResourceError.new("#{request_target(resp)} → #{resp.status}: #{resp.body}", response: resp)
|
|
494
|
-
end
|
|
495
|
-
|
|
496
|
-
JSON.parse(resp.body)
|
|
542
|
+
raise AtlasRb::ResourceError.new("#{request_target(resp)} → #{resp.status}: #{resp.body}", response: resp)
|
|
497
543
|
end
|
|
498
|
-
private_class_method :
|
|
544
|
+
private_class_method :guard_write
|
|
499
545
|
|
|
500
|
-
# The multipart body behind {
|
|
501
|
-
#
|
|
502
|
-
# naming the surface that produced the edit.
|
|
546
|
+
# The multipart body behind {put_mods} and {put_dwc}: the XML document,
|
|
547
|
+
# plus the optional `origin` tag naming the surface that produced the edit.
|
|
503
548
|
#
|
|
504
549
|
# Atlas records `origin` verbatim on the audit event and never branches on
|
|
505
550
|
# it, so a host names its own surfaces (Cerberus sends `metadata_form`,
|
|
@@ -512,13 +557,13 @@ module AtlasRb
|
|
|
512
557
|
# @param origin [String, nil] the edit-origin tag, or `nil` to send none.
|
|
513
558
|
# @return [Hash] the multipart payload.
|
|
514
559
|
# @api private
|
|
515
|
-
def self.
|
|
560
|
+
def self.xml_upload_payload(xml_path, origin)
|
|
516
561
|
payload = { binary: Faraday::Multipart::FilePart.new(File.open(xml_path),
|
|
517
562
|
"application/xml",
|
|
518
563
|
File.basename(xml_path)) }
|
|
519
564
|
payload[:origin] = origin.to_s unless origin.nil? || origin.to_s.empty?
|
|
520
565
|
payload
|
|
521
566
|
end
|
|
522
|
-
private_class_method :
|
|
567
|
+
private_class_method :xml_upload_payload
|
|
523
568
|
end
|
|
524
569
|
end
|
|
@@ -52,10 +52,61 @@ module AtlasRb
|
|
|
52
52
|
def self.put_mods(id, xml_path, nuid: nil, on_behalf_of: nil, origin: nil)
|
|
53
53
|
unwrap(write_resource(
|
|
54
54
|
multipart(nuid, on_behalf_of: on_behalf_of)
|
|
55
|
-
.put('/resources/' + id + '/mods',
|
|
55
|
+
.put('/resources/' + id + '/mods', xml_upload_payload(xml_path, origin))
|
|
56
56
|
))
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
# Replace a Work's Darwin Core record.
|
|
60
|
+
#
|
|
61
|
+
# `PUT`: the document replaces the whole record. The first call creates it,
|
|
62
|
+
# and a call after {delete_dwc} restores it. Each call appends a version.
|
|
63
|
+
# Atlas checks the document's shape; validating it against
|
|
64
|
+
# `tdwg_dwc_simple.xsd` is the caller's job.
|
|
65
|
+
#
|
|
66
|
+
# @param id [String] the Work's NOID.
|
|
67
|
+
# @param xml_path [String] path to the Simple Darwin Core XML to upload.
|
|
68
|
+
# @param nuid [String, nil] optional acting user's NUID.
|
|
69
|
+
# @param on_behalf_of [String, nil] optional NUID for the `On-Behalf-Of`
|
|
70
|
+
# header.
|
|
71
|
+
# @param origin [String, nil] the editing surface to record on the audit
|
|
72
|
+
# event, e.g. `"xml_loader"`. Omitted from the body when nil.
|
|
73
|
+
# @return [AtlasRb::Mash] the Work's `id` and its terms under `"dwc"`.
|
|
74
|
+
# @raise [AtlasRb::NotFoundError] on `404` — no such id, or not a Work.
|
|
75
|
+
# @raise [AtlasRb::ResourceError] on any other non-2xx. A refused document
|
|
76
|
+
# is a `422` whose body names the rule in `error`: `malformed_xml`,
|
|
77
|
+
# `invalid_root`, `record_count` or `duplicate_term`.
|
|
78
|
+
#
|
|
79
|
+
# @example
|
|
80
|
+
# AtlasRb::Resource.put_dwc("xsj3xmz", "/tmp/dwc.xml", origin: "xml_loader")
|
|
81
|
+
def self.put_dwc(id, xml_path, nuid: nil, on_behalf_of: nil, origin: nil)
|
|
82
|
+
unwrap(write_resource(
|
|
83
|
+
multipart(nuid, on_behalf_of: on_behalf_of)
|
|
84
|
+
.put('/resources/' + id + '/dwc', xml_upload_payload(xml_path, origin))
|
|
85
|
+
))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Withdraw a Work's Darwin Core record.
|
|
89
|
+
#
|
|
90
|
+
# Nothing is purged: Atlas keeps the document and its version history, and
|
|
91
|
+
# the next {put_dwc} restores the record. Until then {Work.dwc} answers
|
|
92
|
+
# `nil` and the Work's `metadata_formats` leaves out `"dwc"`.
|
|
93
|
+
#
|
|
94
|
+
# @param id [String] the Work's NOID.
|
|
95
|
+
# @param nuid [String, nil] optional acting user's NUID.
|
|
96
|
+
# @param on_behalf_of [String, nil] optional NUID for the `On-Behalf-Of`
|
|
97
|
+
# header.
|
|
98
|
+
# @return [true] when the record was withdrawn.
|
|
99
|
+
# @raise [AtlasRb::NotFoundError] on `404` — the Work holds no record, or
|
|
100
|
+
# the id is not a Work.
|
|
101
|
+
# @raise [AtlasRb::ResourceError] on any other non-2xx.
|
|
102
|
+
#
|
|
103
|
+
# @example
|
|
104
|
+
# AtlasRb::Resource.delete_dwc("xsj3xmz")
|
|
105
|
+
def self.delete_dwc(id, nuid: nil, on_behalf_of: nil)
|
|
106
|
+
guard_write(connection({}, nuid, on_behalf_of: on_behalf_of).delete('/resources/' + id + '/dwc'))
|
|
107
|
+
true
|
|
108
|
+
end
|
|
109
|
+
|
|
59
110
|
# Adjust a resource's ACL.
|
|
60
111
|
#
|
|
61
112
|
# `PATCH`, and every key merges: a key you omit keeps its stored value.
|
data/lib/atlas_rb/work.rb
CHANGED
|
@@ -613,6 +613,39 @@ module AtlasRb
|
|
|
613
613
|
))
|
|
614
614
|
end
|
|
615
615
|
|
|
616
|
+
# Fetch the Work's Darwin Core record in the requested format.
|
|
617
|
+
#
|
|
618
|
+
# A Work holds a record only when its `metadata_formats` includes `"dwc"`,
|
|
619
|
+
# so check that before calling: a Work with no record answers `nil` here.
|
|
620
|
+
#
|
|
621
|
+
# @param id [String] the Work ID.
|
|
622
|
+
# @param kind [String] one of `"xml"` (default), `"json"` or `"html"`.
|
|
623
|
+
# `"xml"` is the stored Simple Darwin Core document, byte for byte, for a
|
|
624
|
+
# standalone download. `"html"` is the display block, the counterpart of
|
|
625
|
+
# `Work.mods(id, "html")`; each `<dt>` names its term in `data-term`.
|
|
626
|
+
# @param nuid [String, nil] optional acting user's NUID. On the relay-signing
|
|
627
|
+
# path it is signed into the assertion `sub`; on the BYO-JWT (`ATLAS_JWT`)
|
|
628
|
+
# path it is ignored (identity lives in the token).
|
|
629
|
+
# @param on_behalf_of [String, nil] optional NUID for the `On-Behalf-Of`
|
|
630
|
+
# header. Falls through to {AtlasRb.config}.default_on_behalf_of when
|
|
631
|
+
# omitted.
|
|
632
|
+
# @return [String, AtlasRb::Mash, nil] the raw body for `"xml"` and
|
|
633
|
+
# `"html"`; for `"json"`, the Work unwrapped from its `"work"` key, with
|
|
634
|
+
# the terms under `"dwc"`.
|
|
635
|
+
#
|
|
636
|
+
# `nil` when Atlas answers `404` — the Work holds no record (or it was
|
|
637
|
+
# withdrawn), or the id is not a Work.
|
|
638
|
+
# @raise [AtlasRb::ResourceError] on any non-2xx other than `404` / `410`,
|
|
639
|
+
# such as the `403` for a Work the caller may not read.
|
|
640
|
+
# @example
|
|
641
|
+
# AtlasRb::Work.dwc("w-789", "json")["dwc"]["catalogNumber"] # => "S27880"
|
|
642
|
+
def self.dwc(id, kind = 'xml', nuid: nil, on_behalf_of: nil)
|
|
643
|
+
body = read_raw(connection({}, nuid, on_behalf_of: on_behalf_of).get(ROUTE + id + "/dwc.#{kind}"))
|
|
644
|
+
return body unless kind.to_s == 'json' && body
|
|
645
|
+
|
|
646
|
+
AtlasRb::Mash.new(JSON.parse(body))['work']
|
|
647
|
+
end
|
|
648
|
+
|
|
616
649
|
# List the Collections a Work is a *linked* member of.
|
|
617
650
|
#
|
|
618
651
|
# Wraps `GET /works/<id>/linked_members`. Linked membership is the DAG
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: atlas_rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.26.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Cliff
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|