Comment out thread tipping until payments are enabled

2cced7f5f6ed · AtlantisPleb · · parent d03c9a550a35

Comment out thread tipping until payments are enabled

With the payment service disabled, every tip button answered
"Tipping is not enabled here yet". The tip buttons, the Tips link,
the tip event, and the tests that click them are commented out in
place, ready to return with the service. The tips settings page and
the API tip surface stay as they are.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E1mRkPGYmTVvMKqAzmQvy5
Co-Authored-By
Claude Fable 5 <noreply@anthropic.com>

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

Not deployed through the forge lane

No push, promotion, build, or deploy receipt references this commit (receipts are scanned over a bounded recent window). Changes shipped by full node replacement carry their proof in the release gate receipt instead.

Changed files

  • modified docs/forum-bitcoin-tips.md
  • modified lib/openagents_web/live/forum_topic_live.ex
  • modified test/openagents_web/live/forum_tips_live_test.exs

Diff

3 files changed, +140 -121

docs/forum-bitcoin-tips.md modified +3 -1

@@ -3,7 +3,9 @@

3 3
Date: 2026-08-23
4 4
5 5
Status: Current. The domain lives in `OpenAgents.Forum.Tips`; the browser
6
surface is `/forum/tips` and the tip buttons under each post.
6
surface is `/forum/tips`. The tip buttons under each post are commented out
7
in `OpenAgentsWeb.ForumTopicLive` until the payment service is enabled, so
8
every click stops answering "Tipping is not enabled here yet".
7 9
8 10
## What custody means here
9 11
lib/openagents_web/live/forum_topic_live.ex modified +58 -47

@@ -17,13 +17,14 @@ defmodule OpenAgentsWeb.ForumTopicLive do

17 17
  use OpenAgentsWeb, :live_view
18 18
19 19
  alias OpenAgents.Forum
20
  alias OpenAgents.Forum.Tips
20
  # Tipping is commented out until the payment service is enabled here.
21
  # alias OpenAgents.Forum.Tips
21 22
  alias OpenAgents.Markdown
22 23
  alias OpenAgentsWeb.LiveRefresh
23 24
  alias OpenAgentsWeb.OG
24 25
25 26
  # Preset amounts keep tipping one click. Larger amounts go through the API.
26
  @tip_amounts [100, 1_000]
27
  # @tip_amounts [100, 1_000]
27 28
28 29
  def mount(%{"id" => id}, _session, socket) do
29 30
    scope = [operator?: OpenAgents.Accounts.admin?(socket.assigns[:current_user])]

@@ -103,33 +104,37 @@ defmodule OpenAgentsWeb.ForumTopicLive do

103 104
104 105
  # Tipping pays the author's own destination. A fresh idempotency key per
105 106
  # click means a double click cannot pay twice for the same request.
106
  def handle_event("tip", %{"id" => id, "amount" => amount}, socket) do
107
    with %{} = user <- current_user(socket),
108
         {sats, ""} <- Integer.parse(amount),
109
         post when not is_nil(post) <- Enum.find(socket.assigns.posts, &(&1.id == id)) do
110
      request = %{
111
        post: post,
112
        payer_user: user,
113
        payer_actor_ref: "user:#{user.id}",
114
        amount_sats: sats,
115
        idempotency_key: Ecto.UUID.generate()
116
      }
117
118
      case Tips.tip_post(request) do
119
        {:ok, intent} ->
120
          {:noreply, socket |> refresh_panel(:posts) |> put_flash(:info, tip_message(intent))}
121
122
        {:error, {:payment_failed, intent}} ->
123
          {:noreply,
124
           put_flash(socket, :error, "Payment failed: #{intent.failure_code}. Nothing was sent.")}
125
126
        {:error, reason} ->
127
          {:noreply, put_flash(socket, :error, tip_error(reason))}
128
      end
129
    else
130
      _unavailable -> {:noreply, put_flash(socket, :error, "Sign in to tip")}
131
    end
132
  end
107
  #
108
  # Commented out until the payment service is enabled here: with it disabled,
109
  # every click answered "Tipping is not enabled here yet".
110
  #
111
  # def handle_event("tip", %{"id" => id, "amount" => amount}, socket) do
112
  #   with %{} = user <- current_user(socket),
113
  #        {sats, ""} <- Integer.parse(amount),
114
  #        post when not is_nil(post) <- Enum.find(socket.assigns.posts, &(&1.id == id)) do
115
  #     request = %{
116
  #       post: post,
117
  #       payer_user: user,
118
  #       payer_actor_ref: "user:#{user.id}",
119
  #       amount_sats: sats,
120
  #       idempotency_key: Ecto.UUID.generate()
121
  #     }
122
  #
123
  #     case Tips.tip_post(request) do
124
  #       {:ok, intent} ->
125
  #         {:noreply, socket |> refresh_panel(:posts) |> put_flash(:info, tip_message(intent))}
126
  #
127
  #       {:error, {:payment_failed, intent}} ->
128
  #         {:noreply,
129
  #          put_flash(socket, :error, "Payment failed: #{intent.failure_code}. Nothing was sent.")}
130
  #
131
  #       {:error, reason} ->
132
  #         {:noreply, put_flash(socket, :error, tip_error(reason))}
133
  #     end
134
  #   else
135
  #     _unavailable -> {:noreply, put_flash(socket, :error, "Sign in to tip")}
136
  #   end
137
  # end
133 138
134 139
  def handle_event("toggle_closed", _params, socket) do
135 140
    with %{} = user <- current_user(socket),

@@ -167,9 +172,11 @@ defmodule OpenAgentsWeb.ForumTopicLive do

167 172
        </.link>
168 173
        <span class="text-muted-foreground">/</span>
169 174
        <h1 class="text-2xl font-bold">{@topic.title}</h1>
175
        <%!-- Tipping is commented out until the payment service is enabled here.
170 176
        <.link navigate={~p"/forum/tips"} class="text-sm text-muted-foreground hover:text-foreground">
171 177
          Tips
172 178
        </.link>
179
        --%>
173 180
        <%= if @topic.state == "closed" do %>
174 181
          <span class="badge" data-variant="dim">closed</span>
175 182
        <% end %>

@@ -210,6 +217,7 @@ defmodule OpenAgentsWeb.ForumTopicLive do

210 217
          <div class="prose prose-sm dark:prose-invert max-w-none">
211 218
            {Markdown.to_html(post.body_text)}
212 219
          </div>
220
          <%!-- Tipping is commented out until the payment service is enabled here.
213 221
          <footer :if={@current_user} class="flex items-center gap-2 mt-3">
214 222
            <span class="text-xs text-muted-foreground">Tip the author</span>
215 223
            <button

@@ -224,6 +232,7 @@ defmodule OpenAgentsWeb.ForumTopicLive do

224 232
              {amount} sats
225 233
            </button>
226 234
          </footer>
235
          --%>
227 236
        </div>
228 237
      </div>
229 238

@@ -269,22 +278,24 @@ defmodule OpenAgentsWeb.ForumTopicLive do

269 278
    end
270 279
  end
271 280
272
  defp tip_message(%{counted_sats: 0, exclusion_reason: reason, amount_sats: sats})
273
       when is_binary(reason) do
274
    "Sent #{sats} sats. This tip does not change ranking (#{String.replace(reason, "_", " ")})."
275
  end
276
277
  defp tip_message(%{amount_sats: sats}), do: "Sent #{sats} sats"
278
279
  defp tip_error(:tipping_disabled), do: "Tipping is not enabled here yet"
280
  defp tip_error(:no_destination), do: "This author has no tip destination yet"
281
  defp tip_error(:not_accepting_tips), do: "This author is not accepting tips"
282
  defp tip_error(:post_not_visible), do: "This post cannot be tipped"
283
284
  defp tip_error(:payment_service_unavailable),
285
    do: "The payment service is unavailable. Nothing was sent."
286
287
  defp tip_error(_reason), do: "That tip could not be sent"
288
289
  defp tip_amounts, do: @tip_amounts
281
  # Tipping helpers, commented out with the tip event above.
282
  #
283
  # defp tip_message(%{counted_sats: 0, exclusion_reason: reason, amount_sats: sats})
284
  #      when is_binary(reason) do
285
  #   "Sent #{sats} sats. This tip does not change ranking (#{String.replace(reason, "_", " ")})."
286
  # end
287
  #
288
  # defp tip_message(%{amount_sats: sats}), do: "Sent #{sats} sats"
289
  #
290
  # defp tip_error(:tipping_disabled), do: "Tipping is not enabled here yet"
291
  # defp tip_error(:no_destination), do: "This author has no tip destination yet"
292
  # defp tip_error(:not_accepting_tips), do: "This author is not accepting tips"
293
  # defp tip_error(:post_not_visible), do: "This post cannot be tipped"
294
  #
295
  # defp tip_error(:payment_service_unavailable),
296
  #   do: "The payment service is unavailable. Nothing was sent."
297
  #
298
  # defp tip_error(_reason), do: "That tip could not be sent"
299
  #
300
  # defp tip_amounts, do: @tip_amounts
290 301
end
test/openagents_web/live/forum_tips_live_test.exs modified +79 -73

@@ -23,36 +23,38 @@ defmodule OpenAgentsWeb.ForumTipsLiveTest do

23 23
    {Plug.Test.init_test_session(conn, %{"user_id" => user.id}), user}
24 24
  end
25 25
26
  defp author(forum, key) do
27
    {_conn, user} = sign_in(build_conn(), key)
28
    actor_ref = "agent:user_ed8297d8-1279-4b43-a1e7-f7867da19e20"
29
30
    {:ok, link} = Forum.start_actor_link(user, actor_ref)
31
    {:ok, _linked} = Forum.approve_actor_link(link)
32
33
    {:ok, destination} =
34
      Tips.register_destination(%{
35
        user_id: user.id,
36
        kind: "bolt12",
37
        destination: "lno1qsgliveauthor",
38
        label: "Phone wallet"
39
      })
40
41
    {:ok, topic} =
42
      Forum.create_topic(forum, %{
43
        title: "Hello world",
44
        slug: "hello-world",
45
        body_text: "First post body",
46
        idempotency_key: Ecto.UUID.generate(),
47
        actor_ref: actor_ref,
48
        actor_display_name: "Orrery",
49
        actor_slug: "orrery"
50
      })
51
52
    [post] = Forum.list_posts(topic)
53
54
    %{user: user, destination: destination, topic: topic, post: post}
55
  end
26
  # Used only by the commented-out thread tipping tests below.
27
  #
28
  # defp author(forum, key) do
29
  #   {_conn, user} = sign_in(build_conn(), key)
30
  #   actor_ref = "agent:user_ed8297d8-1279-4b43-a1e7-f7867da19e20"
31
  #
32
  #   {:ok, link} = Forum.start_actor_link(user, actor_ref)
33
  #   {:ok, _linked} = Forum.approve_actor_link(link)
34
  #
35
  #   {:ok, destination} =
36
  #     Tips.register_destination(%{
37
  #       user_id: user.id,
38
  #       kind: "bolt12",
39
  #       destination: "lno1qsgliveauthor",
40
  #       label: "Phone wallet"
41
  #     })
42
  #
43
  #   {:ok, topic} =
44
  #     Forum.create_topic(forum, %{
45
  #       title: "Hello world",
46
  #       slug: "hello-world",
47
  #       body_text: "First post body",
48
  #       idempotency_key: Ecto.UUID.generate(),
49
  #       actor_ref: actor_ref,
50
  #       actor_display_name: "Orrery",
51
  #       actor_slug: "orrery"
52
  #     })
53
  #
54
  #   [post] = Forum.list_posts(topic)
55
  #
56
  #   %{user: user, destination: destination, topic: topic, post: post}
57
  # end
56 58
57 59
  test "a signed-in reader saves a destination and sees only its fingerprint", %{conn: conn} do
58 60
    {conn, user} = sign_in(conn, "forum-tips-live-owner")

@@ -85,47 +87,51 @@ defmodule OpenAgentsWeb.ForumTipsLiveTest do

85 87
    assert Tips.active_destination(user.id).accepting_tips == false
86 88
  end
87 89
88
  test "tipping a post from the thread settles and shows the new total", %{
89
    conn: conn,
90
    forum: forum
91
  } do
92
    author = author(forum, "forum-tips-live-author")
93
    {conn, _payer} = sign_in(conn, "forum-tips-live-payer")
94
95
    {:ok, view, _html} = live(conn, ~p"/forum/t/#{author.topic.id}")
96
97
    html = render_click(view, "tip", %{"id" => author.post.id, "amount" => "1000"})
98
99
    assert html =~ "Sent 1000 sats"
100
101
    render_click(view, "tip", %{"id" => author.post.id, "amount" => "1000"})
102
103
    assert Repo.reload!(author.post).tip_sats_counted == 2_000
104
    assert render(view) =~ "2000 sats"
105
  end
106
107
  test "a thread never renders a payment destination", %{conn: conn, forum: forum} do
108
    author = author(forum, "forum-tips-live-privacy")
109
    {conn, _payer} = sign_in(conn, "forum-tips-live-privacy-payer")
110
111
    {:ok, view, _html} = live(conn, ~p"/forum/t/#{author.topic.id}")
112
113
    html = render_click(view, "tip", %{"id" => author.post.id, "amount" => "1000"})
114
115
    refute html =~ "lno1qsgliveauthor"
116
    refute html =~ author.destination.destination
117
  end
118
119
  test "a payment outage tells the payer nothing was sent", %{conn: conn, forum: forum} do
120
    author = author(forum, "forum-tips-live-outage")
121
    {conn, _payer} = sign_in(conn, "forum-tips-live-outage-payer")
122
    TipPaymentServiceStub.unavailable()
123
124
    {:ok, view, _html} = live(conn, ~p"/forum/t/#{author.topic.id}")
125
126
    html = render_click(view, "tip", %{"id" => author.post.id, "amount" => "1000"})
127
128
    assert html =~ "payment service is unavailable"
129
    assert Repo.reload!(author.post).tip_sats_total == 0
130
  end
90
  # Thread tipping is commented out in ForumTopicLive until the payment
91
  # service is enabled here, and these tests go with it. The API-side tip
92
  # tests in ForumTipsApiControllerTest still cover settlement itself.
93
  #
94
  # test "tipping a post from the thread settles and shows the new total", %{
95
  #   conn: conn,
96
  #   forum: forum
97
  # } do
98
  #   author = author(forum, "forum-tips-live-author")
99
  #   {conn, _payer} = sign_in(conn, "forum-tips-live-payer")
100
  #
101
  #   {:ok, view, _html} = live(conn, ~p"/forum/t/#{author.topic.id}")
102
  #
103
  #   html = render_click(view, "tip", %{"id" => author.post.id, "amount" => "1000"})
104
  #
105
  #   assert html =~ "Sent 1000 sats"
106
  #
107
  #   render_click(view, "tip", %{"id" => author.post.id, "amount" => "1000"})
108
  #
109
  #   assert Repo.reload!(author.post).tip_sats_counted == 2_000
110
  #   assert render(view) =~ "2000 sats"
111
  # end
112
  #
113
  # test "a thread never renders a payment destination", %{conn: conn, forum: forum} do
114
  #   author = author(forum, "forum-tips-live-privacy")
115
  #   {conn, _payer} = sign_in(conn, "forum-tips-live-privacy-payer")
116
  #
117
  #   {:ok, view, _html} = live(conn, ~p"/forum/t/#{author.topic.id}")
118
  #
119
  #   html = render_click(view, "tip", %{"id" => author.post.id, "amount" => "1000"})
120
  #
121
  #   refute html =~ "lno1qsgliveauthor"
122
  #   refute html =~ author.destination.destination
123
  # end
124
  #
125
  # test "a payment outage tells the payer nothing was sent", %{conn: conn, forum: forum} do
126
  #   author = author(forum, "forum-tips-live-outage")
127
  #   {conn, _payer} = sign_in(conn, "forum-tips-live-outage-payer")
128
  #   TipPaymentServiceStub.unavailable()
129
  #
130
  #   {:ok, view, _html} = live(conn, ~p"/forum/t/#{author.topic.id}")
131
  #
132
  #   html = render_click(view, "tip", %{"id" => author.post.id, "amount" => "1000"})
133
  #
134
  #   assert html =~ "payment service is unavailable"
135
  #   assert Repo.reload!(author.post).tip_sats_total == 0
136
  # end
131 137
end

This page updates live while a promote is in flight · changelog