@@ -787,22 +787,27 @@ defmodule Algora.Workspace do
787
787
end
788
788
789
789
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
800
801
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 ,
803
803
{ :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 }
806
811
else
807
812
{ :error , reason } ->
808
813
Logger . error ( "Failed to fetch contributions for #{ inspect ( provider_logins ) } : #{ inspect ( reason ) } " )
@@ -858,7 +863,7 @@ defmodule Algora.Workspace do
858
863
end
859
864
end )
860
865
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 }
862
867
end
863
868
864
869
defp add_contribution ( % {
@@ -886,6 +891,74 @@ defmodule Algora.Workspace do
886
891
end )
887
892
end
888
893
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
+
889
962
def remove_existing_amount_labels ( token , owner , repo , number ) do
890
963
case Github . list_labels ( token , owner , repo , number ) do
891
964
{ :ok , labels } ->
0 commit comments