diff --git a/lib/algora/accounts/accounts.ex b/lib/algora/accounts/accounts.ex index ef32cc8a3..ebe416c9e 100644 --- a/lib/algora/accounts/accounts.ex +++ b/lib/algora/accounts/accounts.ex @@ -169,6 +169,36 @@ defmodule Algora.Accounts do list_developers_with(base_query(), criteria) end + def list_contributed_projects(user, opts \\ []) do + query = + from tx in Transaction, + where: tx.type == :credit, + where: tx.status == :succeeded, + where: tx.user_id == ^user.id, + left_join: bounty in assoc(tx, :bounty), + left_join: tip in assoc(tx, :tip), + join: t in Ticket, + on: t.id == bounty.ticket_id or t.id == tip.ticket_id, + left_join: r in assoc(t, :repository), + as: :r, + left_join: ro in assoc(r, :user), + group_by: ro.id, + order_by: [desc: sum(tx.net_amount)], + select: {ro, sum(tx.net_amount)}, + limit: ^opts[:limit] + + query = + if opts[:tech_stack] do + from([b, r: r] in query, + where: fragment("? && ?::citext[]", r.tech_stack, ^opts[:tech_stack]) + ) + else + query + end + + Repo.all(query) + end + @spec fetch_developer(binary()) :: {:ok, User.t()} | {:error, :not_found} def fetch_developer(id) do case list_developers(id: id, limit: 1) do diff --git a/lib/algora/admin/admin.ex b/lib/algora/admin/admin.ex index c239e14d5..73ed62b17 100644 --- a/lib/algora/admin/admin.ex +++ b/lib/algora/admin/admin.ex @@ -21,6 +21,12 @@ defmodule Algora.Admin do require Logger + def init_contributors(repo_owner, repo_name) do + with {:ok, repo} <- Workspace.ensure_repository(token(), repo_owner, repo_name) do + Workspace.ensure_contributors(token(), repo) + end + end + def migrate_user!(old_user_id, new_user_id) do old_user = Accounts.get_user!(old_user_id) diff --git a/lib/algora/settings/settings.ex b/lib/algora/settings/settings.ex index 0e161137e..1a7d51691 100644 --- a/lib/algora/settings/settings.ex +++ b/lib/algora/settings/settings.ex @@ -2,6 +2,7 @@ defmodule Algora.Settings do @moduledoc false use Ecto.Schema + alias Algora.Accounts alias Algora.Repo @primary_key {:key, :string, []} @@ -49,14 +50,39 @@ defmodule Algora.Settings do set("featured_developers", %{"handles" => handles}) end - def get_org_matches(org_handle) when is_binary(org_handle) do - case get("org_matches:#{org_handle}") do - %{"handles" => handles} when is_list(handles) -> handles - _ -> nil + def get_org_matches(org) do + case get("org_matches:#{org.handle}") do + %{"matches" => matches} when is_list(matches) -> + user_map = + [handles: Enum.map(matches, & &1["handle"])] + |> Accounts.list_developers() + |> Map.new(fn user -> {user.handle, user} end) + + Enum.flat_map(matches, fn match -> + if user = Map.get(user_map, match["handle"]) do + # TODO: N+1 + projects = Accounts.list_contributed_projects(user, limit: 2, tech_stack: org.tech_stack) + + [ + %{ + user: user, + projects: projects, + badge_variant: match["badge_variant"], + badge_text: match["badge_text"], + hourly_rate: Money.new(:USD, match["hourly_rate"], no_fraction_if_integer: true) + } + ] + else + [] + end + end) + + _ -> + nil end end - def set_org_matches(org_handle, handles) when is_binary(org_handle) and is_list(handles) do - set("org_matches:#{org_handle}", %{"handles" => handles}) + def set_org_matches(org_handle, matches) when is_binary(org_handle) and is_list(matches) do + set("org_matches:#{org_handle}", %{"matches" => matches}) end end diff --git a/lib/algora_web/components/ui/badge.ex b/lib/algora_web/components/ui/badge.ex index 9ca817786..13867f6fd 100644 --- a/lib/algora_web/components/ui/badge.ex +++ b/lib/algora_web/components/ui/badge.ex @@ -46,7 +46,10 @@ defmodule AlgoraWeb.Components.UI.Badge do "destructive" => "bg-destructive/10 text-destructive border-destructive/20", "success" => "bg-success/10 text-success border-success/20", "warning" => "bg-warning/10 text-warning border-warning/20", - "outline" => "bg-transparent text-foreground border-foreground/30" + "outline" => "bg-transparent text-foreground border-foreground/30", + "indigo" => "bg-indigo-400/10 text-indigo-400 border-indigo-400/20", + "purple" => "bg-purple-400/10 text-purple-400 border-purple-400/20", + "blue" => "bg-blue-400/10 text-blue-400 border-blue-400/20" } } diff --git a/lib/algora_web/live/org/dashboard_live.ex b/lib/algora_web/live/org/dashboard_live.ex index 80b3ef2e3..64f62bd83 100644 --- a/lib/algora_web/live/org/dashboard_live.ex +++ b/lib/algora_web/live/org/dashboard_live.ex @@ -63,16 +63,7 @@ defmodule AlgoraWeb.Org.DashboardLive do contributors = list_contributors(current_org) - matches = - if current_org.handle do - if handles = Algora.Settings.get_org_matches(current_org.handle) do - Repo.all( - from u in User, - where: u.handle in ^handles, - order_by: fragment("array_position(?, ?::text)", ^handles, u.handle) - ) - end - end + matches = Algora.Settings.get_org_matches(current_org) admins_last_active = Algora.Admin.admins_last_active() @@ -281,22 +272,18 @@ defmodule AlgoraWeb.Org.DashboardLive do <.section - :if={@matches != nil && @matches != []} + :if={@matches != []} title="Algora Matches" subtitle="Developers that match your tech stack and requirements" > -