Initial commit on Forgejo
All checks were successful
CI and deploy / Test (push) Successful in 4m52s
CI and deploy / Deploy production (push) Successful in 23s

Fresh repository history for elektrine/tarakan hosted at
https://git.elektrine.com/elektrine/tarakan.
This commit is contained in:
Maxfield Luke 2026-07-29 04:43:40 -04:00
commit af6077b9c3
455 changed files with 78366 additions and 0 deletions

View file

@ -0,0 +1,159 @@
defmodule TarakanWeb.BountyLive.Index do
@moduledoc "Open contracts - the public reward board."
use TarakanWeb, :live_view
import TarakanWeb.BountyComponents
alias Tarakan.Market
@filters [
{"all", "All"},
{"repository", "Repositories"},
{"infestation", "Infestations"},
{"finding", "Findings"}
]
@impl true
def mount(_params, _session, socket) do
{:ok,
socket
|> assign(:page_title, "Contracts")
|> assign(
:meta_description,
"Open contracts on Tarakan. Sponsors post rewards for security work on public targets."
)
|> assign(:canonical_path, ~p"/bounties")
|> assign(:filters, @filters)}
end
@impl true
def handle_params(params, _uri, socket) do
filter = normalize_filter(params["type"])
bounties = Market.list_open(target_type: filter)
{:noreply,
socket
|> assign(:filter, filter || "all")
|> assign(:bounties, bounties)
|> assign(:bounty_count, length(bounties))
|> assign(:open_cents, sum_by(bounties, :amount_cents))
|> assign(:open_credits, sum_by(bounties, :credit_amount))}
end
defp sum_by(bounties, key) do
Enum.reduce(bounties, 0, fn bounty, total -> total + (Map.get(bounty, key) || 0) end)
end
defp normalize_filter(filter) when filter in ["repository", "infestation", "finding"],
do: filter
defp normalize_filter(_), do: nil
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope} current_path={assigns[:current_path]}>
<Layouts.page width={:wide}>
<div class="flex flex-col gap-6 border-b-2 border-strong pb-6 sm:flex-row sm:items-end sm:justify-between">
<div class="min-w-0 max-w-2xl">
<h1 class="font-display text-3xl font-medium uppercase leading-none tracking-[0.02em] text-ink sm:text-5xl">
Contracts
</h1>
</div>
<div class="flex shrink-0 flex-wrap items-center gap-4">
<p class="font-mono text-sm tabular-nums text-ink">
<span class="font-display text-3xl">{@bounty_count}</span>
<span class="ml-1 text-xs uppercase tracking-[0.12em] text-ink-faint">open</span>
</p>
<p :if={@open_cents > 0} class="font-mono text-sm tabular-nums text-ink">
<span class="font-display text-3xl">${div(@open_cents, 100)}</span>
<span class="ml-1 text-xs uppercase tracking-[0.12em] text-ink-faint">escrowed</span>
</p>
<p :if={@open_credits > 0} class="font-mono text-sm tabular-nums text-ink">
<span class="font-display text-3xl">{@open_credits}</span>
<span class="ml-1 text-xs uppercase tracking-[0.12em] text-ink-faint">credits</span>
</p>
<.link
navigate={~p"/bounties/new"}
class="border-2 border-signal px-4 py-1.5 font-display text-xs uppercase tracking-[0.12em] text-signal transition hover:bg-signal hover:text-ground"
>
Post a contract
</.link>
</div>
</div>
<div id="bounty-filters" class="mt-6 flex flex-wrap items-center gap-2">
<.link
:for={{value, label} <- @filters}
patch={~p"/bounties?#{%{type: value}}"}
class={[
"wire-badge font-display text-[10px] uppercase tracking-[0.12em] transition",
@filter == value && "bg-signal text-ground",
@filter != value && "text-ink-muted hover:text-ink"
]}
>
<span class="wire-badge-label">{label}</span>
</.link>
</div>
<div
:if={@bounties == []}
id="bounties-empty"
class="mt-8 bg-panel px-6 py-12 text-center"
>
<p class="text-sm font-medium text-ink">No open contracts right now</p>
<p class="mt-2 text-xs leading-5 text-ink-muted">
<.link navigate={~p"/bounties/new"} class="font-semibold text-signal hover:underline">
Post the first one
</.link>
or browse the <.link
navigate={~p"/jobs"}
class="font-semibold text-signal hover:underline"
>jobs queue</.link>.
</p>
</div>
<ul
:if={@bounties != []}
id="bounties"
class="mt-8 grid gap-4 sm:grid-cols-2 xl:grid-cols-3"
>
<li :for={bounty <- @bounties} id={"bounty-#{bounty.public_id}"}>
<.link
navigate={~p"/bounties/#{bounty.public_id}"}
class="group flex h-full flex-col border-2 border-strong bg-panel transition-colors hover:bg-ground"
>
<div class="flex items-center justify-between border-b-2 border-strong px-4 py-2">
<.notch_badge class="bg-signal text-ground">Contract</.notch_badge>
<span class="font-mono text-[10px] uppercase tracking-[0.12em] text-ink-faint">
{bounty.target_type}
</span>
</div>
<div class="flex flex-1 flex-col px-4 py-4">
<p class="font-display text-3xl font-medium leading-none text-signal">
{amount_label(bounty)}
</p>
<p class="mt-3 text-sm font-semibold leading-5 text-ink group-hover:text-signal">
{bounty.title}
</p>
<p class="mt-2 line-clamp-2 text-xs leading-5 text-ink-muted">
{bounty.description}
</p>
<p class="mt-auto pt-4 font-mono text-[11px] text-ink-faint">
{target_label(bounty)}
<span :if={bounty.sponsor_account} class="mx-1">·</span>
<span :if={bounty.sponsor_account}>by @{bounty.sponsor_account.handle}</span>
<span :if={bounty.expires_at} class="mx-1">·</span>
<span :if={bounty.expires_at}>
expires {Calendar.strftime(bounty.expires_at, "%b %-d")}
</span>
</p>
</div>
</.link>
</li>
</ul>
</Layouts.page>
</Layouts.app>
"""
end
end