Class: AtlasRb::Community

Inherits:
Resource show all
Defined in:
lib/atlas_rb/community.rb

Overview

A top-level grouping in the Atlas hierarchy.

Communities are organizational containers — they hold Collections and, optionally, sub-Communities. Most institutional structure (departments, programs, projects) is modeled as a tree of Communities with Collections at the leaves.

See also: Collection, Work.

Constant Summary collapse

ROUTE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Atlas REST endpoint prefix for this resource.

"/communities/"

Constants included from FaradayHelper

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

Class Method Summary collapse

Methods inherited from Resource

descendant_works, find_many, history, mods_version, mods_versions, permissions, preview

Methods included from FaradayHelper

#connection, #multipart, #system_connection, #with_file_part

Class Method Details

.children(id, nuid: nil, on_behalf_of: nil) ⇒ Array<String>

List the immediate children (sub-Communities and Collections) of a Community.

The endpoint returns just the noids; resolve each through Resource.find (which dispatches by type) when richer payloads are needed.

Examples:

AtlasRb::Community.children("c-123")
# => ["fn106x926", "kw52j804p"]

Parameters:

  • id (String)

    the parent Community 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:

  • (Array<String>)

    child noids from GET /communities/<id>/children.



169
170
171
172
173
# File 'lib/atlas_rb/community.rb', line 169

def self.children(id, nuid: nil, on_behalf_of: nil)
  JSON.parse(
    connection({}, nuid, on_behalf_of: on_behalf_of).get(ROUTE + id + '/children')&.body
  )
end

.create(id = nil, xml_path = nil, nuid: nil, on_behalf_of: nil, depositor: nil) ⇒ Hash

Create a new Community, optionally seeded with MODS metadata.

Pass id = nil to create a top-level Community; pass a Community ID to nest the new Community beneath an existing one.

Examples:

Top-level community, no metadata

AtlasRb::Community.create(nil)

Sub-community seeded from MODS

AtlasRb::Community.create("c-parent", "/tmp/dept-mods.xml")

An institutional container owned by nobody

AtlasRb::Community.create("c-parent", depositor: "000000099")

Parameters:

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

    the parent Community ID, or nil for a top-level Community.

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

    optional path to a MODS XML file. When given, the Community is created and immediately patched with the metadata in the file; the returned Hash reflects the patched state.

  • 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.

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

    NUID to stamp as the Community's intellectual owner. Omit it and Atlas falls through to the acting user. Supply it to attribute a container to someone other than whoever is authorizing the call — e.g. seeding an institutional tree as an admin while attributing it to the anonymous NUID, since nobody personally owns those containers and access to them is via Grouper groups. The depositor is immutable post-create; there is no setter on the update surface.

Returns:

  • (Hash)

    the created Community payload (post-update if xml_path was supplied).



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/atlas_rb/community.rb', line 73

def self.create(id = nil, xml_path = nil, nuid: nil, on_behalf_of: nil, depositor: nil)
  params = { parent_id: id }
  params[:depositor] = depositor if depositor
  result = AtlasRb::Mash.new(JSON.parse(
    connection(params, nuid, on_behalf_of: on_behalf_of).post(ROUTE)&.body
  ))["community"]
  return result if xml_path.to_s.empty?

  update(result["id"], xml_path, nuid: nuid, on_behalf_of: on_behalf_of)
  find(result["id"], nuid: nuid, on_behalf_of: on_behalf_of)
end

.find(id, nuid: nil, on_behalf_of: nil) ⇒ Hash?

Fetch a single Community by ID.

Examples:

AtlasRb::Community.find("c-123")
# => { "id" => "c-123", "title" => "College of Engineering", ... }

Parameters:

  • id (String)

    the Community 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:

  • (Hash, nil)

    the "community" object from the JSON response, already unwrapped, or nil when the Community does not exist (404).

Raises:

  • (AtlasRb::ResourceError)

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



34
35
36
37
# File 'lib/atlas_rb/community.rb', line 34

def self.find(id, nuid: nil, on_behalf_of: nil)
  body = fetch_resource(ROUTE + id, nuid: nuid, on_behalf_of: on_behalf_of)
  body && AtlasRb::Mash.new(body)["community"]
end

.metadata(id, values, nuid: nil, on_behalf_of: nil) ⇒ Hash

Patch individual descriptive-metadata fields without uploading a full MODS document.

Scoped to user-authored descriptive metadata only. Programmatic writes of machine-set Delegate URIs (thumbnails) have their own purpose-specific endpoint — see set_thumbnails.

Examples:

AtlasRb::Community.("c-123", title: "New Name")

Parameters:

  • id (String)

    the Community ID.

  • values (Hash)

    field-level metadata updates (shape determined by the Atlas server, typically a mapping from MODS field name to value).

  • 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)

    the parsed JSON response.



218
219
220
221
222
# File 'lib/atlas_rb/community.rb', line 218

def self.(id, values, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({ metadata: values }, nuid, on_behalf_of: on_behalf_of).patch(ROUTE + id)&.body
  ))
end

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

Fetch the Community's MODS representation in the requested format.

Examples:

HTML rendering for display

AtlasRb::Community.mods("c-123", "html")

Parameters:

  • id (String)

    the Community ID.

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

    one of "json" (default when omitted), "html", or "xml". When nil, Atlas returns its default representation.

  • 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 (JSON, HTML, or XML serialized as a string).



275
276
277
278
279
280
# File 'lib/atlas_rb/community.rb', line 275

def self.mods(id, kind = nil, nuid: nil, on_behalf_of: nil)
  # json default, html, xml
  connection({}, nuid, on_behalf_of: on_behalf_of).get(
    ROUTE + id + '/mods' + (kind.to_s.empty? ? '' : ".#{kind}")
    )&.body
end

.reparent(id, new_parent_id, nuid: nil, on_behalf_of: nil) ⇒ Hash

Move a Community to a different parent Community — or to the top of the tree.

Wraps PATCH /communities/<id>/parent with a parent_id of the new parent Community. Pass new_parent_id = nil to promote the Community to a top-level node (no parent) — mirroring how create treats a nil id; the gem omits the blank param and Atlas reads it as "move to top". Atlas re-parents the Community and synchronously cascades the ancestry index over its descendant Collections and Works; the structural rules (cycle, tombstone guards) are enforced server-side and surface as a 422.

Examples:

Move under another Community

AtlasRb::Community.reparent("c-123", "c-999")

Promote to a top-level Community

AtlasRb::Community.reparent("c-123", nil)

Parameters:

  • id (String)

    the Community ID to move.

  • new_parent_id (String, nil)

    the destination Community ID, or nil to move the Community to the top of the tree.

  • 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)

    the updated "community" object, already unwrapped — the same shape find returns, reflecting the new a_member_of.

Raises:

  • (AtlasRb::StaleResourceError)

    if Atlas reports an optimistic-lock conflict that exhausted its internal retry budget (HTTP 409 with error: "stale_resource").

  • (AtlasRb::ReparentError)

    if Atlas rejects the move on structural grounds (HTTP 422 — cycle, tombstoned_node, tombstoned_parent, parent_not_found). The envelope's error code is exposed as #code.

  • (AtlasRb::ForbiddenError)

    if Atlas refuses the move on authorization grounds (HTTP 403).



122
123
124
125
126
127
# File 'lib/atlas_rb/community.rb', line 122

def self.reparent(id, new_parent_id, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({ parent_id: new_parent_id }, nuid, on_behalf_of: on_behalf_of)
      .patch(ROUTE + id + '/parent')&.body
  ))["community"]
end

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

Attach the three thumbnail/preview Delegate URIs to a Community.

Community-level mirror of Work.set_thumbnails. Atlas dispatches each non-blank URI to its matching Delegate role (thumbnail_image / thumbnail_image_2x / preview_image) via DelegateUpdater. Missing keys are left untouched.

Examples:

AtlasRb::Community.set_thumbnails(
  "c-123",
  thumbnail:    "https://iiif.example.edu/iiif/3/m.jp2/full/!85,85/0/default.jpg",
  thumbnail_2x: "https://iiif.example.edu/iiif/3/m.jp2/full/!170,170/0/default.jpg",
  preview:      "https://iiif.example.edu/iiif/3/m.jp2/full/500,/0/default.jpg"
)

Parameters:

  • id (String)

    the Community ID.

  • 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 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).

Returns:

Raises:

  • (AtlasRb::StaleResourceError)

    if Atlas reports an optimistic-lock conflict that exhausted its internal retry budget (HTTP 409 with error: "stale_resource").



250
251
252
253
254
255
256
# File 'lib/atlas_rb/community.rb', line 250

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
  AtlasRb::Mash.new(JSON.parse(
    connection({}, nuid, on_behalf_of: on_behalf_of)
      .patch(ROUTE + id + '/thumbnails', JSON.dump(body))&.body
  ))
end

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

Tombstone (withdraw) a Community.

The Community remains in Atlas storage but is marked as withdrawn: search and show pages return a withdrawn stub for every user. Atlas rejects the request with 422 has_live_children if the Community still has live (non-tombstoned) members.

Examples:

AtlasRb::Community.tombstone("c-123", nuid: "000000002")

Parameters:

  • id (String)

    the Community ID.

  • nuid (String) (defaults to: nil)

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

  • 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:

  • (Faraday::Response)

    the raw response. 200/204 on success; 422 with {"code":"has_live_children"} if the Community is not empty.



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

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

.update(id, xml_path, nuid: nil, on_behalf_of: nil) ⇒ Hash

Replace a Community's metadata by uploading a MODS XML document.

Examples:

AtlasRb::Community.update("c-123", "/tmp/community-mods.xml")

Parameters:

  • id (String)

    the Community ID.

  • 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:

  • (Hash)

    the parsed JSON response from the patch.



189
190
191
192
193
194
195
196
# File 'lib/atlas_rb/community.rb', line 189

def self.update(id, xml_path, nuid: nil, on_behalf_of: nil)
  payload = { binary: Faraday::Multipart::FilePart.new(File.open(xml_path),
                                                       "application/xml",
                                                       File.basename(xml_path)) }
  AtlasRb::Mash.new(JSON.parse(
    multipart(nuid, on_behalf_of: on_behalf_of).patch(ROUTE + id, payload)&.body
  ))
end