This commit is contained in:
parent
bc9ea818eb
commit
b41f005d9e
9 changed files with 110 additions and 92 deletions
|
|
@ -80,30 +80,30 @@ defmodule Mv.Membership do
|
|||
end
|
||||
|
||||
resource Mv.Membership.JoinRequest do
|
||||
define :list_join_requests, action: :read
|
||||
define :get_join_request, action: :read, get_by: [:id]
|
||||
define :list_join_requests, action: :admin_read
|
||||
define :get_join_request, action: :admin_read, get_by: [:id]
|
||||
define :update_join_request, action: :update
|
||||
define :destroy_join_request, action: :destroy
|
||||
end
|
||||
end
|
||||
|
||||
# Idempotent confirm: implemented in code so duplicate token returns {:ok, existing} (concept §2.3.2)
|
||||
# Idempotent confirm: duplicate token hits unique constraint -> return {:ok, nil} (no public read)
|
||||
@doc """
|
||||
Creates a JoinRequest after confirmation link click (public action with actor: nil).
|
||||
|
||||
Idempotent: if a JoinRequest with the same `confirmation_token_hash` already exists,
|
||||
returns `{:ok, existing}` instead of creating a duplicate (per concept §2.3.2).
|
||||
returns `{:ok, nil}` (no record returned; no public read for security).
|
||||
"""
|
||||
def confirm_join_request(attrs, opts \\ []) do
|
||||
hash = attrs[:confirmation_token_hash] || attrs["confirmation_token_hash"]
|
||||
case do_confirm_join_request(attrs, opts) do
|
||||
{:ok, request} ->
|
||||
{:ok, request}
|
||||
|
||||
if hash do
|
||||
case get_join_request_by_confirmation_token_hash!(hash, opts) do
|
||||
nil -> do_confirm_join_request(attrs, opts)
|
||||
existing -> {:ok, existing}
|
||||
end
|
||||
else
|
||||
do_confirm_join_request(attrs, opts)
|
||||
{:error, %Ash.Error.Invalid{errors: errors}} = error ->
|
||||
if unique_confirmation_token_violation?(errors), do: {:ok, nil}, else: error
|
||||
|
||||
other ->
|
||||
other
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -113,17 +113,12 @@ defmodule Mv.Membership do
|
|||
|> Ash.create(Keyword.put(opts, :domain, __MODULE__))
|
||||
end
|
||||
|
||||
defp get_join_request_by_confirmation_token_hash!(hash, opts) do
|
||||
opts = Keyword.put(opts, :domain, __MODULE__)
|
||||
|
||||
Mv.Membership.JoinRequest
|
||||
|> Ash.Query.filter(confirmation_token_hash == ^hash)
|
||||
|> Ash.read_one(opts)
|
||||
|> case do
|
||||
{:ok, %Mv.Membership.JoinRequest{} = existing} -> existing
|
||||
{:ok, nil} -> nil
|
||||
_ -> nil
|
||||
end
|
||||
defp unique_confirmation_token_violation?(errors) do
|
||||
Enum.any?(errors, fn err ->
|
||||
Map.get(err, :field) == :confirmation_token_hash or
|
||||
((pv = Map.get(err, :private_vars)) &&
|
||||
(is_list(pv) and Keyword.get(pv, :constraint_type) == :unique))
|
||||
end)
|
||||
end
|
||||
|
||||
# Singleton pattern: Get the single settings record
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue