Class: AtlasRb::Compilation

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

Overview

A Compilation (DRS "Set") — a personal, curated, recipe-based grouping of Works and Collections.

The recipe is three noid lists: included collections (resolved transitively — the collection plus everything beneath it), individually included works, and excluded works ("set-asides", subtracted from the resolved union). Atlas resolves the recipe at read time via Compilation.contents; nothing is materialized.

Compilations are Atlas-side ActiveRecord (ephemeral curation, not repository content), but carry a minted NOID as their public id — so ids here look exactly like every other resource's. There is no /mods, thumbnail, or tombstone surface to bind. Membership rules (Works and Collections only, no Communities) are enforced server-side; a rejected add surfaces as CompilationError (422), an authorization refusal as ForbiddenError (403).

See also: Work.add_linked_member — the membership add/remove pairs here mirror that precedent.

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.

"/compilations/"

Class Method Summary collapse

Methods inherited from Resource

find_many, history, mods_version, mods_versions, permissions, preview

Methods included from FaradayHelper

#connection, #multipart, #system_connection

Class Method Details

.add_exclusion(id, work_id, nuid: nil, on_behalf_of: nil) ⇒ Hash

Set a Work aside: subtract it from the Set's resolved contents even though an included collection covers it.

Idempotent. The noid must resolve to a Work. Setting aside a Work that no inclusion currently covers is legal — the recipe lines are independent; the subtraction just matches nothing.

Examples:

AtlasRb::Compilation.add_exclusion("c-123", "w-789", nuid: "000000002")

Parameters:

  • id (String)

    the Compilation ID.

  • work_id (String)

    the Work NOID to set aside.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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 "compilation" object.

Raises:



308
309
310
311
312
313
# File 'lib/atlas_rb/compilation.rb', line 308

def self.add_exclusion(id, work_id, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({ work_id: work_id }, nuid, on_behalf_of: on_behalf_of)
      .post(ROUTE + id + '/exclusions')&.body
  ))["compilation"]
end

.add_included_collection(id, collection_id, nuid: nil, on_behalf_of: nil) ⇒ Hash

Add an include-collection recipe line: everything under the Collection (transitively) joins the Set's resolved contents.

Idempotent — re-adding an included collection is a no-op. The noid must resolve to a Collection: Communities and unknown ids are rejected server-side as a 422.

Examples:

AtlasRb::Compilation.add_included_collection("c-123", "col-456", nuid: "000000002")

Parameters:

  • id (String)

    the Compilation ID.

  • collection_id (String)

    the Collection NOID to include.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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 "compilation" object — the response is the full recipe, so chip counts refresh without a follow-up find.

Raises:



208
209
210
211
212
213
# File 'lib/atlas_rb/compilation.rb', line 208

def self.add_included_collection(id, collection_id, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({ collection_id: collection_id }, nuid, on_behalf_of: on_behalf_of)
      .post(ROUTE + id + '/included_collections')&.body
  ))["compilation"]
end

.add_included_work(id, work_id, nuid: nil, on_behalf_of: nil) ⇒ Hash

Add an include-work recipe line: one Work, included individually.

Idempotent. The noid must resolve to a Work; anything else is a 422.

Examples:

AtlasRb::Compilation.add_included_work("c-123", "w-789", nuid: "000000002")

Parameters:

  • id (String)

    the Compilation ID.

  • work_id (String)

    the Work NOID to include.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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 "compilation" object.

Raises:



258
259
260
261
262
263
# File 'lib/atlas_rb/compilation.rb', line 258

def self.add_included_work(id, work_id, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({ work_id: work_id }, nuid, on_behalf_of: on_behalf_of)
      .post(ROUTE + id + '/included_works')&.body
  ))["compilation"]
end

.contents(id, page: nil, per_page: nil, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash

Resolve a Compilation's recipe into the Works it currently denotes.

Wraps GET /compilations/<id>/contents — included for completeness; the endpoint's primary consumer is CERES (which calls Atlas directly), and Cerberus resolves Set contents via its own Blacklight query. Results are gated to what the caller may discover (public + the caller's groups; admins see everything; tombstoned works excluded) — the same semantics as Cerberus gated discovery.

Examples:

page = AtlasRb::Compilation.contents("c-123", nuid: "000000002")
page.contents.map(&:noid)
page.pagination.total

Parameters:

  • id (String)

    the Compilation ID.

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

    1-indexed page number (default 1).

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

    page size (default 25, capped at 100).

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

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

    { "contents" => [...], "pagination" => { "total", "page", "per_page", "pages" } }. Each entry is a lightweight digest in the Resource.find_many vocabulary — id / noid / klass / title / thumbnail.

Raises:



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

def self.contents(id, page: nil, per_page: nil, nuid: nil, on_behalf_of: nil)
  params = {}
  params[:page]     = page     if page
  params[:per_page] = per_page if per_page
  AtlasRb::Mash.new(JSON.parse(
    connection(params, nuid, on_behalf_of: on_behalf_of).get(ROUTE + id + '/contents')&.body
  ))
end

.create(title, description: nil, nuid: nil, on_behalf_of: nil) ⇒ Hash

Create a Compilation owned by the acting user.

The depositor (owner) is stamped server-side from the authenticated NUID — it is not a parameter and is immutable post-create. New Sets are born private: empty ACLs, no staff default.

Examples:

AtlasRb::Compilation.create("Course readings",
                            description: "HIST 1101",
                            nuid: "000000002")

Parameters:

  • title (String)

    the Set's title (required; blank is a 422).

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

    optional free-text description.

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

    the acting user's NUID, forwarded as the User: header — the created Set's owner. Required for cerberus-token requests.

  • 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 created "compilation" object, already unwrapped.

Raises:



115
116
117
118
119
120
121
# File 'lib/atlas_rb/compilation.rb', line 115

def self.create(title, description: nil, nuid: nil, on_behalf_of: nil)
  params = { title: title }
  params[:description] = description if description
  AtlasRb::Mash.new(JSON.parse(
    connection(params, nuid, on_behalf_of: on_behalf_of).post(ROUTE)&.body
  ))["compilation"]
end

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

Destroy a Compilation.

Owner (or edit-grantee / admin) only. The recipe rows go with it; the Works and Collections it referenced are untouched — a Set is a view, not a container.

Examples:

AtlasRb::Compilation.destroy("c-123", nuid: "000000002")

Parameters:

  • id (String)

    the Compilation ID.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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. Status 204 on success.

Raises:



182
183
184
# File 'lib/atlas_rb/compilation.rb', line 182

def self.destroy(id, nuid: nil, on_behalf_of: nil)
  connection({}, nuid, on_behalf_of: on_behalf_of).delete(ROUTE + id)
end

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

Fetch a single Compilation by ID.

Visibility is per-row: the owner, holders of an explicit read/edit grant, and (for public Sets) anyone — a private Set read by a non-grantee raises ForbiddenError.

Examples:

AtlasRb::Compilation.find("c-123", nuid: "000000002")
# => { "id" => "c-123", "title" => "Course readings", ... }

Parameters:

  • id (String)

    the Compilation ID (NOID).

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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 "compilation" object, already unwrapped — id, title, description, depositor, the three recipe arrays (included_collections, included_works, excluded_works), the ACL arrays, and timestamps.

Raises:



50
51
52
53
54
# File 'lib/atlas_rb/compilation.rb', line 50

def self.find(id, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({}, nuid, on_behalf_of: on_behalf_of).get(ROUTE + id)&.body
  ))["compilation"]
end

.list(owner: nil, page: nil, per_page: nil, nuid: nil, on_behalf_of: nil) ⇒ AtlasRb::Mash

List Compilations, owner-scoped and paginated (newest first).

Defaults to the acting user's own Sets. Pass owner: to list another user's — that is admin-only and raises ForbiddenError for anyone else. There is no public browse surface.

Examples:

My Sets

AtlasRb::Compilation.list(nuid: "000000002")

Another user's Sets (admin)

AtlasRb::Compilation.list(owner: "000000002", nuid: "000000004")

Parameters:

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

    NUID whose Sets to list (admin-only when it isn't the acting user). Omit for "my Sets".

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

    1-indexed page number.

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

    page size override.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

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

    { "compilations" => [...], "pagination" => {...} }. Each entry wraps the same "compilation" object find returns.

Raises:



81
82
83
84
85
86
87
88
89
# File 'lib/atlas_rb/compilation.rb', line 81

def self.list(owner: nil, page: nil, per_page: nil, nuid: nil, on_behalf_of: nil)
  params = {}
  params[:owner]    = owner    if owner
  params[:page]     = page     if page
  params[:per_page] = per_page if per_page
  AtlasRb::Mash.new(JSON.parse(
    connection(params, nuid, on_behalf_of: on_behalf_of).get(ROUTE)&.body
  ))
end

.remove_exclusion(id, work_id, nuid: nil, on_behalf_of: nil) ⇒ Hash

Put a set-aside Work back. Idempotent.

Examples:

AtlasRb::Compilation.remove_exclusion("c-123", "w-789", nuid: "000000002")

Parameters:

  • id (String)

    the Compilation ID.

  • work_id (String)

    the Work NOID to restore to the resolved set.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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 "compilation" object.

Raises:



330
331
332
333
334
335
# File 'lib/atlas_rb/compilation.rb', line 330

def self.remove_exclusion(id, work_id, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({}, nuid, on_behalf_of: on_behalf_of)
      .delete(ROUTE + id + '/exclusions/' + work_id)&.body
  ))["compilation"]
end

.remove_included_collection(id, collection_id, nuid: nil, on_behalf_of: nil) ⇒ Hash

Remove an include-collection recipe line.

Idempotent — removing a collection that is not in the recipe is a 200 no-op (nothing for a client to recover from).

Examples:

AtlasRb::Compilation.remove_included_collection("c-123", "col-456", nuid: "000000002")

Parameters:

  • id (String)

    the Compilation ID.

  • collection_id (String)

    the Collection NOID to remove.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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 "compilation" object.

Raises:



233
234
235
236
237
238
# File 'lib/atlas_rb/compilation.rb', line 233

def self.remove_included_collection(id, collection_id, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({}, nuid, on_behalf_of: on_behalf_of)
      .delete(ROUTE + id + '/included_collections/' + collection_id)&.body
  ))["compilation"]
end

.remove_included_work(id, work_id, nuid: nil, on_behalf_of: nil) ⇒ Hash

Remove an include-work recipe line. Idempotent.

Examples:

AtlasRb::Compilation.remove_included_work("c-123", "w-789", nuid: "000000002")

Parameters:

  • id (String)

    the Compilation ID.

  • work_id (String)

    the Work NOID to remove.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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 "compilation" object.

Raises:



280
281
282
283
284
285
# File 'lib/atlas_rb/compilation.rb', line 280

def self.remove_included_work(id, work_id, nuid: nil, on_behalf_of: nil)
  AtlasRb::Mash.new(JSON.parse(
    connection({}, nuid, on_behalf_of: on_behalf_of)
      .delete(ROUTE + id + '/included_works/' + work_id)&.body
  ))["compilation"]
end

.update(id, title: nil, description: nil, permissions: nil, nuid: nil, on_behalf_of: nil) ⇒ Hash

Update a Compilation's title / description / ACL.

Only the keys you pass are written. The permissions: hash replaces all three grant lists at once (read: / edit: group lists plus edit_users: NUIDs); the depositor is never writable. Server-side, an ACL change emits a permissions audit event (no-op ACL writes are suppressed); recipe membership has its own calls and emits nothing.

Examples:

Rename

AtlasRb::Compilation.update("c-123", title: "Renamed", nuid: "000000002")

Make public (the CERES case)

AtlasRb::Compilation.update("c-123",
                            permissions: { read: ["public"], edit: [], edit_users: [] },
                            nuid: "000000002")

Parameters:

  • id (String)

    the Compilation ID.

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

    new title.

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

    new description.

  • permissions (Hash, nil) (defaults to: nil)

    ACL replacement, e.g. { read: ["public"], edit: [], edit_users: ["000000003"] }.

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

    optional acting user's NUID, forwarded as the User: header. Required for cerberus-token requests; legacy bearer tokens still resolve without it.

  • 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 "compilation" object, already unwrapped.

Raises:



154
155
156
157
158
159
160
161
162
# File 'lib/atlas_rb/compilation.rb', line 154

def self.update(id, title: nil, description: nil, permissions: nil, nuid: nil, on_behalf_of: nil)
  params = {}
  params[:title]       = title       if title
  params[:description] = description if description
  params[:permissions] = permissions if permissions
  AtlasRb::Mash.new(JSON.parse(
    connection(params, nuid, on_behalf_of: on_behalf_of).patch(ROUTE + id)&.body
  ))["compilation"]
end