atlas_rb 1.3.0 → 1.3.2
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 +67 -0
- data/Gemfile.lock +1 -1
- data/README.md +38 -0
- data/lib/atlas_rb/resource.rb +76 -0
- data/lib/atlas_rb/user.rb +91 -0
- data/lib/atlas_rb.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 54691ff87af06d611d63a27333682abfd284c67d6990d0c8400ea2b9b80adb92
|
|
4
|
+
data.tar.gz: 7d3119d56763694dad36c69ded4cbf975af62d6eb070baf36c0df02f422259f1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 86dc095d2be7db4fdefe997cc6b33fabd0d3c1826804b0521fda48b06d17ec4cd3fde492a3926114965d4354823f55043ea7559d4ce82dcc06a288b7fa8afecd
|
|
7
|
+
data.tar.gz: c31c2bea0442ec082ede4a2328c6f7471eb02151021c6e08620b4fef5b254996ad424816493e8d955e202f5c5444e800393b85064dc9feb58a61cbaf126a9e08
|
data/.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.3.
|
|
1
|
+
1.3.2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,72 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.3.2
|
|
4
|
+
|
|
5
|
+
### Added — `AtlasRb::User` (read-only user directory)
|
|
6
|
+
|
|
7
|
+
A user-context binding for Atlas's user directory endpoints — recipient
|
|
8
|
+
typeahead and NUID → name resolution for any surface that today renders a
|
|
9
|
+
bare NUID (User Inbox sender display, Audit History chips, Rights history).
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
AtlasRb::User.search("jan", nuid: "000000002")
|
|
13
|
+
# => [{ "nuid" => "001234567", "name" => "Doe, Jane" }, ...]
|
|
14
|
+
|
|
15
|
+
AtlasRb::User.find_by_nuid("001234567")
|
|
16
|
+
# => { "nuid" => "001234567", "name" => "Doe, Jane" }
|
|
17
|
+
|
|
18
|
+
AtlasRb::User.resolve(["001234567", "007654321"])
|
|
19
|
+
# => one entry per resolvable NUID, ordered by name
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- `search` is the typeahead: case-insensitive match on name, prefix match
|
|
23
|
+
on NUID. Atlas caps the list at 10 and orders by name.
|
|
24
|
+
- `resolve` batch-resolves up to 100 NUIDs in one round-trip (an inbox
|
|
25
|
+
page of senders in one call). Unresolvable NUIDs are dropped — callers
|
|
26
|
+
index by `nuid`.
|
|
27
|
+
- `find_by_nuid` resolves a single NUID; returns `nil` on Atlas's 404
|
|
28
|
+
(unknown NUID, or one held by an excluded role — indistinguishable on
|
|
29
|
+
the wire by design).
|
|
30
|
+
- Minimal disclosure is enforced server-side: entries carry `nuid` +
|
|
31
|
+
`name` only, and `anonymous` / `guest` / `system` rows never appear.
|
|
32
|
+
- Deliberately **not** under `AtlasRb::System` — this is an acting-user
|
|
33
|
+
capability on the ordinary `ATLAS_TOKEN` + `User:` header pairing; the
|
|
34
|
+
`System` namespace stays reserved for system-token calls.
|
|
35
|
+
|
|
36
|
+
## 1.3.1
|
|
37
|
+
|
|
38
|
+
### Added — `AtlasRb::Resource.mods_versions` / `mods_version` (MODS version history)
|
|
39
|
+
|
|
40
|
+
Two bindings for Atlas's MODS version-history endpoints. `mods_versions`
|
|
41
|
+
lists the retained versions of a resource's descriptive metadata;
|
|
42
|
+
`mods_version` fetches the raw MODS XML as of a specific version — together
|
|
43
|
+
enough to drive a line-diff between any two MODS states.
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
history = AtlasRb::Resource.mods_versions("w-789")
|
|
47
|
+
history["versions"].first["version_id"] # => "v5" (newest)
|
|
48
|
+
history["versions"].first["actor_nuid"] # => "000000002"
|
|
49
|
+
|
|
50
|
+
old_xml = AtlasRb::Resource.mods_version("w-789", "v3")
|
|
51
|
+
new_xml = AtlasRb::Resource.mods_version("w-789", "v5")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- `mods_versions` returns the full envelope (`resource_id` + a
|
|
55
|
+
reverse-chronological `versions` array) as an `AtlasRb::Mash`. Each
|
|
56
|
+
descriptor mirrors the audit-event shape (`version_id`, `created`,
|
|
57
|
+
`actor_nuid`, `on_behalf_of_nuid`, `source`, `note`); actor fields are
|
|
58
|
+
correlated from the audit log and may be `null`. Admin-gated server-side.
|
|
59
|
+
- `mods_version` returns the **raw XML body** (mirroring `Work.mods`). Only
|
|
60
|
+
XML is version-recoverable — the JSON access copy is overwritten in place
|
|
61
|
+
— so `kind:` is accepted for parity but XML is the only retained format.
|
|
62
|
+
- Version labels are opaque, sortable OCFL `vN` strings (a Blob's
|
|
63
|
+
preservation envelope occupies earlier versions, so the first MODS
|
|
64
|
+
version is typically `v3`). Treat them as identifiers to feed back into
|
|
65
|
+
`mods_version`, not as ordinals.
|
|
66
|
+
- Both are type-agnostic (Community / Collection / Work) and live on
|
|
67
|
+
`Resource` beside `history` / `permissions`. A resource with no MODS
|
|
68
|
+
returns `{ "versions" => [] }`.
|
|
69
|
+
|
|
3
70
|
## 1.3.0
|
|
4
71
|
|
|
5
72
|
### Added — `AtlasRb::Resource.find_many` (batch resolve by NOID)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -245,6 +245,44 @@ mode-less session events. Atlas stamps `occurred_at` server-side.
|
|
|
245
245
|
Authorization errors (`401` / `403`) surface as raw Faraday responses,
|
|
246
246
|
matching `Resource.history`.
|
|
247
247
|
|
|
248
|
+
### MODS version history
|
|
249
|
+
|
|
250
|
+
Every descriptive-metadata edit retains the prior MODS XML on the server.
|
|
251
|
+
`Resource.mods_versions` lists the retained versions; `Resource.mods_version`
|
|
252
|
+
fetches the raw MODS XML as of one of them — together enough to render a
|
|
253
|
+
line-diff between any two MODS states. Both are type-agnostic (pass any
|
|
254
|
+
Community, Collection, or Work ID).
|
|
255
|
+
|
|
256
|
+
```ruby
|
|
257
|
+
history = AtlasRb::Resource.mods_versions("w-789")
|
|
258
|
+
history["resource_id"] # => "w-789"
|
|
259
|
+
history["versions"].first["version_id"] # => "v5" (newest first)
|
|
260
|
+
history["versions"].first["actor_nuid"] # => "000000002" (or nil)
|
|
261
|
+
|
|
262
|
+
# Fetch two versions and diff them:
|
|
263
|
+
old_xml = AtlasRb::Resource.mods_version("w-789", "v3")
|
|
264
|
+
new_xml = AtlasRb::Resource.mods_version("w-789", "v5")
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`mods_versions` returns the full envelope (`resource_id` + a
|
|
268
|
+
reverse-chronological `versions` array) as an `AtlasRb::Mash`; each
|
|
269
|
+
descriptor mirrors the audit-event shape (`version_id`, `created`,
|
|
270
|
+
`actor_nuid`, `on_behalf_of_nuid`, `source`, `note`), so the two streams
|
|
271
|
+
render with the same helpers. Actor attribution is correlated from the
|
|
272
|
+
audit log and may be `null`. The endpoint is admin-gated server-side
|
|
273
|
+
(it exposes edit attribution).
|
|
274
|
+
|
|
275
|
+
`mods_version` returns the **raw XML body** — like `Work.mods`, not a Mash.
|
|
276
|
+
Only XML is version-recoverable (the JSON access copy is overwritten in
|
|
277
|
+
place), so the server serves historical XML; `kind:` is accepted for parity
|
|
278
|
+
with `Work.mods` but XML is the only retained format.
|
|
279
|
+
|
|
280
|
+
Version labels are **opaque, sortable OCFL `vN` strings**, not a 1-based
|
|
281
|
+
counter — a Blob's preservation envelope occupies earlier versions, so the
|
|
282
|
+
first MODS version is typically `v3`. Treat them as identifiers to feed back
|
|
283
|
+
into `mods_version`. A resource with no MODS returns `{ "versions" => [] }`;
|
|
284
|
+
`401` / `403` surface as raw Faraday responses, matching `Resource.history`.
|
|
285
|
+
|
|
248
286
|
### Re-parenting
|
|
249
287
|
|
|
250
288
|
`reparent` moves a resource to a new structural parent, binding Atlas's
|
data/lib/atlas_rb/resource.rb
CHANGED
|
@@ -166,5 +166,81 @@ module AtlasRb
|
|
|
166
166
|
.get('/resources/' + id + '/history')&.body
|
|
167
167
|
))
|
|
168
168
|
end
|
|
169
|
+
|
|
170
|
+
# List the retained MODS versions for a resource.
|
|
171
|
+
#
|
|
172
|
+
# Wraps Atlas's `GET /resources/<id>/mods/versions`, which returns the
|
|
173
|
+
# full envelope — `resource_id` plus a reverse-chronological `versions`
|
|
174
|
+
# array — as an `AtlasRb::Mash`. Each version descriptor mirrors the
|
|
175
|
+
# audit-event shape (`version_id`, `created`, `actor_nuid`,
|
|
176
|
+
# `on_behalf_of_nuid`, `source`, `note`) so the two streams render with
|
|
177
|
+
# the same helpers; actor fields are correlated from the audit log and
|
|
178
|
+
# may be `null` when a version has no matching edit event.
|
|
179
|
+
#
|
|
180
|
+
# Type-agnostic: pass any Modsable resource ID (Community, Collection,
|
|
181
|
+
# Work). A resource with no MODS comes back as `{ "versions" => [] }`.
|
|
182
|
+
#
|
|
183
|
+
# Version labels are opaque, sortable OCFL `vN` strings — not a 1-based
|
|
184
|
+
# counter — so treat them as identifiers to feed back into
|
|
185
|
+
# {mods_version}, not as ordinals. The server admin-gates this endpoint
|
|
186
|
+
# (it exposes edit attribution); `401` / `403` surface as raw Faraday
|
|
187
|
+
# responses, matching {history}.
|
|
188
|
+
#
|
|
189
|
+
# @param id [String] an Atlas resource ID.
|
|
190
|
+
# @param nuid [String, nil] optional acting user's NUID, forwarded as the
|
|
191
|
+
# `User:` header. Required for cerberus-token requests; legacy bearer
|
|
192
|
+
# tokens still resolve without it.
|
|
193
|
+
# @param on_behalf_of [String, nil] optional NUID for the `On-Behalf-Of`
|
|
194
|
+
# header. Falls through to {AtlasRb.config}.default_on_behalf_of when
|
|
195
|
+
# omitted.
|
|
196
|
+
# @return [AtlasRb::Mash] the parsed envelope, with `"resource_id"` and a
|
|
197
|
+
# `"versions"` array (reverse chronological; possibly empty).
|
|
198
|
+
#
|
|
199
|
+
# @example
|
|
200
|
+
# history = AtlasRb::Resource.mods_versions("w-789")
|
|
201
|
+
# history["versions"].first["version_id"] # => "v5"
|
|
202
|
+
# history["versions"].first["actor_nuid"] # => "000000002"
|
|
203
|
+
def self.mods_versions(id, nuid: nil, on_behalf_of: nil)
|
|
204
|
+
AtlasRb::Mash.new(JSON.parse(
|
|
205
|
+
connection({}, nuid, on_behalf_of: on_behalf_of)
|
|
206
|
+
.get('/resources/' + id + '/mods/versions')&.body
|
|
207
|
+
))
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Fetch the MODS document as of a specific version.
|
|
211
|
+
#
|
|
212
|
+
# Wraps Atlas's `GET /resources/<id>/mods/versions/<version_id>` and
|
|
213
|
+
# returns the **raw response body** (not parsed) — mirroring
|
|
214
|
+
# {Work.mods}. Pass a `version_id` obtained from {mods_versions} (an
|
|
215
|
+
# opaque OCFL `vN` label).
|
|
216
|
+
#
|
|
217
|
+
# Only XML is version-recoverable: the JSON access copy is overwritten in
|
|
218
|
+
# place, so the server serves historical XML (the default). `kind:` is
|
|
219
|
+
# accepted for parity with {Work.mods} but XML is currently the only
|
|
220
|
+
# supported format. An unknown version yields a `404` (raw Faraday
|
|
221
|
+
# response).
|
|
222
|
+
#
|
|
223
|
+
# @param id [String] an Atlas resource ID.
|
|
224
|
+
# @param version_id [String] an OCFL version label from {mods_versions},
|
|
225
|
+
# e.g. `"v3"`.
|
|
226
|
+
# @param kind [String, nil] response format extension. Omit (or pass
|
|
227
|
+
# `"xml"`) for the historical XML — the only format the server retains.
|
|
228
|
+
# @param nuid [String, nil] optional acting user's NUID, forwarded as the
|
|
229
|
+
# `User:` header. Required for cerberus-token requests; legacy bearer
|
|
230
|
+
# tokens still resolve without it.
|
|
231
|
+
# @param on_behalf_of [String, nil] optional NUID for the `On-Behalf-Of`
|
|
232
|
+
# header. Falls through to {AtlasRb.config}.default_on_behalf_of when
|
|
233
|
+
# omitted.
|
|
234
|
+
# @return [String] the raw MODS XML body for that version.
|
|
235
|
+
#
|
|
236
|
+
# @example Diff two MODS versions
|
|
237
|
+
# old_xml = AtlasRb::Resource.mods_version("w-789", "v3")
|
|
238
|
+
# new_xml = AtlasRb::Resource.mods_version("w-789", "v5")
|
|
239
|
+
def self.mods_version(id, version_id, kind: nil, nuid: nil, on_behalf_of: nil)
|
|
240
|
+
connection({}, nuid, on_behalf_of: on_behalf_of).get(
|
|
241
|
+
'/resources/' + id + '/mods/versions/' + version_id +
|
|
242
|
+
(kind.present? ? ".#{kind}" : '')
|
|
243
|
+
)&.body
|
|
244
|
+
end
|
|
169
245
|
end
|
|
170
246
|
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AtlasRb
|
|
4
|
+
# Read-only user directory lookups — typeahead search and NUID → name
|
|
5
|
+
# resolution.
|
|
6
|
+
#
|
|
7
|
+
# This is a **user-context** binding: calls authenticate as the acting
|
|
8
|
+
# user via the standard `ATLAS_TOKEN` + `User:` header pairing, like every
|
|
9
|
+
# other top-level class. It is deliberately *not* part of
|
|
10
|
+
# {AtlasRb::System} — that namespace is structurally reserved for
|
|
11
|
+
# system-token calls ({System::User.find_or_create}), and directory
|
|
12
|
+
# lookups are an ordinary logged-in-user capability.
|
|
13
|
+
#
|
|
14
|
+
# Atlas enforces minimal disclosure: every entry carries `nuid` + `name`
|
|
15
|
+
# only (no email, role, or groups), and rows with role `anonymous`,
|
|
16
|
+
# `guest`, or `system` are never returned. Per the layering principle the
|
|
17
|
+
# gem adds nothing on top — no caching, no name parsing, no result
|
|
18
|
+
# shaping; presentation belongs to the host application.
|
|
19
|
+
class User
|
|
20
|
+
extend AtlasRb::FaradayHelper
|
|
21
|
+
|
|
22
|
+
# Atlas REST endpoint prefix for the user directory.
|
|
23
|
+
# @api private
|
|
24
|
+
ROUTE = "/users"
|
|
25
|
+
|
|
26
|
+
# Typeahead search of the user directory.
|
|
27
|
+
#
|
|
28
|
+
# Case-insensitive match on name, prefix match on NUID (so typing a
|
|
29
|
+
# known NUID works too). Atlas caps the result (10 entries) and orders
|
|
30
|
+
# it by name; a blank query resolves to an empty list.
|
|
31
|
+
#
|
|
32
|
+
# @param query [String] name fragment or NUID prefix to match.
|
|
33
|
+
# @param nuid [String, nil] optional acting user's NUID, forwarded as the
|
|
34
|
+
# `User:` header. Required for cerberus-token requests; legacy bearer
|
|
35
|
+
# tokens still resolve without it.
|
|
36
|
+
# @return [Array<AtlasRb::Mash>] matching directory entries, each
|
|
37
|
+
# carrying `nuid` and `name`.
|
|
38
|
+
#
|
|
39
|
+
# @example Recipient typeahead
|
|
40
|
+
# AtlasRb::User.search("jan", nuid: "000000002")
|
|
41
|
+
# # => [{ "nuid" => "001234567", "name" => "Doe, Jane" }, ...]
|
|
42
|
+
def self.search(query, nuid: nil)
|
|
43
|
+
JSON.parse(
|
|
44
|
+
connection({ q: query }, nuid).get(ROUTE)&.body
|
|
45
|
+
).map { |entry| AtlasRb::Mash.new(entry) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Resolve a single NUID to a directory entry.
|
|
49
|
+
#
|
|
50
|
+
# @param target_nuid [String] the NUID being looked up — the *subject*
|
|
51
|
+
# of the call, distinct from the acting `nuid:` kwarg.
|
|
52
|
+
# @param nuid [String, nil] optional acting user's NUID, forwarded as the
|
|
53
|
+
# `User:` header. Required for cerberus-token requests; legacy bearer
|
|
54
|
+
# tokens still resolve without it.
|
|
55
|
+
# @return [AtlasRb::Mash, nil] the `nuid` + `name` entry, or `nil` when
|
|
56
|
+
# Atlas reports the NUID as absent (unknown, or held by an excluded
|
|
57
|
+
# role — the two are indistinguishable on the wire by design).
|
|
58
|
+
#
|
|
59
|
+
# @example Sender-name display
|
|
60
|
+
# AtlasRb::User.find_by_nuid("001234567")
|
|
61
|
+
# # => { "nuid" => "001234567", "name" => "Doe, Jane" }
|
|
62
|
+
def self.find_by_nuid(target_nuid, nuid: nil)
|
|
63
|
+
response = connection({}, nuid).get("#{ROUTE}/by_nuid/#{target_nuid}")
|
|
64
|
+
return nil if response.status == 404
|
|
65
|
+
|
|
66
|
+
AtlasRb::Mash.new(JSON.parse(response.body))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Batch-resolve a set of NUIDs to directory entries in one call.
|
|
70
|
+
#
|
|
71
|
+
# Same response shape as {.search}. Unresolvable NUIDs (unknown or
|
|
72
|
+
# excluded-role) are dropped, so the result may be shorter than the
|
|
73
|
+
# input — callers index by `nuid`. Atlas caps the batch at 100.
|
|
74
|
+
#
|
|
75
|
+
# @param nuids [Array<String>, String] the NUIDs to resolve.
|
|
76
|
+
# @param nuid [String, nil] optional acting user's NUID, forwarded as the
|
|
77
|
+
# `User:` header. Required for cerberus-token requests; legacy bearer
|
|
78
|
+
# tokens still resolve without it.
|
|
79
|
+
# @return [Array<AtlasRb::Mash>] resolved entries, each carrying `nuid`
|
|
80
|
+
# and `name`, ordered by name.
|
|
81
|
+
#
|
|
82
|
+
# @example Resolve an inbox page of senders in one round-trip
|
|
83
|
+
# senders = AtlasRb::User.resolve(["001234567", "007654321"])
|
|
84
|
+
# by_nuid = senders.index_by { |entry| entry["nuid"] }
|
|
85
|
+
def self.resolve(nuids, nuid: nil)
|
|
86
|
+
JSON.parse(
|
|
87
|
+
connection({ nuids: Array(nuids).join(",") }, nuid).get(ROUTE)&.body
|
|
88
|
+
).map { |entry| AtlasRb::Mash.new(entry) }
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/atlas_rb.rb
CHANGED
|
@@ -18,6 +18,7 @@ require_relative "atlas_rb/work"
|
|
|
18
18
|
require_relative "atlas_rb/file_set"
|
|
19
19
|
require_relative "atlas_rb/blob"
|
|
20
20
|
require_relative "atlas_rb/delegate"
|
|
21
|
+
require_relative "atlas_rb/user"
|
|
21
22
|
require_relative "atlas_rb/admin"
|
|
22
23
|
require_relative "atlas_rb/admin/work"
|
|
23
24
|
require_relative "atlas_rb/admin/collection"
|
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.3.
|
|
4
|
+
version: 1.3.2
|
|
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-06-
|
|
11
|
+
date: 2026-06-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -134,6 +134,7 @@ files:
|
|
|
134
134
|
- lib/atlas_rb/middleware/raise_on_stale_resource.rb
|
|
135
135
|
- lib/atlas_rb/resource.rb
|
|
136
136
|
- lib/atlas_rb/system/user.rb
|
|
137
|
+
- lib/atlas_rb/user.rb
|
|
137
138
|
- lib/atlas_rb/version.rb
|
|
138
139
|
- lib/atlas_rb/work.rb
|
|
139
140
|
- sig/atlas_rb.rbs
|