Skip to content

Commit 8c78a88

Browse files
committed
feat: transfer notifications (#47)
1 parent ac17454 commit 8c78a88

File tree

16 files changed

+742
-134
lines changed

16 files changed

+742
-134
lines changed

.iex.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ alias Algora.Payments.Customer
1818
alias Algora.Payments.PaymentMethod
1919
alias Algora.Payments.Transaction
2020
alias Algora.Repo
21+
alias Algora.Workspace.Ticket
2122

2223
IEx.configure(inspect: [charlists: :as_lists, limit: :infinity], auto_reload: true)
2324

config/config.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ config :algora, Oban,
3434
notify_bounty: 1,
3535
notify_tip_intent: 1,
3636
notify_claim: 1,
37+
notify_transfer: 100,
38+
prompt_payout_connect: 100,
3739
transfers: 1,
3840
activity_notifier: 1,
3941
activity_mailer: 1
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
defmodule Algora.Bounties.Jobs.NotifyTransfer do
2+
@moduledoc false
3+
use Oban.Worker, queue: :notify_transfer
4+
5+
import Ecto.Query
6+
7+
alias Algora.Bounties.Ticket
8+
alias Algora.Github
9+
alias Algora.Payments.Transaction
10+
alias Algora.Repo
11+
alias Algora.Workspace.Installation
12+
alias Algora.Workspace.Ticket
13+
14+
require Logger
15+
16+
@impl Oban.Worker
17+
def perform(%Oban.Job{args: %{"transafer_id" => transafer_id}}) do
18+
with {:ok, ticket} <-
19+
Repo.fetch_one(
20+
from t in Ticket,
21+
left_join: bounty in assoc(t, :bounties),
22+
left_join: tip in assoc(t, :tips),
23+
left_join: tx in Transaction,
24+
on: tx.bounty_id == bounty.id or tx.tip_id == tip.id,
25+
join: repo in assoc(t, :repository),
26+
join: user in assoc(repo, :user),
27+
where: tx.id == ^transafer_id,
28+
select_merge: %{
29+
repository: %{repo | user: user}
30+
}
31+
),
32+
ticket_ref = %{
33+
owner: ticket.repository.user.provider_login,
34+
repo: ticket.repository.name,
35+
number: ticket.number
36+
},
37+
{:ok, transaction} <-
38+
Repo.fetch_one(
39+
from tx in Transaction,
40+
join: user in assoc(tx, :user),
41+
where: tx.id == ^transafer_id,
42+
select_merge: %{user: user}
43+
) do
44+
installation = Repo.get_by(Installation, provider_user_id: ticket.repository.user.id)
45+
body = "🎉🎈 @#{transaction.user.provider_login} has been awarded **#{transaction.net_amount}**! 🎈🎊"
46+
47+
do_perform(ticket_ref, body, installation)
48+
end
49+
end
50+
51+
defp do_perform(ticket_ref, body, nil) do
52+
Github.try_without_installation(&Github.create_issue_comment/5, [
53+
ticket_ref.owner,
54+
ticket_ref.repo,
55+
ticket_ref.number,
56+
body
57+
])
58+
end
59+
60+
defp do_perform(ticket_ref, body, installation) do
61+
with {:ok, token} <- Github.get_installation_token(installation.provider_id) do
62+
Github.create_issue_comment(token, ticket_ref.owner, ticket_ref.repo, ticket_ref.number, body)
63+
end
64+
end
65+
end
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
defmodule Algora.Bounties.Jobs.PromptPayoutConnect do
2+
@moduledoc false
3+
use Oban.Worker, queue: :prompt_payout_connect
4+
5+
import Ecto.Query
6+
7+
alias Algora.Bounties.Ticket
8+
alias Algora.Github
9+
alias Algora.Payments.Transaction
10+
alias Algora.Repo
11+
alias Algora.Workspace.Installation
12+
alias Algora.Workspace.Ticket
13+
14+
require Logger
15+
16+
# TODO: confirm url
17+
@onboarding_url "https://console.algora.io/solve"
18+
19+
@impl Oban.Worker
20+
def perform(%Oban.Job{args: %{"credit_id" => credit_id}}) do
21+
with {:ok, ticket} <-
22+
Repo.fetch_one(
23+
from t in Ticket,
24+
left_join: bounty in assoc(t, :bounties),
25+
left_join: tip in assoc(t, :tips),
26+
left_join: tx in Transaction,
27+
on: tx.bounty_id == bounty.id or tx.tip_id == tip.id,
28+
join: repo in assoc(t, :repository),
29+
join: user in assoc(repo, :user),
30+
where: tx.id == ^credit_id,
31+
select_merge: %{
32+
repository: %{repo | user: user}
33+
}
34+
),
35+
ticket_ref = %{
36+
owner: ticket.repository.user.provider_login,
37+
repo: ticket.repository.name,
38+
number: ticket.number
39+
},
40+
{:ok, transaction} <-
41+
Repo.fetch_one(
42+
from tx in Transaction,
43+
join: user in assoc(tx, :user),
44+
left_join: linked_tx in Transaction,
45+
on: linked_tx.id == tx.linked_transaction_id,
46+
left_join: sender in assoc(linked_tx, :user),
47+
where: tx.id == ^credit_id,
48+
select_merge: %{
49+
user: user,
50+
linked_transaction: %{linked_tx | user: sender}
51+
}
52+
) do
53+
installation = Repo.get_by(Installation, provider_user_id: ticket.repository.user.id)
54+
55+
reward_type =
56+
cond do
57+
transaction.tip_id -> "tip"
58+
transaction.bounty_id -> "bounty"
59+
transaction.contract_id -> "contract"
60+
true -> raise "Unknown transaction type"
61+
end
62+
63+
body =
64+
"@#{transaction.user.provider_login}: You've been awarded a **#{transaction.net_amount}** #{reward_type} #{if transaction.linked_transaction, do: "by **#{transaction.linked_transaction.user.name}**", else: ""}! 👉 [Complete your Algora onboarding](#{@onboarding_url}) to collect the #{reward_type}."
65+
66+
do_perform(ticket_ref, body, installation)
67+
end
68+
end
69+
70+
defp do_perform(ticket_ref, body, nil) do
71+
Github.try_without_installation(&Github.create_issue_comment/5, [
72+
ticket_ref.owner,
73+
ticket_ref.repo,
74+
ticket_ref.number,
75+
body
76+
])
77+
end
78+
79+
defp do_perform(ticket_ref, body, installation) do
80+
with {:ok, token} <- Github.get_installation_token(installation.provider_id) do
81+
Github.create_issue_comment(token, ticket_ref.owner, ticket_ref.repo, ticket_ref.number, body)
82+
end
83+
end
84+
end

lib/algora/integrations/github/github.ex

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ defmodule Algora.Github do
22
@moduledoc false
33
@behaviour Algora.Github.Behaviour
44

5+
require Logger
6+
57
@type token :: String.t()
68

79
def client_id, do: Algora.config([:github, :client_id])
@@ -43,6 +45,27 @@ defmodule Algora.Github do
4345

4446
defp client, do: Application.get_env(:algora, :github_client, Algora.Github.Client)
4547

48+
def try_without_installation(function, args) do
49+
if pat_enabled() do
50+
apply(function, [pat() | args])
51+
else
52+
{_, module} = Function.info(function, :module)
53+
{_, name} = Function.info(function, :name)
54+
function_name = String.trim_leading("#{module}.#{name}", "Elixir.")
55+
56+
formatted_args =
57+
Enum.map_join(args, ", ", fn
58+
arg when is_binary(arg) -> "\"#{arg}\""
59+
arg -> "#{arg}"
60+
end)
61+
62+
Logger.warning("""
63+
App installation not found and GITHUB_PAT_ENABLED is false, skipping Github call:
64+
#{function_name}(#{formatted_args})
65+
""")
66+
end
67+
end
68+
4669
@impl true
4770
def get_repository(token, owner, repo), do: client().get_repository(token, owner, repo)
4871

lib/algora/integrations/stripe/stripe.ex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,16 @@ defmodule Algora.Stripe do
3232

3333
def create(params), do: Algora.Stripe.client(__MODULE__).create(params)
3434
end
35+
36+
defmodule PaymentMethod do
37+
@moduledoc false
38+
39+
def attach(params), do: Algora.Stripe.client(__MODULE__).attach(params)
40+
end
41+
42+
defmodule SetupIntent do
43+
@moduledoc false
44+
45+
def retrieve(id, params), do: Algora.Stripe.client(__MODULE__).retrieve(id, params)
46+
end
3547
end
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule Algora.Payments.Jobs.ExecutePendingTransfers do
1+
defmodule Algora.Payments.Jobs.ExecutePendingTransfer do
22
@moduledoc false
33
use Oban.Worker,
44
queue: :transfers,
@@ -7,7 +7,7 @@ defmodule Algora.Payments.Jobs.ExecutePendingTransfers do
77
alias Algora.Payments
88

99
@impl Oban.Worker
10-
def perform(%Oban.Job{args: %{"user_id" => user_id}}) do
11-
Payments.execute_pending_transfers(user_id)
10+
def perform(%Oban.Job{args: %{"credit_id" => credit_id}}) do
11+
Payments.execute_pending_transfer(credit_id)
1212
end
1313
end

0 commit comments

Comments
 (0)