Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elixir 1.8 compatible #737

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ config :pow, Pow.Ecto.Schema.Password, iterations: 1

config :phoenix, :json_library, Jason

extension_test_modules = [PowEmailConfirmation, PowInvitation, PowEmailConfirmation.PowInvitation, PowPersistentSession, PowResetPassword]
extension_test_modules = [
PowEmailConfirmation,
PowInvitation,
PowEmailConfirmation.PowInvitation,
PowPersistentSession,
PowResetPassword
]

for extension <- extension_test_modules do
endpoint_module = Module.concat([extension, TestWeb.Phoenix.Endpoint])
Expand Down
67 changes: 39 additions & 28 deletions lib/ex_doc/markdown.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,53 @@ if Code.ensure_loaded?(ExDoc.Markdown.Earmark) do
#
# Ref: https://github.com/elixir-lang/ex_doc/issues/889

defmodule ExDoc.Pow.Markdown do
@moduledoc false
defmodule ExDoc.Pow.Markdown do
@moduledoc false

alias ExDoc.Markdown.Earmark
alias ExDoc.Markdown.Earmark

@behaviour ExDoc.Markdown
@behaviour ExDoc.Markdown

@impl ExDoc.Markdown
defdelegate available?, to: Earmark
@impl ExDoc.Markdown
defdelegate available?, to: Earmark

@impl ExDoc.Markdown
def to_ast(text, opts) do
config = Mix.Project.config()[:docs]
source_url = config[:source_url] <> "/" <> source_ref_pattern(config[:source_url], config[:source_ref])
@impl ExDoc.Markdown
def to_ast(text, opts) do
config = Mix.Project.config()[:docs]

text
|> convert_relative_docs_url(source_url)
|> Earmark.to_ast(opts)
end
source_url =
config[:source_url] <> "/" <> source_ref_pattern(config[:source_url], config[:source_ref])

defp source_ref_pattern("https://github.com/" <> _rest, ref), do: "blob/#{ref}"
text
|> convert_relative_docs_url(source_url)
|> Earmark.to_ast(opts)
end

@markdown_regex ~r/(\[[\S ]*\]\()([\S]*?)(\.md|\.ex|\.exs)([\S]*?\))/
defp source_ref_pattern("https://github.com/" <> _rest, ref), do: "blob/#{ref}"

defp convert_relative_docs_url(text, source_url) do
Regex.replace(@markdown_regex, text, fn
_, arg1, "http" <> path, extension, arg3 -> "#{arg1}http#{path}#{extension}#{arg3}"
_, arg1, path, ".md", arg3 -> "#{arg1}#{convert_to_docs_html_url(path)}#{arg3}"
_, arg1, path, extension, arg3 when extension in [".ex", ".exs"] -> "#{arg1}#{convert_to_source_url(path, extension, source_url)}#{arg3}"
end)
end
@markdown_regex ~r/(\[[\S ]*\]\()([\S]*?)(\.md|\.ex|\.exs)([\S]*?\))/

defp convert_to_docs_html_url("../invitation/README"), do: "pow_invitation.html"
defp convert_to_docs_html_url("../email_confirmation/README"), do: "pow_email_confirmation.html"
defp convert_to_docs_html_url(path), do: path <> ".md"
defp convert_relative_docs_url(text, source_url) do
Regex.replace(@markdown_regex, text, fn
_, arg1, "http" <> path, extension, arg3 ->
"#{arg1}http#{path}#{extension}#{arg3}"

defp convert_to_source_url("test/" <> path, extension, source_url), do: source_url <> "/test/" <> path <> extension
end
_, arg1, path, ".md", arg3 ->
"#{arg1}#{convert_to_docs_html_url(path)}#{arg3}"

_, arg1, path, extension, arg3 when extension in [".ex", ".exs"] ->
"#{arg1}#{convert_to_source_url(path, extension, source_url)}#{arg3}"
end)
end

defp convert_to_docs_html_url("../invitation/README"), do: "pow_invitation.html"

defp convert_to_docs_html_url("../email_confirmation/README"),
do: "pow_email_confirmation.html"

defp convert_to_docs_html_url(path), do: path <> ".md"

defp convert_to_source_url("test/" <> path, extension, source_url),
do: source_url <> "/test/" <> path <> extension
end
end
18 changes: 13 additions & 5 deletions lib/extensions/email_confirmation/ecto/context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,33 @@ defmodule PowEmailConfirmation.Ecto.Context do
Checks if the users current e-mail is unconfirmed.
"""
@spec current_email_unconfirmed?(Context.user(), Config.t()) :: boolean()
def current_email_unconfirmed?(%{unconfirmed_email: nil, email_confirmation_token: token, email_confirmed_at: nil}, _config) when not is_nil(token),
do: true
def current_email_unconfirmed?(
%{unconfirmed_email: nil, email_confirmation_token: token, email_confirmed_at: nil},
_config
)
when not is_nil(token),
do: true

def current_email_unconfirmed?(_user, _config),
do: false

@doc """
Checks if the user has a pending e-mail change.
"""
@spec pending_email_change?(Context.user(), Config.t()) :: boolean()
def pending_email_change?(%{unconfirmed_email: email, email_confirmation_token: token}, _config) when not is_nil(email) and not is_nil(token),
do: true
def pending_email_change?(%{unconfirmed_email: email, email_confirmation_token: token}, _config)
when not is_nil(email) and not is_nil(token),
do: true

def pending_email_change?(_user, _config), do: false

@doc """
Confirms e-mail.

See `PowEmailConfirmation.Ecto.Schema.confirm_email_changeset/2`.
"""
@spec confirm_email(Context.user(), map(), Config.t()) :: {:ok, Context.user()} | {:error, Context.changeset()}
@spec confirm_email(Context.user(), map(), Config.t()) ::
{:ok, Context.user()} | {:error, Context.changeset()}
def confirm_email(%user_mod{} = user, params, config) do
user
|> user_mod.confirm_email_changeset(params)
Expand Down
36 changes: 26 additions & 10 deletions lib/extensions/email_confirmation/ecto/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,12 @@ defmodule PowEmailConfirmation.Ecto.Schema do
@impl true
defmacro __using__(_config) do
quote do
def confirm_email_changeset(changeset, attrs), do: pow_confirm_email_changeset(changeset, attrs)
def confirm_email_changeset(changeset, attrs),
do: pow_confirm_email_changeset(changeset, attrs)

defdelegate pow_confirm_email_changeset(changeset, attrs), to: unquote(__MODULE__), as: :confirm_email_changeset
defdelegate pow_confirm_email_changeset(changeset, attrs),
to: unquote(__MODULE__),
as: :confirm_email_changeset

defoverridable confirm_email_changeset: 2
end
Expand Down Expand Up @@ -96,7 +99,7 @@ defmodule PowEmailConfirmation.Ecto.Schema do
email_changed?(changeset) ->
current_email = changeset.data.email
changed_email = Changeset.get_field(changeset, :email)
changeset = set_unconfirmed_email(changeset, current_email, changed_email)
changeset = set_unconfirmed_email(changeset, current_email, changed_email)

case unconfirmed_email_changed?(changeset) do
true -> put_email_confirmation_token(changeset)
Expand All @@ -107,20 +110,21 @@ defmodule PowEmailConfirmation.Ecto.Schema do
changeset
end
end

def changeset(changeset, _attrs, _config), do: changeset

defp built?(changeset), do: Ecto.get_meta(changeset.data, :state) == :built

defp email_reverted?(changeset, attrs) do
param = Map.get(attrs, :email) || Map.get(attrs, "email")
param = Map.get(attrs, :email) || Map.get(attrs, "email")
current = changeset.data.email

param == current
end

defp email_changed?(changeset) do
case Changeset.get_change(changeset, :email) do
nil -> false
nil -> false
_any -> true
end
end
Expand All @@ -139,7 +143,7 @@ defmodule PowEmailConfirmation.Ecto.Schema do

defp unconfirmed_email_changed?(changeset) do
case Changeset.get_change(changeset, :unconfirmed_email) do
nil -> false
nil -> false
_any -> true
end
end
Expand All @@ -154,22 +158,34 @@ defmodule PowEmailConfirmation.Ecto.Schema do
changed to this value, and `:unconfirmed_email` will be set to nil.
"""
@spec confirm_email_changeset(Ecto.Schema.t() | Changeset.t(), map()) :: Changeset.t()
def confirm_email_changeset(%Changeset{data: %{unconfirmed_email: unconfirmed_email}} = changeset, params) when not is_nil(unconfirmed_email) do
def confirm_email_changeset(
%Changeset{data: %{unconfirmed_email: unconfirmed_email}} = changeset,
params
)
when not is_nil(unconfirmed_email) do
confirm_email(changeset, unconfirmed_email, params)
end
def confirm_email_changeset(%Changeset{data: %{email_confirmed_at: nil, email: email}} = changeset, params) do

def confirm_email_changeset(
%Changeset{data: %{email_confirmed_at: nil, email: email}} = changeset,
params
) do
confirm_email(changeset, email, params)
end

def confirm_email_changeset(%Changeset{} = changeset, _params), do: changeset

def confirm_email_changeset(user, params) do
user
|> Changeset.change()
|> confirm_email_changeset(params)
end

defp confirm_email(changeset, email, _params) do
confirmed_at = Pow.Ecto.Schema.__timestamp_for__(changeset.data.__struct__, :email_confirmed_at)
changes =
confirmed_at =
Pow.Ecto.Schema.__timestamp_for__(changeset.data.__struct__, :email_confirmed_at)

changes =
[
email_confirmed_at: confirmed_at,
email: email,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule PowEmailConfirmation.Phoenix.ConfirmationController do
alias Plug.Conn
alias PowEmailConfirmation.Plug

plug :load_user_from_confirmation_token when action in [:show]
plug(:load_user_from_confirmation_token when action in [:show])

@spec process_show(Conn.t(), map()) :: {:ok | :error, map(), Conn.t()}
def process_show(conn, _params), do: Plug.confirm_email(conn, %{})
Expand All @@ -16,6 +16,7 @@ defmodule PowEmailConfirmation.Phoenix.ConfirmationController do
|> put_flash(:info, extension_messages(conn).email_has_been_confirmed(conn))
|> redirect(to: redirect_to(conn))
end

def respond_show({:error, _changeset, conn}) do
conn
|> put_flash(:error, extension_messages(conn).email_confirmation_failed(conn))
Expand All @@ -24,7 +25,7 @@ defmodule PowEmailConfirmation.Phoenix.ConfirmationController do

defp redirect_to(conn) do
case Pow.Plug.current_user(conn) do
nil -> routes(conn).session_path(conn, :new)
nil -> routes(conn).session_path(conn, :new)
_user -> routes(conn).registration_path(conn, :edit)
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,37 +51,51 @@ defmodule PowEmailConfirmation.Phoenix.ControllerCallbacks do

halt_unconfirmed(conn, {:ok, user, conn}, return_path)
end
def before_respond(Pow.Phoenix.RegistrationController, :create, {:error, changeset, conn}, _config) do

def before_respond(
Pow.Phoenix.RegistrationController,
:create,
{:error, changeset, conn},
_config
) do
case PowPlug.__prevent_user_enumeration__(conn, changeset) do
true ->
return_path = routes(conn).after_registration_path(conn)
conn = redirect_with_email_confirmation_required(conn, return_path)
conn = redirect_with_email_confirmation_required(conn, return_path)

{:halt, conn}

false ->
{:error, changeset, conn}
end
end

def before_respond(Pow.Phoenix.RegistrationController, :update, {:ok, user, conn}, _config) do
return_path = routes(conn).after_user_updated_path(conn)

warn_unconfirmed(conn, user, return_path)
end

def before_respond(Pow.Phoenix.SessionController, :create, {:ok, conn}, _config) do
return_path = routes(conn).after_sign_in_path(conn)

halt_unconfirmed(conn, {:ok, conn}, return_path)
end
def before_respond(PowInvitation.Phoenix.InvitationController, :update, {:ok, user, conn}, _config) do

def before_respond(
PowInvitation.Phoenix.InvitationController,
:update,
{:ok, user, conn},
_config
) do
return_path = routes(conn).after_registration_path(conn)

warn_unconfirmed(conn, user, return_path)
end

defp halt_unconfirmed(conn, success_response, return_path) do
case Plug.email_unconfirmed?(conn) do
true -> halt_and_send_confirmation_email(conn, return_path)
true -> halt_and_send_confirmation_email(conn, return_path)
false -> success_response
end
end
Expand All @@ -105,16 +119,21 @@ defmodule PowEmailConfirmation.Phoenix.ControllerCallbacks do
|> Phoenix.Controller.redirect(to: return_path)
end

defp warn_unconfirmed(%{params: %{"user" => %{"email" => email}}} = conn, %{unconfirmed_email: email} = user, return_path) do
defp warn_unconfirmed(
%{params: %{"user" => %{"email" => email}}} = conn,
%{unconfirmed_email: email} = user,
return_path
) do
case Plug.pending_email_change?(conn) do
true -> warn_and_send_confirmation_email(conn, return_path)
true -> warn_and_send_confirmation_email(conn, return_path)
false -> {:ok, user, conn}
end
end

defp warn_unconfirmed(conn, user, _return_path), do: {:ok, user, conn}

defp warn_and_send_confirmation_email(conn, return_path) do
user = PowPlug.current_user(conn)
user = PowPlug.current_user(conn)
error = extension_messages(conn).email_confirmation_required_for_update(conn)

send_confirmation_email(user, conn)
Expand All @@ -135,9 +154,9 @@ defmodule PowEmailConfirmation.Phoenix.ControllerCallbacks do
"""
@spec send_confirmation_email(map(), Conn.t()) :: any()
def send_confirmation_email(user, conn) do
url = confirmation_url(conn, user)
unconfirmed_user = %{user | email: user.unconfirmed_email || user.email}
email = Mailer.email_confirmation(conn, unconfirmed_user, url)
url = confirmation_url(conn, user)
unconfirmed_user = %{user | email: user.unconfirmed_email || user.email}
email = Mailer.email_confirmation(conn, unconfirmed_user, url)

Pow.Phoenix.Mailer.deliver(conn, email)
end
Expand Down
26 changes: 14 additions & 12 deletions lib/extensions/email_confirmation/phoenix/mailers/mail.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ defmodule PowEmailConfirmation.Phoenix.Mail do
@moduledoc false
use Pow.Phoenix.Mailer.Template

template :email_confirmation,
"Confirm your email address",
"""
Hi,
template(
:email_confirmation,
"Confirm your email address",
"""
Hi,

Please use the following link to confirm your e-mail address:
Please use the following link to confirm your e-mail address:

<%= @url %>
""",
"""
<h3>Hi</h3>
<p>Please use the following link to confirm your e-mail address:</p>
<p><a href="<%= @url %>"><%= @url %></a></p>
"""
<%= @url %>
""",
"""
<h3>Hi</h3>
<p>Please use the following link to confirm your e-mail address:</p>
<p><a href="<%= @url %>"><%= @url %></a></p>
"""
)
end
Loading