Skip to content

Commit 6c568ca

Browse files
authored
feat: main bounty form (#110)
1 parent f1eee1b commit 6c568ca

File tree

22 files changed

+565
-141
lines changed

22 files changed

+565
-141
lines changed

lib/algora/bounties/bounties.ex

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ defmodule Algora.Bounties do
9494
end
9595
end
9696

97+
def create_bounty(_params, opts \\ [])
98+
9799
@spec create_bounty(
98100
%{
99101
creator: User.t(),
@@ -118,7 +120,7 @@ defmodule Algora.Bounties do
118120
amount: amount,
119121
ticket_ref: %{owner: repo_owner, repo: repo_name, number: number} = ticket_ref
120122
},
121-
opts \\ []
123+
opts
122124
) do
123125
command_id = opts[:command_id]
124126
shared_with = opts[:shared_with] || []
@@ -177,6 +179,49 @@ defmodule Algora.Bounties do
177179
end)
178180
end
179181

182+
@spec create_bounty(
183+
%{
184+
creator: User.t(),
185+
owner: User.t(),
186+
amount: Money.t(),
187+
title: String.t(),
188+
description: String.t()
189+
},
190+
opts :: [
191+
strategy: strategy(),
192+
visibility: Bounty.visibility() | nil,
193+
shared_with: [String.t()] | nil
194+
]
195+
) ::
196+
{:ok, Bounty.t()} | {:error, atom()}
197+
def create_bounty(%{creator: creator, owner: owner, amount: amount, title: title, description: description}, opts) do
198+
shared_with = opts[:shared_with] || []
199+
200+
Repo.transact(fn ->
201+
with {:ok, ticket} <-
202+
%Ticket{type: :issue}
203+
|> Ticket.changeset(%{title: title, description: description})
204+
|> Repo.insert(),
205+
{:ok, bounty} <-
206+
do_create_bounty(%{
207+
creator: creator,
208+
owner: owner,
209+
amount: amount,
210+
ticket: ticket,
211+
visibility: opts[:visibility],
212+
shared_with: shared_with
213+
}),
214+
{:ok, _job} <- notify_bounty(%{owner: owner, bounty: bounty}) do
215+
broadcast()
216+
{:ok, bounty}
217+
else
218+
{:error, _reason} = error ->
219+
Algora.Admin.alert("Error creating bounty: #{inspect(error)}", :error)
220+
error
221+
end
222+
end)
223+
end
224+
180225
defp claim_to_solution(claim) do
181226
%{
182227
type: :claim,
@@ -337,6 +382,8 @@ defmodule Algora.Bounties do
337382
end
338383
end
339384

385+
def notify_bounty(bounty, opts \\ [])
386+
340387
@spec notify_bounty(
341388
%{
342389
owner: User.t(),
@@ -346,7 +393,7 @@ defmodule Algora.Bounties do
346393
opts :: [installation_id: integer(), command_id: integer(), command_source: :ticket | :comment]
347394
) ::
348395
{:ok, Oban.Job.t()} | {:error, atom()}
349-
def notify_bounty(%{owner: owner, bounty: bounty, ticket_ref: ticket_ref}, opts \\ []) do
396+
def notify_bounty(%{owner: owner, bounty: bounty, ticket_ref: ticket_ref}, opts) do
350397
%{
351398
owner_login: owner.provider_login,
352399
amount: Money.to_string!(bounty.amount, no_fraction_if_integer: true),
@@ -362,6 +409,13 @@ defmodule Algora.Bounties do
362409
|> Oban.insert()
363410
end
364411

412+
@spec notify_bounty(%{owner: User.t(), bounty: Bounty.t()}, opts :: []) ::
413+
{:ok, nil} | {:error, atom()}
414+
def notify_bounty(%{owner: _owner, bounty: bounty}, _opts) do
415+
Algora.Admin.alert("Notify bounty: #{inspect(bounty)}", :error)
416+
{:ok, nil}
417+
end
418+
365419
@spec do_claim_bounty(%{
366420
provider_login: String.t(),
367421
token: String.t(),

lib/algora/organizations/schemas/member.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,6 @@ defmodule Algora.Organizations.Member do
3434
join: o in assoc(m, :org),
3535
where: o.id == ^org_id
3636
end
37+
38+
def can_create_bounty?(role), do: role in [:admin, :mod]
3739
end

lib/algora/workspace/schemas/ticket.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ defmodule Algora.Workspace.Ticket do
2929
timestamps()
3030
end
3131

32+
def changeset(ticket, params) do
33+
ticket
34+
|> cast(params, [:title, :description, :url])
35+
|> validate_required([:title])
36+
|> generate_id()
37+
end
38+
3239
def github_changeset(meta, repo) do
3340
params = %{
3441
provider_id: to_string(meta["id"]),

lib/algora_web.ex

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ defmodule AlgoraWeb do
5656
use Phoenix.LiveView,
5757
layout: {AlgoraWeb.Layouts, :app}
5858

59-
import Tails, only: [classes: 1]
60-
6159
unquote(html_helpers())
6260
end
6361
end
@@ -87,13 +85,17 @@ defmodule AlgoraWeb do
8785
quote do
8886
use Gettext, backend: AlgoraWeb.Gettext
8987

88+
# Core UI components and translation
9089
import AlgoraWeb.CoreComponents
90+
91+
# Enable rendering Svelte components
9192
import LiveSvelte
93+
9294
# HTML escaping functionality
9395
import Phoenix.HTML
94-
# Core UI components and translation
9596

96-
# Enable rendering Svelte components
97+
# class helpers
98+
import Tails, only: [classes: 1]
9799

98100
# Shortcut for generating JS commands
99101
alias Phoenix.LiveView.JS

lib/algora_web/components/layouts/user.html.heex

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,24 @@
189189
</.button>
190190
</ul>
191191
<% end %>
192+
<%= if main_bounty_form = Map.get(assigns, :main_bounty_form) do %>
193+
<.button phx-click="open_main_bounty_form">Create new bounty</.button>
194+
<.drawer
195+
show={@main_bounty_form_open?}
196+
direction="right"
197+
on_cancel="close_main_bounty_form"
198+
>
199+
<.drawer_header>
200+
<.drawer_title>Create new bounty</.drawer_title>
201+
<.drawer_description>
202+
Create and fund a bounty for an issue
203+
</.drawer_description>
204+
</.drawer_header>
205+
<.drawer_content class="mt-4">
206+
<AlgoraWeb.Forms.BountyForm.bounty_form form={main_bounty_form} />
207+
</.drawer_content>
208+
</.drawer>
209+
<% end %>
192210
<div class="ml-auto flex items-center gap-x-6">
193211
<.link
194212
class="group w-fit outline-none"

0 commit comments

Comments
 (0)