100 lines
2.4 KiB
Elixir
100 lines
2.4 KiB
Elixir
defmodule BDS.MCP.ProposalStore do
|
|
@moduledoc false
|
|
|
|
import Ecto.Query
|
|
|
|
alias BDS.MCP.Proposal
|
|
alias BDS.Persistence
|
|
alias BDS.Repo
|
|
|
|
@default_ttl_ms 30 * 60 * 1000
|
|
|
|
def ensure_started, do: :ok
|
|
|
|
def create(kind, data, opts \\ []) when is_binary(kind) and is_map(data) do
|
|
:ok = ensure_started()
|
|
cleanup_expired(opts)
|
|
now = Persistence.now_ms()
|
|
|
|
entity_id = Keyword.get(opts, :entity_id) || derive_entity_id(data)
|
|
|
|
%Proposal{}
|
|
|> Proposal.changeset(%{
|
|
id: Ecto.UUID.generate(),
|
|
kind: kind,
|
|
status: :pending,
|
|
entity_id: entity_id,
|
|
data: data,
|
|
created_at: now,
|
|
expires_at: now + Keyword.get(opts, :ttl_ms, @default_ttl_ms)
|
|
})
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
def get(id) when is_binary(id) do
|
|
:ok = ensure_started()
|
|
cleanup_expired([])
|
|
Repo.get(Proposal, id)
|
|
end
|
|
|
|
def remove(id) when is_binary(id) do
|
|
:ok = ensure_started()
|
|
Repo.delete_all(from proposal in Proposal, where: proposal.id == ^id)
|
|
:ok
|
|
end
|
|
|
|
def list do
|
|
:ok = ensure_started()
|
|
cleanup_expired([])
|
|
|
|
Repo.all(from proposal in Proposal, order_by: [asc: proposal.created_at])
|
|
end
|
|
|
|
def cleanup_expired(opts \\ []) do
|
|
:ok = ensure_started()
|
|
now = Persistence.now_ms()
|
|
on_expire = Keyword.get(opts, :on_expire)
|
|
|
|
expired =
|
|
Repo.all(
|
|
from proposal in Proposal,
|
|
where: proposal.status == :pending and proposal.expires_at <= ^now
|
|
)
|
|
|
|
Enum.each(expired, fn proposal ->
|
|
if is_function(on_expire, 1), do: on_expire.(proposal)
|
|
mark_status(proposal.id, :expired)
|
|
end)
|
|
|
|
Enum.map(expired, &Repo.get(Proposal, &1.id))
|
|
end
|
|
|
|
def mark_accepted(id) when is_binary(id), do: remove(id)
|
|
def mark_discarded(id) when is_binary(id), do: remove(id)
|
|
|
|
defp mark_status(id, status) do
|
|
case Repo.get(Proposal, id) do
|
|
nil ->
|
|
nil
|
|
|
|
proposal ->
|
|
Repo.delete_all(
|
|
from other in Proposal,
|
|
where:
|
|
other.id != ^id and other.kind == ^proposal.kind and
|
|
other.entity_id == ^proposal.entity_id and
|
|
other.status == ^status
|
|
)
|
|
|
|
proposal
|
|
|> Proposal.changeset(%{status: status})
|
|
|> Repo.update!()
|
|
end
|
|
end
|
|
|
|
defp derive_entity_id(data) do
|
|
data["post_id"] || data["script_id"] || data["template_id"] || data["media_id"] ||
|
|
Ecto.UUID.generate()
|
|
end
|
|
end
|