NAME

Concierge::Desk::User - User object enabled by Concierge

VERSION

v0.13.0

SYNOPSIS

# User objects are created by Concierge lifecycle methods,
# not directly by applications.

my $login = $concierge->login_user({
    user_id  => 'alice',
    password => 'secret123',
});
my $user = $login->{user};

# Identity
say $user->user_id;       # "alice"
say $user->user_key;      # random token
say $user->session_id;    # random hex string

# Status
say $user->is_logged_in;  # 1
say $user->is_guest;      # 0
say $user->is_visitor;    # 0

# User data (from memory snapshot)
say $user->moniker;
say $user->email;
say $user->get_user_field('role');

# Update user data (writes to backend and memory)
$user->update_user_data({ theme => 'dark' });

# Refresh from backend
$user->refresh_user_data;

# Session data (get, merge-update, save in one call)
my $data = $user->get_session_data;
$user->update_session_data({ last_page => '/dashboard' });

# Raw session access when needed
my $session = $user->session;

# Password & logout (logged-in users; logout also works for guests)
$user->verify_password('secret123');            # 1, 0, or undef
$user->reset_password('newsecret456');           # 1 or undef
$user->logout;                                   # 1 or undef

DESCRIPTION

Concierge::Desk::User represents a user operating an instance of the application. Objects are created by Concierge's lifecycle methods (admit_visitor, checkin_guest, login_user) and returned to the application.

The available methods depend on the user's participation level:

Visitor -- identity and status methods only
Guest -- adds session access, including logout
Logged-in -- adds user data access, backend read/write, and password operations (verify_password, reset_password)

Logged-in user objects hold a snapshot of user data in memory. The refresh_user_data and update_user_data methods synchronize with the backend storage via closures provided at construction time. The user object does not need to know about or contact the concierge to access its backends. verify_password, reset_password, and logout follow the same closure-based pattern -- see "Password & Logout" below for which participation levels each applies to and why.

A successful logout degrades a guest or logged-in object to visitor-equivalent status in place -- see "logout" for exactly what gets cleared. Participation level is therefore not necessarily fixed for the lifetime of a $user object; it can only ever move toward visitor, never the other way.

CONSTRUCTOR

enable_user

my $user = Concierge::Desk::User->enable_user($user_id, \%options);

Called internally by Concierge. Applications should not call this directly.

%options may include:

session -- a Concierge::Sessions::Session object
user_data -- hashref of user data fields
user_key -- reuse an existing key (otherwise one is generated)
_get_user_data -- closure for reading from the Users backend
_update_user_data -- closure for writing to the Users backend
_verify_password -- closure for checking a password via Auth
_reset_password -- closure for setting a new password via Auth
_logout -- closure for deleting the user's session
_session_valid -- closure for checking the session is still live

_get_user_data, _update_user_data, _verify_password, and _reset_password are only ever provided for logged-in users -- they require an Auth-backed identity and/or a Users-backend record that guests and visitors don't have. _logout and _session_valid are provided for any user holding a session (guest or logged-in), since both only require a session_id, not an identity.

_session_valid backs a fresh, per-call check against the Sessions backend (not a check of any cached in-memory field) used internally by every method that reads or writes session data, user data, or a password -- see "Password & Logout" and "Session Access" below. It exists because a session can become invalid out from under a $user object through no fault of that object's own logout (e.g. expiry, or a different Concierge::Desk::User instance for the same identity logging out first); relying on cached status would miss that.

METHODS

Identity

user_id

my $id = $user->user_id;

Returns the user's identifier string.

user_key

my $key = $user->user_key;

Returns the user's key token. For visitors and guests, this is the same as the generated user_id. For logged-in users, it is a separate random token.

session_id

my $sid = $user->session_id;

Returns the session ID, or undef if the user has no session (visitors).

Status

is_visitor

Returns 1 if the user is a visitor (no session, no user data).

is_guest

Returns 1 if the user is a guest (has session, no user data).

is_logged_in

Returns 1 if the user is logged in (has session and user data).

Session Access

session

my $session = $user->session;

Returns the Concierge::Sessions::Session object, or undef for visitors. The session object provides get_data, set_data, save, and status methods.

For ordinary session-data reads and writes, prefer get_session_data/update_session_data below rather than calling get_data/set_data directly: those are all-or-nothing (set_data replaces the entire data hashref), while the user object's methods merge individual keys and call save for you -- which, as a side effect, extends the session's expiration via its sliding-window renewal. Reach for the raw session object only when its status methods, or a deliberate full replace, are actually needed.

get_session_data

my $data = $user->get_session_data;

Returns the user's session data as a hashref, or an empty hashref if no data has been stored. Returns undef for visitors (no session), or if the session is no longer valid on the backend (e.g. expired, or logged out via a different $user object instance for the same identity).

update_session_data

$user->update_session_data({ cart => \@items, last_page => '/shop' });

Merges %updates into the existing session data and saves to persistent storage, which as a side effect also extends the session's expiration (sliding-window renewal). Existing keys not present in %updates are preserved. Returns 1 on success, undef if the user has no session (visitors) or the session is no longer valid on the backend.

User Data -- Memory Snapshot

These methods read from the in-memory data snapshot loaded at login time. They return undef for visitors and guests.

moniker, email, user_status, access_level

Direct accessors for the corresponding fields in the user data snapshot.

get_user_field

my $value = $user->get_user_field('role');

Returns the value of any field in the user data snapshot.

User Data -- Backend Operations

These methods require a logged-in user (backend closures must be present) with a currently valid session. They return undef if called on a visitor or guest, or if the session has since become invalid (expired, or logged out via a different $user object instance for the same identity) -- even though the closures themselves are still present.

refresh_user_data

$user->refresh_user_data;

Fetches fresh data from the Users backend and replaces the in-memory snapshot. Returns 1 on success, undef on failure or if the session is no longer valid.

update_user_data

$user->update_user_data({ theme => 'dark', role => 'editor' });

Writes %updates to the Users backend and merges them into the in-memory snapshot. Returns 1 on success, undef on failure or if the session is no longer valid.

Password & Logout

These methods mirror Concierge's own verify_password, reset_password, and logout_user, bound at construction time so the user object doesn't need a user_id or session_id argument, or any contact with the concierge, to use them. They return a plain scalar rather than the { success => ... } hashref the Concierge-level methods return -- a deliberate simplification at this convenience layer.

verify_password and reset_password require a logged-in user (an Auth-backed identity) with a currently valid session; they return undef for guests and visitors, and also for a logged-in object whose session has since become invalid (see _session_valid under "enable_user" above), even though the object's closures are still in place. logout only requires a session, so it works for guests as well as logged-in users; it returns undef only for visitors, who have no session to log out of.

This session requirement is deliberately not shared by the corresponding Concierge methods that these mirrors wrap ($concierge->verify_password($user_id, ...), $concierge->reset_password($user_id, ...)): those remain identity-scoped and work with no session at all, which real flows depend on (password-reset-by-email, admin-initiated resets, and similar). The session check belongs only at this convenience layer, where the object represents an interactive login and a missing or invalidated session means it no longer should.

verify_password

my $ok = $user->verify_password($password);

Checks $password against the logged-in user's stored credential. Returns 1 if correct, 0 if incorrect, or undef if not applicable (guest, visitor, or session no longer valid).

reset_password

$user->reset_password($new_password);

Sets a new password for the logged-in user. Returns 1 on success, undef on failure or if not applicable (guest, visitor, or session no longer valid).

logout

$user->logout;

Deletes the user's session (and the concierge's user_key mapping for it). Works for guests as well as logged-in users. Returns 1 on success, undef on failure or if not applicable (visitor, no session).

On success, also cleans up this object in place: all backend closures (_get_user_data, _update_user_data, _verify_password, _reset_password, _logout, _session_valid) and the session/session_id/user_data fields are cleared, and status flips so is_logged_in and is_guest become false and is_visitor becomes true. A $user reference held past logout therefore degrades to visitor-equivalent status rather than retaining stale session data or backend-write capability -- every other method's existing "return undef if not applicable" guards then apply naturally, with no special-casing needed. user_id and user_key are left untouched; they're inert identity strings, not capabilities, and the concierge's own user_keys mapping entry for this session is already gone by this point regardless.

SEE ALSO

Concierge -- creates User objects via lifecycle methods

Concierge::Sessions::Session -- session object API

AUTHOR

Bruce Van Allen <bva@cruzio.com>

LICENSE

This module is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.