Class: AtlasRb::User

Inherits:
Object
  • Object
show all
Extended by:
FaradayHelper
Defined in:
lib/atlas_rb/user.rb

Overview

User directory lookups (typeahead search, NUID → name resolution) plus a person's own account management — enumerating the accounts that share their NUID and choosing a preferred (default) one.

This is a user-context binding: calls authenticate as the acting user via the standard relay-signing path (the acting NUID is signed into the assertion sub), like every other top-level class. It is deliberately not part of System — that namespace is structurally reserved for system-token calls (System::User.find_or_create), and these are ordinary logged-in-user capabilities.

The directory lookups enforce minimal disclosure: every entry carries nuid + name only (no email, role, or groups), and rows with role anonymous, guest, or system are never returned. The account methods (User.accounts / User.set_preferred) do disclose email/groups/affiliation, so Atlas limits them to the person themselves (matching NUID), an admin, or the system principal. Per the layering principle the gem adds nothing on top — no caching, no name parsing, no result shaping; presentation belongs to the host application.

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 the user directory.

"/users"

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

.accounts(target_nuid, nuid: nil) ⇒ AtlasRb::Mash?

List the accounts sharing a NUID — a person's staff/student logins.

Unlike the directory lookups this discloses each account's email, affiliation label, role, stored group set, and which one is preferred — the data the login "you have more than one account" check and the My DRS accounts panel render from. Atlas limits it to the person themselves, an admin, or the system principal; others get a 403.

Examples:

Login-time multi-account detection

AtlasRb::User.accounts("001234567", nuid: "001234567")["accounts"].size # => 2

Parameters:

  • target_nuid (String)

    the NUID whose accounts to list — the subject, distinct from the acting nuid: kwarg.

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

    optional acting user's NUID (signed into the assertion sub); on the BYO-JWT path identity lives in the token.

Returns:

  • (AtlasRb::Mash, nil)

    the envelope: nuid plus an accounts array, each entry carrying email, name, affiliation, role, groups, and preferred.

    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.



131
132
133
134
135
# File 'lib/atlas_rb/user.rb', line 131

def self.accounts(target_nuid, nuid: nil)
  read_body(connection({}, nuid).get("#{ROUTE}/by_nuid/#{target_nuid}/accounts")) do |body|
    AtlasRb::Mash.new(body)
  end
end

.find_by_nuid(target_nuid, nuid: nil) ⇒ AtlasRb::Mash?

Resolve a single NUID to a directory entry.

Examples:

Sender-name display

AtlasRb::User.find_by_nuid("001234567")
# => { "nuid" => "001234567", "name" => "Doe, Jane" }

Parameters:

  • target_nuid (String)

    the NUID being looked up — the subject of the call, distinct from the acting nuid: kwarg.

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

  • (AtlasRb::Mash, nil)

    the nuid + name entry, or nil when Atlas reports the NUID as absent (unknown, or held by an excluded role — the two are indistinguishable on the wire by design).

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.



75
76
77
78
79
# File 'lib/atlas_rb/user.rb', line 75

def self.find_by_nuid(target_nuid, nuid: nil)
  read_body(connection({}, nuid).get("#{ROUTE}/by_nuid/#{target_nuid}")) do |body|
    AtlasRb::Mash.new(body)
  end
end

.resolve(nuids, nuid: nil) ⇒ Array<AtlasRb::Mash>?

Batch-resolve a set of NUIDs to directory entries in one call.

Same response shape as search. Unresolvable NUIDs (unknown or excluded-role) are dropped, so the result may be shorter than the input — callers index by nuid. Atlas caps the batch at 100.

Examples:

Resolve an inbox page of senders in one round-trip

senders = AtlasRb::User.resolve(["001234567", "007654321"])
by_nuid = senders.index_by { |entry| entry["nuid"] }

Parameters:

  • nuids (Array<String>, String)

    the NUIDs to resolve.

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

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

    resolved entries, each carrying nuid and name, ordered by name.

    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.



102
103
104
105
106
# File 'lib/atlas_rb/user.rb', line 102

def self.resolve(nuids, nuid: nil)
  read_body(connection({ nuids: Array(nuids).join(",") }, nuid).get(ROUTE)) do |body|
    body.map { |entry| AtlasRb::Mash.new(entry) }
  end
end

.search(query, nuid: nil) ⇒ Array<AtlasRb::Mash>?

Typeahead search of the user directory.

Case-insensitive match on name, prefix match on NUID (so typing a known NUID works too). Atlas caps the result (10 entries) and orders it by name; a blank query resolves to an empty list.

Examples:

Recipient typeahead

AtlasRb::User.search("jan", nuid: "000000002")
# => [{ "nuid" => "001234567", "name" => "Doe, Jane" }, ...]

Parameters:

  • query (String)

    name fragment or NUID prefix to match.

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

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

    matching directory entries, each carrying nuid and name.

    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.



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

def self.search(query, nuid: nil)
  read_body(connection({ q: query }, nuid).get(ROUTE)) do |body|
    body.map { |entry| AtlasRb::Mash.new(entry) }
  end
end

.set_preferred(target_nuid, email:, nuid: nil) ⇒ AtlasRb::Mash

Set the preferred (default) account for a NUID — the account chosen when a login names no specific one. Same self/admin/system scope as accounts.

Examples:

AtlasRb::User.set_preferred("001234567", email: "[email protected]",
                            nuid: "001234567")

Parameters:

  • target_nuid (String)

    the NUID whose default is being set.

  • email (String)

    the account to make preferred; must be one of the NUID's accounts (else Atlas returns 404).

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

    optional acting user's NUID (signed into sub).

Returns:



149
150
151
152
153
# File 'lib/atlas_rb/user.rb', line 149

def self.set_preferred(target_nuid, email:, nuid: nil)
  response = connection({}, nuid)
             .put("#{ROUTE}/by_nuid/#{target_nuid}/preferred_account", { email: email }.to_json)
  AtlasRb::Mash.new(JSON.parse(response.body))["user"]
end