From 7307dd5774c86c01100ad4efae55502997708584 Mon Sep 17 00:00:00 2001 From: zafer Date: Fri, 10 Jan 2025 11:16:36 +0300 Subject: [PATCH] feat: bounty notifications via Oban job --- config/config.exs | 3 +- lib/algora/bounties/bounties.ex | 58 +++++++------------ lib/algora/bounties/jobs/notify_bounty.ex | 34 +++++++++++ .../github/poller/comment_consumer.ex | 43 +++----------- .../live/community/dashboard_live.ex | 4 +- lib/algora_web/live/org/bounty_hook.ex | 3 +- lib/algora_web/live/org/create_bounty_live.ex | 3 +- lib/algora_web/live/swift_bounties_live.ex | 4 +- 8 files changed, 70 insertions(+), 82 deletions(-) create mode 100644 lib/algora/bounties/jobs/notify_bounty.ex diff --git a/config/config.exs b/config/config.exs index ad4e62b76..6ccf73175 100644 --- a/config/config.exs +++ b/config/config.exs @@ -31,7 +31,8 @@ config :algora, Oban, queues: [ event_consumers: 1, comment_consumers: 1, - github_og_image: 5 + github_og_image: 5, + notify_bounty: 1 ] # Configures the mailer diff --git a/lib/algora/bounties/bounties.ex b/lib/algora/bounties/bounties.ex index 5bb292c7f..cebcbae5e 100644 --- a/lib/algora/bounties/bounties.ex +++ b/lib/algora/bounties/bounties.ex @@ -7,9 +7,9 @@ defmodule Algora.Bounties do alias Algora.Accounts.User alias Algora.Bounties.Bounty alias Algora.Bounties.Claim + alias Algora.Bounties.Jobs alias Algora.Bounties.Tip alias Algora.FeeTier - alias Algora.Github alias Algora.MoneyUtils alias Algora.Organizations.Member alias Algora.Payments @@ -37,9 +37,9 @@ defmodule Algora.Bounties do Phoenix.PubSub.subscribe(Algora.PubSub, "bounties:all") end - @spec create_bounty(%{creator: User.t(), owner: User.t(), amount: Money.t(), ticket: Ticket.t()}) :: + @spec do_create_bounty(%{creator: User.t(), owner: User.t(), amount: Money.t(), ticket: Ticket.t()}) :: {:ok, Bounty.t()} | {:error, atom()} - def create_bounty(%{creator: creator, owner: owner, amount: amount, ticket: ticket}) do + defp do_create_bounty(%{creator: creator, owner: owner, amount: amount, ticket: ticket}) do changeset = Bounty.changeset(%Bounty{}, %{ amount: amount, @@ -72,46 +72,30 @@ defmodule Algora.Bounties do creator: creator, owner: owner, amount: amount, - ticket_ref: %{owner: repo_owner, repo: repo_name, number: number} + ticket_ref: %{owner: repo_owner, repo: repo_name, number: number} = ticket_ref }) do - with {:ok, token} <- Accounts.get_access_token(creator), - {:ok, ticket} <- Workspace.ensure_ticket(token, repo_owner, repo_name, number) do - create_bounty(%{creator: creator, owner: owner, amount: amount, ticket: ticket}) - else - {:error, _reason} = error -> error - end - end - - def notify_bounty(%{owner: owner, bounty: bounty, ticket_ref: ticket_ref}) do - # TODO: post comment in a separate job - body = """ - 💎 **#{owner.provider_login}** is offering a **#{Money.to_string!(bounty.amount, no_fraction_if_integer: true)}** bounty for this issue - - 👉 Got a pull request resolving this? Claim the bounty by commenting `/claim ##{ticket_ref.number}` in your PR and joining swift.algora.io - """ - - Task.start(fn -> - if Github.pat_enabled() do - Github.create_issue_comment( - Github.pat(), - ticket_ref.owner, - ticket_ref.repo, - ticket_ref.number, - body - ) + Repo.transact(fn -> + with {:ok, token} <- Accounts.get_access_token(creator), + {:ok, ticket} <- Workspace.ensure_ticket(token, repo_owner, repo_name, number), + {:ok, bounty} <- do_create_bounty(%{creator: creator, owner: owner, amount: amount, ticket: ticket}), + {:ok, _job} <- notify_bounty(%{owner: owner, bounty: bounty, ticket_ref: ticket_ref}) do + {:ok, bounty} else - Logger.info(""" - Github.create_issue_comment(Github.pat(), "#{ticket_ref.owner}", "#{ticket_ref.repo}", #{ticket_ref.number}, - \"\"\" - #{body} - \"\"\") - """) - - :ok + {:error, _reason} = error -> error end end) end + def notify_bounty(%{owner: owner, bounty: bounty, ticket_ref: ticket_ref}) do + %{ + owner_login: owner.provider_login, + amount: Money.to_string!(bounty.amount, no_fraction_if_integer: true), + ticket_ref: %{owner: ticket_ref.owner, repo: ticket_ref.repo, number: ticket_ref.number} + } + |> Jobs.NotifyBounty.new() + |> Oban.insert() + end + @spec create_tip(%{creator: User.t(), owner: User.t(), recipient: User.t(), amount: Money.t()}) :: {:ok, String.t()} | {:error, atom()} def create_tip(%{creator: creator, owner: owner, recipient: recipient, amount: amount}) do diff --git a/lib/algora/bounties/jobs/notify_bounty.ex b/lib/algora/bounties/jobs/notify_bounty.ex new file mode 100644 index 000000000..71c867a72 --- /dev/null +++ b/lib/algora/bounties/jobs/notify_bounty.ex @@ -0,0 +1,34 @@ +defmodule Algora.Bounties.Jobs.NotifyBounty do + @moduledoc false + use Oban.Worker, queue: :notify_bounty + + alias Algora.Github + + require Logger + + @impl Oban.Worker + def perform(%Oban.Job{args: %{"owner_login" => owner_login, "amount" => amount, "ticket_ref" => ticket_ref}}) do + body = """ + 💎 **#{owner_login}** is offering a **#{amount}** bounty for this issue + + 👉 Got a pull request resolving this? Claim the bounty by commenting `/claim ##{ticket_ref["number"]}` in your PR and joining swift.algora.io + """ + + if Github.pat_enabled() do + Github.create_issue_comment( + Github.pat(), + ticket_ref["owner"], + ticket_ref["repo"], + ticket_ref["number"], + body + ) + else + Logger.info(""" + Github.create_issue_comment(Github.pat(), "#{ticket_ref["owner"]}", "#{ticket_ref["repo"]}", #{ticket_ref["number"]}, + \"\"\" + #{body} + \"\"\") + """) + end + end +end diff --git a/lib/algora/integrations/github/poller/comment_consumer.ex b/lib/algora/integrations/github/poller/comment_consumer.ex index 3892f0487..a8c13c02e 100644 --- a/lib/algora/integrations/github/poller/comment_consumer.ex +++ b/lib/algora/integrations/github/poller/comment_consumer.ex @@ -6,7 +6,6 @@ defmodule Algora.Github.Poller.CommentConsumer do alias Algora.Bounties alias Algora.Github alias Algora.Util - alias Algora.Workspace require Logger @@ -51,42 +50,14 @@ defmodule Algora.Github.Poller.CommentConsumer do end defp run_command({:bounty, args}, ticket_ref, comment) do - owner = Keyword.get(ticket_ref, :owner) - repo = Keyword.get(ticket_ref, :repo) - number = Keyword.get(ticket_ref, :number) - with {:ok, user} <- Accounts.fetch_user_by(provider_id: to_string(comment["user"]["id"])), - {:ok, token} <- Accounts.get_access_token(user), - {:ok, amount} <- Keyword.fetch(args, :amount), - {:ok, ticket} <- Workspace.ensure_ticket(token, owner, repo, number), - {:ok, _bounty} <- - Bounties.create_bounty(%{ - creator: user, - owner: user, - amount: amount, - ticket: ticket - }) do - # TODO: post comment in a separate job - body = """ - 💎 **#{user.provider_login}** is offering a **#{Money.to_string!(amount, no_fraction_if_integer: true)}** bounty for this issue - - 👉 Got a pull request resolving this? Claim the bounty by commenting `/claim ##{number}` in your PR and joining swift.algora.io - """ - - if Github.pat_enabled() do - Github.create_issue_comment(Github.pat(), owner, repo, number, body) - else - Logger.info(""" - Github.create_issue_comment(Github.pat(), "#{owner}", "#{repo}", #{number}, - \"\"\" - #{body} - \"\"\") - """) - - :ok - end - - :ok + {:ok, amount} <- Keyword.fetch(args, :amount) do + Bounties.create_bounty(%{ + creator: user, + owner: user, + amount: amount, + ticket_ref: %{owner: ticket_ref[:owner], repo: ticket_ref[:repo], number: ticket_ref[:number]} + }) else {:error, _reason} = error -> Logger.error("Failed to create bounty: #{inspect(error)}") diff --git a/lib/algora_web/live/community/dashboard_live.ex b/lib/algora_web/live/community/dashboard_live.ex index 85a992eca..45c0a2e35 100644 --- a/lib/algora_web/live/community/dashboard_live.ex +++ b/lib/algora_web/live/community/dashboard_live.ex @@ -220,15 +220,13 @@ defmodule AlgoraWeb.Community.DashboardLive do ticket_ref = get_field(changeset, :ticket_ref) with %{valid?: true} <- changeset, - {:ok, bounty} <- + {:ok, _bounty} <- Bounties.create_bounty(%{ creator: socket.assigns.current_user, owner: socket.assigns.current_user, amount: amount, ticket_ref: ticket_ref }) do - Bounties.notify_bounty(%{owner: socket.assigns.current_user, bounty: bounty, ticket_ref: ticket_ref}) - {:noreply, socket |> assign_achievements() diff --git a/lib/algora_web/live/org/bounty_hook.ex b/lib/algora_web/live/org/bounty_hook.ex index 9bdcc283c..179db5d05 100644 --- a/lib/algora_web/live/org/bounty_hook.ex +++ b/lib/algora_web/live/org/bounty_hook.ex @@ -17,7 +17,8 @@ defmodule AlgoraWeb.Org.BountyHook do # TODO: use AlgoraWeb.Community.DashboardLive.BountyForm with {:ok, [ticket_ref: ticket_ref], _, _, _, _} <- Parser.full_ticket_ref(url), - {:ok, _bounty} <- Bounties.create_bounty(%{creator: creator, owner: owner, ticket: ticket_ref, amount: amount}) do + {:ok, _bounty} <- + Bounties.create_bounty(%{creator: creator, owner: owner, ticket_ref: ticket_ref, amount: amount}) do {:halt, socket |> put_flash(:info, "Bounty created successfully") diff --git a/lib/algora_web/live/org/create_bounty_live.ex b/lib/algora_web/live/org/create_bounty_live.ex index 532c22469..fdfd1d084 100644 --- a/lib/algora_web/live/org/create_bounty_live.ex +++ b/lib/algora_web/live/org/create_bounty_live.ex @@ -458,7 +458,8 @@ defmodule AlgoraWeb.Org.CreateBountyLive do url = get_change(changeset, :ticket_url) with {:ok, [ticket_ref: ticket_ref], _, _, _, _} <- Parser.full_ticket_ref(url), - {:ok, _bounty} <- Bounties.create_bounty(%{creator: creator, owner: owner, ticket: ticket_ref, amount: amount}) do + {:ok, _bounty} <- + Bounties.create_bounty(%{creator: creator, owner: owner, ticket_ref: ticket_ref, amount: amount}) do {:noreply, socket |> put_flash(:info, "Bounty created successfully") diff --git a/lib/algora_web/live/swift_bounties_live.ex b/lib/algora_web/live/swift_bounties_live.ex index 24b721229..38c76bd81 100644 --- a/lib/algora_web/live/swift_bounties_live.ex +++ b/lib/algora_web/live/swift_bounties_live.ex @@ -607,9 +607,7 @@ defmodule AlgoraWeb.SwiftBountiesLive do amount: amount, ticket_ref: ticket_ref }) do - {:ok, bounty} -> - Bounties.notify_bounty(%{owner: socket.assigns.current_user, bounty: bounty, ticket_ref: ticket_ref}) - + {:ok, _bounty} -> {:noreply, socket |> put_flash(:info, "Bounty created")