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

Notify ninjas on their birthday #155

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d463c61
Notify ninjas on their birthday
pedrofp4444 Jan 13, 2023
9ec76c8
Reformulate functions
pedrofp4444 Jan 20, 2023
cc81943
Adjusted notify_ninja_birthday
pedrofp4444 Jan 20, 2023
db40a67
Corrections in lint the code
pedrofp4444 Jan 20, 2023
f86864c
Merge branch 'main' into pp/send-ninja-email-birthday
pedrofp4444 Feb 20, 2023
4859d6a
Add ninjas reference
pedrofp4444 Mar 4, 2023
247f43a
Update lib/bokken_web/templates/email/ninja_birthday.html.eex
pedrofp4444 Mar 4, 2023
2789b8e
Merge branch 'main' into pp/send-ninja-email-birthday
pedrofp4444 Mar 4, 2023
79550aa
Corrected ninja assign
pedrofp4444 Mar 4, 2023
b095f19
Merge branch 'pp/send-ninja-email-birthday' of github.com:coderdojobr…
pedrofp4444 Mar 4, 2023
b60e09f
Change module name
pedrofp4444 Mar 5, 2023
e3b7c6b
Format code
pedrofp4444 Mar 5, 2023
1f641d4
Config :quantum
pedrofp4444 Mar 5, 2023
25e927c
Config :quantum
pedrofp4444 Mar 5, 2023
14b0328
Merge branch 'main' into pp/send-ninja-email-birthday
pedrofp4444 Mar 7, 2023
037c24d
Fix :quantum config
pedrofp4444 Mar 7, 2023
4fa573f
Fix file name
pedrofp4444 Mar 7, 2023
abad75b
Merge branch 'pp/send-ninja-email-birthday' of github.com:coderdojobr…
pedrofp4444 Mar 7, 2023
0523303
Lint code
pedrofp4444 Mar 7, 2023
1646da1
Prepare new push
pedrofp4444 Mar 7, 2023
2261aec
Tests passing locally
pedrofp4444 Mar 7, 2023
d0f0500
Update lib/bokken/events/event_admin.ex
pedrofp4444 Mar 8, 2023
775591e
Change file name and improve code
pedrofp4444 Mar 10, 2023
6a9146a
Format code
pedrofp4444 Mar 10, 2023
3f4a3ba
Merge branch 'main' into pp/send-ninja-email-birthday
pedrofp4444 Mar 14, 2023
4b37245
Update lib/bokken/birthday_notifier.ex
pedrofp4444 Mar 14, 2023
6a0e9c8
Update lib/bokken/scheduler.ex
pedrofp4444 Mar 14, 2023
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
6 changes: 6 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ config :logger, :console,
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason

config :bokken, Bokken.Scheduler,
jobs: [
# Every midnight
{"@daily", {BirthdayNotifier, :notify_ninja_birthday, []}}
]

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
8 changes: 8 additions & 0 deletions lib/bokken/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ defmodule Bokken.Accounts do
[%Ninja{}, ...]

"""

def list_ninjas(preloads) when is_list(preloads) do
Ninja
|> Repo.all()
Expand Down Expand Up @@ -510,6 +511,13 @@ defmodule Bokken.Accounts do
end
end

def get_guardian_email_by_ninja(ninja: user) do
user
|> Repo.preload(:ninja)
|> then(fn user -> get_guardian!(user.ninja.guardian_id, [:user]) end)
|> then(fn guardian -> guardian.user.email end)
end

alias Bokken.Accounts.Organizer

@doc """
Expand Down
4 changes: 3 additions & 1 deletion lib/bokken/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ defmodule Bokken.Application do
# Start the PubSub system
{Phoenix.PubSub, name: Bokken.PubSub},
# Start the Endpoint (http/https)
BokkenWeb.Endpoint
BokkenWeb.Endpoint,
# Start a worker by calling: Bokken.Worker.start_link(arg)
# {Bokken.Worker, arg}
# Operates cronjob tasks using :quantum
Bokken.Scheduler
]

# See https://hexdocs.pm/elixir/Supervisor.html
Expand Down
26 changes: 26 additions & 0 deletions lib/bokken/birthday_notifier.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Bokken.BirthdayNotifier do
@moduledoc """
Executes a task periodically to notify Ninjas on their birthday.
"""

alias Bokken.Accounts
alias BokkenWeb.EventsEmails
import Bokken.Events.EventAdmin

def send_happy_birthday_ninjas do
ninjas = Accounts.list_ninjas([:user])
current_time = Date.utc_today()

ninjas
|> Enum.filter(fn ninja ->
ninja.birthday.month == current_time.month && ninja.birthday.day == current_time.day &&
not is_nil(ninja.user)
end)
|> Enum.map(fn ninja -> ninja.user end)
|> send_email(fn user ->
EventsEmails.ninja_birthday_email(user.ninja,
to: Accounts.get_guardian_email_by_ninja(ninja: user)
)
Comment on lines +14 to +23
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The situation is as follows. Currently not a single ninja has a registered account, meaning this is basically useless. What we could do is send the email to the guardian if the ninja does not have an account associated with them

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But Ninjas are not even supposed to have emails, when I'm using the .email I thought I was sending it to the guardians right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But ninja.user is nil, meaning you won't send it regardless. It works fine locally because we don't have ninjas without users associated with them (but we should)

end)
end
end
17 changes: 17 additions & 0 deletions lib/bokken/events/event_admin.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule Bokken.Events.EventAdmin do
The admin view config of events
"""
alias Bokken.{Events, Pairings}
alias Bokken.Mailer

def list_actions(_conn) do
[
Expand Down Expand Up @@ -46,4 +47,20 @@ defmodule Bokken.Events.EventAdmin do
enrollments_close: nil
]
end

def send_email(users, email) do
users
|> Enum.reduce(
%{success: [], fail: []},
fn user, accumulator ->
case Mailer.deliver(email.(user)) do
{:ok, _} ->
%{success: [user.email | accumulator[:success]], fail: accumulator[:fail]}

{:error, _} ->
%{success: [accumulator[:success]], fail: [user.email | accumulator[:fail]]}
end
end
)
end
Comment on lines +51 to +65
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR in particular, but I am seeing this function used and duplicated in many different contexts. I think we should create an utils file and put it there. What do you think @RuiL1904?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

end
6 changes: 6 additions & 0 deletions lib/bokken/scheduler.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
defmodule Bokken.Scheduler do
@moduledoc """
Standard module to run a cronjob.
"""
use Quantum, otp_app: :bokken
end
18 changes: 1 addition & 17 deletions lib/bokken_web/controllers/event_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ defmodule BokkenWeb.EventController do
alias Bokken.Accounts
alias Bokken.Events
alias Bokken.Events.Event
alias Bokken.Mailer
alias BokkenWeb.EventsEmails
import Bokken.Events.EventAdmin

action_fallback BokkenWeb.FallbackController

Expand Down Expand Up @@ -143,20 +143,4 @@ defmodule BokkenWeb.EventController do
|> render("emails.json", res)
end
end

defp send_email(users, email) do
users
|> List.foldl(
%{success: [], fail: []},
fn user, accumulator ->
case Mailer.deliver(email.(user)) do
{:ok, _} ->
%{success: [user.email | accumulator[:success]], fail: accumulator[:fail]}

{:error, _} ->
%{success: [accumulator[:success]], fail: [user.email | accumulator[:fail]]}
end
end
)
end
end
7 changes: 7 additions & 0 deletions lib/bokken_web/emails/event_emails.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ defmodule BokkenWeb.EventsEmails do
|> render_body(:mentor_event_reminder)
end

def ninja_birthday_email(ninja, to: email) do
base_email(to: email)
|> subject("O CoderDojo Braga deseja-te um feliz aniversário! 🎂")
|> assign(:ninja, ninja)
|> render_body(:ninja_birthday)
end

defp base_email(to: email) do
new()
|> from({"CoderDojo Braga", "[email protected]"})
Expand Down
72 changes: 72 additions & 0 deletions lib/bokken_web/templates/email/ninja_birthday.html.eex
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<table class="wrapper" style="border-collapse: collapse;table-layout: fixed;min-width: 320px;width: 100%;background-color: #fff;" role="presentation" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div>
<div class="layout one-col fixed-width stack" style="Margin: 0 auto;max-width: 600px;min-width: 320px; width: 320px;width: calc(28000% - 167400px);overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;">
<div class="layout__inner" style="border-collapse: collapse;display: table;width: 100%;background-color: #ffffff;">
<div class="column" style="text-align: left;color: #000;font-size: 16px;line-height: 24px;font-family: Avenir,sans-serif;">

<div style="Margin-left: 20px;Margin-right: 20px;">
<div style="mso-line-height-rule: exactly;line-height: 23px;font-size: 1px;">&nbsp;</div>
</div>

<div style="Margin-left: 20px;Margin-right: 20px;">
<div style="mso-line-height-rule: exactly;mso-text-raise: 11px;vertical-align: middle;">
<h1 style="Margin-top: 16px;Margin-bottom: 20px; text-align:center">
🥳 Aniversário 🥳
</h1>
</div>
</div>

<div style="Margin-left: 20px;Margin-right: 20px;">
<div style="mso-line-height-rule: exactly;mso-text-raise: 11px;vertical-align: middle;">
<p style="Margin-top: 16px;Margin-bottom: 20px; text-align:center">
Olá, <%= @ninja.first_name %>! 👋
</p>
</div>
</div>

<div style="Margin-left: 20px;Margin-right: 20px;">
<div style="mso-line-height-rule: exactly;mso-text-raise: 11px;vertical-align: middle;">
<p style="Margin-top: 16px;Margin-bottom: 20px;">
O CoderDojo Braga deseja-te um feliz aniversário! 🎂 Esperamos por ti na próxima sessão! 😄
</p>
</div>
</div>
</div>
</div>
</div>

<div style="mso-line-height-rule: exactly;line-height: 20px;font-size: 20px;">&nbsp;</div>

<div style="background-color: #ebebeb;">
<div class="layout one-col stack" style="Margin: 0 auto;max-width: 600px;min-width: 320px; width: 320px;width: calc(28000% - 167400px);overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;">
<div class="layout__inner" style="border-collapse: collapse;display: table;width: 100%;">
<div class="column" style="text-align: left;color: #000;font-size: 16px;line-height: 24px;font-family: Avenir,sans-serif;">

<div style="Margin-left: 20px;Margin-right: 20px;">
<div style="mso-line-height-rule: exactly;line-height: 20px;font-size: 1px;">&nbsp;</div>
</div>

<div style="Margin-left: 20px;Margin-right: 20px;">
<div style="mso-line-height-rule: exactly;line-height: 3px;font-size: 1px;">&nbsp;</div>
</div>

<div style="font-size: 12px;font-style: normal;font-weight: normal;line-height: 19px;" align="center">
<a style="text-decoration: underline;transition: opacity 0.1s ease-in;color: #222d8f;" href="https://coderdojobraga.org/"><img style="border: 0;display: block;height: auto;width: 100%;max-width: 134px;" alt="CoderDojo Braga" src="https://coderdojo-braga.vercel.app/img/logo.svg" width="134"></a>
</div>

<div style="Margin-left: 20px;Margin-right: 20px;Margin-top: 20px;">
<div style="mso-line-height-rule: exactly;line-height: 1px;font-size: 1px;">&nbsp;</div>
</div>

</div>
</div>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
3 changes: 3 additions & 0 deletions lib/bokken_web/templates/email/ninja_birthday.text.eex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Olá, <%= @ninja.first_name %>! 👋

O CoderDojo Braga deseja-te um feliz aniversário! 🎂 Esperamos por ti na próxima sessão! 😄
3 changes: 3 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ defmodule Bokken.MixProject do
{:plug_cowboy, "~> 2.5"},
{:cors_plug, "~> 3.0"},

# cronjobs
{:quantum, "~> 3.0"},

# utilities
{:gettext, "~> 0.22.1"},
{:jason, "~> 1.3"},
Expand Down
4 changes: 4 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"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"},
"credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"},
"crontab": {:hex, :crontab, "1.1.13", "3bad04f050b9f7f1c237809e42223999c150656a6b2afbbfef597d56df2144c5", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "d67441bec989640e3afb94e123f45a2bc42d76e02988c9613885dc3d01cf7085"},
"db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"},
Expand All @@ -26,6 +27,7 @@
"expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"},
"faker": {:hex, :faker, "0.17.0", "671019d0652f63aefd8723b72167ecdb284baf7d47ad3a82a15e9b8a6df5d1fa", [:mix], [], "hexpm", "a7d4ad84a93fd25c5f5303510753789fc2433ff241bf3b4144d3f6f291658a6a"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"gen_stage": {:hex, :gen_stage, "1.2.0", "ee49244b57803f54bdab08a60a927e1b4e5bb5d635c52eca0f376a0673af3f8c", [:mix], [], "hexpm", "c3e40992c72e74d9c4eda16d7515bf32c9e7b634e827ab11091fff3290f7b503"},
"gettext": {:hex, :gettext, "0.22.1", "e7942988383c3d9eed4bdc22fc63e712b655ae94a672a27e4900e3d4a2c43581", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "ad105b8dab668ee3f90c0d3d94ba75e9aead27a62495c101d94f2657a190ac5d"},
"guardian": {:hex, :guardian, "2.3.1", "2b2d78dc399a7df182d739ddc0e566d88723299bfac20be36255e2d052fd215d", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bbe241f9ca1b09fad916ad42d6049d2600bbc688aba5b3c4a6c82592a54274c3"},
"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"},
Expand Down Expand Up @@ -54,12 +56,14 @@
"plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
"plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
"postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
"quantum": {:hex, :quantum, "3.5.0", "8d2c5ba68c55991e8975aca368e3ab844ba01f4b87c4185a7403280e2c99cf34", [:mix], [{:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.14 or ~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_registry, "~> 0.2", [hex: :telemetry_registry, repo: "hexpm", optional: false]}], "hexpm", "cab737d1d9779f43cb1d701f46dd05ea58146fd96238d91c9e0da662c1982bb6"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"telemetry_registry": {:hex, :telemetry_registry, "0.3.0", "6768f151ea53fc0fbca70dbff5b20a8d663ee4e0c0b2ae589590e08658e76f1e", [:mix, :rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "492e2adbc609f3e79ece7f29fec363a97a2c484ac78a83098535d6564781e917"},
"timex": {:hex, :timex, "3.7.9", "790cdfc4acfce434e442f98c02ea6d84d0239073bfd668968f82ac63e9a6788d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "64691582e5bb87130f721fc709acfb70f24405833998fabf35be968984860ce1"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
Expand Down