Current section

Files

Jump to
supabase_gotrue lib supabase go_true user.ex
Raw

lib/supabase/go_true/user.ex

defmodule Supabase.GoTrue.User do
@moduledoc """
Represents a user profile in the Supabase authentication system.
This schema contains all the user information stored in the GoTrue service, including
authentication details, profile data, and linked identities. The User struct is typically
accessed through `Supabase.GoTrue.get_user/2` after a successful authentication.
## Important Fields
* `id` - Unique identifier (UUID) for the user
* `email` - User's email address (if applicable)
* `phone` - User's phone number (if applicable)
* `user_metadata` - Custom user attributes, editable by the user
* `app_metadata` - Application-controlled attributes, not editable by the user
* `created_at` - Timestamp when the user was created
* `last_sign_in_at` - Timestamp of the user's most recent sign-in
* `confirmed_at` - Timestamp when the user was confirmed (email verification)
* `factors` - Multi-factor authentication methods associated with the user
* `identities` - External identity providers linked to this user (GitHub, Google, etc.)
## Confirmation Status
A user's verification status for email and phone can be determined using the following fields:
* `email_confirmed_at` - Non-nil when email is verified
* `phone_confirmed_at` - Non-nil when phone is verified
## Example Usage
```elixir
# Retrieve user details from a session
{:ok, user} = Supabase.GoTrue.get_user(client, session)
# Check if email is verified
email_verified = user.email_confirmed_at != nil
# Access custom user metadata
profile_pic = user.user_metadata["avatar_url"]
```
## Related Schemas
* `Supabase.GoTrue.User.Factor` - MFA factors associated with the user
* `Supabase.GoTrue.User.Identity` - External identity providers linked to the user
"""
use Ecto.Schema
import Ecto.Changeset
alias Supabase.GoTrue.User.Factor
alias Supabase.GoTrue.User.Identity
@type t :: %__MODULE__{
id: Ecto.UUID.t(),
app_metadata: map,
user_metadata: map,
aud: String.t(),
confirmation_sent_at: NaiveDateTime.t() | nil,
recovery_sent_at: NaiveDateTime.t() | nil,
email_change_sent_at: NaiveDateTime.t() | nil,
new_email: String.t() | nil,
new_phone: String.t() | nil,
invited_at: NaiveDateTime.t() | nil,
action_link: String.t() | nil,
email: String.t() | nil,
phone: String.t() | nil,
created_at: NaiveDateTime.t(),
confirmed_at: NaiveDateTime.t() | nil,
email_confirmed_at: NaiveDateTime.t() | nil,
phone_confirmed_at: NaiveDateTime.t() | nil,
last_sign_in_at: NaiveDateTime.t() | nil,
role: String.t() | nil,
updated_at: NaiveDateTime.t() | nil,
identities: list(Identity) | nil,
factors: list(Factor) | nil
}
@required_fields ~w[id app_metadata aud created_at]a
@optional_fields ~w[confirmation_sent_at recovery_sent_at email_change_sent_at new_email new_phone invited_at action_link email phone confirmed_at email_confirmed_at phone_confirmed_at last_sign_in_at role]a
@derive Jason.Encoder
@primary_key {:id, :binary_id, autogenerate: false}
embedded_schema do
field(:app_metadata, :map)
field(:user_metadata, :map)
field(:aud, :string)
field(:confirmation_sent_at, :naive_datetime)
field(:recovery_sent_at, :naive_datetime)
field(:email_change_sent_at, :naive_datetime)
field(:new_email, :string)
field(:new_phone, :string)
field(:invited_at, :naive_datetime)
field(:action_link, :string)
field(:email, :string)
field(:phone, :string)
field(:confirmed_at, :naive_datetime)
field(:email_confirmed_at, :naive_datetime)
field(:phone_confirmed_at, :naive_datetime)
field(:last_sign_in_at, :naive_datetime)
field(:encrypted_password, :string)
field(:role, :string)
embeds_many(:factors, Factor)
embeds_many(:identities, Identity)
timestamps(inserted_at: :created_at)
end
def changeset(user \\ %__MODULE__{}, attrs) do
user
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
|> cast_embed(:identities, required: false)
|> cast_embed(:factors, required: false)
end
def multiple_changeset(user \\ %__MODULE__{}, attrs) do
user
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
@doc """
Parses and validates a map of user attributes into a User struct.
This function validates that all required fields are present and correctly formatted,
returning either a valid User struct or a changeset with validation errors.
## Parameters
* `attrs` - Map containing user attributes returned from the GoTrue API
## Returns
* `{:ok, user}` - Successfully parsed user
* `{:error, changeset}` - Failed validation with error details
## Examples
iex> attrs = %{
...> "id" => "550e8400-e29b-41d4-a716-446655440000",
...> "email" => "user@example.com",
...> "app_metadata" => %{},
...> "user_metadata" => %{"name" => "Test User"},
...> "aud" => "authenticated",
...> "created_at" => "2023-01-01T00:00:00Z"
...> }
iex> {:ok, user} = Supabase.GoTrue.User.parse(attrs)
iex> user.email
"user@example.com"
"""
def parse(attrs) do
attrs
|> changeset()
|> apply_action(:parse)
end
@doc """
Parses a list of user attribute maps into a list of User structs.
This function attempts to validate and parse each map in the provided list.
If all validations succeed, it returns a list of User structs. If any
validation fails, it returns the first error encountered.
## Parameters
* `list_attrs` - List of maps containing user attributes
## Returns
* `{:ok, [user, ...]}` - Successfully parsed list of users
* `{:error, changeset}` - First validation error encountered
## Examples
iex> attrs_list = [
...> %{"id" => "user1", "app_metadata" => %{}, "aud" => "auth", "created_at" => "2023-01-01T00:00:00Z"},
...> %{"id" => "user2", "app_metadata" => %{}, "aud" => "auth", "created_at" => "2023-01-01T00:00:00Z"}
...> ]
iex> {:ok, users} = Supabase.GoTrue.User.parse_list(attrs_list)
iex> length(users)
2
"""
def parse_list(list_attrs) do
results =
Enum.reduce_while(list_attrs, [], fn attrs, acc ->
changeset = multiple_changeset(attrs)
case result = apply_action(changeset, :parse) do
{:ok, user} -> {:cont, [user | acc]}
{:error, _} -> {:halt, result}
end
end)
if is_list(results), do: {:ok, results}, else: results
end
end