diff --git a/CHANGELOG.md b/CHANGELOG.md index e7fc514..a8078af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## v0.5.0 (TBA) + +This release contains a large refactoring changing the user identity naming to just identity. + +To upgrade, please update the following: + +1. In your PowAssent config change `:user_identities_context` key, if it exists, to `:identities_context` +2. In your user schema module change: + - `user_identity_changeset` method name to `identity_changeset` + - `pow_assent_user_identity_changeset` method call to `pow_assent_identity_changeset` + - `:user_identities` association name to `:identities` in the user schema module +3. In your user identity schema module: + - Change the module name from `MyApp.UserIdentities.UserIdentity` to `MyApp.Users.UserIdentity` + - Change `PowAssent.Ecto.UserIdentities.Schema` module to `PowAssent.Ecto.Identities.Schema` + - Change `pow_assent_user_identity_fields` method call to `pow_assent_identity_fields` + - Move the file from `user_identities` to `users` directory +4. In your context identity modue, if any, change: + - `PowAssent.Ecto.UserIdentities.Context` module to `PowAssent.Ecto.Identities.Context` + ## v0.4.8 (2020-05-18) ### Enhancements diff --git a/README.md b/README.md index 74f7ffb..d15da1a 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ mix pow_assent.install This will add the following files to your app: ```bash -LIB_PATH/user_identities/user_identity.ex +LIB_PATH/users/user_identity.ex PRIV_PATH/repo/migrations/TIMESTAMP_create_user_identities.ex ``` @@ -236,7 +236,7 @@ Add `messages_backend: MyAppWeb.Pow.Messages` to your Pow configuration. You can ## Populate fields -To populate fields in your user struct that are fetched from the provider, you can override the `user_identity_changeset/4` method to cast them: +To populate fields in your user struct that are fetched from the provider, you can override the `identity_changeset/4` method to cast them: ```elixir defmodule MyApp.Users.User do @@ -252,10 +252,10 @@ defmodule MyApp.Users.User do timestamps() end - def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do + def identity_changeset(user_or_changeset, identity, attrs, user_id_attrs) do user_or_changeset |> Ecto.Changeset.cast(attrs, [:custom_field]) - |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs) + |> pow_assent_identity_changeset(identity, attrs, user_id_attrs) end end ``` @@ -338,7 +338,7 @@ defmodule MyApp.Lib.User do use PowAssent.Ecto.Schema schema "users" do - has_many :user_identities, + has_many :identities, MyApp.Lib.UserIdentity, on_delete: :delete_all, foreign_key: :user_id @@ -357,7 +357,7 @@ end Otherwise you'll get an error that reads: ```elixir -warning: invalid association `user_identities` in schema MyApp.Lib.User: associated schema MyApp.UserIdentities.UserIdentity does not exist +warning: invalid association `identities` in schema MyApp.Lib.User: associated schema MyApp.Users.UserIdentity does not exist ``` ## Callback URL with HTTPS behind proxy diff --git a/guides/capture_access_token.md b/guides/capture_access_token.md index f1cb290..95cedb9 100644 --- a/guides/capture_access_token.md +++ b/guides/capture_access_token.md @@ -17,25 +17,25 @@ end ``` ```elixir -# lib/my_app/user_identities/user_identity.ex -defmodule MyApp.UserIdentities.UserIdentity do +# lib/my_app/users/user_identity.ex +defmodule MyApp.Users.UserIdentity do use Ecto.Schema - use PowAssent.Ecto.UserIdentities.Schema, + use PowAssent.Ecto.Identities.Schema, user: MyApp.Users.User schema "user_identities" do field :access_token, :string field :refresh_token, :string - pow_assent_user_identity_fields() + pow_assent_identity_fields() timestamps() end - def changeset(user_identity_or_changeset, attrs) do + def changeset(identity_or_changeset, attrs) do token_params = Map.get(attrs, "token", attrs) - user_identity_or_changeset + identity_or_changeset |> pow_assent_changeset(attrs) |> Ecto.Changeset.cast(token_params, [:access_token, :refresh_token]) |> Ecto.Changeset.validate_required([:access_token]) @@ -46,5 +46,5 @@ end Now access tokens can be retrieved by loading the user identity: ```elixir -user_identity = MyApp.Repo.get_by(MyApp.UserIdentities.UserIdentity, provider: provider, user_id: user.id) +identity = MyApp.Repo.get_by(MyApp.Users.UserIdentity, provider: provider, user_id: user.id) ``` \ No newline at end of file diff --git a/lib/mix/pow_assent.ex b/lib/mix/pow_assent.ex index 59d7a31..de14d65 100644 --- a/lib/mix/pow_assent.ex +++ b/lib/mix/pow_assent.ex @@ -30,11 +30,11 @@ defmodule Mix.PowAssent do #{msg} mix #{task} accepts both a module name and the plural of the resource: - mix #{task} UserIdentities.UserIdentity user_identities + mix #{task} Users.UserIdentity user_identities """) end defp schema_options_from_args(_opts \\ []) defp schema_options_from_args([schema, plural | _rest]), do: %{schema_name: schema, schema_plural: plural} - defp schema_options_from_args(_any), do: %{schema_name: "UserIdentities.UserIdentity", schema_plural: "user_identities"} + defp schema_options_from_args(_any), do: %{schema_name: "Users.UserIdentity", schema_plural: "user_identities"} end diff --git a/lib/mix/tasks/ecto/pow_assent.ecto.gen.migration.ex b/lib/mix/tasks/ecto/pow_assent.ecto.gen.migration.ex index e111700..40a7f01 100644 --- a/lib/mix/tasks/ecto/pow_assent.ecto.gen.migration.ex +++ b/lib/mix/tasks/ecto/pow_assent.ecto.gen.migration.ex @@ -19,7 +19,7 @@ defmodule Mix.Tasks.PowAssent.Ecto.Gen.Migration do """ use Mix.Task - alias PowAssent.Ecto.UserIdentities.Schema.Migration, as: UserIdentitiesMigration + alias PowAssent.Ecto.Identities.Schema.Migration, as: IdentitiesMigration alias Mix.{Ecto, Pow, Pow.Ecto.Migration, PowAssent} @switches [binary_id: :boolean, users_table: :string] @@ -52,8 +52,8 @@ defmodule Mix.Tasks.PowAssent.Ecto.Gen.Migration do defp create_migration_file(%{repo: repo, binary_id: binary_id, users_table: users_table, schema_plural: schema_plural}) do context_base = Pow.app_base(Pow.otp_app()) - schema = UserIdentitiesMigration.new(context_base, schema_plural, repo: repo, binary_id: binary_id, users_table: users_table) - content = UserIdentitiesMigration.gen(schema) + schema = IdentitiesMigration.new(context_base, schema_plural, repo: repo, binary_id: binary_id, users_table: users_table) + content = IdentitiesMigration.gen(schema) Migration.create_migration_file(repo, schema.migration_name, content) end diff --git a/lib/mix/tasks/ecto/pow_assent.ecto.gen.schema.ex b/lib/mix/tasks/ecto/pow_assent.ecto.gen.schema.ex index 27689c5..ed30539 100644 --- a/lib/mix/tasks/ecto/pow_assent.ecto.gen.schema.ex +++ b/lib/mix/tasks/ecto/pow_assent.ecto.gen.schema.ex @@ -9,7 +9,7 @@ defmodule Mix.Tasks.PowAssent.Ecto.Gen.Schema do mix pow_assent.ecto.gen.schema -r MyApp.Repo Accounts.Identity identities This generator will add a schema module file in - `lib/my_app/user_identities/user_identity.ex`. + `lib/my_app/users/user_identity.ex`. ## Arguments @@ -18,7 +18,7 @@ defmodule Mix.Tasks.PowAssent.Ecto.Gen.Schema do """ use Mix.Task - alias PowAssent.Ecto.UserIdentities.Schema.Module, as: SchemaModule + alias PowAssent.Ecto.Identities.Schema.Module, as: SchemaModule alias Mix.{Generator, Pow, PowAssent} @switches [context_app: :string, binary_id: :boolean] diff --git a/lib/pow_assent/ecto/user_identities/context.ex b/lib/pow_assent/ecto/identities/context.ex similarity index 61% rename from lib/pow_assent/ecto/user_identities/context.ex rename to lib/pow_assent/ecto/identities/context.ex index f59ad17..bc938ad 100644 --- a/lib/pow_assent/ecto/user_identities/context.ex +++ b/lib/pow_assent/ecto/identities/context.ex @@ -1,4 +1,4 @@ -defmodule PowAssent.Ecto.UserIdentities.Context do +defmodule PowAssent.Ecto.Identities.Context do @moduledoc """ Handles pow assent user identity context for user identities. @@ -6,10 +6,10 @@ defmodule PowAssent.Ecto.UserIdentities.Context do This module will be used by PowAssent by default. If you wish to have control over context methods, you can do configure - `lib/my_project/user_identities/user_identities.ex` the following way: + `LIB_PATH/user_identities.ex` the following way: defmodule MyApp.UserIdentities do - use PowAssent.Ecto.UserIdentities.Context, + use PowAssent.Ecto.Identities.Context, repo: MyApp.Repo, user: MyApp.Users.User @@ -19,7 +19,7 @@ defmodule PowAssent.Ecto.UserIdentities.Context do end Remember to update the PowAssent configuration with - `user_identities_context: MyApp.UserIdentities`. + `identities_context: MyApp.Identities`. The following Pow methods can be accessed: @@ -41,26 +41,26 @@ defmodule PowAssent.Ecto.UserIdentities.Context do @type changeset :: map() @type user :: map() - @type user_identity :: map() + @type identity :: map() @type user_params :: map() - @type user_identity_params :: map() + @type identity_params :: map() @type user_id_params :: map() @callback get_user_by_provider_uid(binary(), binary()) :: user() | nil - @callback upsert(user(), user_identity_params()) :: - {:ok, user_identity()} + @callback upsert(user(), identity_params()) :: + {:ok, identity()} | {:error, {:bound_to_different_user, changeset()}} | {:error, changeset()} - @callback create_user(user_identity_params(), user_params(), user_id_params() | nil) :: + @callback create_user(identity_params(), user_params(), user_id_params() | nil) :: {:ok, user()} | {:error, {:bound_to_different_user | :invalid_user_id_field, changeset()}} | {:error, changeset()} @callback delete(user(), binary()) :: {:ok, {number(), nil}} | {:error, {:no_password, changeset()}} - @callback all(user()) :: [user_identity()] + @callback all(user()) :: [identity()] # TODO: Remove by 0.4.0 - @callback create(user(), user_identity_params()) :: any() + @callback create(user(), identity_params()) :: any() @doc false defmacro __using__(config) do @@ -71,9 +71,9 @@ defmodule PowAssent.Ecto.UserIdentities.Context do def get_user_by_provider_uid(provider, uid), do: pow_assent_get_user_by_provider_uid(provider, uid) - def upsert(user, user_identity_params), do: pow_assent_upsert(user, user_identity_params) - def create_user(user_identity_params, user_params, user_id_params), - do: pow_assent_create_user(user_identity_params, user_params, user_id_params) + def upsert(user, identity_params), do: pow_assent_upsert(user, identity_params) + def create_user(identity_params, user_params, user_id_params), + do: pow_assent_create_user(identity_params, user_params, user_id_params) def delete(user, provider), do: pow_assent_delete(user, provider) def all(user), do: pow_assent_all(user) @@ -81,12 +81,12 @@ defmodule PowAssent.Ecto.UserIdentities.Context do unquote(__MODULE__).get_user_by_provider_uid(provider, uid, @pow_config) end - def pow_assent_upsert(user, user_identity_params) do - unquote(__MODULE__).upsert(user, user_identity_params, @pow_config) + def pow_assent_upsert(user, identity_params) do + unquote(__MODULE__).upsert(user, identity_params, @pow_config) end - def pow_assent_create_user(user_identity_params, user_params, user_id_params) do - unquote(__MODULE__).create_user(user_identity_params, user_params, user_id_params, @pow_config) + def pow_assent_create_user(identity_params, user_params, user_id_params) do + unquote(__MODULE__).create_user(identity_params, user_params, user_id_params, @pow_config) end def pow_assent_delete(user, provider) do @@ -99,11 +99,11 @@ defmodule PowAssent.Ecto.UserIdentities.Context do # TODO: Remove by 0.4.0 @deprecated "Please use `upsert/2` instead" - defdelegate create(user, user_identity_params), to: __MODULE__, as: :upsert + defdelegate create(user, identity_params), to: __MODULE__, as: :upsert # TODO: Remove by 0.4.0 @deprecated "Please use `pow_assent_upsert/2` instead" - defdelegate pow_assent_create(user, user_identity_params), to: __MODULE__, as: :pow_assent_upsert + defdelegate pow_assent_create(user, identity_params), to: __MODULE__, as: :pow_assent_upsert defoverridable unquote(__MODULE__) end @@ -121,7 +121,7 @@ defmodule PowAssent.Ecto.UserIdentities.Context do opts = repo_opts(config, [:prefix]) config - |> user_identity_schema_mod() + |> identity_schema_mod() |> where([i], i.provider == ^provider and i.uid == ^uid) |> join(:left, [i], i in assoc(i, :user)) |> select([_, u], u) @@ -131,8 +131,8 @@ defmodule PowAssent.Ecto.UserIdentities.Context do # TODO: Remove by 0.4.0 @doc false @deprecated "Use `upsert/3` instead" - @spec create(user(), user_identity_params(), Config.t()) :: {:ok, user_identity()} | {:error, {:bound_to_different_user, changeset()}} | {:error, changeset()} - def create(user, user_identity_params, config), do: upsert(user, user_identity_params, config) + @spec create(user(), identity_params(), Config.t()) :: {:ok, identity()} | {:error, {:bound_to_different_user, changeset()}} | {:error, changeset()} + def create(user, identity_params, config), do: upsert(user, identity_params, config) @doc """ Upserts a user identity. @@ -142,9 +142,9 @@ defmodule PowAssent.Ecto.UserIdentities.Context do Repo module will be fetched from config. """ - @spec upsert(user(), user_identity_params(), Config.t()) :: {:ok, user_identity()} | {:error, {:bound_to_different_user, changeset()}} | {:error, changeset()} - def upsert(user, user_identity_params, config) do - params = convert_params(user_identity_params) + @spec upsert(user(), identity_params(), Config.t()) :: {:ok, identity()} | {:error, {:bound_to_different_user, changeset()}} | {:error, changeset()} + def upsert(user, identity_params, config) do + params = convert_params(identity_params) {uid_provider_params, additional_params} = Map.split(params, ["uid", "provider"]) user @@ -153,16 +153,16 @@ defmodule PowAssent.Ecto.UserIdentities.Context do nil -> insert_identity(user, params, config) identity -> update_identity(identity, additional_params, config) end - |> user_identity_bound_different_user_error() + |> identity_bound_different_user_error() end - defp user_identity_bound_different_user_error({:error, %{errors: errors} = changeset}) do - case unique_constraint_error?(errors, :uid_provider) do + defp identity_bound_different_user_error({:error, %{errors: errors} = changeset}) do + case unique_constraint_error?(errors, :uid) do true -> {:error, {:bound_to_different_user, changeset}} false -> {:error, changeset} end end - defp user_identity_bound_different_user_error(any), do: any + defp identity_bound_different_user_error(any), do: any defp convert_params(params) when is_map(params) do params @@ -175,24 +175,24 @@ defmodule PowAssent.Ecto.UserIdentities.Context do defp convert_param({key, value}) when is_atom(key), do: {Atom.to_string(key), value} defp convert_param({key, value}) when is_binary(key), do: {key, value} - defp insert_identity(user, user_identity_params, config) do - user_identity = Ecto.build_assoc(user, :user_identities) + defp insert_identity(user, identity_params, config) do + identity = Ecto.build_assoc(user, :identities) - user_identity - |> user_identity.__struct__.changeset(user_identity_params) + identity + |> identity.__struct__.changeset(identity_params) |> Context.do_insert(config) end - defp update_identity(user_identity, additional_params, config) do - user_identity - |> user_identity.__struct__.changeset(additional_params) + defp update_identity(identity, additional_params, config) do + identity + |> identity.__struct__.changeset(additional_params) |> Context.do_update(config) end defp get_for_user(user, %{"uid" => uid, "provider" => provider}, config) do - user_identity = Ecto.build_assoc(user, :user_identities).__struct__ + identity = Ecto.build_assoc(user, :identities).__struct__ - repo!(config).get_by(user_identity, [user_id: user.id, provider: provider, uid: uid], repo_opts(config, [:prefix])) + repo!(config).get_by(identity, [user_id: user.id, provider: provider, uid: uid], repo_opts(config, [:prefix])) end @doc """ @@ -200,26 +200,26 @@ defmodule PowAssent.Ecto.UserIdentities.Context do User schema module and repo module will be fetched from config. """ - @spec create_user(user_identity_params(), user_params(), user_id_params() | nil, Config.t()) :: {:ok, user()} | {:error, {:bound_to_different_user | :invalid_user_id_field, changeset()}} | {:error, changeset()} - def create_user(user_identity_params, user_params, user_id_params, config) do - params = convert_params(user_identity_params) + @spec create_user(identity_params(), user_params(), user_id_params() | nil, Config.t()) :: {:ok, user()} | {:error, {:bound_to_different_user | :invalid_user_id_field, changeset()}} | {:error, changeset()} + def create_user(identity_params, user_params, user_id_params, config) do + params = convert_params(identity_params) user_mod = user!(config) user_mod |> struct() - |> user_mod.user_identity_changeset(params, user_params, user_id_params) + |> user_mod.identity_changeset(params, user_params, user_id_params) |> Context.do_insert(config) - |> user_user_identity_bound_different_user_error() + |> user_identity_bound_different_user_error() |> invalid_user_id_error(config) end - defp user_user_identity_bound_different_user_error({:error, %{changes: %{user_identities: [%{errors: errors}]}} = changeset}) do - case unique_constraint_error?(errors, :uid_provider) do + defp user_identity_bound_different_user_error({:error, %{changes: %{identities: [%{errors: errors}]}} = changeset}) do + case unique_constraint_error?(errors, :uid) do true -> {:error, {:bound_to_different_user, changeset}} false -> {:error, changeset} end end - defp user_user_identity_bound_different_user_error(any), do: any + defp user_identity_bound_different_user_error(any), do: any defp unique_constraint_error?(errors, field) do Enum.find_value(errors, false, fn @@ -247,19 +247,19 @@ defmodule PowAssent.Ecto.UserIdentities.Context do @spec delete(user(), binary(), Config.t()) :: {:ok, {number(), nil}} | {:error, {:no_password, changeset()}} def delete(user, provider, config) do - user = repo!(config).preload(user, :user_identities, repo_opts(config, [:prefix]) ++ [force: true]) + user = repo!(config).preload(user, :identities, repo_opts(config, [:prefix]) ++ [force: true]) - user.user_identities + user.identities |> Enum.split_with(&(&1.provider == provider)) |> maybe_delete(user, config) end - defp maybe_delete({user_identities, rest}, %{password_hash: password_hash} = user, config) when length(rest) > 0 or not is_nil(password_hash) do + defp maybe_delete({identities, rest}, %{password_hash: password_hash} = user, config) when length(rest) > 0 or not is_nil(password_hash) do opts = repo_opts(config, [:prefix]) results = user - |> Ecto.assoc(:user_identities) - |> where([i], i.id in ^Enum.map(user_identities, &(&1.id))) + |> Ecto.assoc(:identities) + |> where([i], i.id in ^Enum.map(identities, &(&1.id))) |> repo!(config).delete_all(opts) {:ok, results} @@ -278,29 +278,29 @@ defmodule PowAssent.Ecto.UserIdentities.Context do Repo module will be fetched from config. """ - @spec all(user(), Config.t()) :: [user_identity()] + @spec all(user(), Config.t()) :: [identity()] def all(user, config) do opts = repo_opts(config, [:prefix]) user - |> Ecto.assoc(:user_identities) + |> Ecto.assoc(:identities) |> repo!(config).all(opts) end - defp user_identity_schema_mod(config) when is_list(config) do + defp identity_schema_mod(config) when is_list(config) do config |> user!() - |> user_identity_schema_mod() + |> identity_schema_mod() end - defp user_identity_schema_mod(user_mod) when is_atom(user_mod) do - association = user_mod.__schema__(:association, :user_identities) || raise_no_user_identity_error() + defp identity_schema_mod(user_mod) when is_atom(user_mod) do + association = user_mod.__schema__(:association, :identities) || raise_no_identity_error() association.queryable end - @spec raise_no_user_identity_error :: no_return - defp raise_no_user_identity_error do - Config.raise_error("The `:user` configuration option doesn't have a `:user_identities` association.") + @spec raise_no_identity_error :: no_return + defp raise_no_identity_error do + Config.raise_error("The `:user` configuration option doesn't have a `:identities` association.") end defp repo_opts(config, opts) do diff --git a/lib/pow_assent/ecto/user_identities/schema.ex b/lib/pow_assent/ecto/identities/schema.ex similarity index 68% rename from lib/pow_assent/ecto/user_identities/schema.ex rename to lib/pow_assent/ecto/identities/schema.ex index f3b9a80..d290fcf 100644 --- a/lib/pow_assent/ecto/user_identities/schema.ex +++ b/lib/pow_assent/ecto/identities/schema.ex @@ -1,4 +1,4 @@ -defmodule PowAssent.Ecto.UserIdentities.Schema do +defmodule PowAssent.Ecto.Identities.Schema do @moduledoc """ Handles the Ecto schema for user identity. @@ -7,21 +7,21 @@ defmodule PowAssent.Ecto.UserIdentities.Schema do ## Usage - Configure `lib/my_project/user_identities/user_identity.ex` the following way: + Configure `LIB_PATH/users/user_identity.ex` the following way: - defmodule MyApp.UserIdentities.UserIdentity do + defmodule MyApp.Users.UserIdentity do use Ecto.Schema - use PowAssent.Ecto.UserIdentities.Schema, + use PowAssent.Ecto.Identities.Schema, user: MyApp.Users.User schema "user_identities" do - pow_assent_user_identity_fields() + pow_assent_identity_fields() timestamps() end - def changeset(user_identity_or_changeset, attrs) do - pow_assent_changeset(user_identity_or_changeset, attrs) + def changeset(identity_or_changeset, attrs) do + pow_assent_changeset(identity_or_changeset, attrs) end end @@ -44,7 +44,7 @@ defmodule PowAssent.Ecto.UserIdentities.Schema do @pow_assent_config unquote(config) @spec changeset(Ecto.Schema.t() | Changeset.t(), map()) :: Changeset.t() - def changeset(user_identity_or_changeset, attrs), do: pow_assent_changeset(user_identity_or_changeset, attrs) + def changeset(identity_or_changeset, attrs), do: pow_assent_changeset(identity_or_changeset, attrs) defoverridable unquote(__MODULE__) @@ -57,8 +57,8 @@ defmodule PowAssent.Ecto.UserIdentities.Schema do @doc """ Macro for adding user identity schema fields. """ - @spec pow_assent_user_identity_fields :: Macro.t() - defmacro pow_assent_user_identity_fields do + @spec pow_assent_identity_fields :: Macro.t() + defmacro pow_assent_identity_fields do quote do Enum.each(@pow_assent_assocs, fn {:belongs_to, name, :users} -> @@ -75,11 +75,11 @@ defmodule PowAssent.Ecto.UserIdentities.Schema do @doc false defmacro __pow_assent_methods__ do quote do - import unquote(__MODULE__), only: [pow_assent_user_identity_fields: 0] + import unquote(__MODULE__), only: [pow_assent_identity_fields: 0] @spec pow_assent_changeset(Ecto.Schema.t() | Changeset.t(), map()) :: Changeset.t() - def pow_assent_changeset(user_identity_or_changeset, attrs) do - unquote(__MODULE__).changeset(user_identity_or_changeset, attrs, @pow_assent_config) + def pow_assent_changeset(identity_or_changeset, attrs) do + unquote(__MODULE__).changeset(identity_or_changeset, attrs, @pow_assent_config) end end end @@ -101,12 +101,12 @@ defmodule PowAssent.Ecto.UserIdentities.Schema do @doc """ Validates a user identity. """ - def changeset(user_identity_or_changeset, params, _config) do - user_identity_or_changeset + def changeset(identity_or_changeset, params, _config) do + identity_or_changeset |> Changeset.cast(params, [:provider, :uid, :user_id]) |> Changeset.validate_required([:provider, :uid]) |> Changeset.assoc_constraint(:user) - |> Changeset.unique_constraint(:uid_provider, name: :user_identities_uid_provider_index) + |> Changeset.unique_constraint([:uid, :provider]) end @spec raise_no_user_error :: no_return diff --git a/lib/pow_assent/ecto/user_identities/schema/fields.ex b/lib/pow_assent/ecto/identities/schema/fields.ex similarity index 91% rename from lib/pow_assent/ecto/user_identities/schema/fields.ex rename to lib/pow_assent/ecto/identities/schema/fields.ex index c0c1179..e0bea32 100644 --- a/lib/pow_assent/ecto/user_identities/schema/fields.ex +++ b/lib/pow_assent/ecto/identities/schema/fields.ex @@ -1,4 +1,4 @@ -defmodule PowAssent.Ecto.UserIdentities.Schema.Fields do +defmodule PowAssent.Ecto.Identities.Schema.Fields do @moduledoc """ Handles the Ecto schema fields for user. """ diff --git a/lib/pow_assent/ecto/user_identities/schema/migration.ex b/lib/pow_assent/ecto/identities/schema/migration.ex similarity index 89% rename from lib/pow_assent/ecto/user_identities/schema/migration.ex rename to lib/pow_assent/ecto/identities/schema/migration.ex index 5f524bc..5dfbd32 100644 --- a/lib/pow_assent/ecto/user_identities/schema/migration.ex +++ b/lib/pow_assent/ecto/identities/schema/migration.ex @@ -1,9 +1,9 @@ -defmodule PowAssent.Ecto.UserIdentities.Schema.Migration do +defmodule PowAssent.Ecto.Identities.Schema.Migration do @moduledoc """ Generates schema migration content. """ alias Pow.Ecto.Schema.Migration - alias PowAssent.{Config, Ecto.UserIdentities.Schema.Fields} + alias PowAssent.{Config, Ecto.Identities.Schema.Fields} @doc """ Generates migration schema map. diff --git a/lib/pow_assent/ecto/user_identities/schema/module.ex b/lib/pow_assent/ecto/identities/schema/module.ex similarity index 86% rename from lib/pow_assent/ecto/user_identities/schema/module.ex rename to lib/pow_assent/ecto/identities/schema/module.ex index 5e3a943..8548ca9 100644 --- a/lib/pow_assent/ecto/user_identities/schema/module.ex +++ b/lib/pow_assent/ecto/identities/schema/module.ex @@ -1,4 +1,4 @@ -defmodule PowAssent.Ecto.UserIdentities.Schema.Module do +defmodule PowAssent.Ecto.Identities.Schema.Module do @moduledoc """ Generates schema module content. @@ -11,12 +11,12 @@ defmodule PowAssent.Ecto.UserIdentities.Schema.Module do @template """ defmodule <%= inspect schema.module %> do use Ecto.Schema - use PowAssent.Ecto.UserIdentities.Schema, user: <%= inspect(schema.user_module) %> + use PowAssent.Ecto.Identities.Schema, user: <%= inspect(schema.user_module) %> <%= if schema.binary_id do %> @primary_key {:id, :binary_id, autogenerate: true} @foreign_key_type :binary_id<% end %> schema <%= inspect schema.table %> do - pow_assent_user_identity_fields() + pow_assent_identity_fields() timestamps() end diff --git a/lib/pow_assent/ecto/schema.ex b/lib/pow_assent/ecto/schema.ex index 62f961a..bcc8f44 100644 --- a/lib/pow_assent/ecto/schema.ex +++ b/lib/pow_assent/ecto/schema.ex @@ -27,29 +27,29 @@ defmodule PowAssent.Ecto.Schema do |> pow_changeset(attrs) end - def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do + def identity_changeset(user_or_changeset, identity, attrs, user_id_attrs) do user_or_changeset |> Ecto.Changeset.cast(attrs, [:custom_field]) - |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs) + |> pow_assent_identity_changeset(identity, attrs, user_id_attrs) end end """ alias Ecto.{Changeset, Schema} alias Pow.UUID - @callback user_identity_changeset(Schema.t() | Changeset.t(), Schema.t(), map(), map() | nil) :: Changeset.t() + @callback identity_changeset(Schema.t() | Changeset.t(), Schema.t(), map(), map() | nil) :: Changeset.t() @doc false defmacro __using__(_config) do quote do @behaviour unquote(__MODULE__) - @spec user_identity_changeset(Schema.t() | Changeset.t(), Schema.t(), map(), map() | nil) :: Changeset.t() - def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs), do: pow_assent_user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) + @spec identity_changeset(Schema.t() | Changeset.t(), Schema.t(), map(), map() | nil) :: Changeset.t() + def identity_changeset(user_or_changeset, identity, attrs, user_id_attrs), do: pow_assent_identity_changeset(user_or_changeset, identity, attrs, user_id_attrs) - @spec pow_assent_user_identity_changeset(Schema.t() | Changeset.t(), Schema.t(), map(), map() | nil) :: Changeset.t() - def pow_assent_user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do - unquote(__MODULE__).changeset(user_or_changeset, user_identity, attrs, user_id_attrs, @pow_config) + @spec pow_assent_identity_changeset(Schema.t() | Changeset.t(), Schema.t(), map(), map() | nil) :: Changeset.t() + def pow_assent_identity_changeset(user_or_changeset, identity, attrs, user_id_attrs) do + unquote(__MODULE__).changeset(user_or_changeset, identity, attrs, user_id_attrs, @pow_config) end unquote(__MODULE__).__has_many__() @@ -61,21 +61,19 @@ defmodule PowAssent.Ecto.Schema do @doc false defmacro __has_many__() do quote do - @pow_assocs {:has_many, :user_identities, unquote(__MODULE__).__user_identities_module__(__MODULE__), foreign_key: :user_id, on_delete: :delete_all} + @pow_assocs {:has_many, :identities, unquote(__MODULE__).__identities_module__(__MODULE__), foreign_key: :user_id, on_delete: :delete_all} end end @doc false - def __user_identities_module__(module) do - module - |> Module.split() - |> Enum.reverse() - |> case do - [_schema, base] -> [base] - [_schema, _context | rest] -> rest - end - |> Enum.reverse() - |> Enum.concat([UserIdentities, UserIdentity]) + def __identities_module__(module) do + {_schema, base} = + module + |> Module.split() + |> List.pop_at(-1) + + base + |> Kernel.++([UserIdentity]) |> Module.concat() end @@ -86,14 +84,14 @@ defmodule PowAssent.Ecto.Schema do validation as password is not required. """ @spec changeset(Schema.t() | Changeset.t(), Schema.t(), map(), map() | nil, Config.t()) :: Changeset.t() - def changeset(user_or_changeset, user_identity, attrs, user_id_attrs, _config) do + def changeset(user_or_changeset, identity, attrs, user_id_attrs, _config) do user_or_changeset |> Changeset.change() |> maybe_accept_invitation() |> user_id_field_changeset(attrs, user_id_attrs) |> maybe_email_confirmation_changeset(attrs) - |> Changeset.cast(%{user_identities: [user_identity]}, []) - |> Changeset.cast_assoc(:user_identities) + |> Changeset.cast(%{identities: [identity]}, []) + |> Changeset.cast_assoc(:identities) end defp maybe_accept_invitation(%Changeset{data: %user_mod{invitation_token: token, invitation_accepted_at: nil} = changeset}) when not is_nil(token) do diff --git a/lib/pow_assent/operations.ex b/lib/pow_assent/operations.ex index 4ff48e6..eab8a07 100644 --- a/lib/pow_assent/operations.ex +++ b/lib/pow_assent/operations.ex @@ -3,16 +3,16 @@ defmodule PowAssent.Operations do Operation methods that glues operation calls to context module. A custom context module can be used instead of the default - `PowAssent.Ecto.UserIdentities.Context` if a `:user_identities_context` key + `PowAssent.Ecto.Identities.Context` if a `:identities_context` key is passed in the PowAssent configuration. """ - alias PowAssent.{Config, Ecto.UserIdentities.Context} + alias PowAssent.{Config, Ecto.Identities.Context} alias Pow.Config, as: PowConfig @doc """ Retrieve a user with the strategy provider name and uid. - This calls `Pow.Ecto.UserIdentities.Context.get_user_by_provider_uid/3` or + This calls `Pow.Ecto.Identities.Context.get_user_by_provider_uid/3` or `get_user_by_provider_uid/2` on a custom context module. """ @spec get_user_by_provider_uid(binary(), binary(), Config.t()) :: map() | nil | no_return @@ -27,33 +27,33 @@ defmodule PowAssent.Operations do @doc false @deprecated "Use `upsert/3` instead" @spec create(map(), map(), Config.t()) :: {:ok, map()} | {:error, {:bound_to_different_user, map()}} | {:error, map()} | no_return - def create(user, user_identity_params, config), do: upsert(user, user_identity_params, config) + def create(user, identity_params, config), do: upsert(user, identity_params, config) @doc """ Upserts user identity for the user, and strategy provider name and uid. - This calls `Pow.Ecto.UserIdentities.Context.upsert/3` or + This calls `Pow.Ecto.Identities.Context.upsert/3` or `upsert/2` on a custom context module. """ @spec upsert(map(), map(), Config.t()) :: {:ok, map()} | {:error, {:bound_to_different_user, map()}} | {:error, map()} | no_return - def upsert(user, user_identity_params, config) do + def upsert(user, identity_params, config) do case context_module(config) do - Context -> Context.upsert(user, user_identity_params, config) - module -> module.upsert(user, user_identity_params) + Context -> Context.upsert(user, identity_params, config) + module -> module.upsert(user, identity_params) end end @doc """ Creates user with user identity with the provided user params. - This calls `Pow.Ecto.UserIdentities.Context.create_user/4` or + This calls `Pow.Ecto.Identities.Context.create_user/4` or `create_user/3` on a custom context module. """ @spec create_user(map(), map(), map() | nil, Config.t()) :: {:ok, map()} | {:error, {:bound_to_different_user | :invalid_user_id_field, map()}} | {:error, map()} | no_return - def create_user(user_identity_params, user_params, user_id_params, config) do + def create_user(identity_params, user_params, user_id_params, config) do case context_module(config) do - Context -> Context.create_user(user_identity_params, user_params, user_id_params, config) - module -> module.create_user(user_identity_params, user_params, user_id_params) + Context -> Context.create_user(identity_params, user_params, user_id_params, config) + module -> module.create_user(identity_params, user_params, user_id_params) end end @@ -61,21 +61,21 @@ defmodule PowAssent.Operations do Build a changeset from a blank user struct. It'll use the schema module fetched from the config through - `Pow.Config.user!/1` and call `user_identity_changeset/4` on it. + `Pow.Config.user!/1` and call `identity_changeset/4` on it. """ - @spec user_identity_changeset(map(), map(), map(), Config.t()) :: map() | nil - def user_identity_changeset(params, user_params, user_id_params, config) do + @spec identity_changeset(map(), map(), map(), Config.t()) :: map() | nil + def identity_changeset(params, user_params, user_id_params, config) do user_mod = PowConfig.user!(config) user_mod |> struct() - |> user_mod.user_identity_changeset(params, user_params, user_id_params) + |> user_mod.identity_changeset(params, user_params, user_id_params) end @doc """ Deletes the user identity for user and strategy provider name. - This calls `Pow.Ecto.UserIdentities.Context.delete/3` or + This calls `Pow.Ecto.Identities.Context.delete/3` or `delete/2` on a custom context module. """ @spec delete(map(), binary(), Config.t()) :: {:ok, {number(), nil}} | {:error, {:no_password, map()}} | no_return @@ -89,7 +89,7 @@ defmodule PowAssent.Operations do @doc """ Lists all user identity associations for user. - This calls `Pow.Ecto.UserIdentities.Context.all/2` or + This calls `Pow.Ecto.Identities.Context.all/2` or `all/1` on a custom context module. """ @spec all(map(), Config.t()) :: [map()] | no_return @@ -101,6 +101,6 @@ defmodule PowAssent.Operations do end defp context_module(config) do - Config.get(config, :user_identities_context, Context) + Config.get(config, :identities_context, Context) end end diff --git a/lib/pow_assent/phoenix/controllers/registration_controller.ex b/lib/pow_assent/phoenix/controllers/registration_controller.ex index d10fb78..89eb714 100644 --- a/lib/pow_assent/phoenix/controllers/registration_controller.ex +++ b/lib/pow_assent/phoenix/controllers/registration_controller.ex @@ -32,8 +32,8 @@ defmodule PowAssent.Phoenix.RegistrationController do end @spec process_create(Conn.t(), map()) :: {:ok, map(), Conn.t()} | {:error, map(), Conn.t()} - def process_create(%{private: %{pow_assent_callback_params: %{user_identity: user_identity_params, user: user_params}}} = conn, %{"user" => user_id_params}) do - Plug.create_user(conn, user_identity_params, user_params, user_id_params) + def process_create(%{private: %{pow_assent_callback_params: %{identity: identity_params, user: user_params}}} = conn, %{"user" => user_id_params}) do + Plug.create_user(conn, identity_params, user_params, user_id_params) end @spec respond_create({:ok, map(), Conn.t()} | {:error, map(), Conn.t()}) :: Conn.t() diff --git a/lib/pow_assent/plug.ex b/lib/pow_assent/plug.ex index 9e704ad..90b9eb7 100644 --- a/lib/pow_assent/plug.ex +++ b/lib/pow_assent/plug.ex @@ -11,7 +11,7 @@ defmodule PowAssent.Plug do pow_assent: [ http_adapter: PowAssent.HTTPAdapter.Mint, json_library: Poison, - user_identities_context: MyApp.UserIdentities + identities_context: MyApp.UserIdentities ] """ alias Plug.Conn @@ -77,8 +77,8 @@ defmodule PowAssent.Plug do - `{:error, :strategy}` - An error ocurred during strategy callback phase. `:pow_assent_callback_error` will be populated with the error. - - `{:ok, :upsert_user_identity}` - User identity was created or updated. - - `{:error, :upsert_user_identity}` - User identity could not be created + - `{:ok, :upsert_identity}` - User identity was created or updated. + - `{:error, :upsert_identity}` - User identity could not be created or updated. `:pow_assent_callback_error` will be populated with the changeset. - `{:ok, :create_user}` - User was created. @@ -96,7 +96,7 @@ defmodule PowAssent.Plug do |> callback(provider, params, redirect_uri) |> handle_callback() |> maybe_authenticate() - |> maybe_upsert_user_identity() + |> maybe_upsert_identity() |> maybe_create_user() |> case do %{private: %{pow_assent_callback_state: {:ok, _method}}} = conn -> @@ -107,10 +107,10 @@ defmodule PowAssent.Plug do end end - defp handle_callback({:ok, user_identity_params, user_params, conn}) do + defp handle_callback({:ok, identity_params, user_params, conn}) do conn |> Conn.put_private(:pow_assent_callback_state, {:ok, :strategy}) - |> Conn.put_private(:pow_assent_callback_params, %{user_identity: user_identity_params, user: user_params}) + |> Conn.put_private(:pow_assent_callback_params, %{identity: identity_params, user: user_params}) end defp handle_callback({:error, error, conn}) do conn @@ -119,12 +119,12 @@ defmodule PowAssent.Plug do end defp maybe_authenticate(%{private: %{pow_assent_callback_state: {:ok, :strategy}, pow_assent_callback_params: params}} = conn) do - user_identity_params = Map.fetch!(params, :user_identity) + identity_params = Map.fetch!(params, :identity) case Pow.Plug.current_user(conn) do nil -> conn - |> authenticate(user_identity_params) + |> authenticate(identity_params) |> case do {:ok, conn} -> conn {:error, conn} -> conn @@ -136,8 +136,8 @@ defmodule PowAssent.Plug do end defp maybe_authenticate(conn), do: conn - defp maybe_upsert_user_identity(%{private: %{pow_assent_callback_state: {:ok, :strategy}, pow_assent_callback_params: params}} = conn) do - user_identity_params = Map.fetch!(params, :user_identity) + defp maybe_upsert_identity(%{private: %{pow_assent_callback_state: {:ok, :strategy}, pow_assent_callback_params: params}} = conn) do + identity_params = Map.fetch!(params, :identity) case Pow.Plug.current_user(conn) do nil -> @@ -145,19 +145,19 @@ defmodule PowAssent.Plug do _user -> conn - |> upsert_identity(user_identity_params) + |> upsert_identity(identity_params) |> case do - {:ok, _user_identity, conn} -> - Conn.put_private(conn, :pow_assent_callback_state, {:ok, :upsert_user_identity}) + {:ok, _identity, conn} -> + Conn.put_private(conn, :pow_assent_callback_state, {:ok, :upsert_identity}) {:error, changeset, conn} -> conn - |> Conn.put_private(:pow_assent_callback_state, {:error, :upsert_user_identity}) + |> Conn.put_private(:pow_assent_callback_state, {:error, :upsert_identity}) |> Conn.put_private(:pow_assent_callback_error, changeset) end end end - defp maybe_upsert_user_identity(conn), do: conn + defp maybe_upsert_identity(conn), do: conn defp maybe_create_user(%{private: %{pow_assent_registration: false}} = conn) do conn @@ -165,13 +165,13 @@ defmodule PowAssent.Plug do |> Conn.put_private(:pow_assent_callback_error, nil) end defp maybe_create_user(%{private: %{pow_assent_callback_state: {:ok, :strategy}, pow_assent_callback_params: params}} = conn) do - user_params = Map.fetch!(params, :user) - user_identity_params = Map.fetch!(params, :user_identity) + user_params = Map.fetch!(params, :user) + identity_params = Map.fetch!(params, :identity) case Pow.Plug.current_user(conn) do nil -> conn - |> create_user(user_identity_params, user_params) + |> create_user(identity_params, user_params) |> case do {:ok, _user, conn} -> Conn.put_private(conn, :pow_assent_callback_state, {:ok, :create_user}) @@ -214,8 +214,8 @@ defmodule PowAssent.Plug do user |> normalize_username() - |> split_user_identity_params() - |> handle_user_identity_params(other_params, provider, conn) + |> split_identity_params() + |> handle_identity_params(other_params, provider, conn) end defp parse_callback_response({:error, error}, _provider, conn), do: {:error, error, conn} @@ -226,22 +226,22 @@ defmodule PowAssent.Plug do end defp normalize_username(params), do: params - defp split_user_identity_params(%{"sub" => uid} = params) do + defp split_identity_params(%{"sub" => uid} = params) do user_params = Map.delete(params, "sub") {%{"uid" => uid}, user_params} end - defp handle_user_identity_params({user_identity_params, user_params}, other_params, provider, conn) do - user_identity_params = Map.put(user_identity_params, "provider", provider) - other_params = for {key, value} <- other_params, into: %{}, do: {Atom.to_string(key), value} + defp handle_identity_params({identity_params, user_params}, other_params, provider, conn) do + identity_params = Map.put(identity_params, "provider", provider) + other_params = for {key, value} <- other_params, into: %{}, do: {Atom.to_string(key), value} - user_identity_params = - user_identity_params + identity_params = + identity_params |> Map.put("provider", provider) |> Map.merge(other_params) - {:ok, user_identity_params, user_params, conn} + {:ok, identity_params, user_params, conn} end @doc """ @@ -294,7 +294,7 @@ defmodule PowAssent.Plug do @doc false @deprecated "Use `upsert_identity/2` instead" @spec create_identity(Conn.t(), map()) :: {:ok, map(), Conn.t()} | {:error, {:bound_to_different_user, map()} | map(), Conn.t()} - def create_identity(conn, user_identity_params), do: upsert_identity(conn, user_identity_params) + def create_identity(conn, identity_params), do: upsert_identity(conn, identity_params) @doc """ Will upsert identity for the current user. @@ -303,15 +303,15 @@ defmodule PowAssent.Plug do the callbacks stored with `put_create_session_callback/2` will run. """ @spec upsert_identity(Conn.t(), map()) :: {:ok, map(), Conn.t()} | {:error, {:bound_to_different_user, map()} | map(), Conn.t()} - def upsert_identity(conn, user_identity_params) do + def upsert_identity(conn, identity_params) do config = fetch_config(conn) user = Plug.current_user(conn) user - |> Operations.upsert(user_identity_params, config) + |> Operations.upsert(identity_params, config) |> case do - {:ok, user_identity} -> {:ok, user_identity, create_session(conn, user, user_identity_params, config)} - {:error, error} -> {:error, error, conn} + {:ok, identity} -> {:ok, identity, create_session(conn, user, identity_params, config)} + {:error, error} -> {:error, error, conn} end end @@ -322,13 +322,13 @@ defmodule PowAssent.Plug do the callbacks stored with `put_create_session_callback/2` will run. """ @spec create_user(Conn.t(), map(), map(), map() | nil) :: {:ok, map(), Conn.t()} | {:error, {:bound_to_different_user | :invalid_user_id_field, map()} | map(), Conn.t()} - def create_user(conn, user_identity_params, user_params, user_id_params \\ nil) do + def create_user(conn, identity_params, user_params, user_id_params \\ nil) do config = fetch_config(conn) - user_identity_params + identity_params |> Operations.create_user(user_params, user_id_params, config) |> case do - {:ok, user} -> {:ok, user, create_session(conn, user, user_identity_params, config)} + {:ok, user} -> {:ok, user, create_session(conn, user, identity_params, config)} {:error, error} -> {:error, error, conn} end end @@ -340,7 +340,7 @@ defmodule PowAssent.Plug do def change_user(conn, params \\ %{}, user_params \\ %{}, user_id_params \\ %{}) do config = fetch_config(conn) - Operations.user_identity_changeset(params, user_params, user_id_params, config) + Operations.identity_changeset(params, user_params, user_id_params, config) end @doc """ diff --git a/mix.exs b/mix.exs index d04cf8e..fa28b99 100644 --- a/mix.exs +++ b/mix.exs @@ -34,7 +34,7 @@ defmodule PowAssent.MixProject do {:pow, "~> 1.0.19"}, {:assent, "~> 0.1.2"}, - {:ecto, "~> 2.2 or ~> 3.0"}, + {:ecto, "~> 3.4.2 or ~> 3.5"}, {:phoenix, ">= 1.3.0 and < 1.6.0"}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0"}, {:plug, ">= 1.5.0 and < 2.0.0", optional: true}, @@ -45,8 +45,8 @@ defmodule PowAssent.MixProject do {:ex_doc, "~> 0.21.0", only: :dev}, - {:ecto_sql, "~> 3.1", only: :test}, - {:postgrex, "~> 0.14.0", only: :test}, + {:ecto_sql, "~> 3.4", only: :test}, + {:postgrex, "~> 0.15.0", only: :test}, {:bypass, "~> 1.0.0", only: :test} ] end diff --git a/mix.lock b/mix.lock index c466294..c1150b6 100644 --- a/mix.lock +++ b/mix.lock @@ -9,8 +9,8 @@ "db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"}, "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"}, "earmark": {:hex, :earmark, "1.4.4", "4821b8d05cda507189d51f2caeef370cf1e18ca5d7dfb7d31e9cafe6688106a4", [:mix], [], "hexpm", "1f93aba7340574847c0f609da787f0d79efcab51b044bb6e242cae5aca9d264d"}, - "ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "fd0f11a8454e490ae11b6f69aa1ed9e0352641242d014cc3d2f420d7743f6966"}, - "ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cdb6a76a6d88b256fd1bfc37da66cfc96f0935591c5114c1123b04c150828b69"}, + "ecto": {:hex, :ecto, "3.4.4", "a2c881e80dc756d648197ae0d936216c0308370332c5e77a2325a10293eef845", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4bd3ad62abc3b21fb629f0f7a3dab23a192fca837d257dd08449fba7373561"}, + "ecto_sql": {:hex, :ecto_sql, "3.4.4", "d28bac2d420f708993baed522054870086fd45016a9d09bb2cd521b9c48d32ea", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "edb49af715dd72f213b66adfd0f668a43c17ed510b5d9ac7528569b23af57fe8"}, "ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"}, "jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"}, "makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49736fe5b66a08d8575bf5321d716bac5da20c8e6b97714fec2bcd6febcfa1f8"}, @@ -25,7 +25,7 @@ "plug": {:hex, :plug, "1.10.1", "c56a6d9da7042d581159bcbaef873ba9d87f15dce85420b0d287bca19f40f9bd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "b5cd52259817eb8a31f2454912ba1cff4990bca7811918878091cb2ab9e52cb8"}, "plug_cowboy": {:hex, :plug_cowboy, "2.2.1", "fcf58aa33227a4322a050e4783ee99c63c031a2e7f9a2eb7340d55505e17f30f", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3b43de24460d87c0971887286e7a20d40462e48eb7235954681a20cee25ddeb6"}, "plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"}, - "postgrex": {:hex, :postgrex, "0.14.3", "5754dee2fdf6e9e508cbf49ab138df964278700b764177e8f3871e658b345a1e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "0ec1f09319f29b4dfc2d0e08c776834d219faae0da3536f3d9460f6793e6af1f"}, + "postgrex": {:hex, :postgrex, "0.15.4", "5d691c25fc79070705a2ff0e35ce0822b86a0ee3c6fdb7a4fb354623955e1aed", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "306515b9d975fcb2478dc337a1d27dc3bf8af7cd71017c333fe9db3a3d211b0a"}, "pow": {:hex, :pow, "1.0.20", "b99993811af5233681bfc521e81ca706d25a56f2be54bad6424db327ce840ab9", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.3.0 and < 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "4b6bd271399ccb353abbdbdc316199fe7fd7ae36bbf47059d53e366831c34fc8"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"}, "telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm", "4738382e36a0a9a2b6e25d67c960e40e1a2c95560b9f936d8e29de8cd858480f"}, diff --git a/test/mix/tasks/ecto/pow_assent.ecto.gen.schema_test.exs b/test/mix/tasks/ecto/pow_assent.ecto.gen.schema_test.exs index e1d4a75..c97463e 100644 --- a/test/mix/tasks/ecto/pow_assent.ecto.gen.schema_test.exs +++ b/test/mix/tasks/ecto/pow_assent.ecto.gen.schema_test.exs @@ -4,7 +4,7 @@ defmodule Mix.Tasks.PowAssent.Ecto.Gen.SchemaTest do alias Mix.Tasks.PowAssent.Ecto.Gen.Schema @tmp_path Path.join(["tmp", inspect(Schema)]) - @expected_file Path.join(["lib", "pow_assent", "user_identities", "user_identity.ex"]) + @expected_file Path.join(["lib", "pow_assent", "users", "user_identity.ex"]) setup do File.rm_rf!(@tmp_path) @@ -21,7 +21,7 @@ defmodule Mix.Tasks.PowAssent.Ecto.Gen.SchemaTest do content = File.read!(@expected_file) - assert content =~ "defmodule PowAssent.UserIdentities.UserIdentity do" + assert content =~ "defmodule PowAssent.Users.UserIdentity do" assert content =~ "user: PowAssent.Users.User" assert content =~ "timestamps()" end) @@ -46,7 +46,7 @@ defmodule Mix.Tasks.PowAssent.Ecto.Gen.SchemaTest do File.cd!(@tmp_path, fn -> Schema.run([]) - assert_raise Mix.Error, "schema file can't be created, there is already a schema file in lib/pow_assent/user_identities/user_identity.ex.", fn -> + assert_raise Mix.Error, "schema file can't be created, there is already a schema file in lib/pow_assent/users/user_identity.ex.", fn -> Schema.run([]) end end) diff --git a/test/mix/tasks/pow_assent.install_test.exs b/test/mix/tasks/pow_assent.install_test.exs index e5f4667..9d1dd88 100644 --- a/test/mix/tasks/pow_assent.install_test.exs +++ b/test/mix/tasks/pow_assent.install_test.exs @@ -16,7 +16,7 @@ defmodule Mix.Tasks.PowAssent.InstallTest do File.cd!(@tmp_path, fn -> Install.run([]) - assert File.ls!("lib/pow_assent/user_identities") == ["user_identity.ex"] + assert File.ls!("lib/pow_assent/users") == ["user_identity.ex"] end) end @@ -51,19 +51,19 @@ defmodule Mix.Tasks.PowAssent.InstallTest do test "raises error on invalid schema name or table" do File.cd!(@tmp_path, fn -> assert_raise Mix.Error, ~r/Invalid arguments/, fn -> - Install.run(~w(UserIdentities.UserIdentity)) + Install.run(~w(Users.UserIdentity)) end - assert_raise Mix.Error, ~r/Expected the schema argument, "useridentities.useridentity", to be a valid module name/, fn -> - Install.run(~w(useridentities.useridentity useridentities)) + assert_raise Mix.Error, ~r/Expected the schema argument, "users.useridentity", to be a valid module name/, fn -> + Install.run(~w(users.useridentity useridentities)) end assert_raise Mix.Error, ~r/Expected the plural argument, "UserIdentities", to be all lowercase using snake_case convention/, fn -> - Install.run(~w(UserIdentities.UserIdentity UserIdentities)) + Install.run(~w(Users.UserIdentity UserIdentities)) end assert_raise Mix.Error, ~r/Expected the plural argument, "useridentities:", to be all lowercase using snake_case convention/, fn -> - Install.run(~w(UserIdentities.UserIdentity useridentities:)) + Install.run(~w(Users.UserIdentity useridentities:)) end end) end diff --git a/test/pow_assent/ecto/identities/context_test.exs b/test/pow_assent/ecto/identities/context_test.exs new file mode 100644 index 0000000..5754b9c --- /dev/null +++ b/test/pow_assent/ecto/identities/context_test.exs @@ -0,0 +1,208 @@ +defmodule PowAssent.Test.Ecto.Users.UserWithoutIdentities do + @moduledoc false + use Ecto.Schema + use Pow.Ecto.Schema + + schema "users" do + pow_user_fields() + timestamps() + end +end + +defmodule PowAssent.Test.Ecto.Users.UserWithAccessTokenIdentities do + @moduledoc false + use Ecto.Schema + use Pow.Ecto.Schema + use PowAssent.Ecto.Schema + + schema "users" do + has_many :identities, PowAssent.Test.WithAccessToken.Users.UserIdentity, foreign_key: :user_id, on_delete: :delete_all + + pow_user_fields() + timestamps() + end +end + +defmodule PowAssent.Ecto.Identities.ContextTest do + use PowAssent.Test.Ecto.TestCase + doctest PowAssent.Ecto.Identities.Context + + alias Ecto.Changeset + alias PowAssent.Ecto.Identities.Context + alias PowAssent.Test.Ecto.{Repo, Users.User, Users.UserWithoutIdentities, Users.UserWithAccessTokenIdentities, Users.User} + + @config [repo: Repo, user: User] + @identity_params %{provider: "test_provider", uid: "1"} + + describe "get_user_by_provider_uid/2" do + setup do + user = + %User{} + |> Changeset.change(email: "test@example.com", identities: [@identity_params]) + |> Repo.insert!() + + user = Repo.get!(user.__struct__, user.id) + + {:ok, user: user} + end + + test "retrieves", %{user: user} do + assert Context.get_user_by_provider_uid("test_provider", "1", @config) == user + assert Context.get_user_by_provider_uid("test_provider", 1, @config) == user + + refute Context.get_user_by_provider_uid("test_provider", "2", @config) + + Repo.delete!(user) + refute Context.get_user_by_provider_uid("test_provider", "1", @config) + end + + test "requires user has :identities assoc" do + assert_raise PowAssent.Config.ConfigError, "The `:user` configuration option doesn't have a `:identities` association.", fn -> + Context.get_user_by_provider_uid("test_provider", "2", repo: Repo, user: UserWithoutIdentities) + end + end + end + + @config_with_access_token [repo: Repo, user: UserWithAccessTokenIdentities] + @identity_params_with_access_token Map.put(@identity_params, :token, %{access_token: "access_token"}) + + describe "upsert/3" do + setup do + user = + %UserWithAccessTokenIdentities{} + |> Changeset.change(email: "test@example.com") + |> Repo.insert!() + + {:ok, user: user} + end + + test "inserts with valid params", %{user: user} do + assert {:ok, identity} = Context.upsert(user, @identity_params_with_access_token, @config_with_access_token) + assert identity.provider == "test_provider" + assert identity.uid == "1" + end + + test "inserts with integer uid param", %{user: user} do + params = Map.put(@identity_params_with_access_token, :uid, 1) + + assert {:ok, identity} = Context.upsert(user, params, @config_with_access_token) + assert identity.uid == "1" + end + + test "updates with valid params", %{user: user} do + assert {:ok, prev_identity} = Context.upsert(user, @identity_params_with_access_token, @config_with_access_token) + assert prev_identity.access_token + refute prev_identity.refresh_token + + params = Map.put(@identity_params_with_access_token, :token, %{access_token: "changed_access_token", refresh_token: "refresh_token"}) + + assert {:ok, identity} = Context.upsert(user, params, @config_with_access_token) + assert prev_identity.id == identity.id + assert identity.provider == "test_provider" + assert identity.uid == "1" + assert identity.access_token == "changed_access_token" + assert identity.refresh_token == "refresh_token" + + params = Map.put(@identity_params_with_access_token, :uid, 1) + + assert {:ok, identity} = Context.upsert(user, params, @config_with_access_token) + assert identity.uid == "1" + assert identity.access_token == "access_token" + end + + test "when other user has provider uid", %{user: user} do + _second_user = + %UserWithAccessTokenIdentities{} + |> Changeset.change(email: "test-2@example.com") + |> Changeset.cast(%{identities: [@identity_params_with_access_token]}, []) + |> Changeset.cast_assoc(:identities) + |> Repo.insert!() + + assert {:error, {:bound_to_different_user, _changeset}} = Context.upsert(user, @identity_params_with_access_token, @config_with_access_token) + end + end + + describe "create_user/4" do + @user_params %{name: "John Doe", email: "test@example.com"} + + test "with valid params" do + assert {:ok, user} = Context.create_user(@identity_params, @user_params, nil, @config) + user = Repo.preload(user, :identities, force: true) + + assert user.name == "John Doe" + assert user.email == "test@example.com" + assert [identity] = user.identities + assert identity.provider == "test_provider" + assert identity.uid == "1" + end + + test "with valid params with access token" do + assert {:ok, user} = Context.create_user(@identity_params_with_access_token, @user_params, nil, @config_with_access_token) + user = Repo.preload(user, :identities, force: true) + + assert [identity] = user.identities + assert identity.provider == "test_provider" + assert identity.uid == "1" + assert identity.access_token == "access_token" + end + + test "with integer uid param" do + params = Map.put(@identity_params, "uid", 1) + + assert {:ok, user} = Context.create_user(params, @user_params, nil, @config) + user = Repo.preload(user, :identities, force: true) + + assert [identity] = user.identities + assert identity.uid == "1" + end + + test "when other user has provider uid" do + _second_user = + %User{} + |> Changeset.change(email: "test-2@example.com", identities: [@identity_params]) + |> Repo.insert!() + + assert {:error, {:bound_to_different_user, _changeset}} = Context.create_user(@identity_params, @user_params, nil, @config) + end + + test "when user id field is missing" do + assert {:error, {:invalid_user_id_field, _changeset}} = Context.create_user(@identity_params, Map.delete(@user_params, :email), nil, @config) + end + end + + describe "delete/3" do + setup do + user = + %User{} + |> Changeset.change(email: "test@example.com", identities: [@identity_params, %{provider: "test_provider", uid: "2"}]) + |> Repo.insert!() + + {:ok, user: user} + end + + test "requires password hash or other identity", %{user: user} do + assert {:error, {:no_password, _changeset}} = Context.delete(user, "test_provider", @config) + + Repo.insert!(Ecto.build_assoc(user, :identities, %{provider: "another_provider", uid: "1"})) + assert {:ok, {2, nil}} = Context.delete(user, "test_provider", @config) + + user = %{user | password_hash: "password"} + assert {:ok, {1, nil}} = Context.delete(user, "another_provider", @config) + end + end + + test "all/2 retrieves" do + user = + %User{} + |> Changeset.change(email: "test@example.com", identities: [%{provider: "test_provider", uid: "1"}, %{provider: "other_provider", uid: "1"}]) + |> Repo.insert!() + + second_user = + %User{} + |> Changeset.change(email: "test-2@example.com", identities: [%{provider: "test_provider", uid: "2"}]) + |> Repo.insert!() + + assert [%{provider: "test_provider", uid: "2"}] = Context.all(second_user, @config) + assert [%{provider: "test_provider", uid: "1"}, %{provider: "other_provider", uid: "1"}] = Context.all(user, @config) + end +end diff --git a/test/pow_assent/ecto/user_identities/schema_test.exs b/test/pow_assent/ecto/identities/schema_test.exs similarity index 79% rename from test/pow_assent/ecto/user_identities/schema_test.exs rename to test/pow_assent/ecto/identities/schema_test.exs index 213b1b0..9b3f5f6 100644 --- a/test/pow_assent/ecto/user_identities/schema_test.exs +++ b/test/pow_assent/ecto/identities/schema_test.exs @@ -1,17 +1,17 @@ module_raised_with = try do - defmodule PowAssent.Test.UserIdentities.InvalidUserIdentity do - use PowAssent.Ecto.UserIdentities.Schema + defmodule PowAssent.Test.Users.InvalidUserIdentity do + use PowAssent.Ecto.Identities.Schema end rescue e in PowAssent.Config.ConfigError -> e.message end -defmodule PowAssent.Ecto.UserIdentities.SchemaTest do +defmodule PowAssent.Ecto.Identities.SchemaTest do use PowAssent.Test.Ecto.TestCase - doctest PowAssent.Ecto.UserIdentities.Schema + doctest PowAssent.Ecto.Identities.Schema - alias PowAssent.Test.Ecto.{Repo, UserIdentities.UserIdentity, Users.User} + alias PowAssent.Test.Ecto.{Repo, Users.UserIdentity, Users.User} test "raises error during compile when there's no `:user` configuration" do assert unquote(module_raised_with) =~ "No :user configuration option found for user identity schema module." @@ -61,7 +61,7 @@ defmodule PowAssent.Ecto.UserIdentities.SchemaTest do |> UserIdentity.changeset(@valid_params) |> Repo.insert() - assert changeset.errors[:uid_provider] == {"has already been taken", [constraint: :unique, constraint_name: "user_identities_uid_provider_index"]} + assert changeset.errors[:uid] == {"has already been taken", [constraint: :unique, constraint_name: "user_identities_uid_provider_index"]} end end end diff --git a/test/pow_assent/ecto/schema_test.exs b/test/pow_assent/ecto/schema_test.exs index e2b5d03..99e0a5d 100644 --- a/test/pow_assent/ecto/schema_test.exs +++ b/test/pow_assent/ecto/schema_test.exs @@ -22,25 +22,27 @@ defmodule PowAssent.Ecto.SchemaTest do test "user_schema/1" do user = %User{} - assert Map.has_key?(user, :user_identities) - assert %{on_delete: :delete_all} = User.__schema__(:association, :user_identities) + assert Map.has_key?(user, :identities) + assert %{on_delete: on_delete, queryable: queryable} = User.__schema__(:association, :identities) + assert on_delete == :delete_all + assert queryable == PowAssent.Test.Ecto.Users.UserIdentity end - @user_identity %{ + @identity %{ provider: "test_provider", uid: "1" } - describe "user_identity_changeset/4" do + describe "identity_changeset/4" do test "validates required" do - changeset = User.user_identity_changeset(%User{}, %{}, %{}, nil) + changeset = User.identity_changeset(%User{}, %{}, %{}, nil) - assert [user_identity] = changeset.changes.user_identities - assert user_identity.errors[:uid] == {"can't be blank", [validation: :required]} - assert user_identity.errors[:provider] == {"can't be blank", [validation: :required]} + assert [identity] = changeset.changes.identities + assert identity.errors[:uid] == {"can't be blank", [validation: :required]} + assert identity.errors[:provider] == {"can't be blank", [validation: :required]} assert changeset.errors[:name] == {"can't be blank", [validation: :required]} - changeset = User.user_identity_changeset(%User{}, @user_identity, %{email: "test@example.com", name: "John Doe"}, nil) + changeset = User.identity_changeset(%User{}, @identity, %{email: "test@example.com", name: "John Doe"}, nil) assert changeset.valid? assert changeset.changes[:name] == "John Doe" end @@ -48,21 +50,21 @@ defmodule PowAssent.Ecto.SchemaTest do test "validates unique" do {:ok, _user} = %User{email: "test@example.com"} - |> Ecto.Changeset.cast(%{"user_identities" => [@user_identity]}, []) - |> Ecto.Changeset.cast_assoc(:user_identities) + |> Ecto.Changeset.cast(%{"identities" => [@identity]}, []) + |> Ecto.Changeset.cast_assoc(:identities) |> Repo.insert() assert {:error, changeset} = %User{email: "john.doe@example.com", name: "John Doe"} - |> User.user_identity_changeset(@user_identity, %{}, nil) + |> User.identity_changeset(@identity, %{}, nil) |> Repo.insert() - assert [user_identity] = changeset.changes.user_identities - assert user_identity.errors[:uid_provider] == {"has already been taken", [constraint: :unique, constraint_name: "user_identities_uid_provider_index"]} + assert [identity] = changeset.changes.identities + assert identity.errors[:uid] == {"has already been taken", [constraint: :unique, constraint_name: "user_identities_uid_provider_index"]} end test "uses case insensitive value for user id" do - changeset = User.user_identity_changeset(%User{}, @user_identity, %{email: "Test@EXAMPLE.com", name: "John Doe"}, nil) + changeset = User.identity_changeset(%User{}, @identity, %{email: "Test@EXAMPLE.com", name: "John Doe"}, nil) assert changeset.valid? assert Ecto.Changeset.get_field(changeset, :email) == "test@example.com" end @@ -77,7 +79,7 @@ defmodule PowAssent.Ecto.SchemaTest do use PowAssent.Ecto.Schema schema "users" do - has_many :user_identities, PowAssent.Test.Ecto.UserIdentities.UserIdentity, foreign_key: :user_id, on_delete: :delete_all + has_many :identities, PowAssent.Test.Ecto.Users.UserIdentity, foreign_key: :user_id, on_delete: :delete_all field :email, :string @@ -86,39 +88,39 @@ defmodule PowAssent.Ecto.SchemaTest do timestamps() end - def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do + def identity_changeset(user_or_changeset, identity, attrs, user_id_attrs) do user_or_changeset |> Ecto.Changeset.cast(attrs, [:email]) - |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs) + |> pow_assent_identity_changeset(identity, attrs, user_id_attrs) end end - describe "user_identity_changeset/4 with PowEmailConfirmation" do + describe "identity_changeset/4 with PowEmailConfirmation" do test "sets :email_confirmed_at when provided as attrs" do provider_params = %{email: "test@example.com", email_verified: true, name: "John Doe"} - changeset = User.user_identity_changeset(%User{}, @user_identity, provider_params, nil) + changeset = User.identity_changeset(%User{}, @identity, provider_params, nil) assert changeset.changes[:email] refute changeset.changes[:email_confirmed_at] refute changeset.changes[:email_confirmation_token] - changeset = UserConfirmEmail.user_identity_changeset(%UserConfirmEmail{}, @user_identity, provider_params, %{email: "foo@example.com"}) + changeset = UserConfirmEmail.identity_changeset(%UserConfirmEmail{}, @identity, provider_params, %{email: "foo@example.com"}) assert changeset.changes[:email] refute changeset.changes[:email_confirmed_at] assert changeset.changes[:email_confirmation_token] - changeset = UserConfirmEmail.user_identity_changeset(%UserConfirmEmail{}, @user_identity, provider_params, %{email: "test@example.com"}) + changeset = UserConfirmEmail.identity_changeset(%UserConfirmEmail{}, @identity, provider_params, %{email: "test@example.com"}) assert changeset.changes[:email] assert changeset.changes[:email_confirmed_at] refute changeset.changes[:email_confirmation_token] - changeset = UserConfirmEmail.user_identity_changeset(%UserConfirmEmail{}, @user_identity, provider_params, nil) + changeset = UserConfirmEmail.identity_changeset(%UserConfirmEmail{}, @identity, provider_params, nil) assert changeset.changes[:email] assert changeset.changes[:name] == "John Doe" assert changeset.changes[:email_confirmed_at] refute changeset.changes[:email_confirmation_token] - changeset = UserConfirmEmail.user_identity_changeset(%UserConfirmEmail{}, @user_identity, Map.delete(provider_params, :email_verified), nil) + changeset = UserConfirmEmail.identity_changeset(%UserConfirmEmail{}, @identity, Map.delete(provider_params, :email_verified), nil) assert changeset.changes[:email] assert changeset.changes[:name] == "John Doe" refute changeset.changes[:email_confirmed_at] @@ -128,12 +130,12 @@ defmodule PowAssent.Ecto.SchemaTest do test "sets :email_confirmed_at when provided as attrs and :email is not user id field" do provider_params = %{email: "test@example.com", email_verified: true} - changeset = UsernameUserWithEmail.user_identity_changeset(%UsernameUserWithEmail{}, @user_identity, Map.delete(provider_params, :email_verified), %{username: "john.doe"}) + changeset = UsernameUserWithEmail.identity_changeset(%UsernameUserWithEmail{}, @identity, Map.delete(provider_params, :email_verified), %{username: "john.doe"}) assert changeset.changes[:email] refute changeset.changes[:email_confirmed_at] assert changeset.changes[:email_confirmation_token] - changeset = UsernameUserWithEmail.user_identity_changeset(%UsernameUserWithEmail{}, @user_identity, provider_params, %{username: "john.doe"}) + changeset = UsernameUserWithEmail.identity_changeset(%UsernameUserWithEmail{}, @identity, provider_params, %{username: "john.doe"}) assert changeset.changes[:username] assert changeset.changes[:email] assert changeset.changes[:email_confirmed_at] @@ -141,15 +143,15 @@ defmodule PowAssent.Ecto.SchemaTest do end end - describe "user_identity_changeset/4 with PowInvitation" do + describe "identity_changeset/4 with PowInvitation" do test "sets :invitation_accepted_at when is invited user" do - changeset = InvitationUser.user_identity_changeset(%InvitationUser{}, @user_identity, %{}, %{email: "test@example.com"}) + changeset = InvitationUser.identity_changeset(%InvitationUser{}, @identity, %{}, %{email: "test@example.com"}) refute changeset.changes[:invitation_accepted_at] - changeset = InvitationUser.user_identity_changeset(%InvitationUser{invitation_token: "token", invitation_accepted_at: DateTime.utc_now()}, @user_identity, %{}, %{email: "test@example.com"}) + changeset = InvitationUser.identity_changeset(%InvitationUser{invitation_token: "token", invitation_accepted_at: DateTime.utc_now()}, @identity, %{}, %{email: "test@example.com"}) refute changeset.changes[:invitation_accepted_at] - changeset = InvitationUser.user_identity_changeset(%InvitationUser{invitation_token: "token"}, @user_identity, %{}, %{email: "test@example.com"}) + changeset = InvitationUser.identity_changeset(%InvitationUser{invitation_token: "token"}, @identity, %{}, %{email: "test@example.com"}) assert changeset.changes[:invitation_accepted_at] end end @@ -161,8 +163,8 @@ defmodule PowAssent.Ecto.SchemaTest do use PowAssent.Ecto.Schema schema "users" do - has_many :user_identities, - MyApp.UserIdentities.UserIdentity, + has_many :identities, + MyApp.Users.UserIdentity, on_delete: :nothing pow_user_fields() @@ -174,14 +176,17 @@ defmodule PowAssent.Ecto.SchemaTest do test "schema/2 with overridden fields" do user = %OverrideAssocUser{} - assert Map.has_key?(user, :user_identities) - assert %{on_delete: :nothing} = OverrideAssocUser.__schema__(:association, :user_identities) + assert Map.has_key?(user, :identities) + assert %{on_delete: on_delete, queryable: queryable} = OverrideAssocUser.__schema__(:association, :identities) + assert on_delete == :nothing + assert queryable == MyApp.Users.UserIdentity end test "schema/2 with no context user module name" do user = %PowAssent.NoContextUser{} - assert Map.has_key?(user, :user_identities) - assert %{queryable: PowAssent.UserIdentities.UserIdentity} = PowAssent.NoContextUser.__schema__(:association, :user_identities) + assert Map.has_key?(user, :identities) + assert %{queryable: queryable} = PowAssent.NoContextUser.__schema__(:association, :identities) + assert queryable == PowAssent.UserIdentity end end diff --git a/test/pow_assent/ecto/user_identities/context_test.exs b/test/pow_assent/ecto/user_identities/context_test.exs deleted file mode 100644 index 54329ca..0000000 --- a/test/pow_assent/ecto/user_identities/context_test.exs +++ /dev/null @@ -1,208 +0,0 @@ -defmodule PowAssent.Test.Ecto.Users.UserWithoutUserIdentities do - @moduledoc false - use Ecto.Schema - use Pow.Ecto.Schema - - schema "users" do - pow_user_fields() - timestamps() - end -end - -defmodule PowAssent.Test.Ecto.Users.UserWithAccessTokenUserIdentities do - @moduledoc false - use Ecto.Schema - use Pow.Ecto.Schema - use PowAssent.Ecto.Schema - - schema "users" do - has_many :user_identities, PowAssent.Test.WithAccessToken.UserIdentities.UserIdentity, foreign_key: :user_id, on_delete: :delete_all - - pow_user_fields() - timestamps() - end -end - -defmodule PowAssent.Ecto.UserIdentities.ContextTest do - use PowAssent.Test.Ecto.TestCase - doctest PowAssent.Ecto.UserIdentities.Context - - alias Ecto.Changeset - alias PowAssent.Ecto.UserIdentities.Context - alias PowAssent.Test.Ecto.{Repo, Users.User, Users.UserWithoutUserIdentities, Users.UserWithAccessTokenUserIdentities, Users.User} - - @config [repo: Repo, user: User] - @user_identity_params %{provider: "test_provider", uid: "1"} - - describe "get_user_by_provider_uid/2" do - setup do - user = - %User{} - |> Changeset.change(email: "test@example.com", user_identities: [@user_identity_params]) - |> Repo.insert!() - - user = Repo.get!(user.__struct__, user.id) - - {:ok, user: user} - end - - test "retrieves", %{user: user} do - assert Context.get_user_by_provider_uid("test_provider", "1", @config) == user - assert Context.get_user_by_provider_uid("test_provider", 1, @config) == user - - refute Context.get_user_by_provider_uid("test_provider", "2", @config) - - Repo.delete!(user) - refute Context.get_user_by_provider_uid("test_provider", "1", @config) - end - - test "requires user has :user_identities assoc" do - assert_raise PowAssent.Config.ConfigError, "The `:user` configuration option doesn't have a `:user_identities` association.", fn -> - Context.get_user_by_provider_uid("test_provider", "2", repo: Repo, user: UserWithoutUserIdentities) - end - end - end - - @config_with_access_token [repo: Repo, user: UserWithAccessTokenUserIdentities] - @user_identity_params_with_access_token Map.put(@user_identity_params, :token, %{access_token: "access_token"}) - - describe "upsert/3" do - setup do - user = - %UserWithAccessTokenUserIdentities{} - |> Changeset.change(email: "test@example.com") - |> Repo.insert!() - - {:ok, user: user} - end - - test "inserts with valid params", %{user: user} do - assert {:ok, user_identity} = Context.upsert(user, @user_identity_params_with_access_token, @config_with_access_token) - assert user_identity.provider == "test_provider" - assert user_identity.uid == "1" - end - - test "inserts with integer uid param", %{user: user} do - params = Map.put(@user_identity_params_with_access_token, :uid, 1) - - assert {:ok, user_identity} = Context.upsert(user, params, @config_with_access_token) - assert user_identity.uid == "1" - end - - test "updates with valid params", %{user: user} do - assert {:ok, prev_user_identity} = Context.upsert(user, @user_identity_params_with_access_token, @config_with_access_token) - assert prev_user_identity.access_token - refute prev_user_identity.refresh_token - - params = Map.put(@user_identity_params_with_access_token, :token, %{access_token: "changed_access_token", refresh_token: "refresh_token"}) - - assert {:ok, user_identity} = Context.upsert(user, params, @config_with_access_token) - assert prev_user_identity.id == user_identity.id - assert user_identity.provider == "test_provider" - assert user_identity.uid == "1" - assert user_identity.access_token == "changed_access_token" - assert user_identity.refresh_token == "refresh_token" - - params = Map.put(@user_identity_params_with_access_token, :uid, 1) - - assert {:ok, user_identity} = Context.upsert(user, params, @config_with_access_token) - assert user_identity.uid == "1" - assert user_identity.access_token == "access_token" - end - - test "when other user has provider uid", %{user: user} do - _second_user = - %UserWithAccessTokenUserIdentities{} - |> Changeset.change(email: "test-2@example.com") - |> Changeset.cast(%{user_identities: [@user_identity_params_with_access_token]}, []) - |> Changeset.cast_assoc(:user_identities) - |> Repo.insert!() - - assert {:error, {:bound_to_different_user, _changeset}} = Context.upsert(user, @user_identity_params_with_access_token, @config_with_access_token) - end - end - - describe "create_user/4" do - @user_params %{name: "John Doe", email: "test@example.com"} - - test "with valid params" do - assert {:ok, user} = Context.create_user(@user_identity_params, @user_params, nil, @config) - user = Repo.preload(user, :user_identities, force: true) - - assert user.name == "John Doe" - assert user.email == "test@example.com" - assert [user_identity] = user.user_identities - assert user_identity.provider == "test_provider" - assert user_identity.uid == "1" - end - - test "with valid params with access token" do - assert {:ok, user} = Context.create_user(@user_identity_params_with_access_token, @user_params, nil, @config_with_access_token) - user = Repo.preload(user, :user_identities, force: true) - - assert [user_identity] = user.user_identities - assert user_identity.provider == "test_provider" - assert user_identity.uid == "1" - assert user_identity.access_token == "access_token" - end - - test "with integer uid param" do - params = Map.put(@user_identity_params, "uid", 1) - - assert {:ok, user} = Context.create_user(params, @user_params, nil, @config) - user = Repo.preload(user, :user_identities, force: true) - - assert [user_identity] = user.user_identities - assert user_identity.uid == "1" - end - - test "when other user has provider uid" do - _second_user = - %User{} - |> Changeset.change(email: "test-2@example.com", user_identities: [@user_identity_params]) - |> Repo.insert!() - - assert {:error, {:bound_to_different_user, _changeset}} = Context.create_user(@user_identity_params, @user_params, nil, @config) - end - - test "when user id field is missing" do - assert {:error, {:invalid_user_id_field, _changeset}} = Context.create_user(@user_identity_params, Map.delete(@user_params, :email), nil, @config) - end - end - - describe "delete/3" do - setup do - user = - %User{} - |> Changeset.change(email: "test@example.com", user_identities: [@user_identity_params, %{provider: "test_provider", uid: "2"}]) - |> Repo.insert!() - - {:ok, user: user} - end - - test "requires password hash or other identity", %{user: user} do - assert {:error, {:no_password, _changeset}} = Context.delete(user, "test_provider", @config) - - Repo.insert!(Ecto.build_assoc(user, :user_identities, %{provider: "another_provider", uid: "1"})) - assert {:ok, {2, nil}} = Context.delete(user, "test_provider", @config) - - user = %{user | password_hash: "password"} - assert {:ok, {1, nil}} = Context.delete(user, "another_provider", @config) - end - end - - test "all/2 retrieves" do - user = - %User{} - |> Changeset.change(email: "test@example.com", user_identities: [%{provider: "test_provider", uid: "1"}, %{provider: "other_provider", uid: "1"}]) - |> Repo.insert!() - - second_user = - %User{} - |> Changeset.change(email: "test-2@example.com", user_identities: [%{provider: "test_provider", uid: "2"}]) - |> Repo.insert!() - - assert [%{provider: "test_provider", uid: "2"}] = Context.all(second_user, @config) - assert [%{provider: "test_provider", uid: "1"}, %{provider: "other_provider", uid: "1"}] = Context.all(user, @config) - end -end diff --git a/test/pow_assent/phoenix/controllers/authorization_controller_test.exs b/test/pow_assent/phoenix/controllers/authorization_controller_test.exs index e27486f..8764942 100644 --- a/test/pow_assent/phoenix/controllers/authorization_controller_test.exs +++ b/test/pow_assent/phoenix/controllers/authorization_controller_test.exs @@ -161,9 +161,9 @@ defmodule PowAssent.Phoenix.AuthorizationControllerTest do assert redirected_to(conn) == "/registration_created" assert user = Pow.Plug.current_user(conn) - assert [user_identity] = user.user_identities - assert user_identity.uid == "new_user" - assert user_identity.provider == "test_provider" + assert [identity] = user.identities + assert identity.uid == "new_user" + assert identity.provider == "test_provider" refute conn.private[:plug_session]["pow_assent_session"] refute get_pow_assent_session(conn, :session_params) end @@ -186,8 +186,8 @@ defmodule PowAssent.Phoenix.AuthorizationControllerTest do assert redirected_to(conn) == Routes.pow_assent_registration_path(conn, :add_user_id, "test_provider") assert conn.private[:plug_session]["pow_assent_session"] - assert %{"test_provider" => %{user_identity: user_identity, user: user}} = get_pow_assent_session(conn, :callback_params) - assert user_identity == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} + assert %{"test_provider" => %{identity: identity, user: user}} = get_pow_assent_session(conn, :callback_params) + assert identity == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} assert user == %{"name" => "John Doe", "email" => ""} refute get_pow_assent_session(conn, :session_params) assert get_pow_assent_session(conn, :callback_params) @@ -201,8 +201,8 @@ defmodule PowAssent.Phoenix.AuthorizationControllerTest do assert redirected_to(conn) == Routes.pow_assent_registration_path(conn, :add_user_id, "test_provider") assert conn.private[:plug_session]["pow_assent_session"] - assert %{"test_provider" => %{user_identity: user_identity, user: user}} = get_pow_assent_session(conn, :callback_params) - assert user_identity == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} + assert %{"test_provider" => %{identity: identity, user: user}} = get_pow_assent_session(conn, :callback_params) + assert identity == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} assert user == %{"name" => "John Doe", "email" => "taken@example.com"} refute get_pow_assent_session(conn, :session_params) assert get_pow_assent_session(conn, :callback_params) @@ -242,9 +242,9 @@ defmodule PowAssent.Phoenix.AuthorizationControllerTest do assert redirected_to(conn) == "/registration_created" assert user = Pow.Plug.current_user(conn) - assert [user_identity] = user.user_identities - assert user_identity.uid == "new_user" - assert user_identity.provider == "test_provider" + assert [identity] = user.identities + assert identity.uid == "new_user" + assert identity.provider == "test_provider" refute conn.private[:plug_session]["pow_assent_session"] refute get_pow_assent_session(conn, :session_params) end @@ -309,8 +309,8 @@ defmodule PowAssent.Phoenix.AuthorizationControllerTest do assert redirected_to(conn) == Routes.pow_assent_registration_path(conn, :add_user_id, "test_provider") assert conn.private[:plug_session]["pow_assent_session"] - assert %{"test_provider" => %{user_identity: user_identity, user: user}} = get_pow_assent_session(conn, :callback_params) - assert user_identity == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} + assert %{"test_provider" => %{identity: identity, user: user}} = get_pow_assent_session(conn, :callback_params) + assert identity == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} assert user == %{"name" => "John Doe", "email" => "taken@example.com", "email_verified" => true} refute get_pow_assent_session(conn, :session_params) assert get_pow_assent_session(conn, :callback_params) @@ -406,8 +406,8 @@ defmodule PowAssent.Phoenix.AuthorizationControllerTest do refute conn.private[:plug_session]["pow_assent_session"] refute get_pow_assent_session(conn, :session_params) assert user = Pow.Plug.current_user(conn) - assert [user_identity] = user.user_identities - assert user_identity.access_token == "access_token" + assert [identity] = user.identities + assert identity.access_token == "access_token" end test "when identity exists updates identity", %{conn: conn, bypass: bypass} do diff --git a/test/pow_assent/phoenix/controllers/registration_controller_test.exs b/test/pow_assent/phoenix/controllers/registration_controller_test.exs index c35ff39..7ec9418 100644 --- a/test/pow_assent/phoenix/controllers/registration_controller_test.exs +++ b/test/pow_assent/phoenix/controllers/registration_controller_test.exs @@ -5,7 +5,7 @@ defmodule PowAssent.Phoenix.RegistrationControllerTest do @provider "test_provider" @token_params %{"access_token" => "access_token"} - @user_identity_params %{"provider" => @provider, "uid" => "new_user", "token" => @token_params} + @identity_params %{"provider" => @provider, "uid" => "new_user", "token" => @token_params} @user_params %{"name" => "John Doe"} setup %{conn: conn} do @@ -45,7 +45,7 @@ defmodule PowAssent.Phoenix.RegistrationControllerTest do end test "shows with changeset stored in session", %{conn: conn} do - {:error, {:invalid_user_id_field, changeset}} = PowAssent.Ecto.UserIdentities.Context.create_user(@user_identity_params, Map.put(@user_params, "email", "taken@example.com"), nil, repo: PowAssent.Test.RepoMock, user: PowAssent.Test.Ecto.Users.User) + {:error, {:invalid_user_id_field, changeset}} = PowAssent.Ecto.Identities.Context.create_user(@identity_params, Map.put(@user_params, "email", "taken@example.com"), nil, repo: PowAssent.Test.RepoMock, user: PowAssent.Test.Ecto.Users.User) conn = conn |> Conn.put_private(:pow_assent_session, %{changeset: changeset, callback_params: provider_params()}) @@ -100,7 +100,7 @@ defmodule PowAssent.Phoenix.RegistrationControllerTest do end test "with identity already bound to another user", %{conn: conn} do - params = provider_params(user_identity_params: %{"uid" => "identity_taken"}) + params = provider_params(identity_params: %{"uid" => "identity_taken"}) conn = conn |> Conn.put_private(:pow_assent_session, %{callback_params: params}) @@ -164,15 +164,15 @@ defmodule PowAssent.Phoenix.RegistrationControllerTest do assert redirected_to(conn) == "/registration_created" assert user = Pow.Plug.current_user(conn) - assert [user_identity] = user.user_identities - assert user_identity.access_token == "access_token" + assert [identity] = user.identities + assert identity.access_token == "access_token" end end defp provider_params(opts \\ []) do - user_identity_params = Map.merge(@user_identity_params, Keyword.get(opts, :user_identity_params, %{})) + identity_params = Map.merge(@identity_params, Keyword.get(opts, :identity_params, %{})) user_params = Map.merge(@user_params, Keyword.get(opts, :user_params, %{})) - %{@provider => %{user_identity: user_identity_params, user: user_params}} + %{@provider => %{identity: identity_params, user: user_params}} end end diff --git a/test/pow_assent/plug_test.exs b/test/pow_assent/plug_test.exs index a77444b..5740bc1 100644 --- a/test/pow_assent/plug_test.exs +++ b/test/pow_assent/plug_test.exs @@ -5,7 +5,7 @@ defmodule PowAssent.PlugTest do alias Plug.{Conn, ProcessStore, Session, Test} alias Pow.Plug.Session, as: PowSession alias PowAssent.Plug - alias PowAssent.Test.{Ecto.UserIdentities.UserIdentity, Ecto.Users.User, EtsCacheMock, RepoMock} + alias PowAssent.Test.{Ecto.Users.UserIdentity, Ecto.Users.User, EtsCacheMock, RepoMock} import PowAssent.Test.TestProvider, only: [expect_oauth2_flow: 2, put_oauth2_env: 1, put_oauth2_env: 2] @@ -72,16 +72,16 @@ defmodule PowAssent.PlugTest do assert params["redirect_uri"] == "https://example.com/" end) - assert {:ok, user_identity_params, user_params, _conn} = Plug.callback(conn, "test_provider", %{"code" => "access_token"}, "https://example.com/") - assert user_identity_params == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} + assert {:ok, identity_params, user_params, _conn} = Plug.callback(conn, "test_provider", %{"code" => "access_token"}, "https://example.com/") + assert identity_params == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} assert user_params == %{"name" => "John Doe", "email" => "test@example.com"} end test "returns user params with preferred username as username", %{conn: conn, bypass: bypass} do expect_oauth2_flow(bypass, user: %{preferred_username: "john.doe"}) - assert {:ok, user_identity_params, user_params, _conn} = Plug.callback(conn, "test_provider", %{"code" => "access_token"}, "https://example.com/") - assert user_identity_params == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} + assert {:ok, identity_params, user_params, _conn} = Plug.callback(conn, "test_provider", %{"code" => "access_token"}, "https://example.com/") + assert identity_params == %{"provider" => "test_provider", "uid" => "new_user", "token" => %{"access_token" => "access_token"}} assert user_params == %{"username" => "john.doe", "name" => "John Doe", "email" => "test@example.com"} end end @@ -124,16 +124,16 @@ defmodule PowAssent.PlugTest do end test "creates user identity", %{conn: conn} do - assert {:ok, user_identity, conn} = Plug.upsert_identity(conn, @new_identity_params) + assert {:ok, identity, conn} = Plug.upsert_identity(conn, @new_identity_params) - assert user_identity.id == :inserted + assert identity.id == :inserted assert fetch_session_id(conn) end test "updates user identity", %{conn: conn} do - assert {:ok, user_identity, conn} = Plug.upsert_identity(conn, @existing_identity_params) + assert {:ok, identity, conn} = Plug.upsert_identity(conn, @existing_identity_params) - assert user_identity.id == :updated + assert identity.id == :updated assert fetch_session_id(conn) end @@ -148,10 +148,10 @@ defmodule PowAssent.PlugTest do test "calls create session callback", %{conn: init_conn} do init_conn = Plug.put_create_session_callback(init_conn, &Conn.put_private(&1, :callback_called, {&2, &3})) - assert {:ok, _user_identity, conn} = Plug.upsert_identity(init_conn, @new_identity_params) + assert {:ok, _identity, conn} = Plug.upsert_identity(init_conn, @new_identity_params) assert {"test_provider", _config} = conn.private[:callback_called] - assert {:ok, _user_identity, conn} = Plug.upsert_identity(init_conn, @existing_identity_params) + assert {:ok, _identity, conn} = Plug.upsert_identity(init_conn, @existing_identity_params) assert {"test_provider", _config} = conn.private[:callback_called] assert {:error, {:bound_to_different_user, _changeset}, conn} = Plug.upsert_identity(init_conn, @identity_taken_params) @@ -160,44 +160,44 @@ defmodule PowAssent.PlugTest do end describe "create_user/3" do - @user_identity_attrs %{"provider" => "test_provider", "uid" => "new_user"} - @user_identity_attrs_taken %{"provider" => "test_provider", "uid" => "identity_taken"} - @user_attrs %{"name" => "John Doe", "email" => "test@example.com"} - @user_attrs_no_user_id %{"name" => "John Doe"} + @identity_attrs %{"provider" => "test_provider", "uid" => "new_user"} + @identity_attrs_taken %{"provider" => "test_provider", "uid" => "identity_taken"} + @user_attrs %{"name" => "John Doe", "email" => "test@example.com"} + @user_attrs_no_user_id %{"name" => "John Doe"} test "creates user", %{conn: conn} do - assert {:ok, user, conn} = Plug.create_user(conn, @user_identity_attrs, @user_attrs) + assert {:ok, user, conn} = Plug.create_user(conn, @identity_attrs, @user_attrs) assert user.id == :inserted assert fetch_session_id(conn) end test "with missing user id", %{conn: conn} do - assert {:error, {:invalid_user_id_field, _changeset}, conn} = Plug.create_user(conn, @user_identity_attrs, @user_attrs_no_user_id) + assert {:error, {:invalid_user_id_field, _changeset}, conn} = Plug.create_user(conn, @identity_attrs, @user_attrs_no_user_id) refute fetch_session_id(conn) end test "with identity already taken", %{conn: conn} do - assert {:error, {:bound_to_different_user, _changeset}, conn} = Plug.create_user(conn, @user_identity_attrs_taken, @user_attrs) + assert {:error, {:bound_to_different_user, _changeset}, conn} = Plug.create_user(conn, @identity_attrs_taken, @user_attrs) refute fetch_session_id(conn) end test "calls create session callback", %{conn: init_conn} do init_conn = Plug.put_create_session_callback(init_conn, &Conn.put_private(&1, :callback_called, {&2, &3})) - assert {:ok, _user, conn} = Plug.create_user(init_conn, @user_identity_attrs, @user_attrs) + assert {:ok, _user, conn} = Plug.create_user(init_conn, @identity_attrs, @user_attrs) assert {"test_provider", _config} = conn.private[:callback_called] - assert {:error, {:invalid_user_id_field, _changeset}, conn} = Plug.create_user(init_conn, @user_identity_attrs, @user_attrs_no_user_id) + assert {:error, {:invalid_user_id_field, _changeset}, conn} = Plug.create_user(init_conn, @identity_attrs, @user_attrs_no_user_id) refute conn.private[:callback_called] - assert {:error, {:bound_to_different_user, _changeset}, conn} = Plug.create_user(init_conn, @user_identity_attrs_taken, @user_attrs) + assert {:error, {:bound_to_different_user, _changeset}, conn} = Plug.create_user(init_conn, @identity_attrs_taken, @user_attrs) refute conn.private[:callback_called] end end describe "delete_identity/3" do - @user %User{id: 1, password_hash: "", user_identities: [%UserIdentity{id: 1, provider: "test_provider"}, %UserIdentity{id: 2, provider: "other_provider"}]} + @user %User{id: 1, password_hash: "", identities: [%UserIdentity{id: 1, provider: "test_provider"}, %UserIdentity{id: 2, provider: "other_provider"}]} test "deletes", %{conn: conn} do conn = Pow.Plug.assign_current_user(conn, @user, @default_config) diff --git a/test/support/ecto/priv/migrations/3_create_user_identities.exs b/test/support/ecto/priv/migrations/3_create_user_identities.exs index a292022..243b415 100644 --- a/test/support/ecto/priv/migrations/3_create_user_identities.exs +++ b/test/support/ecto/priv/migrations/3_create_user_identities.exs @@ -1,6 +1,6 @@ require Pow.Ecto.Schema.Migration PowAssent.Test.Ecto -|> PowAssent.Ecto.UserIdentities.Schema.Migration.new("user_identities") -|> PowAssent.Ecto.UserIdentities.Schema.Migration.gen() +|> PowAssent.Ecto.Identities.Schema.Migration.new("user_identities") +|> PowAssent.Ecto.Identities.Schema.Migration.gen() |> Code.eval_string() diff --git a/test/support/ecto/user_identities/user_identity.ex b/test/support/ecto/user_identities/user_identity.ex deleted file mode 100644 index 62d568b..0000000 --- a/test/support/ecto/user_identities/user_identity.ex +++ /dev/null @@ -1,12 +0,0 @@ -defmodule PowAssent.Test.Ecto.UserIdentities.UserIdentity do - @moduledoc false - use Ecto.Schema - use PowAssent.Ecto.UserIdentities.Schema, - user: PowAssent.Test.Ecto.Users.User - - schema "user_identities" do - pow_assent_user_identity_fields() - - timestamps() - end -end diff --git a/test/support/ecto/user.ex b/test/support/ecto/users/user.ex similarity index 77% rename from test/support/ecto/user.ex rename to test/support/ecto/users/user.ex index 51fcfd7..5850f75 100644 --- a/test/support/ecto/user.ex +++ b/test/support/ecto/users/user.ex @@ -18,10 +18,10 @@ defmodule PowAssent.Test.Ecto.Users.User do |> pow_changeset(attrs) end - def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do + def identity_changeset(user_or_changeset, identity, attrs, user_id_attrs) do user_or_changeset |> validate_name(attrs) - |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs) + |> pow_assent_identity_changeset(identity, attrs, user_id_attrs) end defp validate_name(changeset, attrs) do diff --git a/test/support/ecto/users/user_identity.ex b/test/support/ecto/users/user_identity.ex new file mode 100644 index 0000000..b7c3b58 --- /dev/null +++ b/test/support/ecto/users/user_identity.ex @@ -0,0 +1,12 @@ +defmodule PowAssent.Test.Ecto.Users.UserIdentity do + @moduledoc false + use Ecto.Schema + use PowAssent.Ecto.Identities.Schema, + user: PowAssent.Test.Ecto.Users.User + + schema "user_identities" do + pow_assent_identity_fields() + + timestamps() + end +end diff --git a/test/support/extensions/email_confirmation/repo_mock.ex b/test/support/extensions/email_confirmation/repo_mock.ex index 4b7785c..78aad18 100644 --- a/test/support/extensions/email_confirmation/repo_mock.ex +++ b/test/support/extensions/email_confirmation/repo_mock.ex @@ -1,7 +1,7 @@ defmodule PowAssent.Test.EmailConfirmation.RepoMock do @moduledoc false - alias PowAssent.Test.EmailConfirmation.{UserIdentities.UserIdentity, Users.User} + alias PowAssent.Test.EmailConfirmation.{Users.UserIdentity, Users.User} alias PowAssent.Test.RepoMock def one(query, _opts) do diff --git a/test/support/extensions/email_confirmation/user.ex b/test/support/extensions/email_confirmation/user.ex index c4d5a61..e06c1cb 100644 --- a/test/support/extensions/email_confirmation/user.ex +++ b/test/support/extensions/email_confirmation/user.ex @@ -14,10 +14,10 @@ defmodule PowAssent.Test.EmailConfirmation.Users.User do timestamps() end - def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do + def identity_changeset(user_or_changeset, identity, attrs, user_id_attrs) do user_or_changeset |> validate_name(attrs) - |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs) + |> pow_assent_identity_changeset(identity, attrs, user_id_attrs) end defp validate_name(changeset, attrs) do diff --git a/test/support/extensions/email_confirmation/user_identity.ex b/test/support/extensions/email_confirmation/user_identity.ex index 855a4f9..87fe4c5 100644 --- a/test/support/extensions/email_confirmation/user_identity.ex +++ b/test/support/extensions/email_confirmation/user_identity.ex @@ -1,10 +1,10 @@ -defmodule PowAssent.Test.EmailConfirmation.UserIdentities.UserIdentity do +defmodule PowAssent.Test.EmailConfirmation.Users.UserIdentity do @moduledoc false use Ecto.Schema - use PowAssent.Ecto.UserIdentities.Schema, + use PowAssent.Ecto.Identities.Schema, user: PowAssent.Test.EmailConfirmation.Users.User schema "user_identities" do - pow_assent_user_identity_fields() + pow_assent_identity_fields() end end diff --git a/test/support/extensions/invitation/repo_mock.ex b/test/support/extensions/invitation/repo_mock.ex index 145eeb9..88f50a2 100644 --- a/test/support/extensions/invitation/repo_mock.ex +++ b/test/support/extensions/invitation/repo_mock.ex @@ -1,7 +1,7 @@ defmodule PowAssent.Test.Invitation.RepoMock do @moduledoc false - alias PowAssent.Test.Invitation.{Users.User, UserIdentities.UserIdentity} + alias PowAssent.Test.Invitation.{Users.User, Users.UserIdentity} alias PowAssent.Test.RepoMock @user %User{id: 1, email: "test@example.com"} diff --git a/test/support/extensions/invitation/user.ex b/test/support/extensions/invitation/user.ex index 89eaba3..c56f48c 100644 --- a/test/support/extensions/invitation/user.ex +++ b/test/support/extensions/invitation/user.ex @@ -7,8 +7,8 @@ defmodule PowAssent.Test.Invitation.Users.User do use PowAssent.Ecto.Schema schema "users" do - has_many :user_identities, - PowAssent.Test.Invitation.UserIdentities.UserIdentity, + has_many :identities, + PowAssent.Test.Invitation.Users.UserIdentity, on_delete: :delete_all, foreign_key: :user_id diff --git a/test/support/extensions/invitation/user_identity.ex b/test/support/extensions/invitation/user_identity.ex index 146c0f9..dbd0a26 100644 --- a/test/support/extensions/invitation/user_identity.ex +++ b/test/support/extensions/invitation/user_identity.ex @@ -1,10 +1,10 @@ -defmodule PowAssent.Test.Invitation.UserIdentities.UserIdentity do +defmodule PowAssent.Test.Invitation.Users.UserIdentity do @moduledoc false use Ecto.Schema - use PowAssent.Ecto.UserIdentities.Schema, + use PowAssent.Ecto.Identities.Schema, user: PowAssent.Test.Invitation.Users.User schema "user_identities" do - pow_assent_user_identity_fields() + pow_assent_identity_fields() end end diff --git a/test/support/repo_mock.ex b/test/support/repo_mock.ex index 1bc062d..c2306dc 100644 --- a/test/support/repo_mock.ex +++ b/test/support/repo_mock.ex @@ -1,7 +1,7 @@ defmodule PowAssent.Test.RepoMock do @moduledoc false - alias PowAssent.Test.Ecto.{UserIdentities.UserIdentity, Users.User} + alias PowAssent.Test.Ecto.{Users.UserIdentity, Users.User} def one(query, _opts) do case inspect(query) =~ "left_join: u1 in assoc(u0, :user)" and inspect(query) =~ "where: u0.provider == ^\"test_provider\" and u0.uid == ^\"existing_user\"" do @@ -17,7 +17,7 @@ defmodule PowAssent.Test.RepoMock do @spec insert(%{action: any, valid?: boolean}, any) :: {:error, %{action: :insert, valid?: false}} | {:ok, %{id: 1}} def insert(%{changes: %{provider: "test_provider", uid: "identity_taken"}} = changeset, _opts) do - changeset = Ecto.Changeset.add_error(changeset, :uid_provider, "has already been taken", constraint: :unique, constraint_name: "user_identities_uid_provider_index") + changeset = Ecto.Changeset.add_error(changeset, :uid, "has already been taken", constraint: :unique, constraint_name: "user_identities_uid_provider_index") {:error, %{changeset | action: :insert}} end @@ -26,10 +26,10 @@ defmodule PowAssent.Test.RepoMock do {:error, %{changeset | action: :insert}} end - def insert(%{valid?: true, changes: %{user_identities: [%{changes: %{provider: "test_provider", uid: "identity_taken"}} = user_identity_changeset]}} = changeset, _opts) do - user_identity_changeset = Ecto.Changeset.add_error(user_identity_changeset, :uid_provider, "has already been taken", constraint: :unique, constraint_name: "user_identities_uid_provider_index") - user_identity_changeset = %{user_identity_changeset | action: :insert} - changeset = Ecto.Changeset.put_change(changeset, :user_identities, [user_identity_changeset]) + def insert(%{valid?: true, changes: %{identities: [%{changes: %{provider: "test_provider", uid: "identity_taken"}} = identity_changeset]}} = changeset, _opts) do + identity_changeset = Ecto.Changeset.add_error(identity_changeset, :uid, "has already been taken", constraint: :unique, constraint_name: "user_identities_uid_provider_index") + identity_changeset = %{identity_changeset | action: :insert} + changeset = Ecto.Changeset.put_change(changeset, :identities, [identity_changeset]) {:error, %{changeset | action: :insert}} end @@ -54,8 +54,8 @@ defmodule PowAssent.Test.RepoMock do def get_by!(struct, [id: id], _opts), do: Process.get({struct, id}) - def preload(%User{id: :multiple_identities} = user, :user_identities, force: true), do: %{user | user_identities: [%UserIdentity{id: 1, provider: "test_provider"}, %UserIdentity{id: 2, provider: "other_provider"}]} - def preload(user, :user_identities, force: true), do: %{user | user_identities: [%UserIdentity{id: 1, provider: "test_provider"}]} + def preload(%User{id: :multiple_identities} = user, :identities, force: true), do: %{user | identities: [%UserIdentity{id: 1, provider: "test_provider"}, %UserIdentity{id: 2, provider: "other_provider"}]} + def preload(user, :identities, force: true), do: %{user | identities: [%UserIdentity{id: 1, provider: "test_provider"}]} def delete_all(query, _opts) do case inspect(query) =~ "where: u0.user_id == ^1, where: u0.id in ^[1]" do diff --git a/test/support/with_access_token/repo_mock.ex b/test/support/with_access_token/repo_mock.ex index 25aa371..498ae9b 100644 --- a/test/support/with_access_token/repo_mock.ex +++ b/test/support/with_access_token/repo_mock.ex @@ -1,7 +1,7 @@ defmodule PowAssent.Test.WithAccessToken.RepoMock do @moduledoc false - alias PowAssent.Test.WithAccessToken.{UserIdentities.UserIdentity, Users.User} + alias PowAssent.Test.WithAccessToken.{Users.UserIdentity, Users.User} alias PowAssent.Test.RepoMock def one(query, _opts) do diff --git a/test/support/with_access_token/user_identity.ex b/test/support/with_access_token/user_identity.ex index b9f7db6..615b570 100644 --- a/test/support/with_access_token/user_identity.ex +++ b/test/support/with_access_token/user_identity.ex @@ -1,22 +1,22 @@ -defmodule PowAssent.Test.WithAccessToken.UserIdentities.UserIdentity do +defmodule PowAssent.Test.WithAccessToken.Users.UserIdentity do @moduledoc false use Ecto.Schema - use PowAssent.Ecto.UserIdentities.Schema, + use PowAssent.Ecto.Identities.Schema, user: PowAssent.Test.WithAccessToken.Users.User schema "user_identities" do field :access_token, :string field :refresh_token, :string - pow_assent_user_identity_fields() + pow_assent_identity_fields() timestamps() end - def changeset(user_identity_or_changeset, attrs) do + def changeset(identity_or_changeset, attrs) do token_params = Map.get(attrs, "token") || Map.get(attrs, :token) || attrs - user_identity_or_changeset + identity_or_changeset |> pow_assent_changeset(attrs) |> Ecto.Changeset.cast(token_params, [:access_token, :refresh_token]) |> Ecto.Changeset.validate_required([:access_token])