chore(AshAuthenticationPhoenix): added library and updated ressources testing password strategy
This commit is contained in:
parent
f154eea055
commit
192ceaed45
24 changed files with 682 additions and 25 deletions
|
|
@ -1,7 +1,9 @@
|
||||||
[
|
[
|
||||||
import_deps: [
|
import_deps: [
|
||||||
|
:ash_authentication_phoenix,
|
||||||
:ash_admin,
|
:ash_admin,
|
||||||
:ash_postgres,
|
:ash_postgres,
|
||||||
|
:ash_authentication,
|
||||||
:ash_phoenix,
|
:ash_phoenix,
|
||||||
:ash,
|
:ash,
|
||||||
:reactor,
|
:reactor,
|
||||||
|
|
|
||||||
10
.igniter.exs
Normal file
10
.igniter.exs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# This is a configuration file for igniter.
|
||||||
|
# For option documentation, see https://hexdocs.pm/igniter/Igniter.Project.IgniterConfig.html
|
||||||
|
# To keep it up to date, use `mix igniter.setup`
|
||||||
|
[
|
||||||
|
module_location: :outside_matching_folder,
|
||||||
|
extensions: [{Igniter.Extensions.Phoenix, []}],
|
||||||
|
deps_location: :last_list_literal,
|
||||||
|
source_folders: ["lib", "test/support"],
|
||||||
|
dont_move_files: [~r"lib/mix"]
|
||||||
|
]
|
||||||
|
|
@ -7,6 +7,7 @@ const path = require("path")
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: [
|
content: [
|
||||||
|
"../deps/ash_authentication_phoenix/**/*.*ex",
|
||||||
"./js/**/*.js",
|
"./js/**/*.js",
|
||||||
"../lib/mv_web.ex",
|
"../lib/mv_web.ex",
|
||||||
"../lib/mv_web/**/*.*ex"
|
"../lib/mv_web/**/*.*ex"
|
||||||
|
|
|
||||||
|
|
@ -84,3 +84,8 @@ config :phoenix_live_view,
|
||||||
|
|
||||||
# Disable swoosh api client as it is only required for production adapters.
|
# Disable swoosh api client as it is only required for production adapters.
|
||||||
config :swoosh, :api_client, false
|
config :swoosh, :api_client, false
|
||||||
|
|
||||||
|
config :mv, :secret_key_base, "ryn7D6ssmIHQFWIks2sFiTGATgwwAR1+3bN8p7fy6qVtB8qnxOuk1uyAwHz1Q8WB"
|
||||||
|
|
||||||
|
# Signing Secret for Authentication
|
||||||
|
config :mv, :token_signing_secret, "IwUwi65TrEeExwBXXFPGm2I7889NsL"
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ defmodule Mv.Accounts do
|
||||||
|
|
||||||
resources do
|
resources do
|
||||||
resource Mv.Accounts.User do
|
resource Mv.Accounts.User do
|
||||||
define(:create_user, action: :create)
|
define :create_user, action: :create
|
||||||
define(:list_users, action: :read)
|
define :list_users, action: :read
|
||||||
define(:update_user, action: :update)
|
define :update_user, action: :update
|
||||||
define(:destroy_user, action: :destroy)
|
define :destroy_user, action: :destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
resource Mv.Accounts.Token
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
11
lib/accounts/token.ex
Normal file
11
lib/accounts/token.ex
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Mv.Accounts.Token do
|
||||||
|
use Ash.Resource,
|
||||||
|
data_layer: AshPostgres.DataLayer,
|
||||||
|
extensions: [AshAuthentication.TokenResource],
|
||||||
|
domain: Mv.Accounts
|
||||||
|
|
||||||
|
postgres do
|
||||||
|
table "tokens"
|
||||||
|
repo Mv.Repo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,26 +1,78 @@
|
||||||
defmodule Mv.Accounts.User do
|
defmodule Mv.Accounts.User do
|
||||||
use Ash.Resource,
|
use Ash.Resource,
|
||||||
domain: Mv.Accounts,
|
domain: Mv.Accounts,
|
||||||
data_layer: AshPostgres.DataLayer
|
data_layer: AshPostgres.DataLayer,
|
||||||
|
extensions: [AshAuthentication]
|
||||||
|
|
||||||
|
# authorizers: [Ash.Policy.Authorizer]
|
||||||
|
|
||||||
postgres do
|
postgres do
|
||||||
table("users")
|
table "users"
|
||||||
repo(Mv.Repo)
|
repo Mv.Repo
|
||||||
end
|
end
|
||||||
|
|
||||||
attributes do
|
authentication do
|
||||||
uuid_primary_key(:id)
|
tokens do
|
||||||
|
enabled? true
|
||||||
|
token_resource Mv.Accounts.Token
|
||||||
|
signing_secret fn _, _ ->
|
||||||
|
{:ok, Application.get_env(:mv, :token_signing_secret)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
attribute(:email, :string, allow_nil?: true, public?: true)
|
strategies do
|
||||||
attribute(:password_hash, :string, sensitive?: true)
|
password :password do
|
||||||
attribute(:oicd_id, :string)
|
identity_field :email
|
||||||
|
hash_provider AshAuthentication.BcryptProvider
|
||||||
|
confirmation_required? false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
actions do
|
actions do
|
||||||
defaults([:read, :destroy, :create, :update])
|
defaults [:read, :create, :destroy, :update]
|
||||||
|
|
||||||
|
read :get_by_subject do
|
||||||
|
description "Get a user by the subject claim in a JWT"
|
||||||
|
argument :subject, :string, allow_nil?: false
|
||||||
|
get? true
|
||||||
|
prepare AshAuthentication.Preparations.FilterBySubject
|
||||||
|
end
|
||||||
|
|
||||||
|
# read :sign_in_with_example do
|
||||||
|
# argument :user_info, :map, allow_nil?: false
|
||||||
|
# argument :oauth_tokens, :map, allow_nil?: false
|
||||||
|
# prepare AshAuthentication.Strategy.OAuth2.SignInPreparation
|
||||||
|
|
||||||
|
# filter expr(email == get_path(^arg(:user_info), [:email]))
|
||||||
|
# end
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes do
|
||||||
|
uuid_primary_key :id
|
||||||
|
|
||||||
|
attribute :email, :ci_string, allow_nil?: false, public?: true
|
||||||
|
attribute :hashed_password, :string, sensitive?: true, allow_nil?: true
|
||||||
|
attribute :oicd_id, :string, allow_nil?: true
|
||||||
end
|
end
|
||||||
|
|
||||||
relationships do
|
relationships do
|
||||||
belongs_to(:member, Mv.Membership.Member)
|
belongs_to :member, Mv.Membership.Member
|
||||||
end
|
end
|
||||||
|
|
||||||
|
identities do
|
||||||
|
identity :unique_email, [:email]
|
||||||
|
end
|
||||||
|
|
||||||
|
# You can customize this if you wish, but this is a safe default that
|
||||||
|
# only allows user data to be interacted with via AshAuthentication.
|
||||||
|
# policies do
|
||||||
|
# bypass AshAuthentication.Checks.AshAuthenticationInteraction do
|
||||||
|
# authorize_if(always())
|
||||||
|
# end
|
||||||
|
|
||||||
|
# policy always() do
|
||||||
|
# forbid_if(always())
|
||||||
|
# end
|
||||||
|
# end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
defmodule Mv.Accounts.User.Senders.SendNewUserConfirmationEmail do
|
||||||
|
@moduledoc """
|
||||||
|
Sends an email for a new user to confirm their email address.
|
||||||
|
"""
|
||||||
|
|
||||||
|
use AshAuthentication.Sender
|
||||||
|
use MvWeb, :verified_routes
|
||||||
|
|
||||||
|
import Swoosh.Email
|
||||||
|
|
||||||
|
alias Mv.Mailer
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def send(user, token, _) do
|
||||||
|
new()
|
||||||
|
# TODO: Replace with your email
|
||||||
|
|> from({"noreply", "noreply@example.com"})
|
||||||
|
|> to(to_string(user.email))
|
||||||
|
|> subject("Confirm your email address")
|
||||||
|
|> html_body(body(token: token))
|
||||||
|
|> Mailer.deliver!()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp body(params) do
|
||||||
|
url = url(~p"/confirm_new_user/#{params[:token]}")
|
||||||
|
|
||||||
|
"""
|
||||||
|
<p>Click this link to confirm your email:</p>
|
||||||
|
<p><a href="#{url}">#{url}</a></p>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
32
lib/mv/accounts/user/senders/send_password_reset_email.ex
Normal file
32
lib/mv/accounts/user/senders/send_password_reset_email.ex
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
defmodule Mv.Accounts.User.Senders.SendPasswordResetEmail do
|
||||||
|
@moduledoc """
|
||||||
|
Sends a password reset email
|
||||||
|
"""
|
||||||
|
|
||||||
|
use AshAuthentication.Sender
|
||||||
|
use MvWeb, :verified_routes
|
||||||
|
|
||||||
|
import Swoosh.Email
|
||||||
|
|
||||||
|
alias Mv.Mailer
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def send(user, token, _) do
|
||||||
|
new()
|
||||||
|
# TODO: Replace with your email
|
||||||
|
|> from({"noreply", "noreply@example.com"})
|
||||||
|
|> to(to_string(user.email))
|
||||||
|
|> subject("Reset your password")
|
||||||
|
|> html_body(body(token: token))
|
||||||
|
|> Mailer.deliver!()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp body(params) do
|
||||||
|
url = url(~p"/password-reset/#{params[:token]}")
|
||||||
|
|
||||||
|
"""
|
||||||
|
<p>Click this link to reset your password:</p>
|
||||||
|
<p><a href="#{url}">#{url}</a></p>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -14,6 +14,7 @@ defmodule Mv.Application do
|
||||||
{Phoenix.PubSub, name: Mv.PubSub},
|
{Phoenix.PubSub, name: Mv.PubSub},
|
||||||
# Start the Finch HTTP client for sending emails
|
# Start the Finch HTTP client for sending emails
|
||||||
{Finch, name: Mv.Finch},
|
{Finch, name: Mv.Finch},
|
||||||
|
{AshAuthentication.Supervisor, otp_app: :my},
|
||||||
# Start a worker by calling: Mv.Worker.start_link(arg)
|
# Start a worker by calling: Mv.Worker.start_link(arg)
|
||||||
# {Mv.Worker, arg},
|
# {Mv.Worker, arg},
|
||||||
# Start to serve requests, typically the last entry
|
# Start to serve requests, typically the last entry
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ defmodule Mv.Repo do
|
||||||
@impl true
|
@impl true
|
||||||
def installed_extensions do
|
def installed_extensions do
|
||||||
# Add extensions here, and the migration generator will install them.
|
# Add extensions here, and the migration generator will install them.
|
||||||
["ash-functions"]
|
["ash-functions", "citext"]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Don't open unnecessary transactions
|
# Don't open unnecessary transactions
|
||||||
|
|
|
||||||
20
lib/mv_web/auth_overrides.ex
Normal file
20
lib/mv_web/auth_overrides.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
defmodule MvWeb.AuthOverrides do
|
||||||
|
use AshAuthentication.Phoenix.Overrides
|
||||||
|
|
||||||
|
# configure your UI overrides here
|
||||||
|
|
||||||
|
# First argument to `override` is the component name you are overriding.
|
||||||
|
# The body contains any number of configurations you wish to override
|
||||||
|
# Below are some examples
|
||||||
|
|
||||||
|
# For a complete reference, see https://hexdocs.pm/ash_authentication_phoenix/ui-overrides.html
|
||||||
|
|
||||||
|
# override AshAuthentication.Phoenix.Components.Banner do
|
||||||
|
# set :image_url, "https://media.giphy.com/media/g7GKcSzwQfugw/giphy.gif"
|
||||||
|
# set :text_class, "bg-red-500"
|
||||||
|
# end
|
||||||
|
|
||||||
|
# override AshAuthentication.Phoenix.Components.SignIn do
|
||||||
|
# set :show_banner, false
|
||||||
|
# end
|
||||||
|
end
|
||||||
55
lib/mv_web/controllers/auth_controller.ex
Normal file
55
lib/mv_web/controllers/auth_controller.ex
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
defmodule MvWeb.AuthController do
|
||||||
|
use MvWeb, :controller
|
||||||
|
use AshAuthentication.Phoenix.Controller
|
||||||
|
|
||||||
|
def success(conn, activity, user, _token) do
|
||||||
|
return_to = get_session(conn, :return_to) || ~p"/"
|
||||||
|
|
||||||
|
message =
|
||||||
|
case activity do
|
||||||
|
{:confirm_new_user, :confirm} -> "Your email address has now been confirmed"
|
||||||
|
{:password, :reset} -> "Your password has successfully been reset"
|
||||||
|
_ -> "You are now signed in"
|
||||||
|
end
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> delete_session(:return_to)
|
||||||
|
|> store_in_session(user)
|
||||||
|
# If your resource has a different name, update the assign name here (i.e :current_admin)
|
||||||
|
|> assign(:current_user, user)
|
||||||
|
|> put_flash(:info, message)
|
||||||
|
|> redirect(to: return_to)
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure(conn, activity, reason) do
|
||||||
|
message =
|
||||||
|
case {activity, reason} do
|
||||||
|
{_,
|
||||||
|
%AshAuthentication.Errors.AuthenticationFailed{
|
||||||
|
caused_by: %Ash.Error.Forbidden{
|
||||||
|
errors: [%AshAuthentication.Errors.CannotConfirmUnconfirmedUser{}]
|
||||||
|
}
|
||||||
|
}} ->
|
||||||
|
"""
|
||||||
|
You have already signed in another way, but have not confirmed your account.
|
||||||
|
You can confirm your account using the link we sent to you, or by resetting your password.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
"Incorrect email or password"
|
||||||
|
end
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, message)
|
||||||
|
|> redirect(to: ~p"/sign-in")
|
||||||
|
end
|
||||||
|
|
||||||
|
def sign_out(conn, _params) do
|
||||||
|
return_to = get_session(conn, :return_to) || ~p"/"
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> clear_session()
|
||||||
|
|> put_flash(:info, "You are now signed out")
|
||||||
|
|> redirect(to: return_to)
|
||||||
|
end
|
||||||
|
end
|
||||||
44
lib/mv_web/live_user_auth.ex
Normal file
44
lib/mv_web/live_user_auth.ex
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
defmodule MvWeb.LiveUserAuth do
|
||||||
|
@moduledoc """
|
||||||
|
Helpers for authenticating users in LiveViews.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import Phoenix.Component
|
||||||
|
use MvWeb, :verified_routes
|
||||||
|
|
||||||
|
# This is used for nested liveviews to fetch the current user.
|
||||||
|
# To use, place the following at the top of that liveview:
|
||||||
|
# on_mount {MvWeb.LiveUserAuth, :current_user}
|
||||||
|
def on_mount(:current_user, _params, session, socket) do
|
||||||
|
return_to = session[:return_to]
|
||||||
|
socket =
|
||||||
|
socket
|
||||||
|
|> assign(:return_to, return_to)
|
||||||
|
|> AshAuthentication.Phoenix.LiveSession.assign_new_resources(session)
|
||||||
|
{:cont, session, socket}
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_mount(:live_user_optional, _params, _session, socket) do
|
||||||
|
if socket.assigns[:current_user] do
|
||||||
|
{:cont, socket}
|
||||||
|
else
|
||||||
|
{:cont, assign(socket, :current_user, nil)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_mount(:live_user_required, _params, _session, socket) do
|
||||||
|
if socket.assigns[:current_user] do
|
||||||
|
{:cont, socket}
|
||||||
|
else
|
||||||
|
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/sign-in")}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_mount(:live_no_user, _params, _session, socket) do
|
||||||
|
if socket.assigns[:current_user] do
|
||||||
|
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/")}
|
||||||
|
else
|
||||||
|
{:cont, assign(socket, :current_user, nil)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
defmodule MvWeb.MemberLive.Index do
|
defmodule MvWeb.MemberLive.Index do
|
||||||
use MvWeb, :live_view
|
use MvWeb, :live_view
|
||||||
|
|
||||||
|
on_mount {MvWeb.LiveUserAuth, :live_user_required}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
defmodule MvWeb.Router do
|
defmodule MvWeb.Router do
|
||||||
use MvWeb, :router
|
use MvWeb, :router
|
||||||
|
|
||||||
|
use AshAuthentication.Phoenix.Router
|
||||||
|
|
||||||
|
import AshAuthentication.Plug.Helpers
|
||||||
|
|
||||||
pipeline :browser do
|
pipeline :browser do
|
||||||
plug :accepts, ["html"]
|
plug :accepts, ["html"]
|
||||||
plug :fetch_session
|
plug :fetch_session
|
||||||
|
|
@ -8,22 +12,46 @@ defmodule MvWeb.Router do
|
||||||
plug :put_root_layout, html: {MvWeb.Layouts, :root}
|
plug :put_root_layout, html: {MvWeb.Layouts, :root}
|
||||||
plug :protect_from_forgery
|
plug :protect_from_forgery
|
||||||
plug :put_secure_browser_headers
|
plug :put_secure_browser_headers
|
||||||
|
plug :load_from_session
|
||||||
plug :set_locale
|
plug :set_locale
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :api do
|
pipeline :api do
|
||||||
plug :accepts, ["json"]
|
plug :accepts, ["json"]
|
||||||
|
plug :load_from_bearer
|
||||||
|
plug :set_actor, :user
|
||||||
|
end
|
||||||
|
|
||||||
|
scope "/", MvWeb do
|
||||||
|
pipe_through :browser
|
||||||
|
|
||||||
|
ash_authentication_live_session :authenticated_routes do
|
||||||
|
# in each liveview, add one of the following at the top of the module:
|
||||||
|
#
|
||||||
|
# If an authenticated user must be present:
|
||||||
|
# on_mount {MvWeb.LiveUserAuth, :live_user_required}
|
||||||
|
#
|
||||||
|
# If an authenticated user *may* be present:
|
||||||
|
# on_mount {MvWeb.LiveUserAuth, :live_user_optional}
|
||||||
|
#
|
||||||
|
# If an authenticated user must *not* be present:
|
||||||
|
# on_mount {MvWeb.LiveUserAuth, :live_no_user}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", MvWeb do
|
scope "/", MvWeb do
|
||||||
pipe_through :browser
|
pipe_through :browser
|
||||||
|
|
||||||
get "/", PageController, :home
|
get "/", PageController, :home
|
||||||
live "/members", MemberLive.Index, :index
|
|
||||||
live "/members/new", MemberLive.Index, :new
|
ash_authentication_live_session :session_name do
|
||||||
live "/members/:id/edit", MemberLive.Index, :edit
|
live "/members", MemberLive.Index, :index
|
||||||
live "/members/:id", MemberLive.Show, :show
|
live "/members/new", MemberLive.Index, :new
|
||||||
live "/members/:id/show/edit", MemberLive.Show, :edit
|
live "/members/:id/edit", MemberLive.Index, :edit
|
||||||
|
live "/members/:id", MemberLive.Show, :show
|
||||||
|
live "/members/:id/show/edit", MemberLive.Show, :edit
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
live "/property_types", PropertyTypeLive.Index, :index
|
live "/property_types", PropertyTypeLive.Index, :index
|
||||||
live "/property_types/new", PropertyTypeLive.Index, :new
|
live "/property_types/new", PropertyTypeLive.Index, :new
|
||||||
|
|
@ -38,6 +66,30 @@ defmodule MvWeb.Router do
|
||||||
live "/properties/:id/show/edit", PropertyLive.Show, :edit
|
live "/properties/:id/show/edit", PropertyLive.Show, :edit
|
||||||
|
|
||||||
post "/set_locale", LocaleController, :set_locale
|
post "/set_locale", LocaleController, :set_locale
|
||||||
|
auth_routes AuthController, Mv.Accounts.User, path: "/auth"
|
||||||
|
sign_out_route AuthController
|
||||||
|
|
||||||
|
# Remove these if you'd like to use your own authentication views
|
||||||
|
sign_in_route register_path: "/register",
|
||||||
|
reset_path: "/reset",
|
||||||
|
auth_routes_prefix: "/auth",
|
||||||
|
on_mount: [{MvWeb.LiveUserAuth, :live_no_user}],
|
||||||
|
overrides: [MvWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default]
|
||||||
|
|
||||||
|
# Remove this if you do not want to use the reset password feature
|
||||||
|
reset_route auth_routes_prefix: "/auth",
|
||||||
|
overrides: [MvWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default]
|
||||||
|
|
||||||
|
# Remove this if you do not use the confirmation strategy
|
||||||
|
confirm_route Mv.Accounts.User, :confirm_new_user,
|
||||||
|
auth_routes_prefix: "/auth",
|
||||||
|
overrides: [MvWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default]
|
||||||
|
|
||||||
|
# Remove this if you do not use the magic link strategy.
|
||||||
|
# magic_sign_in_route(Mv.Accounts.User, :magic_link,
|
||||||
|
# auth_routes_prefix: "/auth",
|
||||||
|
# overrides: [MvWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default]
|
||||||
|
# )
|
||||||
end
|
end
|
||||||
|
|
||||||
# Other scopes may use custom stacks.
|
# Other scopes may use custom stacks.
|
||||||
|
|
|
||||||
3
mix.exs
3
mix.exs
|
|
@ -92,7 +92,8 @@ defmodule Mv.MixProject do
|
||||||
"tailwind mv --minify",
|
"tailwind mv --minify",
|
||||||
"esbuild mv --minify",
|
"esbuild mv --minify",
|
||||||
"phx.digest"
|
"phx.digest"
|
||||||
]
|
],
|
||||||
|
"phx.routes": ["phx.routes", "ash_authentication.phoenix.routes"]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
10
mix.lock
10
mix.lock
|
|
@ -15,7 +15,8 @@
|
||||||
"ecto": {:hex, :ecto, "3.12.6", "8bf762dc5b87d85b7aca7ad5fe31ef8142a84cea473a3381eb933bd925751300", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c0cba01795463eebbcd9e4b5ef53c1ee8e68b9c482baef2a80de5a61e7a57fe"},
|
"ecto": {:hex, :ecto, "3.12.6", "8bf762dc5b87d85b7aca7ad5fe31ef8142a84cea473a3381eb933bd925751300", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c0cba01795463eebbcd9e4b5ef53c1ee8e68b9c482baef2a80de5a61e7a57fe"},
|
||||||
"ecto_commons": {:hex, :ecto_commons, "0.3.6", "7b1d9e59396cf8c8cbe5a26d50d03f9b6d0fe6c640210dd503622f276f1e59bb", [:mix], [{:burnex, "~> 3.0", [hex: :burnex, repo: "hexpm", optional: true]}, {:ecto, "~> 3.4", [hex: :ecto, repo: "hexpm", optional: false]}, {:ex_phone_number, "~> 0.2", [hex: :ex_phone_number, repo: "hexpm", optional: false]}, {:luhn, "~> 0.3.0", [hex: :luhn, repo: "hexpm", optional: false]}], "hexpm", "3f12981a1e398f206c5d2014e7b732b7ec91b110b9cb84875cb5b28fc75d7a0a"},
|
"ecto_commons": {:hex, :ecto_commons, "0.3.6", "7b1d9e59396cf8c8cbe5a26d50d03f9b6d0fe6c640210dd503622f276f1e59bb", [:mix], [{:burnex, "~> 3.0", [hex: :burnex, repo: "hexpm", optional: true]}, {:ecto, "~> 3.4", [hex: :ecto, repo: "hexpm", optional: false]}, {:ex_phone_number, "~> 0.2", [hex: :ex_phone_number, repo: "hexpm", optional: false]}, {:luhn, "~> 0.3.0", [hex: :luhn, repo: "hexpm", optional: false]}], "hexpm", "3f12981a1e398f206c5d2014e7b732b7ec91b110b9cb84875cb5b28fc75d7a0a"},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"},
|
"ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"},
|
||||||
"esbuild": {:hex, :esbuild, "0.10.0", "b0aa3388a1c23e727c5a3e7427c932d89ee791746b0081bbe56103e9ef3d291f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "468489cda427b974a7cc9f03ace55368a83e1a7be12fba7e30969af78e5f8c70"},
|
"elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
|
||||||
|
"esbuild": {:hex, :esbuild, "0.9.0", "f043eeaca4932ca8e16e5429aebd90f7766f31ac160a25cbd9befe84f2bc068f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b415027f71d5ab57ef2be844b2a10d0c1b5a492d431727f43937adce22ba45ae"},
|
||||||
"ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"},
|
"ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"},
|
||||||
"ex_phone_number": {:hex, :ex_phone_number, "0.4.5", "2065cc48c3e9d1ed9821f50877c32f2f6898362cb990f44147ca217c5d1374ed", [:mix], [{:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}], "hexpm", "67163f8706f8cbfef1b1f4b9230c461f19786d0d79fd0b22cbeeefc6f0b99d4a"},
|
"ex_phone_number": {:hex, :ex_phone_number, "0.4.5", "2065cc48c3e9d1ed9821f50877c32f2f6898362cb990f44147ca217c5d1374ed", [:mix], [{:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}], "hexpm", "67163f8706f8cbfef1b1f4b9230c461f19786d0d79fd0b22cbeeefc6f0b99d4a"},
|
||||||
"expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"},
|
"expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"},
|
||||||
|
|
@ -24,12 +25,14 @@
|
||||||
"floki": {:hex, :floki, "0.37.1", "d7aaee758c8a5b4a7495799a4260754fec5530d95b9c383c03b27359dea117cf", [:mix], [], "hexpm", "673d040cb594d31318d514590246b6dd587ed341d3b67e17c1c0eb8ce7ca6f04"},
|
"floki": {:hex, :floki, "0.37.1", "d7aaee758c8a5b4a7495799a4260754fec5530d95b9c383c03b27359dea117cf", [:mix], [], "hexpm", "673d040cb594d31318d514590246b6dd587ed341d3b67e17c1c0eb8ce7ca6f04"},
|
||||||
"gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"},
|
"gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"},
|
||||||
"glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"},
|
"glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"},
|
||||||
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized", depth: 1]},
|
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]},
|
||||||
"hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
|
"hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
|
||||||
"igniter": {:hex, :igniter, "0.6.7", "4e183afc59d89289e223c4282fd3e9bb39b82e28d0aa6d3369f70fbd3e21a243", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "43b0a584dc84fd1320772c87047355b604ed2bcdd25392b17f7da8bdd09b61ac"},
|
"igniter": {:hex, :igniter, "0.6.7", "4e183afc59d89289e223c4282fd3e9bb39b82e28d0aa6d3369f70fbd3e21a243", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "43b0a584dc84fd1320772c87047355b604ed2bcdd25392b17f7da8bdd09b61ac"},
|
||||||
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
|
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
|
||||||
"iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"},
|
"iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"},
|
||||||
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
||||||
|
"joken": {:hex, :joken, "2.6.2", "5daaf82259ca603af4f0b065475099ada1b2b849ff140ccd37f4b6828ca6892a", [:mix], [{:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5134b5b0a6e37494e46dbf9e4dad53808e5e787904b7c73972651b51cce3d72b"},
|
||||||
|
"jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"},
|
||||||
"libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"},
|
"libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"},
|
||||||
"live_debugger": {:hex, :live_debugger, "0.2.4", "2e0b02874ca562ba2d8cebb9e024c25c0ae9c1f4ee499135a70814e1dea6183e", [:mix], [{:igniter, ">= 0.5.40 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20.4 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "bfd0db143be54ccf2872f15bfd2209fbec1083d0b06b81b4cedeecb2fa9ac208"},
|
"live_debugger": {:hex, :live_debugger, "0.2.4", "2e0b02874ca562ba2d8cebb9e024c25c0ae9c1f4ee499135a70814e1dea6183e", [:mix], [{:igniter, ">= 0.5.40 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20.4 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "bfd0db143be54ccf2872f15bfd2209fbec1083d0b06b81b4cedeecb2fa9ac208"},
|
||||||
"luhn": {:hex, :luhn, "0.3.3", "5aa0c6a32c2db4b9db9f9b883ba8301c1ae169d57199b9e6cb1ba2707bc51d96", [:mix], [], "hexpm", "3e823a913a25aab51352c727f135278d22954874d5f0835be81ed4fec3daf78d"},
|
"luhn": {:hex, :luhn, "0.3.3", "5aa0c6a32c2db4b9db9f9b883ba8301c1ae169d57199b9e6cb1ba2707bc51d96", [:mix], [], "hexpm", "3e823a913a25aab51352c727f135278d22954874d5f0835be81ed4fec3daf78d"},
|
||||||
|
|
@ -54,7 +57,8 @@
|
||||||
"reactor": {:hex, :reactor, "0.15.4", "ef0c56a901c132529a14ab59fed0ccb4fcecb24308fb189a94c908255d4fdafc", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "783bf62fd0c72ded033afabdb8b6190b7048769771a2a97256e6f0bf4fb0a891"},
|
"reactor": {:hex, :reactor, "0.15.4", "ef0c56a901c132529a14ab59fed0ccb4fcecb24308fb189a94c908255d4fdafc", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}, {:ymlr, "~> 5.0", [hex: :ymlr, repo: "hexpm", optional: false]}], "hexpm", "783bf62fd0c72ded033afabdb8b6190b7048769771a2a97256e6f0bf4fb0a891"},
|
||||||
"req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"},
|
"req": {:hex, :req, "0.5.10", "a3a063eab8b7510785a467f03d30a8d95f66f5c3d9495be3474b61459c54376c", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "8a604815743f8a2d3b5de0659fa3137fa4b1cffd636ecb69b30b2b9b2c2559be"},
|
||||||
"rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"},
|
"rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"},
|
||||||
"sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"},
|
"slugify": {:hex, :slugify, "1.3.1", "0d3b8b7e5c1eeaa960e44dce94382bee34a39b3ea239293e457a9c5b47cc6fd3", [:mix], [], "hexpm", "cb090bbeb056b312da3125e681d98933a360a70d327820e4b7f91645c4d8be76"},
|
||||||
|
"sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
|
||||||
"sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"},
|
"sourceror": {:hex, :sourceror, "1.10.0", "38397dedbbc286966ec48c7af13e228b171332be1ad731974438c77791945ce9", [:mix], [], "hexpm", "29dbdfc92e04569c9d8e6efdc422fc1d815f4bd0055dc7c51b8800fb75c4b3f1"},
|
||||||
"spark": {:hex, :spark, "2.2.65", "4c10d109c108417ce394158f330be09ef184878bde45de6462397fbda68cec29", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "d66d5070a77f4c69cb4f007e941ac17d5d751ce71190fcd6e6e5fb42ba86f101"},
|
"spark": {:hex, :spark, "2.2.65", "4c10d109c108417ce394158f330be09ef184878bde45de6462397fbda68cec29", [:mix], [{:igniter, ">= 0.3.64 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: true]}], "hexpm", "d66d5070a77f4c69cb4f007e941ac17d5d751ce71190fcd6e6e5fb42ba86f101"},
|
||||||
"spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"},
|
"spitfire": {:hex, :spitfire, "0.2.1", "29e154873f05444669c7453d3d931820822cbca5170e88f0f8faa1de74a79b47", [:mix], [], "hexpm", "6eeed75054a38341b2e1814d41bb0a250564092358de2669fdb57ff88141d91b"},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
defmodule Mv.Repo.Migrations.AddAccountsDomainExtensions1 do
|
||||||
|
@moduledoc """
|
||||||
|
Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback
|
||||||
|
|
||||||
|
This file was autogenerated with `mix ash_postgres.generate_migrations`
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
execute("CREATE EXTENSION IF NOT EXISTS \"citext\"")
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
# Uncomment this if you actually want to uninstall the extensions
|
||||||
|
# when this migration is rolled back:
|
||||||
|
# execute("DROP EXTENSION IF EXISTS \"citext\"")
|
||||||
|
end
|
||||||
|
end
|
||||||
31
priv/repo/migrations/20250602071122_add_accounts_domain.exs
Normal file
31
priv/repo/migrations/20250602071122_add_accounts_domain.exs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
defmodule Mv.Repo.Migrations.AddAccountsDomain do
|
||||||
|
@moduledoc """
|
||||||
|
Updates resources based on their most recent snapshots.
|
||||||
|
|
||||||
|
This file was autogenerated with `mix ash_postgres.generate_migrations`
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
rename table(:users), :password_hash, to: :hashed_password
|
||||||
|
|
||||||
|
alter table(:users) do
|
||||||
|
modify :email, :citext, null: false
|
||||||
|
modify :id, :uuid, default: fragment("gen_random_uuid()")
|
||||||
|
end
|
||||||
|
|
||||||
|
create unique_index(:users, [:email], name: "users_unique_email_index")
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
drop_if_exists unique_index(:users, [:email], name: "users_unique_email_index")
|
||||||
|
|
||||||
|
alter table(:users) do
|
||||||
|
modify :id, :uuid, default: fragment("uuid_generate_v7()")
|
||||||
|
modify :email, :text, null: true
|
||||||
|
end
|
||||||
|
|
||||||
|
rename table(:users), :hashed_password, to: :password_hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"ash_functions_version": 5,
|
"ash_functions_version": 5,
|
||||||
"installed": [
|
"installed": [
|
||||||
"ash-functions"
|
"ash-functions",
|
||||||
|
"citext"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
89
priv/resource_snapshots/repo/tokens/20250602064357.json
Normal file
89
priv/resource_snapshots/repo/tokens/20250602064357.json
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "updated_at",
|
||||||
|
"type": "utc_datetime_usec"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "created_at",
|
||||||
|
"type": "utc_datetime_usec"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "extra_data",
|
||||||
|
"type": "map"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "purpose",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "expires_at",
|
||||||
|
"type": "utc_datetime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "subject",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": true,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "jti",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"base_filter": null,
|
||||||
|
"check_constraints": [],
|
||||||
|
"custom_indexes": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true,
|
||||||
|
"hash": "FEFA652DA83D7A45390F6667C92DB6E8E8D5CDF709B37834CC4C8AD38E52CFFC",
|
||||||
|
"identities": [],
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"repo": "Elixir.Mv.Repo",
|
||||||
|
"schema": null,
|
||||||
|
"table": "tokens"
|
||||||
|
}
|
||||||
88
priv/resource_snapshots/repo/users/20250602064357.json
Normal file
88
priv/resource_snapshots/repo/users/20250602064357.json
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "fragment(\"uuid_generate_v7()\")",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": true,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "id",
|
||||||
|
"type": "uuid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "email",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "password_hash",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "oicd_id",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": {
|
||||||
|
"deferrable": false,
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"index?": false,
|
||||||
|
"match_type": null,
|
||||||
|
"match_with": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"name": "users_member_id_fkey",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"schema": "public",
|
||||||
|
"table": "members"
|
||||||
|
},
|
||||||
|
"size": null,
|
||||||
|
"source": "member_id",
|
||||||
|
"type": "uuid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"base_filter": null,
|
||||||
|
"check_constraints": [],
|
||||||
|
"custom_indexes": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true,
|
||||||
|
"hash": "48E05AF26A1C25A2D34E5BB3AB26654456D7BD4A73B9C92FC439835D9E453861",
|
||||||
|
"identities": [],
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"repo": "Elixir.Mv.Repo",
|
||||||
|
"schema": null,
|
||||||
|
"table": "users"
|
||||||
|
}
|
||||||
103
priv/resource_snapshots/repo/users/20250602071122.json
Normal file
103
priv/resource_snapshots/repo/users/20250602071122.json
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "fragment(\"gen_random_uuid()\")",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": true,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "id",
|
||||||
|
"type": "uuid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "email",
|
||||||
|
"type": "citext"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "hashed_password",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "oicd_id",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": {
|
||||||
|
"deferrable": false,
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"index?": false,
|
||||||
|
"match_type": null,
|
||||||
|
"match_with": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"name": "users_member_id_fkey",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"schema": "public",
|
||||||
|
"table": "members"
|
||||||
|
},
|
||||||
|
"size": null,
|
||||||
|
"source": "member_id",
|
||||||
|
"type": "uuid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"base_filter": null,
|
||||||
|
"check_constraints": [],
|
||||||
|
"custom_indexes": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true,
|
||||||
|
"hash": "C8B3A4BCBE42E1FFECED346B254902C69E402ADC2528CF4941D342A6E08164FC",
|
||||||
|
"identities": [
|
||||||
|
{
|
||||||
|
"all_tenants?": false,
|
||||||
|
"base_filter": null,
|
||||||
|
"index_name": "users_unique_email_index",
|
||||||
|
"keys": [
|
||||||
|
{
|
||||||
|
"type": "atom",
|
||||||
|
"value": "email"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "unique_email",
|
||||||
|
"nils_distinct?": true,
|
||||||
|
"where": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"repo": "Elixir.Mv.Repo",
|
||||||
|
"schema": null,
|
||||||
|
"table": "users"
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue