forked from shibao/cannery
fix registration email
This commit is contained in:
parent
d685ca5c74
commit
e5a5b4299c
@ -11,8 +11,6 @@ import Config
|
|||||||
# before starting your production server.
|
# before starting your production server.
|
||||||
config :cannery, CanneryWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
|
config :cannery, CanneryWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
|
||||||
|
|
||||||
config :cannery, Cannery.Application, automigrate: true
|
|
||||||
|
|
||||||
# Do not print debug messages in production
|
# Do not print debug messages in production
|
||||||
config :logger, level: :info
|
config :logger, level: :info
|
||||||
|
|
||||||
|
@ -67,6 +67,9 @@ if config_env() == :prod do
|
|||||||
|
|
||||||
config :cannery, CanneryWeb.Endpoint, secret_key_base: secret_key_base
|
config :cannery, CanneryWeb.Endpoint, secret_key_base: secret_key_base
|
||||||
|
|
||||||
|
# Automatically apply migrations
|
||||||
|
config :cannery, Cannery.Application, automigrate: true
|
||||||
|
|
||||||
# Set up SMTP settings
|
# Set up SMTP settings
|
||||||
config :cannery, Cannery.Mailer,
|
config :cannery, Cannery.Mailer,
|
||||||
adapter: Swoosh.Adapters.SMTP,
|
adapter: Swoosh.Adapters.SMTP,
|
||||||
@ -87,22 +90,4 @@ if config_env() == :prod do
|
|||||||
#
|
#
|
||||||
# Then you can assemble a release by calling `mix release`.
|
# Then you can assemble a release by calling `mix release`.
|
||||||
# See `mix help release` for more information.
|
# See `mix help release` for more information.
|
||||||
|
|
||||||
# ## Configuring the mailer
|
|
||||||
#
|
|
||||||
# In production you need to configure the mailer to use a different adapter.
|
|
||||||
# Also, you may need to configure the Swoosh API client of your choice if you
|
|
||||||
# are not using SMTP. Here is an example of the configuration:
|
|
||||||
#
|
|
||||||
# config :cannery, Cannery.Mailer,
|
|
||||||
# adapter: Swoosh.Adapters.Mailgun,
|
|
||||||
# api_key: System.get_env("MAILGUN_API_KEY"),
|
|
||||||
# domain: System.get_env("MAILGUN_DOMAIN")
|
|
||||||
#
|
|
||||||
# For this example you need include a HTTP client required by Swoosh API client.
|
|
||||||
# Swoosh supports Hackney and Finch out of the box:
|
|
||||||
#
|
|
||||||
# config :swoosh, :api_client, Swoosh.ApiClient.Hackney
|
|
||||||
#
|
|
||||||
# See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details.
|
|
||||||
end
|
end
|
||||||
|
@ -4,10 +4,10 @@ defmodule Cannery.Accounts do
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import Ecto.Query, warn: false
|
import Ecto.Query, warn: false
|
||||||
alias Cannery.Repo
|
alias Cannery.{Mailer, Repo}
|
||||||
alias Cannery.Accounts.{User, UserToken}
|
alias Cannery.Accounts.{User, UserToken}
|
||||||
alias Cannery.Mailer
|
|
||||||
alias Ecto.{Changeset, Multi}
|
alias Ecto.{Changeset, Multi}
|
||||||
|
alias Oban.Job
|
||||||
|
|
||||||
## Database getters
|
## Database getters
|
||||||
|
|
||||||
@ -202,8 +202,7 @@ defmodule Cannery.Accounts do
|
|||||||
{:ok, %{to: ..., body: ...}}
|
{:ok, %{to: ..., body: ...}}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@spec deliver_update_email_instructions(User.t(), String.t(), function) ::
|
@spec deliver_update_email_instructions(User.t(), String.t(), function) :: Job.t()
|
||||||
{:ok, any()} | {:error, atom()}
|
|
||||||
def deliver_update_email_instructions(user, current_email, update_email_url_fun)
|
def deliver_update_email_instructions(user, current_email, update_email_url_fun)
|
||||||
when is_function(update_email_url_fun, 1) do
|
when is_function(update_email_url_fun, 1) do
|
||||||
{encoded_token, user_token} = UserToken.build_email_token(user, "change:#{current_email}")
|
{encoded_token, user_token} = UserToken.build_email_token(user, "change:#{current_email}")
|
||||||
@ -319,8 +318,7 @@ defmodule Cannery.Accounts do
|
|||||||
{:error, :already_confirmed}
|
{:error, :already_confirmed}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@spec deliver_user_confirmation_instructions(User.t(), function) ::
|
@spec deliver_user_confirmation_instructions(User.t(), function) :: Job.t()
|
||||||
{:ok, any()} | {:error, atom()}
|
|
||||||
def deliver_user_confirmation_instructions(user, confirmation_url_fun)
|
def deliver_user_confirmation_instructions(user, confirmation_url_fun)
|
||||||
when is_function(confirmation_url_fun, 1) do
|
when is_function(confirmation_url_fun, 1) do
|
||||||
if user.confirmed_at do
|
if user.confirmed_at do
|
||||||
@ -367,8 +365,7 @@ defmodule Cannery.Accounts do
|
|||||||
{:ok, %{to: ..., body: ...}}
|
{:ok, %{to: ..., body: ...}}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@spec deliver_user_reset_password_instructions(User.t(), function()) ::
|
@spec deliver_user_reset_password_instructions(User.t(), function()) :: Job.t()
|
||||||
{:ok, any()} | {:error, atom()}
|
|
||||||
def deliver_user_reset_password_instructions(user, reset_password_url_fun)
|
def deliver_user_reset_password_instructions(user, reset_password_url_fun)
|
||||||
when is_function(reset_password_url_fun, 1) do
|
when is_function(reset_password_url_fun, 1) do
|
||||||
{encoded_token, user_token} = UserToken.build_email_token(user, "reset_password")
|
{encoded_token, user_token} = UserToken.build_email_token(user, "reset_password")
|
||||||
|
@ -7,7 +7,7 @@ defmodule Cannery.Email do
|
|||||||
`lib/cannery_web/templates/layout/email.txt.heex` for text emails.
|
`lib/cannery_web/templates/layout/email.txt.heex` for text emails.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
use Phoenix.Swoosh, view: Cannery.EmailView, layout: {Cannery.LayoutView, :email}
|
use Phoenix.Swoosh, view: CanneryWeb.EmailView, layout: {CanneryWeb.LayoutView, :email}
|
||||||
import CanneryWeb.Gettext
|
import CanneryWeb.Gettext
|
||||||
alias Cannery.Accounts.User
|
alias Cannery.Accounts.User
|
||||||
alias CanneryWeb.EmailView
|
alias CanneryWeb.EmailView
|
||||||
@ -19,33 +19,27 @@ defmodule Cannery.Email do
|
|||||||
|
|
||||||
@spec base_email(User.t(), String.t()) :: t()
|
@spec base_email(User.t(), String.t()) :: t()
|
||||||
defp base_email(%User{email: email}, subject) do
|
defp base_email(%User{email: email}, subject) do
|
||||||
new()
|
from = Application.get_env(:cannery, Cannery.Mailer)[:email_from] || "noreply@localhost"
|
||||||
|> to(email)
|
name = Application.get_env(:cannery, Cannery.Mailer)[:email_name]
|
||||||
|> from({
|
new() |> to(email) |> from({name, from}) |> subject(subject)
|
||||||
Application.get_env(:cannery, Cannery.Mailer)[:email_name],
|
|
||||||
Application.get_env(:cannery, Cannery.Mailer)[:email_from]
|
|
||||||
})
|
|
||||||
|> subject(subject)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec welcome_email(User.t(), String.t()) :: t()
|
@spec generate_email(String.t(), User.t(), attrs :: map()) :: t()
|
||||||
def welcome_email(user, url) do
|
def generate_email("welcome", user, %{"url" => url}) do
|
||||||
user
|
user
|
||||||
|> base_email(dgettext("emails", "Confirm your %{name} account", name: "Cannery"))
|
|> base_email(dgettext("emails", "Confirm your %{name} account", name: "Cannery"))
|
||||||
|> render_body("confirm_email.html", %{user: user, url: url})
|
|> render_body("confirm_email.html", %{user: user, url: url})
|
||||||
|> text_body(EmailView.render("confirm_email.txt", %{user: user, url: url}))
|
|> text_body(EmailView.render("confirm_email.txt", %{user: user, url: url}))
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec reset_password_email(User.t(), String.t()) :: t()
|
def generate_email("reset_password", user, %{"url" => url}) do
|
||||||
def reset_password_email(user, url) do
|
|
||||||
user
|
user
|
||||||
|> base_email(dgettext("emails", "Reset your %{name} password", name: "Cannery"))
|
|> base_email(dgettext("emails", "Reset your %{name} password", name: "Cannery"))
|
||||||
|> render_body("reset_password.html", %{user: user, url: url})
|
|> render_body("reset_password.html", %{user: user, url: url})
|
||||||
|> text_body(EmailView.render("reset_password.txt", %{user: user, url: url}))
|
|> text_body(EmailView.render("reset_password.txt", %{user: user, url: url}))
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec update_email(User.t(), String.t()) :: t()
|
def generate_email("update_email", user, %{"url" => url}) do
|
||||||
def update_email(user, url) do
|
|
||||||
user
|
user
|
||||||
|> base_email(dgettext("emails", "Update your %{name} email", name: "Cannery"))
|
|> base_email(dgettext("emails", "Update your %{name} email", name: "Cannery"))
|
||||||
|> render_body("update_email.html", %{user: user, url: url})
|
|> render_body("update_email.html", %{user: user, url: url})
|
||||||
|
@ -4,10 +4,10 @@ defmodule Cannery.EmailWorker do
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
use Oban.Worker, queue: :mailers
|
use Oban.Worker, queue: :mailers
|
||||||
alias Cannery.Mailer
|
alias Cannery.{Accounts, Mailer, Email}
|
||||||
|
|
||||||
@impl Oban.Worker
|
@impl Oban.Worker
|
||||||
def perform(%Oban.Job{args: email}) do
|
def perform(%Oban.Job{args: %{"email" => email, "user_id" => user_id, "attrs" => attrs}}) do
|
||||||
email |> Mailer.deliver()
|
Email.generate_email(email, user_id |> Accounts.get_user!(), attrs) |> Mailer.deliver()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,33 +1,40 @@
|
|||||||
defmodule Cannery.Mailer do
|
defmodule Cannery.Mailer do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Mailer adapter for emails
|
Mailer adapter for emails
|
||||||
|
|
||||||
|
Since emails are loaded as Oban jobs, the `:attrs` map must be serializable to
|
||||||
|
json with Jason, which restricts the use of structs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
use Swoosh.Mailer, otp_app: :cannery
|
use Swoosh.Mailer, otp_app: :cannery
|
||||||
alias Cannery.{Accounts.User, Email, EmailWorker}
|
alias Cannery.{Accounts.User, EmailWorker}
|
||||||
alias Oban.Job
|
alias Oban.Job
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Deliver instructions to confirm account.
|
Deliver instructions to confirm account.
|
||||||
"""
|
"""
|
||||||
@spec deliver_confirmation_instructions(User.t(), String.t()) :: {:ok, Job.t()}
|
@spec deliver_confirmation_instructions(User.t(), String.t()) :: Job.t()
|
||||||
def deliver_confirmation_instructions(user, url) do
|
def deliver_confirmation_instructions(%User{id: user_id}, url) do
|
||||||
{:ok, Email.welcome_email(user, url) |> EmailWorker.new() |> Oban.insert!()}
|
%{email: :welcome, user_id: user_id, attrs: %{url: url}}
|
||||||
|
|> EmailWorker.new()
|
||||||
|
|> Oban.insert!()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Deliver instructions to reset a user password.
|
Deliver instructions to reset a user password.
|
||||||
"""
|
"""
|
||||||
@spec deliver_reset_password_instructions(User.t(), String.t()) :: {:ok, Job.t()}
|
@spec deliver_reset_password_instructions(User.t(), String.t()) :: Job.t()
|
||||||
def deliver_reset_password_instructions(user, url) do
|
def deliver_reset_password_instructions(%User{id: user_id}, url) do
|
||||||
{:ok, Email.reset_password_email(user, url) |> EmailWorker.new() |> Oban.insert!()}
|
%{email: :reset_password, user_id: user_id, attrs: %{url: url}}
|
||||||
|
|> EmailWorker.new()
|
||||||
|
|> Oban.insert!()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Deliver instructions to update a user email.
|
Deliver instructions to update a user email.
|
||||||
"""
|
"""
|
||||||
@spec deliver_update_email_instructions(User.t(), String.t()) :: {:ok, Job.t()}
|
@spec deliver_update_email_instructions(User.t(), String.t()) :: Job.t()
|
||||||
def deliver_update_email_instructions(user, url) do
|
def deliver_update_email_instructions(%User{id: user_id}, url) do
|
||||||
{:ok, Email.update_email(user, url) |> EmailWorker.new() |> Oban.insert!()}
|
%{email: :update, user_id: user_id, attrs: %{url: url}} |> EmailWorker.new() |> Oban.insert!()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -62,11 +62,10 @@ defmodule CanneryWeb.UserRegistrationController do
|
|||||||
invite |> Invites.use_invite!()
|
invite |> Invites.use_invite!()
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, _} =
|
Accounts.deliver_user_confirmation_instructions(
|
||||||
Accounts.deliver_user_confirmation_instructions(
|
user,
|
||||||
user,
|
&Routes.user_confirmation_url(conn, :confirm, &1)
|
||||||
&Routes.user_confirmation_url(conn, :confirm, &1)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, dgettext("prompts", "User created successfully."))
|
|> put_flash(:info, dgettext("prompts", "User created successfully."))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
defmodule CanneryWeb.LayoutView do
|
defmodule CanneryWeb.LayoutView do
|
||||||
use CanneryWeb, :view
|
use CanneryWeb, :view
|
||||||
alias Cannery.Accounts
|
alias Cannery.Accounts
|
||||||
alias CanneryWeb.HomeLive
|
alias CanneryWeb.{Endpoint, HomeLive}
|
||||||
|
|
||||||
# Phoenix LiveDashboard is available only in development by default,
|
# Phoenix LiveDashboard is available only in development by default,
|
||||||
# so we instruct Elixir to not warn if the dashboard route is missing.
|
# so we instruct Elixir to not warn if the dashboard route is missing.
|
||||||
|
@ -13,10 +13,10 @@ msgstr ""
|
|||||||
#, elixir-format, ex-autogen
|
#, elixir-format, ex-autogen
|
||||||
#: lib/cannery_web/component/topbar.ex:96
|
#: lib/cannery_web/component/topbar.ex:96
|
||||||
#: lib/cannery_web/templates/layout/topbar.html.heex:36
|
#: lib/cannery_web/templates/layout/topbar.html.heex:36
|
||||||
#: lib/cannery_web/templates/user_confirmation/new.html.heex:24
|
#: lib/cannery_web/templates/user_confirmation/new.html.heex:26
|
||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:39
|
#: lib/cannery_web/templates/user_registration/new.html.heex:39
|
||||||
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:39
|
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:41
|
||||||
#: lib/cannery_web/templates/user_reset_password/new.html.heex:25
|
#: lib/cannery_web/templates/user_reset_password/new.html.heex:27
|
||||||
#: lib/cannery_web/templates/user_session/new.html.heex:3
|
#: lib/cannery_web/templates/user_session/new.html.heex:3
|
||||||
#: lib/cannery_web/templates/user_session/new.html.heex:35
|
#: lib/cannery_web/templates/user_session/new.html.heex:35
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
@ -25,12 +25,12 @@ msgstr ""
|
|||||||
#, elixir-format, ex-autogen
|
#, elixir-format, ex-autogen
|
||||||
#: lib/cannery_web/component/topbar.ex:89
|
#: lib/cannery_web/component/topbar.ex:89
|
||||||
#: lib/cannery_web/templates/layout/topbar.html.heex:28
|
#: lib/cannery_web/templates/layout/topbar.html.heex:28
|
||||||
#: lib/cannery_web/templates/user_confirmation/new.html.heex:20
|
#: lib/cannery_web/templates/user_confirmation/new.html.heex:21
|
||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:3
|
#: lib/cannery_web/templates/user_registration/new.html.heex:3
|
||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:34
|
#: lib/cannery_web/templates/user_registration/new.html.heex:34
|
||||||
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:35
|
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:36
|
||||||
#: lib/cannery_web/templates/user_reset_password/new.html.heex:21
|
#: lib/cannery_web/templates/user_reset_password/new.html.heex:22
|
||||||
#: lib/cannery_web/templates/user_session/new.html.heex:40
|
#: lib/cannery_web/templates/user_session/new.html.heex:41
|
||||||
msgid "Register"
|
msgid "Register"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ msgstr ""
|
|||||||
#, elixir-format, ex-autogen
|
#, elixir-format, ex-autogen
|
||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:43
|
#: lib/cannery_web/templates/user_registration/new.html.heex:43
|
||||||
#: lib/cannery_web/templates/user_reset_password/new.html.heex:3
|
#: lib/cannery_web/templates/user_reset_password/new.html.heex:3
|
||||||
#: lib/cannery_web/templates/user_session/new.html.heex:44
|
#: lib/cannery_web/templates/user_session/new.html.heex:46
|
||||||
msgid "Forgot your password?"
|
msgid "Forgot your password?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -21,17 +21,17 @@ msgid "This email was sent from %{name} at %{url}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, elixir-format, ex-autogen
|
#, elixir-format, ex-autogen
|
||||||
#: lib/cannery/accounts/email.ex:34
|
#: lib/cannery/accounts/email.ex:30
|
||||||
msgid "Confirm your %{name} account"
|
msgid "Confirm your %{name} account"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, elixir-format, ex-autogen
|
#, elixir-format, ex-autogen
|
||||||
#: lib/cannery/accounts/email.ex:42
|
#: lib/cannery/accounts/email.ex:37
|
||||||
msgid "Reset your %{name} password"
|
msgid "Reset your %{name} password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, elixir-format, ex-autogen
|
#, elixir-format, ex-autogen
|
||||||
#: lib/cannery/accounts/email.ex:50
|
#: lib/cannery/accounts/email.ex:44
|
||||||
msgid "Update your %{name} email"
|
msgid "Update your %{name} email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ msgid "User confirmed successfully."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, elixir-format, ex-autogen
|
#, elixir-format, ex-autogen
|
||||||
#: lib/cannery_web/controllers/user_registration_controller.ex:72
|
#: lib/cannery_web/controllers/user_registration_controller.ex:71
|
||||||
msgid "User created successfully."
|
msgid "User created successfully."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user