Class: AtlasRb::Resource

Inherits:
Object
  • Object
show all
Extended by:
FaradayHelper
Defined in:
lib/atlas_rb/resource.rb,
lib/atlas_rb/resource_types.rb,
lib/atlas_rb/resource_writes.rb

Overview

Reopens Resource with the writes that need no type. Atlas serves each one as a verb on the /resources/{id} sub-resource that already serves its GET, so a caller holding only a NOID never resolves the type first.

Loaded after the subclasses because the typed writes delegate here, and because TYPE_MAP in resource_types.rb has the same ordering requirement.

The names are deliberately not update and metadata. Neither typed name says which document it writes, and Resource.mods / .permissions are already taken by the reads — overloading them by arity would give one name two behaviours on the ACL surface.

Atlas refuses a type that cannot take the write; the gem does not pre-check. A MODS write aimed at a FileSet answers 404, the same as the GET on that path.

There are no typed counterparts. One URL serves every type, so a typed write would name a type it could not enforce. The subclasses still answer these methods, because they inherit them — AtlasRb::Work.tombstone(id) is the same call as AtlasRb::Resource.tombstone(id), and neither checks that id names a Work. That has always been true of the generic reads too; Resource.find is the call that reports a type.

Direct Known Subclasses

Blob, Collection, Community, Compilation, Delegate, FileSet, Person, Work

Constant Summary collapse

TYPE_MAP =

Every type the Atlas resolver can answer with, keyed by each spelling the DRS stack produces for it: Atlas's wire key ("file_set"), the Ruby class name Solr indexes as internal_resource ("FileSet"), and the capitalize-of-the-wire-key form ("File_set") that a caller can still be holding from a value this gem emitted before class_for existed. A caller cannot tell which of the three it holds, so all three resolve.

Stated rather than derived: Blob's ROUTE is /files/, so nothing in the routes turns a type into its class either.

{
  "work" => Work, "Work" => Work,
  "collection" => Collection, "Collection" => Collection,
  "community" => Community, "Community" => Community,
  "compilation" => Compilation, "Compilation" => Compilation,
  "file_set" => FileSet, "FileSet" => FileSet, "File_set" => FileSet,
  "blob" => Blob, "Blob" => Blob,
  "delegate" => Delegate, "Delegate" => Delegate,
  "person" => Person, "Person" => Person
}.freeze

Constants included from FaradayHelper

FaradayHelper::ASSERTION_AUDIENCE, FaradayHelper::ASSERTION_ISSUER, FaradayHelper::ASSERTION_TTL, FaradayHelper::INSTRUMENTATION_EVENT

Class Method Summary collapse

Methods included from FaradayHelper

connection, multipart, read_body, read_raw, system_connection, with_file_part

Class Method Details

.class_for(name) ⇒ Class

Resolve a resource-type string to the class that models it.

Use this on any type that arrives as runtime data — find's "klass", a Solr internal_resource value, or Atlas's wire key — rather than reaching into this namespace with const_get. The set is closed and stated in TYPE_MAP; it is not a naming rule.

An unrecognized type raises instead of resolving to nil or to whatever constant happens to bear that name. A caller holding a type this gem does not define has to hear about it here, where the cause is, rather than at the NoMethodError a few frames later.

Examples:

Dispatching on a type that arrives as data

found = AtlasRb::Resource.find("b8gtjvk")
AtlasRb::Resource.class_for(found["klass"]).find(found["resource"]["id"])

Every spelling of one type

AtlasRb::Resource.class_for("file_set") # => AtlasRb::FileSet
AtlasRb::Resource.class_for("FileSet")  # => AtlasRb::FileSet
AtlasRb::Resource.class_for("File_set") # => AtlasRb::FileSet

Parameters:

  • name (String, Symbol)

    a resource type in any of the three spellings TYPE_MAP accepts.

Returns:

  • (Class)

    the AtlasRb class for that type.

Raises:

  • (ArgumentError)

    when the gem defines no class for that type.



54
55
56
57
58
# File 'lib/atlas_rb/resource_types.rb', line 54

def self.class_for(name)
  TYPE_MAP.fetch(name.to_s) do
    raise ArgumentError, "unknown Atlas resource type: #{name.inspect}"
  end
end

.descendant_works(id, page: nil, per_page: nil, include_linked: nil, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash?

Every Work beneath a resource, at any depth — the structural counterpart to Compilation.contents. Wraps GET /resources/<id>/descendant_works, which flattens the resource's full descendant subtree to the Works it contains, gated to what the caller may read and paginated Solr-side. Gives a Collection the flatten-to-Works capability a Set already has, so a bulk export (e.g. hyperion) pages one gated, fast call family instead of the client-side children → find_many → recurse walk.

Returns the same digest shape as find_many / Compilation.contents ({ "id", "noid", "klass", "title", "thumbnail" }) under a "works" key, plus a "pagination" envelope (total / page / per_page / pages). Membership is structural (a_member_of) only; pass include_linked: true to also surface linked members (a_linked_member_of). Restricted Works never appear for a caller who may not read them; tombstoned Works are dropped.

Examples:

Page a Collection's whole subtree of Works

result = AtlasRb::Resource.descendant_works("col-456", per_page: 100)
result["works"].map { |w| w["noid"] }
result.dig("pagination", "pages")

Parameters:

  • id (String)

    an Atlas resource ID (subtree root; any type).

  • page (Integer, nil) (defaults to: nil)

    1-based page (default 1 server-side).

  • per_page (Integer, nil) (defaults to: nil)

    page size (server default 25, capped 100).

  • include_linked (Boolean, nil) (defaults to: nil)

    also include linked members when truthy; structural-only by default.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (AtlasRb::Mash, nil)

    the parsed envelope, with a "works" digest array and a "pagination" block; nil when the id resolves to nothing (404).

Raises:

  • (AtlasRb::ResourceError)

    on any non-2xx other than 404 / 410 (an auth or validation envelope, a 5xx, a proxy's 503), carrying Atlas's status and body so the failure is attributable at the boundary.



149
150
151
152
153
154
155
156
# File 'lib/atlas_rb/resource.rb', line 149

def self.descendant_works(id, page: nil, per_page: nil, include_linked: nil, nuid: nil, on_behalf_of: nil)
  params = {}
  params[:page]           = page           if page
  params[:per_page]       = per_page       if per_page
  params[:include_linked] = include_linked unless include_linked.nil?
  read_body(connection(params, nuid, on_behalf_of: on_behalf_of)
              .get('/resources/' + id + '/descendant_works')) { |body| AtlasRb::Mash.new(body) }
end

.find(id, nuid: nil, on_behalf_of: nil) ⇒ Hash{String => String, Hash}?

Resolve any Atlas resource by ID without knowing its type up front.

The Atlas server returns a single-key JSON object whose key names the resource type ("community", "collection", "work", etc.); this method splits that into a normalized { "klass" => ..., "resource" => ... } pair so callers can dispatch on type.

What the resolver covers

Atlas answers /resources/:id for its Valkyrie-backed types only: Work, Collection, Community, FileSet, Blob, Delegate and Person. A Compilation is an ActiveRecord row in Atlas rather than a Valkyrie resource, so the resolver never finds one — use Compilation.find for those. That makes nil ambiguous: it means "no such id" or "that id names a Compilation".

Examples:

Polymorphic lookup

AtlasRb::Resource.find("abc123")
# => { "klass" => "Work", "resource" => { "id" => "abc123", "title" => "..." } }

Parameters:

  • id (String)

    an Atlas resource ID of any type.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (Hash{String => String, Hash}, nil)

    hash with two keys, or nil when the id resolves to nothing (404):

    • "klass" — the resource type as its class name, e.g. "Work", "FileSet". That is the spelling Solr carries as internal_resource, and class_for turns it into the class.
    • "resource" — the resource payload as a Hash.

Raises:

  • (AtlasRb::ResourceError)

    on any non-2xx other than 404 / 410 (e.g. an auth/validation error envelope), carrying Atlas's status + body.

  • (ArgumentError)

    when Atlas names a type this gem defines no class for. See class_for.



58
59
60
61
62
63
64
65
66
67
# File 'lib/atlas_rb/resource.rb', line 58

def self.find(id, nuid: nil, on_behalf_of: nil)
  result = fetch_resource('/resources/' + id, nuid: nuid, on_behalf_of: on_behalf_of)
  return nil if result.nil?

  # The class's own name, never `capitalize` over the wire key: `capitalize`
  # answers `"File_set"` for a `file_set`, which is not a constant in this
  # namespace, and callers resolve this string to a class.
  AtlasRb::Mash.new("klass" => class_for(result.first[0]).name.split("::").last,
                    "resource" => result.first[1])
end

.find_many(ids, nuid: nil, on_behalf_of: nil) ⇒ Array<AtlasRb::Mash>?

Resolve many resources by NOID in a single round-trip.

Wraps Atlas's POST /resources/find_many, which returns one lightweight digest per resolvable resource — { "id", "noid", "klass", "title", "thumbnail", "tombstoned" } — rather than full typed payloads. Use it anywhere a set of ids would otherwise be resolved with a find-per-id fan-out (breadcrumb chains, linked-member lists, load-destination pickers): one HTTP call instead of N.

The ids travel in the request body, so the list is not bounded by URL length. The result is unordered and may be shorter than the input — unresolvable ids are dropped silently, and tombstoned resources come back flagged ("tombstoned" => true) rather than omitted. Index the result by "noid"; do not assume positional correspondence with ids.

Examples:

Resolve a set of collection titles in one call

nodes  = AtlasRb::Resource.find_many(["col-456", "col-457", "missing"])
by_noid = nodes.index_by { |n| n["noid"] }
by_noid["col-456"].title   # => "Some Collection"

Parameters:

  • ids (Array<String>)

    resource NOIDs to resolve. (Raw Valkyrie ids are not a supported input — the endpoint resolves alternate ids only.)

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (Array<AtlasRb::Mash>, nil)

    one digest Mash per resolved resource (dot- or string-keyed access); empty when nothing resolved.

    nil when Atlas answers 404 — nothing is there to read, or, with a misconfigured ATLAS_URL, the route is not Atlas's at all.

Raises:

  • (AtlasRb::ResourceError)

    on any non-2xx other than 404 / 410 (an auth or validation envelope, a 5xx, a proxy's 503), carrying Atlas's status and body so the failure is attributable at the boundary.



105
106
107
108
109
110
# File 'lib/atlas_rb/resource.rb', line 105

def self.find_many(ids, nuid: nil, on_behalf_of: nil)
  read_body(
    connection({}, nuid, on_behalf_of: on_behalf_of)
      .post('/resources/find_many', JSON.dump(ids: Array(ids)))
  ) { |body| body.map { |node| AtlasRb::Mash.new(node) } }
end

.history(id, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash?

TODO:

Add pagination support once Atlas's history endpoint exposes page / per_page query params. Today the endpoint returns the full history in one shot.

Fetch the audit-event history for a resource.

Wraps Atlas's GET /resources/<id>/history endpoint, which returns the full envelope (resource_id + reverse-chronological events array). The whole envelope is preserved so callers can confirm the events belong to the requested resource; access events as result["events"].

Authorization errors (401 / 403) are intentionally not caught here — they surface as raw Faraday responses for the calling application's rescue layer to translate.

Examples:

result = AtlasRb::Resource.history("abc12345")
result["resource_id"]            # => "abc12345"
result["events"].first["action"] # => "create"

Parameters:

  • id (String)

    an Atlas resource ID.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (AtlasRb::Mash, nil)

    the parsed envelope from GET /resources/<id>/history, with "resource_id" and an "events" array (reverse chronological; possibly empty).

    nil when Atlas answers 404 — nothing is there to read, or, with a misconfigured ATLAS_URL, the route is not Atlas's at all.

Raises:

  • (AtlasRb::ResourceError)

    on any non-2xx other than 404 / 410 (an auth or validation envelope, a 5xx, a proxy's 503), carrying Atlas's status and body so the failure is attributable at the boundary.



249
250
251
252
# File 'lib/atlas_rb/resource.rb', line 249

def self.history(id, nuid: nil, on_behalf_of: nil)
  read_body(connection({}, nuid, on_behalf_of: on_behalf_of)
              .get('/resources/' + id + '/history')) { |body| AtlasRb::Mash.new(body) }
end

.mods(id, kind = nil, nuid: nil, on_behalf_of: nil) ⇒ String?

Fetch the CURRENT MODS of any Modsable resource by NOID — the polymorphic sibling of Work.mods / Collection.mods / Community.mods. Wraps GET /resources/<id>/mods[.kind] and returns the raw response body (not parsed), mirroring the typed wrappers. Lets a caller holding only a NOID (no type) fetch descriptive MODS in one call, instead of resolving the klass first to pick the typed route — e.g. a bulk Collection/Set MODS export that has bare member NOIDs from Collection.children.

Examples:

Bulk-export a Set's members' MODS without klass dispatch

AtlasRb::Collection.children(set_id).each do |noid|
  xml = AtlasRb::Resource.mods(noid, "xml")
end

Parameters:

  • id (String)

    an Atlas resource ID (NOID).

  • kind (String, nil) (defaults to: nil)

    response-format extension: omit for the JSON projection (the server default), or pass "xml" for MODS XML ("json" / "html" also accepted). Output is byte-identical to the typed route for the resolved type.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (String, nil)

    the raw MODS body (XML or JSON per kind). The server returns 404 (empty body) for an unknown id, a non-Modsable resource, or one with no MODS.

Raises:

  • (AtlasRb::ResourceError)

    on any non-2xx other than 404 / 410 (an auth or validation envelope, a 5xx, a proxy's 503), carrying Atlas's status and body so the failure is attributable at the boundary.



283
284
285
286
287
# File 'lib/atlas_rb/resource.rb', line 283

def self.mods(id, kind = nil, nuid: nil, on_behalf_of: nil)
  read_raw(connection({}, nuid, on_behalf_of: on_behalf_of).get(
             '/resources/' + id + '/mods' + (kind.to_s.empty? ? '' : ".#{kind}")
           ))
end

.mods_version(id, version_id, kind: nil, nuid: nil, on_behalf_of: nil) ⇒ String?

Fetch the MODS document as of a specific version.

Wraps Atlas's GET /resources/<id>/mods/versions/<version_id> and returns the raw response body (not parsed) — mirroring Work.mods. Pass a version_id obtained from mods_versions (an opaque OCFL vN label).

Only XML is version-recoverable: the JSON access copy is overwritten in place, so the server serves historical XML (the default). kind: is accepted for parity with Work.mods but XML is currently the only supported format. An unknown version yields a 404 (raw Faraday response).

Examples:

Diff two MODS versions

old_xml = AtlasRb::Resource.mods_version("w-789", "v3")
new_xml = AtlasRb::Resource.mods_version("w-789", "v5")

Parameters:

  • id (String)

    an Atlas resource ID.

  • version_id (String)

    an OCFL version label from mods_versions, e.g. "v3".

  • kind (String, nil) (defaults to: nil)

    response format extension. Omit (or pass "xml") for the historical XML — the only format the server retains.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (String, nil)

    the raw MODS XML body for that version.

    nil when Atlas answers 404 — nothing is there to read, or, with a misconfigured ATLAS_URL, the route is not Atlas's at all.

Raises:

  • (AtlasRb::ResourceError)

    on any non-2xx other than 404 / 410 (an auth or validation envelope, a 5xx, a proxy's 503), carrying Atlas's status and body so the failure is attributable at the boundary.



366
367
368
369
370
371
# File 'lib/atlas_rb/resource.rb', line 366

def self.mods_version(id, version_id, kind: nil, nuid: nil, on_behalf_of: nil)
  read_raw(connection({}, nuid, on_behalf_of: on_behalf_of).get(
             '/resources/' + id + '/mods/versions/' + version_id +
               (kind.to_s.empty? ? '' : ".#{kind}")
           ))
end

.mods_versions(id, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash?

List the retained MODS versions for a resource.

Wraps Atlas's GET /resources/<id>/mods/versions, which returns the full envelope — resource_id plus a reverse-chronological versions array — as an AtlasRb::Mash. Each version descriptor mirrors the audit-event shape (version_id, created, actor_nuid, on_behalf_of_nuid, source, note) so the two streams render with the same helpers; actor fields are correlated from the audit log and may be null when a version has no matching edit event.

Type-agnostic: pass any Modsable resource ID (Community, Collection, Work). A resource with no MODS comes back as { "versions" => [] }.

Version labels are opaque, sortable OCFL vN strings — not a 1-based counter — so treat them as identifiers to feed back into mods_version, not as ordinals. The server admin-gates this endpoint (it exposes edit attribution); 401 / 403 surface as raw Faraday responses, matching history.

Examples:

history = AtlasRb::Resource.mods_versions("w-789")
history["versions"].first["version_id"] # => "v5"
history["versions"].first["actor_nuid"]  # => "000000002"

Parameters:

  • id (String)

    an Atlas resource ID.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (AtlasRb::Mash, nil)

    the parsed envelope, with "resource_id" and a "versions" array (reverse chronological; possibly empty).

    nil when Atlas answers 404 — nothing is there to read, or, with a misconfigured ATLAS_URL, the route is not Atlas's at all.

Raises:

  • (AtlasRb::ResourceError)

    on any non-2xx other than 404 / 410 (an auth or validation envelope, a 5xx, a proxy's 503), carrying Atlas's status and body so the failure is attributable at the boundary.



327
328
329
330
# File 'lib/atlas_rb/resource.rb', line 327

def self.mods_versions(id, nuid: nil, on_behalf_of: nil)
  read_body(connection({}, nuid, on_behalf_of: on_behalf_of)
              .get('/resources/' + id + '/mods/versions')) { |body| AtlasRb::Mash.new(body) }
end

.permissions(id, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash?

Fetch the access-control entries for a resource.

Routed through fetch_resource so a refusal stays a refusal. Atlas gates this endpoint on the caller's read right over the resource itself and answers 403 with an { "error", "action", "subject" } envelope, which has no "resource" key — parsing it directly would hand back the same nil an unknown id gives, and a caller cannot tell "may not see it" from "is not there".

Examples:

AtlasRb::Resource.permissions("abc123")
# => { "type" => "Work", "depositor" => "001234567",
#      "read" => [...], "edit" => [...], "edit_users" => [...] }

Parameters:

  • id (String)

    an Atlas resource ID.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (AtlasRb::Mash, nil)

    the "resource" payload from GET /resources/<id>/permissions, typically containing read/write/admin grant lists; nil when Atlas reports the resource is absent (404).

Raises:

  • (AtlasRb::ResourceError)

    on any other non-2xx — notably 403, carrying status so the caller can render its own forbidden page.



207
208
209
210
211
212
# File 'lib/atlas_rb/resource.rb', line 207

def self.permissions(id, nuid: nil, on_behalf_of: nil)
  result = fetch_resource('/resources/' + id + '/permissions', nuid: nuid, on_behalf_of: on_behalf_of)
  return nil if result.nil?

  AtlasRb::Mash.new(result)["resource"]
end

.preview(xml_path, nuid: nil, on_behalf_of: nil) ⇒ String

Validate a MODS XML document against Atlas's schema without persisting it.

Useful for surfacing validation errors in UIs before the user commits.

Examples:

AtlasRb::Resource.preview("/tmp/draft-mods.xml")

Parameters:

  • xml_path (String)

    path to a MODS XML file on disk.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

Returns:

  • (String)

    the raw response body from POST /resources/preview — typically a JSON or XML error report.



174
175
176
177
178
179
# File 'lib/atlas_rb/resource.rb', line 174

def self.preview(xml_path, nuid: nil, on_behalf_of: nil)
  payload = { binary: Faraday::Multipart::FilePart.new(File.open(xml_path),
                                                       "application/xml",
                                                       File.basename(xml_path)) }
  multipart(nuid, on_behalf_of: on_behalf_of).post('/resources/preview', payload)&.body
end

.put_mods(id, xml_path, nuid: nil, on_behalf_of: nil, origin: nil) ⇒ AtlasRb::Mash

Replace a resource's MODS document.

PUT, not PATCH: the caller assembles the whole document. Descriptive merge logic lives in the client, so a partial document replaces rather than merges, and the verb says so.

Examples:

AtlasRb::Resource.put_mods("xsj3xmz", "/tmp/work.xml", origin: "xml_editor")

Parameters:

  • id (String)

    the resource's NOID.

  • xml_path (String)

    path to the MODS XML to upload.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID. On the relay-signing path it is signed into the assertion sub; on the BYO-JWT (ATLAS_JWT) path it is ignored (identity lives in the token).

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header. Falls through to AtlasRb.config.default_on_behalf_of when omitted.

  • origin (String, nil) (defaults to: nil)

    the editing surface to record on the audit event, e.g. "xml_editor". Omitted from the body when nil.

Returns:

Raises:



52
53
54
55
56
57
# File 'lib/atlas_rb/resource_writes.rb', line 52

def self.put_mods(id, xml_path, nuid: nil, on_behalf_of: nil, origin: nil)
  unwrap(write_resource(
           multipart(nuid, on_behalf_of: on_behalf_of)
             .put('/resources/' + id + '/mods', mods_upload_payload(xml_path, origin))
         ))
end

.reparent(id, new_parent_id = nil, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash

Move a resource under a different parent.

Authorization is two-sided — the caller needs the right on the moved node and on the destination. Omit new_parent_id to move a Community to the top of the tree.

Parameters:

  • id (String)

    the NOID of the resource to move.

  • new_parent_id (String, nil) (defaults to: nil)

    the destination's NOID.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID.

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header.

Returns:

Raises:



124
125
126
127
128
129
# File 'lib/atlas_rb/resource_writes.rb', line 124

def self.reparent(id, new_parent_id = nil, nuid: nil, on_behalf_of: nil)
  unwrap(write_resource(
           connection({ parent_id: new_parent_id }, nuid, on_behalf_of: on_behalf_of)
             .patch('/resources/' + id + '/parent')
         ))
end

.set_permissions(id, values, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash

Adjust a resource's ACL.

PATCH, and every key merges: a key you omit keeps its stored value. Pass an explicit empty array to clear one. So changing a single slot no longer needs the read-the-whole-envelope-and-write-it-back round trip.

Examples:

Publish, leaving every other key alone

AtlasRb::Resource.set_permissions("xsj3xmz", { "read" => ["public"] })

Parameters:

  • id (String)

    the resource's NOID.

  • values (Hash)

    the ACL keys to change — any of embargo, depositor, proxy_uploader, edit_users, read, edit.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID.

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header.

Returns:

Raises:

  • (AtlasRb::NotFoundError)

    on 404 — the write did not happen.

  • (AtlasRb::ResourceError)

    on any other non-2xx, including the 403 Atlas answers when a caller tries to remove a grant for a group it does not belong to.



79
80
81
82
83
84
# File 'lib/atlas_rb/resource_writes.rb', line 79

def self.set_permissions(id, values, nuid: nil, on_behalf_of: nil)
  unwrap(write_resource(
           connection({ permissions: values }, nuid, on_behalf_of: on_behalf_of)
             .patch('/resources/' + id + '/permissions')
         ))
end

.set_thumbnails(id, thumbnail: nil, thumbnail_2x: nil, preview: nil, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash

Attach the three thumbnail-family IIIF Delegate URIs to a resource.

Only the URIs you pass are upserted; an omitted key is left untouched.

Parameters:

  • id (String)

    the resource's NOID.

  • thumbnail (String, nil) (defaults to: nil)

    IIIF URI for the ~85² thumbnail.

  • thumbnail_2x (String, nil) (defaults to: nil)

    IIIF URI for the ~170² 2x thumbnail.

  • preview (String, nil) (defaults to: nil)

    IIIF URI for the ~500w preview image.

  • nuid (String, nil) (defaults to: nil)

    optional acting user's NUID.

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header.

Returns:

Raises:



101
102
103
104
105
106
107
# File 'lib/atlas_rb/resource_writes.rb', line 101

def self.set_thumbnails(id, thumbnail: nil, thumbnail_2x: nil, preview: nil, nuid: nil, on_behalf_of: nil)
  body = { thumbnail: thumbnail, thumbnail_2x: thumbnail_2x, preview: preview }.compact
  unwrap(write_resource(
           connection({}, nuid, on_behalf_of: on_behalf_of)
             .patch('/resources/' + id + '/thumbnails', JSON.dump(body))
         ))
end

.tombstone(id, nuid: nil, on_behalf_of: nil) ⇒ Faraday::Response

Restore is the operator's counterpart and lives in Admin::Resource, where the namespace is the marker.

Tombstone (withdraw) a resource.

Returns the raw response rather than raising, because Atlas refuses a container that still holds live children with a 422 carrying has_live_children — a legitimate answer the caller has to read, not an error. Reversible via restore.

Parameters:

  • id (String)

    the resource's NOID.

  • nuid (String, nil) (defaults to: nil)

    the acting user's NUID, stamped on the resource as tombstoned_by.

  • on_behalf_of (String, nil) (defaults to: nil)

    optional NUID for the On-Behalf-Of header.

Returns:

  • (Faraday::Response)

    the raw response — read status yourself.



147
148
149
# File 'lib/atlas_rb/resource_writes.rb', line 147

def self.tombstone(id, nuid: nil, on_behalf_of: nil)
  connection({}, nuid, on_behalf_of: on_behalf_of).post('/resources/' + id + '/tombstone')
end