Skip to content

Commit 7467234

Browse files
committed
feat: add repo_contributions_synced field to users and skip refetching
1 parent 6e43296 commit 7467234

File tree

3 files changed

+98
-15
lines changed

3 files changed

+98
-15
lines changed

lib/algora/accounts/schemas/user.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ defmodule Algora.Accounts.User do
117117

118118
field :email_recipients, {:array, :map}, default: []
119119
field :language_contributions_synced, :boolean, default: false
120+
field :repo_contributions_synced, :boolean, default: false
120121

121122
has_many :identities, Identity
122123
has_many :memberships, Member, foreign_key: :user_id

lib/algora/workspace/workspace.ex

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -787,22 +787,27 @@ defmodule Algora.Workspace do
787787
end
788788

789789
def fetch_top_contributions(token, provider_logins) when is_list(provider_logins) do
790-
with {:ok, contributions} <- Algora.Cloud.top_contributions(provider_logins),
791-
{:ok, users} <- ensure_users(token, provider_logins),
792-
:ok <- add_contributions(token, users, contributions) do
793-
{:ok, contributions}
794-
else
795-
{:error, reason} ->
796-
Logger.error("Failed to fetch contributions for #{inspect(provider_logins)}: #{inspect(reason)}")
797-
{:error, reason}
798-
end
799-
end
790+
users_with_contributions = get_users_with_contributions(provider_logins)
791+
users_with_contributions_logins = Enum.map(users_with_contributions, & &1.provider_login)
792+
793+
users_without_contributions = provider_logins -- users_with_contributions_logins
794+
795+
cloud_result =
796+
if Enum.empty?(users_without_contributions) do
797+
{:ok, []}
798+
else
799+
Algora.Cloud.top_contributions(users_without_contributions)
800+
end
800801

801-
def fetch_top_contributions_async(token, provider_logins) when is_list(provider_logins) do
802-
with {:ok, contributions} <- Algora.Cloud.top_contributions(provider_logins),
802+
with {:ok, cloud_contributions} <- cloud_result,
803803
{:ok, users} <- ensure_users(token, provider_logins),
804-
:ok <- add_contributions_async(token, users, contributions) do
805-
{:ok, users}
804+
:ok <- add_contributions(token, users, cloud_contributions) do
805+
# Always mark users as synced after fetching from Cloud API
806+
mark_users_as_synced(users_without_contributions, users)
807+
808+
existing_contributions = get_existing_contributions(users_with_contributions_logins)
809+
all_contributions = existing_contributions ++ cloud_contributions
810+
{:ok, all_contributions}
806811
else
807812
{:error, reason} ->
808813
Logger.error("Failed to fetch contributions for #{inspect(provider_logins)}: #{inspect(reason)}")
@@ -858,7 +863,7 @@ defmodule Algora.Workspace do
858863
end
859864
end)
860865

861-
if Enum.any?(results, fn result -> result != :ok end), do: {:error, :failed}, else: :ok
866+
if results == [] or Enum.any?(results, fn result -> result == :ok end), do: :ok, else: {:error, :failed}
862867
end
863868

864869
defp add_contribution(%{
@@ -886,6 +891,74 @@ defmodule Algora.Workspace do
886891
end)
887892
end
888893

894+
@spec get_users_with_contributions(list(String.t())) :: list(User.t())
895+
defp get_users_with_contributions(provider_logins) do
896+
# Get users who either have contributions OR have been marked as synced
897+
users_with_contributions =
898+
Repo.all(
899+
from u in User,
900+
join: uc in UserContribution,
901+
on: uc.user_id == u.id,
902+
where: u.provider == "github",
903+
where: u.provider_login in ^provider_logins,
904+
distinct: u.id,
905+
select: u
906+
)
907+
908+
users_marked_synced =
909+
Repo.all(
910+
from u in User,
911+
where: u.provider == "github",
912+
where: u.provider_login in ^provider_logins,
913+
where: u.repo_contributions_synced == true,
914+
select: u
915+
)
916+
917+
# Combine and deduplicate by id
918+
Enum.uniq_by(users_with_contributions ++ users_marked_synced, & &1.id)
919+
end
920+
921+
@spec get_existing_contributions(list(String.t())) :: list(map())
922+
defp get_existing_contributions(provider_logins) do
923+
Repo.all(
924+
from uc in UserContribution,
925+
join: u in assoc(uc, :user),
926+
join: r in assoc(uc, :repository),
927+
join: repo_owner in assoc(r, :user),
928+
where: u.provider == "github",
929+
where: u.provider_login in ^provider_logins,
930+
select: %{
931+
provider_login: u.provider_login,
932+
repo_name: fragment("? || '/' || ?", repo_owner.provider_login, r.name),
933+
contribution_count: uc.contribution_count
934+
}
935+
)
936+
end
937+
938+
@spec mark_users_as_synced(list(String.t()), list(User.t())) :: :ok
939+
defp mark_users_as_synced(users_without_contributions, users) do
940+
if not Enum.empty?(users_without_contributions) do
941+
Logger.info("Marking users as repo_contributions_synced: #{inspect(users_without_contributions)}")
942+
943+
# Update all users that were queried from Cloud API to mark them as synced
944+
users_map = Enum.group_by(users, & &1.provider_login)
945+
946+
Enum.each(users_without_contributions, fn provider_login ->
947+
case users_map[provider_login] do
948+
[user] ->
949+
user
950+
|> Ecto.Changeset.change(%{repo_contributions_synced: true})
951+
|> Repo.update()
952+
953+
_ ->
954+
Logger.warning("User not found for marking as synced: #{provider_login}")
955+
end
956+
end)
957+
end
958+
959+
:ok
960+
end
961+
889962
def remove_existing_amount_labels(token, owner, repo, number) do
890963
case Github.list_labels(token, owner, repo, number) do
891964
{:ok, labels} ->
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule Algora.Repo.Migrations.AddRepoContributionsSyncedToUsers do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:users) do
6+
add :repo_contributions_synced, :boolean, default: false, null: false
7+
end
8+
end
9+
end

0 commit comments

Comments
 (0)