Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/algora/bounties/bounties.ex
Original file line number Diff line number Diff line change
Expand Up @@ -917,12 +917,14 @@ defmodule Algora.Bounties do
|> join(:left, [t: t], r in assoc(t, :repository), as: :r)
|> join(:left, [r: r], ro in assoc(r, :user), as: :ro)
|> where([b], not is_nil(b.amount))
|> where([b], b.status != :cancelled)
|> apply_criteria(criteria)
|> order_by([b], desc: b.amount, desc: b.inserted_at, desc: b.id)
|> select([b, o: o, t: t, ro: ro, r: r], %{
id: b.id,
inserted_at: b.inserted_at,
amount: b.amount,
status: b.status,
owner: %{
id: o.id,
name: o.name,
Expand Down Expand Up @@ -956,6 +958,7 @@ defmodule Algora.Bounties do
join: user in assoc(c, :user),
left_join: s in assoc(c, :source),
where: t.id in ^ticket_ids,
where: c.status != :cancelled,
select_merge: %{user: user, source: s}
)
end
Expand Down
4 changes: 3 additions & 1 deletion lib/algora_web/controllers/webhooks/github_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ defmodule AlgoraWeb.Webhooks.GithubController do
from c in Claim,
join: s in assoc(c, :source),
join: u in assoc(c, :user),
where: c.status != :cancelled,
where: s.id == ^source.id,
where: u.provider == "github",
where: u.provider_id == ^to_string(payload["pull_request"]["user"]["id"]),
Expand All @@ -82,7 +83,7 @@ defmodule AlgoraWeb.Webhooks.GithubController do

%Claim{group_id: group_id} ->
Repo.update_all(
from(c in Claim, where: c.group_id == ^group_id),
from(c in Claim, where: c.group_id == ^group_id, where: c.status != :cancelled),
set: [status: :approved]
)

Expand All @@ -93,6 +94,7 @@ defmodule AlgoraWeb.Webhooks.GithubController do
join: tru in assoc(tr, :user),
join: u in assoc(c, :user),
where: c.group_id == ^group_id,
where: c.status != :cancelled,
order_by: [desc: c.group_share, asc: c.inserted_at],
select_merge: %{
target: %{t | repository: %{tr | user: tru}},
Expand Down
34 changes: 34 additions & 0 deletions test/algora/bounties_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ defmodule Algora.BountiesTest do
alias Algora.PSP
alias Bounties.Tip

setup do
repo_owner = insert!(:user)
repo = insert!(:repository, %{user: repo_owner})
ticket = insert!(:ticket, %{repository: repo})

%{ticket: ticket}
end

describe "bounties" do
test "create" do
creator = insert!(:user)
Expand Down Expand Up @@ -369,4 +377,30 @@ defmodule Algora.BountiesTest do
assert response == String.trim(expected_response)
end
end

describe "list_bounties/1" do
test "does not include cancelled bounties", %{ticket: ticket} do
insert!(:bounty, status: :open, ticket: ticket, owner: insert!(:user))
insert!(:bounty, status: :paid, ticket: ticket, owner: insert!(:user))
insert!(:bounty, status: :cancelled, ticket: ticket, owner: insert!(:user))

bounties = Bounties.list_bounties()
assert Enum.any?(bounties, &(&1.status == :open))
assert Enum.any?(bounties, &(&1.status == :paid))
refute Enum.any?(bounties, &(&1.status == :cancelled))
end
end

describe "list_claims/1" do
test "does not include cancelled claims", %{ticket: ticket} do
insert!(:claim, status: :pending, target: ticket, user: insert!(:user))
insert!(:claim, status: :approved, target: ticket, user: insert!(:user))
insert!(:claim, status: :cancelled, target: ticket, user: insert!(:user))

claims = Bounties.list_claims([ticket.id])
assert Enum.any?(claims, &(&1.status == :pending))
assert Enum.any?(claims, &(&1.status == :approved))
refute Enum.any?(claims, &(&1.status == :cancelled))
end
end
end
78 changes: 76 additions & 2 deletions test/algora_web/controllers/webhooks/github_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule AlgoraWeb.Webhooks.GithubControllerTest do
alias Algora.Github.Webhook
alias Algora.Payments.Transaction
alias Algora.Repo
alias Algora.Workspace.Ticket
alias AlgoraWeb.Webhooks.GithubController

setup do
Expand Down Expand Up @@ -220,7 +221,7 @@ defmodule AlgoraWeb.Webhooks.GithubControllerTest do

test "does not allow multiple claims in a single PR", ctx do
issue_number1 = :rand.uniform(1000)
issue_number2 = :rand.uniform(1000)
issue_number2 = issue_number1 + 1
pr_number = :rand.uniform(1000)

process_scenario!(ctx, [
Expand Down Expand Up @@ -252,7 +253,7 @@ defmodule AlgoraWeb.Webhooks.GithubControllerTest do

test "cancels existing claim when attempting to claim a different bounty in the same PR", ctx do
issue_number1 = :rand.uniform(1000)
issue_number2 = :rand.uniform(1000)
issue_number2 = issue_number1 + 1
pr_number = :rand.uniform(1000)

process_scenario!(ctx, [
Expand Down Expand Up @@ -510,6 +511,79 @@ defmodule AlgoraWeb.Webhooks.GithubControllerTest do
assert is_nil(transfer)
end

test "handles autopay when claim is changed to a different bounty and PR is merged", ctx do
issue_number1 = :rand.uniform(1000)
issue_number2 = issue_number1 + :rand.uniform(1000)
pr_number = issue_number1 + :rand.uniform(1000)

customer = insert!(:customer, user: ctx[:org])
_payment_method = insert!(:payment_method, is_default: true, customer: customer)

process_scenario!(ctx, [
%{
event_action: "issue_comment.created",
user_type: :admin,
body: "/bounty $100",
params: %{"issue" => %{"number" => issue_number1}}
},
%{
event_action: "issue_comment.created",
user_type: :admin,
body: "/bounty $200",
params: %{"issue" => %{"number" => issue_number2}}
},
%{
event_action: "pull_request.opened",
user_type: :unauthorized,
body: "/claim #{issue_number1}",
params: %{"pull_request" => %{"number" => pr_number}}
},
%{
event_action: "pull_request.edited",
user_type: :unauthorized,
body: "/claim #{issue_number2}",
params: %{"pull_request" => %{"number" => pr_number}}
},
%{
event_action: "pull_request.closed",
user_type: :unauthorized,
body: "/claim #{issue_number2}",
params: %{"pull_request" => %{"number" => pr_number, "merged_at" => DateTime.to_iso8601(DateTime.utc_now())}}
}
])

ticket1 = Repo.get_by!(Ticket, number: issue_number1)
ticket2 = Repo.get_by!(Ticket, number: issue_number2)

_bounty1 = Repo.get_by!(Bounty, ticket_id: ticket1.id)
bounty2 = Repo.get_by!(Bounty, ticket_id: ticket2.id)

cancelled_claim = Repo.get_by!(Claim, target_id: ticket1.id)
active_claim = Repo.get_by!(Claim, target_id: ticket2.id)

assert active_claim.status == :approved
assert cancelled_claim.status == :cancelled

charge = Repo.one!(from t in Transaction, where: t.type == :charge)
assert Money.equal?(charge.net_amount, Money.new(:USD, 200))
assert charge.status == :initialized
assert charge.user_id == ctx[:org].id

debit = Repo.one!(from t in Transaction, where: t.type == :debit)
assert Money.equal?(debit.net_amount, Money.new(:USD, 200))
assert debit.status == :initialized
assert debit.user_id == ctx[:org].id
assert debit.bounty_id == bounty2.id
assert debit.claim_id == active_claim.id

credit = Repo.one!(from t in Transaction, where: t.type == :credit)
assert Money.equal?(credit.net_amount, Money.new(:USD, 200))
assert credit.status == :initialized
assert credit.user_id == ctx[:unauthorized_user].id
assert credit.bounty_id == bounty2.id
assert credit.claim_id == active_claim.id
end

test "prevents duplicate transaction creation when receiving multiple PR closed events", ctx do
issue_number = :rand.uniform(1000)
pr_number = :rand.uniform(1000)
Expand Down
4 changes: 3 additions & 1 deletion test/support/factory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,9 @@ defmodule Algora.Factory do

def bounty_factory do
%Algora.Bounties.Bounty{
id: Nanoid.generate()
id: Nanoid.generate(),
status: :open,
amount: Money.new!(100, :USD)
}
end

Expand Down