Returns the primary role struct for the given user or nil.
Preference order:
- first element of preloaded
roleslist - first
rolein preloadeduser_role_assignments - nil
The Accounts context.
Updates a user by admin without requiring password. Used for administrative user management where password changes are optional.
Updates a user's password by admin (super admin only). Used for administrative password resets.
Emulates that the email will change without actually changing it in the database.
Changeset for user.
Returns an %Ecto.Changeset{} for changing the user email.
Returns a changeset for tracking onboarding user changes with validations.
Returns an %Ecto.Changeset{} for changing the user password.
Returns an %Ecto.Changeset{} for tracking user changes.
Confirms a user by the given token.
Create a new User.
Creates a user from OAuth provider data (Google, PAuS, etc).
Delete a single user.
Deletes the signed token with the given context.
Delivers the magic link login instructions to the given user.
Delivers the confirmation email instructions to the given user.
Delivers the reset password email to the given user.
Delivers the update email instructions to the given user.
Generates a session token.
Gets a single user by ID (safe version). Returns nil if not found.
Gets a single user.
Gets the user by confirmation token without confirming.
Gets a user by email.
Gets a user by email and password.
Get a user by email or register it it's doesn't exist.
Gets a user by login (email, username, or identifier) and password.
Gets the user with the given magic link token.
Gets the user by reset password token.
Gets the user with the given signed token.
Verifies a session token and returns all auth data needed for cross-app token generation in a single optimized call.
Gets user statistics.
Gets a user by identifier with all library associations preloaded.
Fetches minimal user auth data by user_id with roles preloaded.
Checks if a user has a password set.
Checks if a user is currently manually suspended. Takes into account suspension end dates.
Automatically lifts expired suspensions. Should be called periodically (e.g., via a scheduled job).
Gets all users.
Gets all users with paginated results
Logs the user in by magic link.
Returns the primary role struct for the given user or nil.
Registers a user.
Resets the user password.
Searches users by username, email, or fullname.
Search users with pagination. Returns {users, total_pages}.
Accepts page, per_page, and the same params map as search_users/1.
Checks whether the user is in sudo mode.
Manually suspends a user account with a reason.
Lifts the manual suspension from a user account.
Update an existing user data.
Updates the user email using the given token.
Updates a user's profile during onboarding with required field validations.
Updates the user password.
Updates the user password.
Updates a user by admin without requiring password. Used for administrative user management where password changes are optional.
Updates a user's password by admin (super admin only). Used for administrative password resets.
Emulates that the email will change without actually changing it in the database.
iex> apply_user_email(user, "valid password", %{email: ...})
{:ok, %User{}}
iex> apply_user_email(user, "invalid password", %{email: ...})
{:error, %Ecto.Changeset{}}
Changeset for user.
Returns an %Ecto.Changeset{} for changing the user email.
iex> change_user_email(user)
%Ecto.Changeset{data: %User{}}
Returns a changeset for tracking onboarding user changes with validations.
Returns an %Ecto.Changeset{} for changing the user password.
iex> change_user_password(user)
%Ecto.Changeset{data: %User{}}
Returns an %Ecto.Changeset{} for tracking user changes.
iex> change_user_registration(user)
%Ecto.Changeset{data: %User{}}
Confirms a user by the given token.
If the token matches, the user account is marked as confirmed and the token is deleted.
Create a new User.
Creates a user from OAuth provider data (Google, PAuS, etc).
This function handles user creation from various OAuth providers. If the user already exists, it updates their last login information.
iex> create_user_from_oauth(%{email: "user@example.com", name: "John Doe", auth_provider: "google"})
{:ok, %User{}}
iex> create_user_from_oauth(%{email: "invalid", name: "John"})
{:error, %Ecto.Changeset{}}
Delete a single user.
Deletes the signed token with the given context.
Delivers the magic link login instructions to the given user.
Delivers the confirmation email instructions to the given user.
iex> deliver_user_confirmation_instructions(user, &url(~p"/users/confirm/#{&1}"))
{:ok, %{to: ..., body: ...}}
iex> deliver_user_confirmation_instructions(confirmed_user, &url(~p"/users/confirm/#{&1}"))
{:error, :already_confirmed}
Delivers the reset password email to the given user.
iex> deliver_user_reset_password_instructions(user, &url(~p"/users/reset_password/#{&1}"))
{:ok, %{to: ..., body: ...}}
Delivers the update email instructions to the given user.
iex> deliver_user_update_email_instructions(user, current_email, &url(~p"/users/settings/confirm_email/#{&1}"))
{:ok, %{to: ..., body: ...}}
Generates a session token.
Gets a single user by ID (safe version). Returns nil if not found.
iex> get_user(123)
%User{}
iex> get_user(456)
nil
Gets a single user.
Raises Ecto.NoResultsError if the User does not exist.
iex> get_user!(123)
%User{}
iex> get_user!(456)
** (Ecto.NoResultsError)
Gets the user by confirmation token without confirming.
iex> get_user_by_confirmation_token("validtoken")
%User{}
iex> get_user_by_confirmation_token("invalidtoken")
nil
Gets a user by email.
iex> get_user_by_email("foo@example.com")
%User{}
iex> get_user_by_email("unknown@example.com")
nil
Gets a user by email and password.
iex> get_user_by_email_and_password("foo@example.com", "correct_password")
%User{}
iex> get_user_by_email_and_password("foo@example.com", "invalid_password")
nil
Get a user by email or register it it's doesn't exist.
Gets a user by login (email, username, or identifier) and password.
This function attempts to find a user by checking:
iex> get_user_by_login_and_password("foo@example.com", "correct_password")
%User{}
iex> get_user_by_login_and_password("username", "correct_password")
%User{}
iex> get_user_by_login_and_password("12345", "correct_password")
%User{}
iex> get_user_by_login_and_password("foo@example.com", "invalid_password")
nil
Gets the user with the given magic link token.
Gets the user by reset password token.
iex> get_user_by_reset_password_token("validtoken")
%User{}
iex> get_user_by_reset_password_token("invalidtoken")
nil
Gets the user with the given signed token.
Verifies a session token and returns all auth data needed for cross-app token generation in a single optimized call.
This is the primary function Curatorian should call during session verification. It replaces the pattern of:
{:ok, %{
user_id: binary(), # UUID string
node_id: integer(),
node_name: String.t(), # organization display name
node_abbr: String.t(), # organization abbreviation
roles: [%{name: String.t()}]
}}
{:error, :invalid_token} # token did not verify
{:error, :user_not_found} # token valid but user missing (deleted?)
{:error, :node_not_found} # user exists but node missing (corrupted data?)case Voile.Schema.Accounts.get_user_session_auth(session_token) do
{:ok, auth_info} ->
cross_app_token = Curatorian.CrossAppToken.sign(auth_info)
# ...
{:error, reason} ->
# redirect to login
end
Gets user statistics.
Gets a user by identifier with all library associations preloaded.
Fetches minimal user auth data by user_id with roles preloaded.
Returns only the fields needed for cross-app token generation. Does not load any library associations (transactions, fines, reservations, audit_logs, collection_permissions). Significantly lighter than preload_user_assocs/1 for auth-only use cases.
{:ok, %{
user_id: binary(), # UUID
node_id: integer(),
roles: [%{name: String.t()}]
}}
{:error, :not_found}case Voile.Schema.Accounts.get_user_with_roles(user.id) do
{:ok, auth_data} -> # proceed
{:error, :not_found} -> # handle missing user
end
Checks if a user has a password set.
iex> has_password?(user)
true
iex> has_password?(oauth_user)
false
Checks if a user is currently manually suspended. Takes into account suspension end dates.
iex> is_manually_suspended?(user)
true
iex> is_manually_suspended?(user_with_expired_suspension)
false
Automatically lifts expired suspensions. Should be called periodically (e.g., via a scheduled job).
Returns the count of users whose suspensions were lifted.
Gets all users.
Gets all users with paginated results
Logs the user in by magic link.
There are three cases to consider:
The user has already confirmed their email. They are logged in and the magic link is expired.
The user has not confirmed their email and no password is set. In this case, the user gets confirmed, logged in, and all tokens - including session ones - are expired. In theory, no other tokens exist but we delete all of them for best security practices.
The user has not confirmed their email but a password is set.
This cannot happen in the default implementation but may be the
source of security pitfalls. See the "Mixing magic link and password registration" section of
mix help phx.gen.auth.
Returns the primary role struct for the given user or nil.
Preference order:
roles listrole in preloaded user_role_assignmentsRegisters a user.
iex> register_user(%{field: value})
{:ok, %User{}}
iex> register_user(%{field: bad_value})
{:error, %Ecto.Changeset{}}
Resets the user password.
iex> reset_user_password(user, %{password: "new long password", password_confirmation: "new long password"})
{:ok, %User{}}
iex> reset_user_password(user, %{password: "valid", password_confirmation: "not the same"})
{:error, %Ecto.Changeset{}}
Searches users by username, email, or fullname.
Accepts either a plain query string or a map of filters.
Example usages: search_users("alice") search_users(%{"query" => "alice", "node_id" => "1"})
Search users with pagination. Returns {users, total_pages}.
Accepts page, per_page, and the same params map as search_users/1.
Checks whether the user is in sudo mode.
The user is in sudo mode when the last authentication was done no further than 20 minutes ago. The limit can be given as second argument in minutes.
Manually suspends a user account with a reason.
Options:
:ends_at - DateTime when suspension should automatically expire (optional):reason - Reason for suspension (required):suspended_by_id - ID of the admin who suspended the user (required)iex> suspend_user(user, %{
reason: "Violation of terms",
suspended_by_id: admin_id,
ends_at: ~U[2025-12-31 23:59:59Z]
})
{:ok, %User{}}
iex> suspend_user(user, %{reason: "", suspended_by_id: admin_id})
{:error, %Ecto.Changeset{}}
Lifts the manual suspension from a user account.
iex> unsuspend_user(user)
{:ok, %User{}}
Update an existing user data.
Updates the user email using the given token.
If the token matches, the user email is updated and the token is deleted. The confirmed_at date is also updated to the current time.
Updates a user's profile during onboarding with required field validations.
Updates the user password.
Returns a tuple with the updated user, as well as a list of expired tokens.
iex> update_user_password(user, %{password: ...})
{:ok, {%User{}, [...]}}
iex> update_user_password(user, %{password: "too short"})
{:error, %Ecto.Changeset{}}
Updates the user password.
iex> update_user_password(user, "valid password", %{password: ...})
{:ok, %User{}}
iex> update_user_password(user, "invalid password", %{password: ...})
{:error, %Ecto.Changeset{}}