defmodule Frenzy.User do use Ecto.Schema import Ecto.Changeset schema "users" do field :username, :string field :password, :string, virtual: true field :password_hash, :string field :fever_password, :string, virtual: true field :fever_auth_token, :string field :oidc_subject, :string has_many :approved_clients, Frenzy.ApprovedClient, on_delete: :delete_all has_many :groups, Frenzy.Group, on_delete: :delete_all has_many :feeds, through: [:groups, :feeds] timestamps() end @type t() :: %__MODULE__{ __meta__: Ecto.Schema.Metadata.t(), id: integer() | nil, username: String.t(), password: String.t() | nil, password_hash: String.t(), fever_password: String.t() | nil, fever_auth_token: String.t(), oidc_subject: String.t() | nil, approved_clients: [Frenzy.ApprovedClient.t()] | Ecto.Association.NotLoaded.t(), groups: [Frenzy.Group.t()] | Ecto.Association.NotLoaded.t(), inserted_at: NaiveDateTime.t(), updated_at: NaiveDateTime.t() } @doc false def changeset(user, attrs) do user |> cast(attrs, [:username, :password_hash]) |> validate_required([:username, :password_hash]) end def registration_changeset(user, attrs) do user |> cast(attrs, [:username, :password, :fever_password]) |> validate_length(:password, min: 8) |> validate_length(:fever_password, min: 8) |> put_password_hash() |> put_fever_token() end def change_password_changeset(user, attrs) do user |> cast(attrs, [:password]) |> validate_length(:password, min: 8) |> put_password_hash() end def change_fever_password_changeset(user, attrs) do user |> cast(attrs, [:username, :fever_password]) |> validate_length(:fever_password, min: 8) |> put_fever_token() end def set_oidc_subject_changeset(user, attrs) do user |> cast(attrs, [:oidc_subject]) end defp put_password_hash( %Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset ) do change(changeset, Bcrypt.add_hash(password)) end defp put_fever_token( %Ecto.Changeset{ valid?: true, changes: %{fever_password: fever_password} } = changeset ) do username = Map.get(changeset.changes, "username") || changeset.data.username IO.inspect(username) change(changeset, %{ fever_auth_token: :crypto.hash(:md5, "#{username}:#{fever_password}") |> Base.encode16(case: :lower) }) end end