forked from shibao/cannery
fix dialyzer, credo and format
This commit is contained in:
parent
f5b3eb4a5e
commit
04d798aaa7
@ -4,8 +4,9 @@ defmodule Cannery.Accounts do
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Cannery.{Repo}
|
||||
alias Cannery.Accounts.{User, UserToken, UserNotifier}
|
||||
alias Cannery.Repo
|
||||
alias Cannery.Accounts.{User, UserNotifier, UserToken}
|
||||
alias Ecto.{Changeset, Multi}
|
||||
|
||||
## Database getters
|
||||
|
||||
@ -89,10 +90,10 @@ defmodule Cannery.Accounts do
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> register_user(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
{:error, %Changeset{}}
|
||||
|
||||
"""
|
||||
@spec register_user(map()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
@spec register_user(map()) :: {:ok, User.t()} | {:error, Changeset.t()}
|
||||
def register_user(attrs) do
|
||||
# if no registered users, make first user an admin
|
||||
attrs =
|
||||
@ -104,15 +105,16 @@ defmodule Cannery.Accounts do
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking user changes.
|
||||
Returns an `%Changeset{}` for tracking user changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_user_registration(user)
|
||||
%Ecto.Changeset{data: %User{}}
|
||||
%Changeset{data: %User{}}
|
||||
|
||||
"""
|
||||
@spec change_user_registration(User.t(), map()) :: Ecto.Changeset.t()
|
||||
@spec change_user_registration(User.t() | User.new_user()) :: Changeset.t()
|
||||
@spec change_user_registration(User.t() | User.new_user(), map()) :: Changeset.t()
|
||||
def change_user_registration(user, attrs \\ %{}) do
|
||||
User.registration_changeset(user, attrs, hash_password: false)
|
||||
end
|
||||
@ -120,29 +122,29 @@ defmodule Cannery.Accounts do
|
||||
## Settings
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for changing the user email.
|
||||
Returns an `%Changeset{}` for changing the user email.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_user_email(user)
|
||||
%Ecto.Changeset{data: %User{}}
|
||||
%Changeset{data: %User{}}
|
||||
|
||||
"""
|
||||
@spec change_user_email(User.t(), map()) :: Ecto.Changeset.t()
|
||||
@spec change_user_email(User.t(), map()) :: Changeset.t()
|
||||
def change_user_email(user, attrs \\ %{}) do
|
||||
User.email_changeset(user, attrs)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for changing the user role.
|
||||
Returns an `%Changeset{}` for changing the user role.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_user_role(user)
|
||||
%Ecto.Changeset{data: %User{}}
|
||||
%Changeset{data: %User{}}
|
||||
|
||||
"""
|
||||
@spec change_user_role(User.t(), atom()) :: Ecto.Changeset.t()
|
||||
@spec change_user_role(User.t(), atom()) :: Changeset.t()
|
||||
def change_user_role(user, role) do
|
||||
User.role_changeset(user, role)
|
||||
end
|
||||
@ -157,16 +159,16 @@ defmodule Cannery.Accounts do
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> apply_user_email(user, "invalid password", %{email: ...})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
{:error, %Changeset{}}
|
||||
|
||||
"""
|
||||
@spec apply_user_email(User.t(), String.t(), map()) ::
|
||||
{:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
{:ok, User.t()} | {:error, Changeset.t()}
|
||||
def apply_user_email(user, password, attrs) do
|
||||
user
|
||||
|> User.email_changeset(attrs)
|
||||
|> User.validate_current_password(password)
|
||||
|> Ecto.Changeset.apply_action(:update)
|
||||
|> Changeset.apply_action(:update)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@ -175,7 +177,7 @@ defmodule Cannery.Accounts do
|
||||
If the token matches, the user email is updated and the token is deleted.
|
||||
The confirmed_at date is also updated to the current time.
|
||||
"""
|
||||
@spec update_user_email(User.t(), UserToken.t()) :: {:ok, any()} | :error
|
||||
@spec update_user_email(User.t(), String.t()) :: :ok | :error
|
||||
def update_user_email(user, token) do
|
||||
context = "change:#{user.email}"
|
||||
|
||||
@ -188,12 +190,13 @@ defmodule Cannery.Accounts do
|
||||
end
|
||||
end
|
||||
|
||||
@spec user_email_multi(User.t(), String.t(), String.t()) :: Multi.t()
|
||||
defp user_email_multi(user, email, context) do
|
||||
changeset = user |> User.email_changeset(%{email: email}) |> User.confirm_changeset()
|
||||
|
||||
Ecto.Multi.new()
|
||||
|> Ecto.Multi.update(:user, changeset)
|
||||
|> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, [context]))
|
||||
Multi.new()
|
||||
|> Multi.update(:user, changeset)
|
||||
|> Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, [context]))
|
||||
end
|
||||
|
||||
@doc """
|
||||
@ -216,15 +219,15 @@ defmodule Cannery.Accounts do
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for changing the user password.
|
||||
Returns an `%Changeset{}` for changing the user password.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_user_password(user)
|
||||
%Ecto.Changeset{data: %User{}}
|
||||
%Changeset{data: %User{}}
|
||||
|
||||
"""
|
||||
@spec change_user_password(User.t(), map()) :: Ecto.Changeset.t()
|
||||
@spec change_user_password(User.t(), map()) :: Changeset.t()
|
||||
def change_user_password(user, attrs \\ %{}) do
|
||||
User.password_changeset(user, attrs, hash_password: false)
|
||||
end
|
||||
@ -238,20 +241,20 @@ defmodule Cannery.Accounts do
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> update_user_password(user, "invalid password", %{password: ...})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
{:error, %Changeset{}}
|
||||
|
||||
"""
|
||||
@spec update_user_password(User.t(), String.t(), map()) ::
|
||||
{:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
{:ok, User.t()} | {:error, Changeset.t()}
|
||||
def update_user_password(user, password, attrs) do
|
||||
changeset =
|
||||
user
|
||||
|> User.password_changeset(attrs)
|
||||
|> User.validate_current_password(password)
|
||||
|
||||
Ecto.Multi.new()
|
||||
|> Ecto.Multi.update(:user, changeset)
|
||||
|> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, :all))
|
||||
Multi.new()
|
||||
|> Multi.update(:user, changeset)
|
||||
|> Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, :all))
|
||||
|> Repo.transaction()
|
||||
|> case do
|
||||
{:ok, %{user: user}} -> {:ok, user}
|
||||
@ -269,7 +272,7 @@ defmodule Cannery.Accounts do
|
||||
@doc """
|
||||
Generates a session token.
|
||||
"""
|
||||
@spec generate_user_session_token(User.t()) :: UserToken.t()
|
||||
@spec generate_user_session_token(User.t()) :: String.t()
|
||||
def generate_user_session_token(user) do
|
||||
{token, user_token} = UserToken.build_session_token(user)
|
||||
Repo.insert!(user_token)
|
||||
@ -279,7 +282,7 @@ defmodule Cannery.Accounts do
|
||||
@doc """
|
||||
Gets the user with the given signed token.
|
||||
"""
|
||||
@spec get_user_by_session_token(UserToken.t()) :: User.t()
|
||||
@spec get_user_by_session_token(String.t()) :: User.t()
|
||||
def get_user_by_session_token(token) do
|
||||
{:ok, query} = UserToken.verify_session_token_query(token)
|
||||
Repo.one(query)
|
||||
@ -288,7 +291,7 @@ defmodule Cannery.Accounts do
|
||||
@doc """
|
||||
Deletes the signed token with the given context.
|
||||
"""
|
||||
@spec delete_session_token(UserToken.t()) :: :ok
|
||||
@spec delete_session_token(String.t()) :: :ok
|
||||
def delete_session_token(token) do
|
||||
Repo.delete_all(UserToken.token_and_context_query(token, "session"))
|
||||
:ok
|
||||
@ -298,7 +301,7 @@ defmodule Cannery.Accounts do
|
||||
Returns a boolean if registration is allowed or not
|
||||
"""
|
||||
@spec allow_registration?() :: boolean()
|
||||
def allow_registration?() do
|
||||
def allow_registration? do
|
||||
Application.get_env(:cannery, CanneryWeb.Endpoint)[:registration] == "public" or
|
||||
list_users_by_role(:admin) |> Enum.empty?()
|
||||
end
|
||||
@ -336,7 +339,7 @@ defmodule Cannery.Accounts do
|
||||
If the token matches, the user account is marked as confirmed
|
||||
and the token is deleted.
|
||||
"""
|
||||
@spec confirm_user(UserToken.t()) :: {:ok, User.t()} | atom()
|
||||
@spec confirm_user(String.t()) :: {:ok, User.t()} | atom()
|
||||
def confirm_user(token) do
|
||||
with {:ok, query} <- UserToken.verify_email_token_query(token, "confirm"),
|
||||
%User{} = user <- Repo.one(query),
|
||||
@ -348,9 +351,9 @@ defmodule Cannery.Accounts do
|
||||
end
|
||||
|
||||
defp confirm_user_multi(user) do
|
||||
Ecto.Multi.new()
|
||||
|> Ecto.Multi.update(:user, User.confirm_changeset(user))
|
||||
|> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, ["confirm"]))
|
||||
Multi.new()
|
||||
|> Multi.update(:user, User.confirm_changeset(user))
|
||||
|> Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, ["confirm"]))
|
||||
end
|
||||
|
||||
## Reset password
|
||||
@ -385,7 +388,7 @@ defmodule Cannery.Accounts do
|
||||
nil
|
||||
|
||||
"""
|
||||
@spec get_user_by_reset_password_token(UserToken.t()) :: User.t() | nil
|
||||
@spec get_user_by_reset_password_token(String.t()) :: User.t() | nil
|
||||
def get_user_by_reset_password_token(token) do
|
||||
with {:ok, query} <- UserToken.verify_email_token_query(token, "reset_password"),
|
||||
%User{} = user <- Repo.one(query) do
|
||||
@ -404,14 +407,14 @@ defmodule Cannery.Accounts do
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> reset_user_password(user, %{password: "valid", password_confirmation: "not the same"})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
{:error, %Changeset{}}
|
||||
|
||||
"""
|
||||
@spec reset_user_password(User.t(), map()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
@spec reset_user_password(User.t(), map()) :: {:ok, User.t()} | {:error, Changeset.t()}
|
||||
def reset_user_password(user, attrs) do
|
||||
Ecto.Multi.new()
|
||||
|> Ecto.Multi.update(:user, User.password_changeset(user, attrs))
|
||||
|> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, :all))
|
||||
Multi.new()
|
||||
|> Multi.update(:user, User.password_changeset(user, attrs))
|
||||
|> Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, :all))
|
||||
|> Repo.transaction()
|
||||
|> case do
|
||||
{:ok, %{user: user}} -> {:ok, user}
|
||||
|
@ -1,8 +1,12 @@
|
||||
defmodule Cannery.Accounts.User do
|
||||
@moduledoc """
|
||||
A cannery user
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Cannery.Accounts.{User}
|
||||
alias Cannery.Invites.{Invite}
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Cannery.{Accounts.User, Invites.Invite}
|
||||
|
||||
@derive {Inspect, except: [:password]}
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@ -19,8 +23,8 @@ defmodule Cannery.Accounts.User do
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@type t :: %{
|
||||
id: Ecto.UUID.t(),
|
||||
@type t :: %User{
|
||||
id: UUID.t(),
|
||||
email: String.t(),
|
||||
password: String.t(),
|
||||
hashed_password: String.t(),
|
||||
@ -31,6 +35,8 @@ defmodule Cannery.Accounts.User do
|
||||
updated_at: NaiveDateTime.t()
|
||||
}
|
||||
|
||||
@type new_user :: %User{}
|
||||
|
||||
@doc """
|
||||
A user changeset for registration.
|
||||
|
||||
@ -48,8 +54,8 @@ defmodule Cannery.Accounts.User do
|
||||
validations on a LiveView form), this option can be set to `false`.
|
||||
Defaults to `true`.
|
||||
"""
|
||||
@spec registration_changeset(User.t(), map()) :: Ecto.Changeset.t()
|
||||
@spec registration_changeset(User.t(), map(), keyword()) :: Ecto.Changeset.t()
|
||||
@spec registration_changeset(User.t() | User.new_user(), map()) :: Changeset.t()
|
||||
@spec registration_changeset(User.t() | User.new_user(), map(), keyword()) :: Changeset.t()
|
||||
def registration_changeset(user, attrs, opts \\ []) do
|
||||
user
|
||||
|> cast(attrs, [:email, :password, :role])
|
||||
@ -61,12 +67,12 @@ defmodule Cannery.Accounts.User do
|
||||
A user changeset for role.
|
||||
|
||||
"""
|
||||
@spec role_changeset(User.t(), atom()) :: Ecto.Changeset.t()
|
||||
@spec role_changeset(User.t(), atom()) :: Changeset.t()
|
||||
def role_changeset(user, role) do
|
||||
user |> cast(%{"role" => role}, [:role])
|
||||
end
|
||||
|
||||
@spec validate_email(Ecto.Changeset.t()) :: Ecto.Changeset.t()
|
||||
@spec validate_email(Changeset.t()) :: Changeset.t()
|
||||
defp validate_email(changeset) do
|
||||
changeset
|
||||
|> validate_required([:email])
|
||||
@ -76,7 +82,7 @@ defmodule Cannery.Accounts.User do
|
||||
|> unique_constraint(:email)
|
||||
end
|
||||
|
||||
@spec validate_password(Ecto.Changeset.t(), keyword()) :: Ecto.Changeset.t()
|
||||
@spec validate_password(Changeset.t(), keyword()) :: Changeset.t()
|
||||
defp validate_password(changeset, opts) do
|
||||
changeset
|
||||
|> validate_required([:password])
|
||||
@ -87,7 +93,7 @@ defmodule Cannery.Accounts.User do
|
||||
|> maybe_hash_password(opts)
|
||||
end
|
||||
|
||||
@spec maybe_hash_password(Ecto.Changeset.t(), keyword()) :: Ecto.Changeset.t()
|
||||
@spec maybe_hash_password(Changeset.t(), keyword()) :: Changeset.t()
|
||||
defp maybe_hash_password(changeset, opts) do
|
||||
hash_password? = Keyword.get(opts, :hash_password, true)
|
||||
password = get_change(changeset, :password)
|
||||
@ -106,7 +112,7 @@ defmodule Cannery.Accounts.User do
|
||||
|
||||
It requires the email to change otherwise an error is added.
|
||||
"""
|
||||
@spec email_changeset(User.t(), map()) :: Ecto.Changeset.t()
|
||||
@spec email_changeset(User.t(), map()) :: Changeset.t()
|
||||
def email_changeset(user, attrs) do
|
||||
user
|
||||
|> cast(attrs, [:email])
|
||||
@ -129,8 +135,8 @@ defmodule Cannery.Accounts.User do
|
||||
validations on a LiveView form), this option can be set to `false`.
|
||||
Defaults to `true`.
|
||||
"""
|
||||
@spec password_changeset(User.t(), map()) :: Ecto.Changeset.t()
|
||||
@spec password_changeset(User.t(), map(), keyword()) :: Ecto.Changeset.t()
|
||||
@spec password_changeset(User.t(), map()) :: Changeset.t()
|
||||
@spec password_changeset(User.t(), map(), keyword()) :: Changeset.t()
|
||||
def password_changeset(user, attrs, opts \\ []) do
|
||||
user
|
||||
|> cast(attrs, [:password])
|
||||
@ -141,10 +147,10 @@ defmodule Cannery.Accounts.User do
|
||||
@doc """
|
||||
Confirms the account by setting `confirmed_at`.
|
||||
"""
|
||||
@spec confirm_changeset(User.t()) :: Ecto.Changeset.t()
|
||||
def confirm_changeset(user) do
|
||||
@spec confirm_changeset(User.t() | Changeset.t()) :: Changeset.t()
|
||||
def confirm_changeset(user_or_changeset) do
|
||||
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
|
||||
change(user, confirmed_at: now)
|
||||
user_or_changeset |> change(confirmed_at: now)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@ -167,12 +173,10 @@ defmodule Cannery.Accounts.User do
|
||||
@doc """
|
||||
Validates the current password otherwise adds an error to the changeset.
|
||||
"""
|
||||
@spec validate_current_password(Ecto.Changeset.t(), String.t()) :: Ecto.UUID.t()
|
||||
@spec validate_current_password(Changeset.t(), String.t()) :: Changeset.t()
|
||||
def validate_current_password(changeset, password) do
|
||||
if valid_password?(changeset.data, password) do
|
||||
changeset
|
||||
else
|
||||
add_error(changeset, :current_password, "is not valid")
|
||||
end
|
||||
if valid_password?(changeset.data, password),
|
||||
do: changeset,
|
||||
else: changeset |> add_error(:current_password, "is not valid")
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule Cannery.Accounts.UserNotifier do
|
||||
@moduledoc """
|
||||
Contains all user emails and notifications
|
||||
"""
|
||||
|
||||
# For simplicity, this module simply logs messages to the terminal.
|
||||
# You should replace it by a proper email or notification tool, such as:
|
||||
#
|
||||
|
@ -1,7 +1,12 @@
|
||||
defmodule Cannery.Accounts.UserToken do
|
||||
@moduledoc """
|
||||
Schema for serialized user session and authentication tokens
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Query
|
||||
alias Cannery.{Accounts}
|
||||
alias Ecto.{Query, UUID}
|
||||
alias Cannery.{Accounts.User, Accounts.UserToken}
|
||||
|
||||
@hash_algorithm :sha256
|
||||
@rand_size 32
|
||||
@ -19,19 +24,33 @@ defmodule Cannery.Accounts.UserToken do
|
||||
field :token, :binary
|
||||
field :context, :string
|
||||
field :sent_to, :string
|
||||
belongs_to :user, Accounts.User
|
||||
|
||||
belongs_to :user, User
|
||||
|
||||
timestamps(updated_at: false)
|
||||
end
|
||||
|
||||
@type t :: %UserToken{
|
||||
id: UUID.t(),
|
||||
token: String.t(),
|
||||
context: String.t(),
|
||||
sent_to: String.t(),
|
||||
user: User.t(),
|
||||
user_id: UUID.t(),
|
||||
inserted_at: NaiveDateTime.t()
|
||||
}
|
||||
|
||||
@type new_token :: %UserToken{}
|
||||
|
||||
@doc """
|
||||
Generates a token that will be stored in a signed place,
|
||||
such as session or cookie. As they are signed, those
|
||||
tokens do not need to be hashed.
|
||||
"""
|
||||
def build_session_token(user) do
|
||||
@spec build_session_token(User.t()) :: {token :: String.t(), UserToken.new_token()}
|
||||
def build_session_token(%{id: user_id}) do
|
||||
token = :crypto.strong_rand_bytes(@rand_size)
|
||||
{token, %Accounts.UserToken{token: token, context: "session", user_id: user.id}}
|
||||
{token, %UserToken{token: token, context: "session", user_id: user_id}}
|
||||
end
|
||||
|
||||
@doc """
|
||||
@ -39,6 +58,7 @@ defmodule Cannery.Accounts.UserToken do
|
||||
|
||||
The query returns the user found by the token.
|
||||
"""
|
||||
@spec verify_session_token_query(String.t()) :: {:ok, Query.t()}
|
||||
def verify_session_token_query(token) do
|
||||
query =
|
||||
from token in token_and_context_query(token, "session"),
|
||||
@ -57,16 +77,19 @@ defmodule Cannery.Accounts.UserToken do
|
||||
The token is valid for a week as long as users don't change
|
||||
their email.
|
||||
"""
|
||||
@spec build_email_token(User.t(), String.t()) :: {String.t(), UserToken.new_token()}
|
||||
def build_email_token(user, context) do
|
||||
build_hashed_token(user, context, user.email)
|
||||
end
|
||||
|
||||
@spec build_hashed_token(User.t(), String.t(), String.t()) ::
|
||||
{String.t(), UserToken.new_token()}
|
||||
defp build_hashed_token(user, context, sent_to) do
|
||||
token = :crypto.strong_rand_bytes(@rand_size)
|
||||
hashed_token = :crypto.hash(@hash_algorithm, token)
|
||||
|
||||
{Base.url_encode64(token, padding: false),
|
||||
%Accounts.UserToken{
|
||||
%UserToken{
|
||||
token: hashed_token,
|
||||
context: context,
|
||||
sent_to: sent_to,
|
||||
@ -79,6 +102,7 @@ defmodule Cannery.Accounts.UserToken do
|
||||
|
||||
The query returns the user found by the token.
|
||||
"""
|
||||
@spec verify_email_token_query(String.t(), String.t()) :: {:ok, Query.t()} | :error
|
||||
def verify_email_token_query(token, context) do
|
||||
case Base.url_decode64(token, padding: false) do
|
||||
{:ok, decoded_token} ->
|
||||
@ -98,6 +122,7 @@ defmodule Cannery.Accounts.UserToken do
|
||||
end
|
||||
end
|
||||
|
||||
@spec days_for_context(<<_::56>>) :: non_neg_integer()
|
||||
defp days_for_context("confirm"), do: @confirm_validity_in_days
|
||||
defp days_for_context("reset_password"), do: @reset_password_validity_in_days
|
||||
|
||||
@ -106,6 +131,7 @@ defmodule Cannery.Accounts.UserToken do
|
||||
|
||||
The query returns the user token record.
|
||||
"""
|
||||
@spec verify_change_email_token_query(String.t(), String.t()) :: {:ok, Query.t()} | :error
|
||||
def verify_change_email_token_query(token, context) do
|
||||
case Base.url_decode64(token, padding: false) do
|
||||
{:ok, decoded_token} ->
|
||||
@ -125,18 +151,20 @@ defmodule Cannery.Accounts.UserToken do
|
||||
@doc """
|
||||
Returns the given token with the given context.
|
||||
"""
|
||||
@spec token_and_context_query(String.t(), String.t()) :: Query.t()
|
||||
@spec token_and_context_query(User.t(), :all | nonempty_maybe_improper_list()) :: Query.t()
|
||||
def token_and_context_query(token, context) do
|
||||
from Accounts.UserToken, where: [token: ^token, context: ^context]
|
||||
from UserToken, where: [token: ^token, context: ^context]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets all tokens for the given user for the given contexts.
|
||||
"""
|
||||
def user_and_contexts_query(user, :all) do
|
||||
from t in Accounts.UserToken, where: t.user_id == ^user.id
|
||||
def user_and_contexts_query(%{id: user_id}, :all) do
|
||||
from t in UserToken, where: t.user_id == ^user_id
|
||||
end
|
||||
|
||||
def user_and_contexts_query(user, [_ | _] = contexts) do
|
||||
from t in Accounts.UserToken, where: t.user_id == ^user.id and t.context in ^contexts
|
||||
def user_and_contexts_query(%{id: user_id}, [_ | _] = contexts) do
|
||||
from t in UserToken, where: t.user_id == ^user_id and t.context in ^contexts
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,11 @@
|
||||
defmodule Cannery.Ammo.AmmoGroup do
|
||||
@moduledoc """
|
||||
A group of a certain ammunition type.
|
||||
|
||||
Can be placed in a container, and contains auxiliary information such as the
|
||||
amount paid for that ammunition, or what condition it is in
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Cannery.{Accounts, Ammo, Containers, Tags}
|
||||
|
@ -1,4 +1,10 @@
|
||||
defmodule Cannery.Ammo.AmmoType do
|
||||
@moduledoc """
|
||||
An ammunition type.
|
||||
|
||||
Contains statistical information about the ammunition.
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
|
@ -4,9 +4,8 @@ defmodule Cannery.Containers do
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Cannery.Repo
|
||||
|
||||
alias Cannery.Containers.Container
|
||||
alias Cannery.{Containers.Container, Repo}
|
||||
alias Ecto.{Changeset, UUID}
|
||||
|
||||
@doc """
|
||||
Returns the list of containers.
|
||||
@ -17,6 +16,7 @@ defmodule Cannery.Containers do
|
||||
[%Container{}, ...]
|
||||
|
||||
"""
|
||||
@spec list_containers() :: [Container.t()]
|
||||
def list_containers do
|
||||
Repo.all(Container)
|
||||
end
|
||||
@ -35,6 +35,7 @@ defmodule Cannery.Containers do
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
@spec get_container!(container_id :: UUID.t()) :: Container.t()
|
||||
def get_container!(id), do: Repo.get!(Container, id)
|
||||
|
||||
@doc """
|
||||
@ -49,10 +50,9 @@ defmodule Cannery.Containers do
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_container(attrs \\ %{}) do
|
||||
%Container{}
|
||||
|> Container.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
@spec create_container(attrs :: map()) :: {:ok, Container.t()} | {:error, Changeset.t()}
|
||||
def create_container(attrs) do
|
||||
%Container{} |> Container.changeset(attrs) |> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
@ -67,10 +67,10 @@ defmodule Cannery.Containers do
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_container(%Container{} = container, attrs) do
|
||||
container
|
||||
|> Container.changeset(attrs)
|
||||
|> Repo.update()
|
||||
@spec update_container(Container.t() | Ecto.Changeset.t(), map()) ::
|
||||
{:ok, Container.t()} | {:error, Ecto.Changeset.t()}
|
||||
def update_container(container, attrs) do
|
||||
container |> Container.changeset(attrs) |> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
@ -85,9 +85,9 @@ defmodule Cannery.Containers do
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_container(%Container{} = container) do
|
||||
Repo.delete(container)
|
||||
end
|
||||
@spec delete_container(Container.t() | Ecto.Changeset.t()) ::
|
||||
{:ok, Container.t()} | {:error, Ecto.Changeset.t()}
|
||||
def delete_container(container), do: Repo.delete(container)
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking container changes.
|
||||
@ -97,8 +97,11 @@ defmodule Cannery.Containers do
|
||||
iex> change_container(container)
|
||||
%Ecto.Changeset{data: %Container{}}
|
||||
|
||||
iex> change_container(%Ecto.Changeset{})
|
||||
%Ecto.Changeset{data: %Container{}}
|
||||
|
||||
"""
|
||||
def change_container(%Container{} = container, attrs \\ %{}) do
|
||||
Container.changeset(container, attrs)
|
||||
end
|
||||
@spec change_container(Container.t()) :: Changeset.t()
|
||||
@spec change_container(Container.t(), map()) :: Changeset.t()
|
||||
def change_container(container, attrs \\ %{}), do: container |> Container.changeset(attrs)
|
||||
end
|
||||
|
@ -1,7 +1,12 @@
|
||||
defmodule Cannery.Containers.Container do
|
||||
@moduledoc """
|
||||
A container that holds ammunition and belongs to a user.
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Cannery.{Accounts}
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Cannery.{Accounts.User, Containers.Container}
|
||||
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
@ -11,27 +16,30 @@ defmodule Cannery.Containers.Container do
|
||||
field :location, :string
|
||||
field :type, :string
|
||||
|
||||
belongs_to :user, Accounts.User
|
||||
belongs_to :user, User
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@type t :: %{
|
||||
id: Ecto.UUID.t(),
|
||||
@type t :: %Container{
|
||||
id: UUID.t(),
|
||||
name: String.t(),
|
||||
desc: String.t(),
|
||||
location: String.t(),
|
||||
type: String.t(),
|
||||
user: Accounts.User.t(),
|
||||
user_id: Ecto.UUID.t(),
|
||||
user: User.t(),
|
||||
user_id: UUID.t(),
|
||||
inserted_at: NaiveDateTime.t(),
|
||||
updated_at: NaiveDateTime.t()
|
||||
}
|
||||
|
||||
@type new_container :: %Container{}
|
||||
|
||||
@doc false
|
||||
@spec changeset(Container.t() | Container.new_container(), map()) :: Changeset.t()
|
||||
def changeset(container, attrs) do
|
||||
container
|
||||
|> cast(attrs, [:name, :desc, :type, :location, :user_id])
|
||||
|> validate_required([:name, :desc, :type, :location, :user_id])
|
||||
|> validate_required([:name, :type, :user_id])
|
||||
end
|
||||
end
|
||||
|
@ -1,28 +1,34 @@
|
||||
defmodule Cannery.Containers.ContainerTag do
|
||||
@moduledoc """
|
||||
Thru-table struct for associating Cannery.Containers.Container and
|
||||
Cannery.Tags.Tag.
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Cannery.{Containers, Tags}
|
||||
alias Cannery.{Containers.Container, Containers.ContainerTag, Tags.Tag}
|
||||
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
schema "container_tags" do
|
||||
belongs_to :container, Containers.Container
|
||||
belongs_to :tag, Tags.Tag
|
||||
belongs_to :container, Container
|
||||
belongs_to :tag, Tag
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@type t :: %{
|
||||
@type t :: %ContainerTag{
|
||||
id: Ecto.UUID.t(),
|
||||
container: Containers.Container.t(),
|
||||
container: Container.t(),
|
||||
container_id: Ecto.UUID.t(),
|
||||
tag: Tags.Tag.t(),
|
||||
tag: Tag.t(),
|
||||
tag_id: Ecto.UUID.t(),
|
||||
inserted_at: NaiveDateTime.t(),
|
||||
updated_at: NaiveDateTime.t()
|
||||
}
|
||||
|
||||
@doc false
|
||||
@spec changeset(ContainerTag.t(), map()) :: Ecto.Changeset.t()
|
||||
def changeset(container_tag, attrs) do
|
||||
container_tag
|
||||
|> cast(attrs, [:tag_id, :container_id])
|
||||
|
@ -4,8 +4,8 @@ defmodule Cannery.Invites do
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Cannery.{Accounts, Repo}
|
||||
alias Cannery.Invites.Invite
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Cannery.{Accounts.User, Invites.Invite, Repo}
|
||||
|
||||
@invite_token_length 20
|
||||
|
||||
@ -49,7 +49,7 @@ defmodule Cannery.Invites do
|
||||
iex> get_invite_by_token("invalid_token")
|
||||
nil
|
||||
"""
|
||||
@spec get_invite_by_token(String.t()) :: Invite.t() | nil
|
||||
@spec get_invite_by_token(String.t() | nil) :: Invite.t() | nil
|
||||
def get_invite_by_token(nil), do: nil
|
||||
def get_invite_by_token(""), do: nil
|
||||
|
||||
@ -86,22 +86,22 @@ defmodule Cannery.Invites do
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_invite(%Accounts.User{id: "1"}, %{field: value})
|
||||
iex> create_invite(%User{id: "1"}, %{field: value})
|
||||
{:ok, %Invite{}}
|
||||
|
||||
iex> create_invite("1", %{field: value})
|
||||
{:ok, %Invite{}}
|
||||
|
||||
iex> create_invite(%Accounts.User{id: "1"}, %{field: bad_value})
|
||||
iex> create_invite(%User{id: "1"}, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
@spec create_invite(user_or_user_id :: Accounts.User.t() | Ecto.UUID.t(), attrs :: map()) ::
|
||||
Invite.t()
|
||||
def create_invite(%{id: user_id}, attrs) do
|
||||
create_invite(user_id, attrs)
|
||||
end
|
||||
@spec create_invite(user :: User.t(), attrs :: map()) ::
|
||||
{:ok, Invite.t()} | {:error, Changeset.t()}
|
||||
def create_invite(%{id: user_id}, attrs), do: create_invite(user_id, attrs)
|
||||
|
||||
@spec create_invite(user_id :: UUID.t(), attrs :: map()) ::
|
||||
{:ok, Invite.t()} | {:error, Changeset.t()}
|
||||
def create_invite(user_id, attrs) when not (user_id |> is_nil()) do
|
||||
attrs =
|
||||
attrs
|
||||
|
@ -1,7 +1,14 @@
|
||||
defmodule Cannery.Invites.Invite do
|
||||
@moduledoc """
|
||||
An invite, created by an admin to allow someone to join their instance. An
|
||||
invite can be enabled or disabled, and can have an optional number of uses if
|
||||
`:uses_left` is defined.
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Cannery.{Accounts}
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Cannery.{Accounts.User, Invites.Invite}
|
||||
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
@ -11,22 +18,27 @@ defmodule Cannery.Invites.Invite do
|
||||
field :uses_left, :integer, default: nil
|
||||
field :disabled_at, :naive_datetime
|
||||
|
||||
belongs_to :user, Accounts.User
|
||||
belongs_to :user, User
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@type t :: %{
|
||||
id: Ecto.UUID.t(),
|
||||
@type t :: %Invite{
|
||||
id: UUID.t(),
|
||||
name: String.t(),
|
||||
token: String.t(),
|
||||
uses_left: integer() | nil,
|
||||
disabled_at: NaiveDateTime.t(),
|
||||
user: Accounts.User.t(),
|
||||
user_id: Ecto.UUID.t()
|
||||
user: User.t(),
|
||||
user_id: UUID.t(),
|
||||
inserted_at: NaiveDateTime.t(),
|
||||
updated_at: NaiveDateTime.t()
|
||||
}
|
||||
|
||||
@type new_invite :: %Invite{}
|
||||
|
||||
@doc false
|
||||
@spec changeset(Invite.t() | Invite.new_invite(), map()) :: Changeset.t()
|
||||
def changeset(invite, attrs) do
|
||||
invite
|
||||
|> cast(attrs, [:name, :token, :uses_left, :disabled_at, :user_id])
|
||||
|
@ -1,3 +1,7 @@
|
||||
defmodule Cannery.Mailer do
|
||||
@moduledoc """
|
||||
Mailer adapter for emails
|
||||
"""
|
||||
|
||||
use Swoosh.Mailer, otp_app: :cannery
|
||||
end
|
||||
|
@ -1,4 +1,10 @@
|
||||
defmodule Cannery.Release do
|
||||
@moduledoc """
|
||||
Contains tasks that will be included in the Mix release
|
||||
|
||||
Ex. `load_app/0` can be invoked with `mix load_app`.
|
||||
"""
|
||||
|
||||
@app :cannery
|
||||
|
||||
def rollback(repo, version) do
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule Cannery.Repo.Migrator do
|
||||
@moduledoc """
|
||||
Genserver to automatically run migrations in prod env
|
||||
"""
|
||||
|
||||
use GenServer
|
||||
require Logger
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
defmodule Cannery.Tags.Tag do
|
||||
@moduledoc """
|
||||
Tags are added to containers to help organize, and can include custom-defined
|
||||
text and bg colors.
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Cannery.{Accounts}
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Cannery.{Accounts.User, Tags.Tag}
|
||||
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
@ -10,23 +16,26 @@ defmodule Cannery.Tags.Tag do
|
||||
field :bg_color, :string
|
||||
field :text_color, :string
|
||||
|
||||
belongs_to :user, Accounts.User
|
||||
belongs_to :user, User
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@type t :: %{
|
||||
id: Ecto.UUID.t(),
|
||||
@type t :: %Tag{
|
||||
id: UUID.t(),
|
||||
name: String.t(),
|
||||
bg_color: String.t(),
|
||||
text_color: String.t(),
|
||||
user: Accounts.User.t(),
|
||||
user_id: Ecto.UUID.t(),
|
||||
user: User.t(),
|
||||
user_id: UUID.t(),
|
||||
inserted_at: NaiveDateTime.t(),
|
||||
updated_at: NaiveDateTime.t()
|
||||
}
|
||||
|
||||
@type new_tag() :: %Tag{}
|
||||
|
||||
@doc false
|
||||
@spec changeset(Tag.t() | Tag.new_tag(), map()) :: Changeset.t()
|
||||
def changeset(tag, attrs) do
|
||||
tag
|
||||
|> cast(attrs, [:name, :bg_color, :text_color, :user_id])
|
||||
|
@ -1,8 +1,12 @@
|
||||
defmodule CanneryWeb.Component.Topbar do
|
||||
@moduledoc """
|
||||
Component that renders a topbar with user functions/links
|
||||
"""
|
||||
|
||||
use CanneryWeb, :component
|
||||
|
||||
alias Cannery.{Accounts}
|
||||
alias CanneryWeb.{HomeLive}
|
||||
alias Cannery.Accounts
|
||||
alias CanneryWeb.HomeLive
|
||||
|
||||
def topbar(assigns) do
|
||||
assigns =
|
||||
|
@ -1,9 +1,13 @@
|
||||
defmodule CanneryWeb.UserAuth do
|
||||
@moduledoc """
|
||||
Functions for user session and authentication
|
||||
"""
|
||||
|
||||
import Plug.Conn
|
||||
import Phoenix.Controller
|
||||
|
||||
alias Cannery.Accounts
|
||||
alias CanneryWeb.{HomeLive}
|
||||
alias CanneryWeb.HomeLive
|
||||
alias CanneryWeb.Router.Helpers, as: Routes
|
||||
|
||||
# Make the remember me cookie valid for 60 days.
|
||||
@ -37,6 +41,11 @@ defmodule CanneryWeb.UserAuth do
|
||||
|> redirect(to: user_return_to || signed_in_path(conn))
|
||||
end
|
||||
|
||||
@spec maybe_write_remember_me_cookie(
|
||||
Plug.Conn.t(),
|
||||
String.t() | any(),
|
||||
%{required(String.t()) => String.t()} | any()
|
||||
) :: Plug.Conn.t()
|
||||
defp maybe_write_remember_me_cookie(conn, token, %{"remember_me" => "true"}) do
|
||||
put_resp_cookie(conn, @remember_me_cookie, token, @remember_me_options)
|
||||
end
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.AmmoGroupLive.FormComponent do
|
||||
@moduledoc """
|
||||
Livecomponent that can update or create an Cannery.Ammo.AmmoGroup
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_component
|
||||
|
||||
alias Cannery.Ammo
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.AmmoGroupLive.Index do
|
||||
@moduledoc """
|
||||
Liveview to show a Cannery.Ammo.AmmoGroup index
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
|
||||
alias Cannery.Ammo
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.AmmoGroupLive.Show do
|
||||
@moduledoc """
|
||||
Liveview for showing and editing an Cannery.Ammo.AmmoGroup
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
|
||||
alias Cannery.Ammo
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.AmmoTypeLive.FormComponent do
|
||||
@moduledoc """
|
||||
Livecomponent that can update or create an Cannery.Ammo.AmmoType
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_component
|
||||
|
||||
alias Cannery.Ammo
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.AmmoTypeLive.Index do
|
||||
@moduledoc """
|
||||
Liveview for showing a Cannery.Ammo.AmmoType index
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
|
||||
alias Cannery.Ammo
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.AmmoTypeLive.Show do
|
||||
@moduledoc """
|
||||
Liveview for showing and editing an Cannery.Ammo.AmmoType
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
|
||||
alias Cannery.Ammo
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.ContainerLive.FormComponent do
|
||||
@moduledoc """
|
||||
Livecomponent that can update or create an Cannery.Containers.Container
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_component
|
||||
|
||||
alias Cannery.Containers
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.ContainerLive.Index do
|
||||
@moduledoc """
|
||||
Liveview for showing Cannery.Containers.Container index
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
|
||||
alias Cannery.Containers
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.ContainerLive.Show do
|
||||
@moduledoc """
|
||||
Liveview for showing and editing a Cannery.Containers.Container
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
|
||||
alias Cannery.Containers
|
||||
|
@ -1,6 +1,10 @@
|
||||
defmodule CanneryWeb.HomeLive do
|
||||
@moduledoc """
|
||||
Liveview for the home page
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
alias Cannery.{Accounts}
|
||||
alias Cannery.Accounts
|
||||
|
||||
@impl true
|
||||
def mount(_params, session, socket) do
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.InviteLive.FormComponent do
|
||||
@moduledoc """
|
||||
Livecomponent that can update or create an Cannery.Invites.Invite
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_component
|
||||
|
||||
alias Cannery.Invites
|
||||
|
@ -1,8 +1,12 @@
|
||||
defmodule CanneryWeb.InviteLive.Index do
|
||||
@moduledoc """
|
||||
Liveview to show a Cannery.Invites.Invite index
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
|
||||
alias Cannery.{Invites}
|
||||
alias Cannery.Invites.{Invite}
|
||||
alias Cannery.Invites
|
||||
alias Cannery.Invites.Invite
|
||||
|
||||
@impl true
|
||||
def mount(_params, session, socket) do
|
||||
|
@ -1,7 +1,11 @@
|
||||
defmodule CanneryWeb.LiveHelpers do
|
||||
@moduledoc """
|
||||
Contains common helper functions for liveviews
|
||||
"""
|
||||
|
||||
import Phoenix.LiveView.Helpers
|
||||
import Phoenix.LiveView, only: [assign_new: 3]
|
||||
alias Cannery.{Accounts}
|
||||
alias Cannery.Accounts
|
||||
|
||||
@doc """
|
||||
Renders a component inside the `CanneryWeb.ModalComponent` component.
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.ModalComponent do
|
||||
@moduledoc """
|
||||
Livecomponent that displays a floating modal window
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_component
|
||||
|
||||
@impl true
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.TagLive.FormComponent do
|
||||
@moduledoc """
|
||||
Livecomponent that can update or create an Cannery.Tags.Tag
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_component
|
||||
|
||||
alias Cannery.Tags
|
||||
@ -103,7 +107,7 @@ defmodule CanneryWeb.TagLive.FormComponent do
|
||||
Returns a random tag color in `#ffffff` hex format
|
||||
"""
|
||||
@spec random_color() :: String.t()
|
||||
def random_color() do
|
||||
def random_color do
|
||||
["#cc0066", "#ff6699", "#6666ff", "#0066cc", "#00cc66", "#669900", "#ff9900", "#996633"]
|
||||
|> Enum.random()
|
||||
end
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.TagLive.Index do
|
||||
@moduledoc """
|
||||
Liveview to show a Cannery.Tags.Tag index
|
||||
"""
|
||||
|
||||
use CanneryWeb, :live_view
|
||||
|
||||
alias Cannery.Tags
|
||||
|
@ -1,4 +1,8 @@
|
||||
defmodule CanneryWeb.Telemetry do
|
||||
@moduledoc """
|
||||
Collects telemetry
|
||||
"""
|
||||
|
||||
use Supervisor
|
||||
import Telemetry.Metrics
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
defmodule CanneryWeb.LayoutView do
|
||||
use CanneryWeb, :view
|
||||
alias Cannery.{Accounts}
|
||||
alias CanneryWeb.{HomeLive}
|
||||
alias Cannery.Accounts
|
||||
alias CanneryWeb.HomeLive
|
||||
|
||||
# Phoenix LiveDashboard is available only in development by default,
|
||||
# so we instruct Elixir to not warn if the dashboard route is missing.
|
||||
|
@ -16,6 +16,7 @@ defmodule CanneryWeb.ChannelCase do
|
||||
"""
|
||||
|
||||
use ExUnit.CaseTemplate
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
using do
|
||||
quote do
|
||||
@ -29,8 +30,8 @@ defmodule CanneryWeb.ChannelCase do
|
||||
end
|
||||
|
||||
setup tags do
|
||||
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Cannery.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
|
||||
pid = Sandbox.start_owner!(Cannery.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Sandbox.stop_owner(pid) end)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
@ -16,6 +16,7 @@ defmodule CanneryWeb.ConnCase do
|
||||
"""
|
||||
|
||||
use ExUnit.CaseTemplate
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
using do
|
||||
quote do
|
||||
@ -32,8 +33,8 @@ defmodule CanneryWeb.ConnCase do
|
||||
end
|
||||
|
||||
setup tags do
|
||||
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Cannery.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
|
||||
pid = Sandbox.start_owner!(Cannery.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Sandbox.stop_owner(pid) end)
|
||||
{:ok, conn: Phoenix.ConnTest.build_conn()}
|
||||
end
|
||||
|
||||
|
@ -15,6 +15,7 @@ defmodule Cannery.DataCase do
|
||||
"""
|
||||
|
||||
use ExUnit.CaseTemplate
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
using do
|
||||
quote do
|
||||
@ -28,8 +29,8 @@ defmodule Cannery.DataCase do
|
||||
end
|
||||
|
||||
setup tags do
|
||||
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Cannery.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
|
||||
pid = Sandbox.start_owner!(Cannery.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Sandbox.stop_owner(pid) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
|
@ -4,7 +4,7 @@ defmodule Cannery.AccountsFixtures do
|
||||
entities via the `Cannery.Accounts` context.
|
||||
"""
|
||||
|
||||
alias Cannery.{Accounts}
|
||||
alias Cannery.Accounts
|
||||
|
||||
def unique_user_email, do: "user#{System.unique_integer()}@example.com"
|
||||
def valid_user_password, do: "hello world!"
|
||||
|
Loading…
Reference in New Issue
Block a user