mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
Checkpoint
This commit is contained in:
104
apps/fg_http/lib/fg_http/password_resets.ex
Normal file
104
apps/fg_http/lib/fg_http/password_resets.ex
Normal file
@@ -0,0 +1,104 @@
|
||||
defmodule FgHttp.PasswordResets do
|
||||
@moduledoc """
|
||||
The PasswordResets context.
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias FgHttp.Repo
|
||||
|
||||
alias FgHttp.PasswordResets.PasswordReset
|
||||
|
||||
@doc """
|
||||
Returns the list of password_resets.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_password_resets()
|
||||
[%PasswordReset{}, ...]
|
||||
|
||||
"""
|
||||
def list_password_resets do
|
||||
Repo.all(PasswordReset)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single password_reset.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the Password reset does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_password_reset!(123)
|
||||
%PasswordReset{}
|
||||
|
||||
iex> get_password_reset!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_password_reset!(id), do: Repo.get!(PasswordReset, id)
|
||||
|
||||
@doc """
|
||||
Creates a password_reset.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_password_reset(%{field: value})
|
||||
{:ok, %PasswordReset{}}
|
||||
|
||||
iex> create_password_reset(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_password_reset(attrs \\ %{}) do
|
||||
%PasswordReset{}
|
||||
|> PasswordReset.create_changeset(attrs)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a password_reset.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_password_reset(password_reset, %{field: new_value})
|
||||
{:ok, %PasswordReset{}}
|
||||
|
||||
iex> update_password_reset(password_reset, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_password_reset(%PasswordReset{} = password_reset, attrs) do
|
||||
password_reset
|
||||
|> PasswordReset.update_changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a password_reset.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_password_reset(password_reset)
|
||||
{:ok, %PasswordReset{}}
|
||||
|
||||
iex> delete_password_reset(password_reset)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_password_reset(%PasswordReset{} = password_reset) do
|
||||
Repo.delete(password_reset)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking password_reset changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_password_reset(password_reset)
|
||||
%Ecto.Changeset{data: %PasswordReset{}}
|
||||
|
||||
"""
|
||||
def change_password_reset(%PasswordReset{} = password_reset, attrs \\ %{}) do
|
||||
PasswordReset.changeset(password_reset, attrs)
|
||||
end
|
||||
end
|
||||
64
apps/fg_http/lib/fg_http/password_resets/password_reset.ex
Normal file
64
apps/fg_http/lib/fg_http/password_resets/password_reset.ex
Normal file
@@ -0,0 +1,64 @@
|
||||
defmodule FgHttp.PasswordResets.PasswordReset do
|
||||
@moduledoc """
|
||||
Schema for PasswordReset
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
alias FgHttp.{Users, Users.User}
|
||||
|
||||
@token_num_bytes 8
|
||||
|
||||
schema "password_resets" do
|
||||
field :reset_sent_at, :utc_datetime
|
||||
field :reset_token, :string
|
||||
field :user_email, :string, virtual: true
|
||||
belongs_to :user, User
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(password_reset, attrs) do
|
||||
password_reset
|
||||
|> cast(attrs, [:user_id, :user_email, :reset_sent_at, :reset_token])
|
||||
end
|
||||
|
||||
@doc false
|
||||
def create_changeset(password_reset, attrs) do
|
||||
password_reset
|
||||
|> cast(attrs, [:user_id, :user_email, :reset_sent_at, :reset_token])
|
||||
|> load_user_from_email()
|
||||
|> generate_reset_token()
|
||||
|> validate_required([:reset_token, :user_id])
|
||||
|> unique_constraint(:reset_token)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def update_changeset(password_reset, attrs) do
|
||||
password_reset
|
||||
|> cast(attrs, [:user_id, :user_email, :reset_sent_at, :reset_token])
|
||||
|> validate_required([:reset_token])
|
||||
end
|
||||
|
||||
defp load_user_from_email(
|
||||
%Ecto.Changeset{
|
||||
valid?: true,
|
||||
changes: %{user_email: user_email}
|
||||
} = changeset
|
||||
) do
|
||||
user = Users.get_user!(email: user_email)
|
||||
put_change(changeset, :user_id, user.id)
|
||||
end
|
||||
|
||||
defp load_user_from_email(changeset), do: changeset
|
||||
|
||||
defp generate_reset_token(%Ecto.Changeset{valid?: true} = changeset) do
|
||||
random_bytes = :crypto.strong_rand_bytes(@token_num_bytes)
|
||||
random_string = Base.url_encode64(random_bytes)
|
||||
put_change(changeset, :reset_token, random_string)
|
||||
end
|
||||
|
||||
defp generate_reset_token(changeset), do: changeset
|
||||
end
|
||||
@@ -39,10 +39,6 @@ defmodule FgHttp.Users do
|
||||
Repo.get_by!(User, email: email)
|
||||
end
|
||||
|
||||
def get_user!(reset_token: reset_token) do
|
||||
Repo.get_by!(User, reset_token: reset_token)
|
||||
end
|
||||
|
||||
def get_user!(id), do: Repo.get!(User, id)
|
||||
|
||||
@doc """
|
||||
|
||||
@@ -11,8 +11,6 @@ defmodule FgHttp.Users.User do
|
||||
schema "users" do
|
||||
field :email, :string
|
||||
field :confirmed_at, :utc_datetime
|
||||
field :reset_sent_at, :utc_datetime
|
||||
field :reset_token, :string
|
||||
field :last_signed_in_at, :utc_datetime
|
||||
field :password_hash, :string
|
||||
|
||||
|
||||
@@ -4,35 +4,28 @@ defmodule FgHttpWeb.PasswordResetController do
|
||||
"""
|
||||
|
||||
use FgHttpWeb, :controller
|
||||
alias FgHttp.{Users, Users.User}
|
||||
alias FgHttp.{PasswordResets, PasswordResets.PasswordReset}
|
||||
|
||||
plug FgHttpWeb.Plugs.RedirectAuthenticated
|
||||
|
||||
def new(conn, _params) do
|
||||
changeset = PasswordReset.changeset(%PasswordReset{}, %{})
|
||||
|
||||
conn
|
||||
|> render("new.html", changeset: User.changeset(%User{}))
|
||||
|> render("new.html", changeset: changeset)
|
||||
end
|
||||
|
||||
# Don't actually create anything. Instead, update the user with a reset token and send
|
||||
# the password reset email.
|
||||
def create(conn, %{
|
||||
"password_reset" =>
|
||||
%{
|
||||
reset_token: reset_token,
|
||||
password: _password,
|
||||
password_confirmation: _password_confirmation,
|
||||
current_password: _current_password
|
||||
} = user_params
|
||||
}) do
|
||||
user = Users.get_user!(reset_token: reset_token)
|
||||
|
||||
case Users.update_user(user, user_params) do
|
||||
{:ok, _user} ->
|
||||
def create(conn, %{"password_reset" => %{"user_email" => _} = password_reset_params}) do
|
||||
case PasswordResets.create_password_reset(password_reset_params) do
|
||||
{:ok, _password_reset} ->
|
||||
conn
|
||||
|> render("success.html")
|
||||
|> clear_session()
|
||||
|> put_flash(:info, "Password reset successfully. Please sign in with your new password.")
|
||||
|> redirect(to: Routes.session_path(conn, :new))
|
||||
|
||||
{:error, changeset} ->
|
||||
conn
|
||||
|> put_flash(:error, "Error creating password reset.")
|
||||
|> render("new.html", changeset: changeset)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,6 +20,8 @@ defmodule FgHttpWeb.Router do
|
||||
scope "/", FgHttpWeb do
|
||||
pipe_through :browser
|
||||
|
||||
resources "/password_resets", PasswordResetController, only: [:new, :create]
|
||||
|
||||
resources "/user", UserController, singleton: true, only: [:show, :edit, :update, :delete]
|
||||
resources "/users", UserController, only: [:new, :create]
|
||||
|
||||
|
||||
@@ -14,16 +14,17 @@
|
||||
<nav class="f6 fw6 ttu tracked fl">
|
||||
<%= link("Fireguard", to: FgHttpWeb.Endpoint.url(), class: "link dim white dib mr3") %>
|
||||
</nav>
|
||||
<%= if @user_signed_in? do %>
|
||||
<nav class="f6 fw6 ttu tracked fr">
|
||||
<nav class="f6 fw6 ttu tracked fr">
|
||||
<%= if @user_signed_in? do %>
|
||||
<%= link("Devices", to: Routes.device_path(@conn, :index), class: "link dim white dib mr3") %>
|
||||
<%= link("Sign out", to: Routes.session_path(@conn, :delete, @current_session), method: :delete, class: "link dim white dib mr3") %>
|
||||
</nav>
|
||||
<% else %>
|
||||
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= link("Sign in", to: Routes.session_path(@conn, :new), class: "link dim white dib mr3") %>
|
||||
<% end %>
|
||||
</nav>
|
||||
</header>
|
||||
<main class="mw7 mw9-ns center pa3 pt5 ph5-ns">
|
||||
<%= render_flash(@conn) %>
|
||||
<%= @inner_content %>
|
||||
</main>
|
||||
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<h1>Edit Password reset</h1>
|
||||
|
||||
<%= render "form.html", Map.put(assigns, :action, Routes.password_reset_path(@conn, :update, @password_reset)) %>
|
||||
|
||||
<span><%= link "Back", to: Routes.password_reset_path(@conn, :index) %></span>
|
||||
@@ -0,0 +1,19 @@
|
||||
<%= form_for @changeset, @action, fn f -> %>
|
||||
<%= if @changeset.action do %>
|
||||
<div class="alert alert-danger">
|
||||
<p>Oops, something went wrong! Please check the errors below.</p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= label f, :reset_sent_at %>
|
||||
<%= datetime_select f, :reset_sent_at %>
|
||||
<%= error_tag f, :reset_sent_at %>
|
||||
|
||||
<%= label f, :reset_token %>
|
||||
<%= text_input f, :reset_token %>
|
||||
<%= error_tag f, :reset_token %>
|
||||
|
||||
<div>
|
||||
<%= submit "Save" %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -0,0 +1,28 @@
|
||||
<h1>Listing Password resets</h1>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Reset sent at</th>
|
||||
<th>Reset token</th>
|
||||
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= for password_reset <- @password_resets do %>
|
||||
<tr>
|
||||
<td><%= password_reset.reset_sent_at %></td>
|
||||
<td><%= password_reset.reset_token %></td>
|
||||
|
||||
<td>
|
||||
<span><%= link "Show", to: Routes.password_reset_path(@conn, :show, password_reset) %></span>
|
||||
<span><%= link "Edit", to: Routes.password_reset_path(@conn, :edit, password_reset) %></span>
|
||||
<span><%= link "Delete", to: Routes.password_reset_path(@conn, :delete, password_reset), method: :delete, data: [confirm: "Are you sure?"] %></span>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<span><%= link "New Password reset", to: Routes.password_reset_path(@conn, :new) %></span>
|
||||
@@ -0,0 +1,5 @@
|
||||
<h1>New Password reset</h1>
|
||||
|
||||
<%= render "form.html", Map.put(assigns, :action, Routes.password_reset_path(@conn, :create)) %>
|
||||
|
||||
<span><%= link "Back", to: Routes.session_path(@conn, :new) %></span>
|
||||
@@ -0,0 +1,18 @@
|
||||
<h1>Show Password reset</h1>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<strong>Reset sent at:</strong>
|
||||
<%= @password_reset.reset_sent_at %>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<strong>Reset token:</strong>
|
||||
<%= @password_reset.reset_token %>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<span><%= link "Edit", to: Routes.password_reset_path(@conn, :edit, @password_reset) %></span>
|
||||
<span><%= link "Back", to: Routes.password_reset_path(@conn, :index) %></span>
|
||||
@@ -1,3 +1,20 @@
|
||||
defmodule FgHttpWeb.LayoutView do
|
||||
use FgHttpWeb, :view
|
||||
|
||||
def render_flash(conn) do
|
||||
~E"""
|
||||
<section id="flash">
|
||||
<%= if get_flash(conn, :error) do %>
|
||||
<div id="flash-error">
|
||||
<%= get_flash(conn, :error) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= if get_flash(conn, :error) do %>
|
||||
<div id="flash-error">
|
||||
<%= get_flash(conn, :error) %>
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
defmodule FgHttpWeb.PasswordResetView do
|
||||
use FgHttpWeb, :view
|
||||
end
|
||||
@@ -7,8 +7,6 @@ defmodule FgHttp.Repo.Migrations.CreateUsers do
|
||||
add :confirmed_at, :utc_datetime
|
||||
add :password_hash, :string
|
||||
add :last_signed_in_at, :utc_datetime
|
||||
add :reset_sent_at, :utc_datetime
|
||||
add :reset_token, :utc_datetime
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
defmodule FgHttp.Repo.Migrations.CreatePasswordResets do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create table(:password_resets) do
|
||||
add :reset_sent_at, :utc_datetime
|
||||
add :reset_token, :string, null: false
|
||||
add :user_id, references(:users, on_delete: :delete_all), null: false
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
create unique_index(:password_resets, [:reset_token])
|
||||
create index(:password_resets, [:user_id])
|
||||
end
|
||||
end
|
||||
87
apps/fg_http/test/fg_http/password_resets_test.exs
Normal file
87
apps/fg_http/test/fg_http/password_resets_test.exs
Normal file
@@ -0,0 +1,87 @@
|
||||
defmodule FgHttp.PasswordResetsTest do
|
||||
use FgHttp.DataCase
|
||||
|
||||
alias FgHttp.{Fixtures, PasswordResets}
|
||||
|
||||
describe "password_resets" do
|
||||
alias FgHttp.PasswordResets.PasswordReset
|
||||
|
||||
@valid_attrs %{reset_sent_at: "2010-04-17T14:00:00Z"}
|
||||
@update_attrs %{reset_sent_at: "2011-05-18T15:01:01Z"}
|
||||
@invalid_attrs %{reset_sent_at: nil}
|
||||
|
||||
def password_reset_fixture(attrs \\ %{}) do
|
||||
{:ok, password_reset} =
|
||||
attrs
|
||||
|> Enum.into(%{user_id: Fixtures.user().id})
|
||||
|> Enum.into(@valid_attrs)
|
||||
|> PasswordResets.create_password_reset()
|
||||
|
||||
password_reset
|
||||
end
|
||||
|
||||
test "list_password_resets/0 returns all password_resets" do
|
||||
password_reset = password_reset_fixture()
|
||||
assert PasswordResets.list_password_resets() == [password_reset]
|
||||
end
|
||||
|
||||
test "get_password_reset!/1 returns the password_reset with given id" do
|
||||
password_reset = password_reset_fixture()
|
||||
assert PasswordResets.get_password_reset!(password_reset.id) == password_reset
|
||||
end
|
||||
|
||||
test "create_password_reset/1 with valid data creates a password_reset" do
|
||||
user_id = Fixtures.user().id
|
||||
valid_attrs = Map.merge(@valid_attrs, %{user_id: user_id})
|
||||
|
||||
assert {:ok, %PasswordReset{} = password_reset} =
|
||||
PasswordResets.create_password_reset(valid_attrs)
|
||||
|
||||
assert password_reset.reset_sent_at ==
|
||||
DateTime.from_naive!(~N[2010-04-17T14:00:00Z], "Etc/UTC")
|
||||
|
||||
assert password_reset.reset_token
|
||||
assert password_reset.user_id == user_id
|
||||
end
|
||||
|
||||
test "create_password_reset/1 with invalid data returns error changeset" do
|
||||
assert {:error, %Ecto.Changeset{}} = PasswordResets.create_password_reset(@invalid_attrs)
|
||||
end
|
||||
|
||||
test "update_password_reset/2 with valid data updates the password_reset" do
|
||||
password_reset = password_reset_fixture()
|
||||
|
||||
assert {:ok, %PasswordReset{} = password_reset} =
|
||||
PasswordResets.update_password_reset(password_reset, @update_attrs)
|
||||
|
||||
assert password_reset.reset_sent_at ==
|
||||
DateTime.from_naive!(~N[2011-05-18T15:01:01Z], "Etc/UTC")
|
||||
|
||||
assert password_reset.reset_token
|
||||
end
|
||||
|
||||
test "update_password_reset/2 with invalid data returns error changeset" do
|
||||
invalid_attrs = Map.merge(@invalid_attrs, %{reset_token: nil})
|
||||
password_reset = password_reset_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} =
|
||||
PasswordResets.update_password_reset(password_reset, invalid_attrs)
|
||||
|
||||
assert password_reset == PasswordResets.get_password_reset!(password_reset.id)
|
||||
end
|
||||
|
||||
test "delete_password_reset/1 deletes the password_reset" do
|
||||
password_reset = password_reset_fixture()
|
||||
assert {:ok, %PasswordReset{}} = PasswordResets.delete_password_reset(password_reset)
|
||||
|
||||
assert_raise Ecto.NoResultsError, fn ->
|
||||
PasswordResets.get_password_reset!(password_reset.id)
|
||||
end
|
||||
end
|
||||
|
||||
test "change_password_reset/1 returns a password_reset changeset" do
|
||||
password_reset = password_reset_fixture()
|
||||
assert %Ecto.Changeset{} = PasswordResets.change_password_reset(password_reset)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
defmodule FgHttpWeb.DeviceControllerTest do
|
||||
use FgHttpWeb.ConnCase, async: true
|
||||
|
||||
import FgHttp.Fixtures
|
||||
alias FgHttp.Fixtures
|
||||
|
||||
@create_attrs %{public_key: "foobar"}
|
||||
@update_attrs %{name: "some updated name"}
|
||||
@@ -73,7 +73,7 @@ defmodule FgHttpWeb.DeviceControllerTest do
|
||||
end
|
||||
|
||||
defp create_device(_) do
|
||||
device = fixture(:device)
|
||||
device = Fixtures.device()
|
||||
{:ok, device: device}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
defmodule FgHttpWeb.PasswordResetControllerTest do
|
||||
use FgHttpWeb.ConnCase, async: true
|
||||
|
||||
@create_attrs %{user_email: "test"}
|
||||
|
||||
describe "new password_reset" do
|
||||
test "renders form", %{unauthed_conn: conn} do
|
||||
conn = get(conn, Routes.password_reset_path(conn, :new))
|
||||
assert html_response(conn, 200) =~ "New Password reset"
|
||||
end
|
||||
end
|
||||
|
||||
describe "create password_reset" do
|
||||
test "redirects to sign in when data is valid", %{unauthed_conn: conn} do
|
||||
conn = post(conn, Routes.password_reset_path(conn, :create), password_reset: @create_attrs)
|
||||
|
||||
assert redirected_to(conn) == Routes.session_path(conn, :new)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -19,7 +19,7 @@ defmodule FgHttpWeb.ConnCase do
|
||||
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
import FgHttp.Fixtures
|
||||
alias FgHttp.Fixtures
|
||||
|
||||
using do
|
||||
quote do
|
||||
@@ -38,10 +38,10 @@ defmodule FgHttpWeb.ConnCase do
|
||||
end
|
||||
|
||||
def authed_conn do
|
||||
user = fixture(:user)
|
||||
user = Fixtures.user()
|
||||
|
||||
session =
|
||||
fixture(:session, %{
|
||||
Fixtures.session(%{
|
||||
user_id: user.id,
|
||||
user_password: "test",
|
||||
user_email: "test"
|
||||
|
||||
@@ -2,12 +2,15 @@ defmodule FgHttp.Fixtures do
|
||||
@moduledoc """
|
||||
Convenience helpers for inserting records
|
||||
"""
|
||||
alias FgHttp.{Devices, Repo, Sessions, Users, Users.User}
|
||||
alias FgHttp.{Devices, PasswordResets, Repo, Sessions, Users, Users.User}
|
||||
|
||||
def fixture(:user) do
|
||||
def user(attrs \\ %{}) do
|
||||
case Repo.get_by(User, email: "test") do
|
||||
nil ->
|
||||
attrs = %{email: "test", password: "test", password_confirmation: "test"}
|
||||
attrs =
|
||||
attrs
|
||||
|> Enum.into(%{email: "test", password: "test", password_confirmation: "test"})
|
||||
|
||||
{:ok, user} = Users.create_user(attrs)
|
||||
user
|
||||
|
||||
@@ -16,13 +19,24 @@ defmodule FgHttp.Fixtures do
|
||||
end
|
||||
end
|
||||
|
||||
def fixture(:device) do
|
||||
attrs = %{public_key: "foobar", ifname: "wg0", name: "factory"}
|
||||
{:ok, device} = Devices.create_device(Map.merge(%{user_id: fixture(:user).id}, attrs))
|
||||
def device(attrs \\ %{}) do
|
||||
attrs =
|
||||
attrs
|
||||
|> Enum.into(%{user_id: user().id})
|
||||
|> Enum.into(%{public_key: "foobar", ifname: "wg0", name: "factory"})
|
||||
|
||||
{:ok, device} = Devices.create_device(attrs)
|
||||
device
|
||||
end
|
||||
|
||||
def fixture(:session, attrs \\ %{}) do
|
||||
{:ok, _session} = Sessions.create_session(attrs)
|
||||
def session(attrs \\ %{}) do
|
||||
{:ok, session} = Sessions.create_session(attrs)
|
||||
session
|
||||
end
|
||||
|
||||
def password_reset(attrs \\ %{}) do
|
||||
create_attrs = Map.merge(attrs, %{user_email: user().email})
|
||||
{:ok, password_reset} = PasswordResets.create_password_reset(create_attrs)
|
||||
password_reset
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user