Skip to content

Commit

Permalink
chore: rework docs
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasmazza committed May 2, 2022
1 parent 60ce96b commit 60fa960
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 24 deletions.
24 changes: 23 additions & 1 deletion lib/mix/tasks/swoosh.gallery.html.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
defmodule Mix.Tasks.Swoosh.Gallery.Html do
@moduledoc """
Serialize the given Swoosh.Gallery module and outputs HTML files to a folder.
Generate static files from a `Swoosh.Gallery` module that can be distributed and
hosted without your application's code, on places like Amazon S3 or GitHub/GitLab Pages.
## Example
mix swoosh.gallery.html --gallery Sample.Mailer.Gallery --path /tmp/emails
* creating /tmp/emails
* creating /tmp/emails/index.html
* creating /tmp/emails/notifications.new_follower.html
* creating /tmp/emails/notifications.new_follower/preview.html
* creating /tmp/emails/notifications.new_message.html
* creating /tmp/emails/notifications.new_message/preview.html
* creating /tmp/emails/email_with_attachment.html
* creating /tmp/emails/email_with_attachment/preview.html
* creating /tmp/emails/email_with_attachment/attachments/0/file.pdf
* creating /tmp/emails/welcome_users.html
* creating /tmp/emails/welcome_users/preview.html
## Command line options
* `-g`, `--gallery` - the gallery that will be used
* `-p`, `--path` - path where the static files should be generated
"""
use Mix.Task
require Mix.Generator
Expand Down
117 changes: 96 additions & 21 deletions lib/swoosh/gallery.ex
Original file line number Diff line number Diff line change
@@ -1,23 +1,87 @@
defmodule Swoosh.Gallery do
@moduledoc ~S"""
Swoosh.Gallery is a module used to map a preview to a path in order to later
be exposed through Plug or generate docs with `mix swoosh.gen.gallery` task.
Swoosh.Gallery is a library to preview and display your Swoosh mailers to everyone,
either by exposing the previews on your application's router or publishing it on
your favorite static host solution.
## Examples
## Getting Started
You will a gallery module to organize all your previews, and implement the expected
callbacks on your mailer modules:
defmodule MyApp.SwooshGallery do
defmodule MyApp.Mailer.Gallery do
use Swoosh.Gallery
preview("/welcome", MyApp.Emails.Welcome)
preview("/welcome", MyApp.Mailer.WelcomeMailer)
end
defmodule MyApp.Mailer.WelcomeMailer do
# the expected Swoosh / Phoenix.Swoosh code that you already have to deliver emails
use Phoenix.Swoosh, view: SampleWeb.WelcomeMailerView, layout: {MyApp.LayoutView, :email}
def welcome(user) do
new()
|> from("[email protected]")
|> to({user.name, user.email})
|> subject("Welcome to Sample App")
|> render_body("welcome.html", user: user)
end
# `preview/0` function that builds your email using fixture data
def preview do
welcome(%{email: "[email protected]", name: "Test User!"})
end
# `preview_details/0` with some useful metadata about your mailer
def preview_details do
[
title: "Welcome to MyApp!",
description: "First email to welcome users into the platform"
]
end
end
Then in your router:
Then in your router, you can mount your Gallery to expose it to the web:
forward "/gallery", MyApp.Mailer.Gallery
Or, you can generate static web pages with all the previews from your gallery:
mix swoosh.gallery.html --gallery MyApp.Mailer.Gallery --path "_build/emails"
### Generating preview data
forward "/gallery", MyApp.SwooshGallery
Previews should be built using in memory fixture data and we do **not recommend** that you
reuse your application's code to query for existing data or generate files during runtime. The
`preview/0` can be invoked multiple times as you navigate through your gallery on your browser
when mounting it on the router or when using the `swoosh.gallery.html` task to generate the static
pages.
Or, you can generate HTML pages from it:
defmodule MyApp.Mailer.SendContractEmail do
def send_contract(user, blob) do
contract =
Swoosh.Attachment.new({:data, blob}, filename: "contract.pdf", content_type: "application/pdf")
new()
|> to({user.name, user.email})
|> subject("Here is your Contract")
|> attachment(contract)
|> render_body(:contract, user: user)
end
# Bad - invokes application code to query data and generate the PDF contents
def preview do
user = MyApp.Users.find_user("[email protected]")
{:ok, blob} = MyApp.Contracts.build_contract(user)
build(user, blob)
end
mix swoosh.gallery.html --gallery MyApp.SwooshGallery --path "_build/emails"
# Good - uses in memory structs and existing fixtures
def preview do
blob = File.read!("#{Application.app_dir(:tiger, "my_app")}/fixtures/sample.pdf")
build(%User{}, blob)
end
end
"""

defmacro __using__(_options) do
Expand Down Expand Up @@ -54,8 +118,14 @@ defmodule Swoosh.Gallery do
## Examples
preview("/welcome", MyApp.Emails.Welcome)
defmodule MyApp.Mailer.Gallery do
use Swoosh.Gallery
preview "/welcome", MyApp.Emails.Welcome
preview "/account-confirmed", MyApp.Emails.AccountConfirmed
preview "/password-reset", MyApp.Emails.PasswordReset
end
"""
@spec preview(String.t(), module()) :: no_return()
defmacro preview(path, module) do
Expand All @@ -74,14 +144,20 @@ defmodule Swoosh.Gallery do
end

@doc """
Defines a scope in which previews can be nested. Each group needs a path and a `:title`
option.
Defines a scope in which previews can be nested when rendered on your gallery.
Each group needs a path and a `:title` option.
## Example
group "/onboarding", title: "Onboarding Emails" do
preview "/welcome", MyApp.Emails.Welcome
preview "/account-confirmed", MyApp.Emails.AccountConfirmed
defmodule MyApp.Mailer.Gallery do
use Swoosh.Gallery
group "/onboarding", title: "Onboarding Emails" do
preview "/welcome", MyApp.Emails.Welcome
preview "/account-confirmed", MyApp.Emails.AccountConfirmed
end
preview "/password-reset", MyApp.Emails.PasswordReset
end
## Options
Expand Down Expand Up @@ -111,19 +187,17 @@ defmodule Swoosh.Gallery do
end
end

@doc ~S"""
Evaluates a preview. It loads the results of email_mfa into the email property.
"""
# Evaluates a preview. It loads the results of email_mfa into the email property.
@doc false
@spec eval_preview(%{:email_mfa => {module(), atom(), list()}}) :: map()
def eval_preview(%{email: _email} = preview), do: preview

def eval_preview(%{email_mfa: {module, fun, opts}} = preview) do
Map.put(preview, :email, apply(module, fun, opts))
end

@doc ~S"""
Evaluates a preview and reads the attachment at a given index position.
"""
# Evaluates a preview and reads the attachment at a given index position.
@doc false
@spec read_email_attachment_at(%{email_mfa: {atom, atom, list}}, integer()) ::
{:error, :invalid_attachment | :not_found}
| {:ok, %{content_type: String.t(), data: any}}
Expand Down Expand Up @@ -177,6 +251,7 @@ defmodule Swoosh.Gallery do
raise ArgumentError, "router paths must be strings, got: #{inspect(path)}"
end

@doc false
def build_preview_path(nil, path), do: path
def build_preview_path(group, path), do: "#{group}.#{path}"
end
3 changes: 2 additions & 1 deletion lib/swoosh/gallery/plug.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule Swoosh.Gallery.Plug do
@moduledoc """
Plug that serves pages useful for previewing the gallery of emails in development.
Plug to mount a `Swoosh.Gallery` into an existing Phoenix/Plug application. Gallery themselves
will forward `init/1` and `call/2` to this dmoule, so users don't need to use it directly.
## Examples
Expand Down
4 changes: 3 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,17 @@ defmodule SwooshGallery.MixProject do

defp deps do
[
{:swoosh, "~> 1.5"},
{:plug_cowboy, ">= 1.0.0"},
{:swoosh, "~> 1.5"},
{:ex_doc, "~> 0.21", only: [:dev, :test], runtime: false},
{:hackney, "~> 1.9", only: [:test]},
{:tailwind, "~> 0.1", only: [:dev, :test]}
]
end

defp docs do
[
main: "Swoosh.Gallery",
source_ref: "v#{@version}",
source_url: "https://github.com/remoteoss/swoosh_gallery"
]
Expand Down
6 changes: 6 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"},
"ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"plug": {:hex, :plug, "1.13.3", "93b299039c21a8b82cc904d13812bce4ced45cf69153e8d35ca16ffb3e8c5d98", [:mix], [{:mime, "~> 1.0 or ~> 2.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.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "98c8003e4faf7b74a9ac41bee99e328b08f069bf932747d4a7532e97ae837a17"},
"plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"},
Expand Down

0 comments on commit 60fa960

Please sign in to comment.