11package fr .zenika .opensource .stats .ressources .workflow ;
22
3+ import io .quarkus .logging .Log ;
34import jakarta .enterprise .context .ApplicationScoped ;
45import jakarta .inject .Inject ;
56import jakarta .ws .rs .POST ;
1011import jakarta .ws .rs .core .Response ;
1112
1213import java .time .LocalDate ;
14+ import org .eclipse .microprofile .config .inject .ConfigProperty ;
1315import java .util .List ;
1416import java .util .Set ;
17+ import java .util .HashSet ;
1518import java .util .stream .Collectors ;
1619
1720import fr .zenika .opensource .stats .beans .CustomStatsContributionsUserByMonth ;
@@ -39,13 +42,31 @@ public class WorkflowRessources {
3942 @ Inject
4043 FirestoreServices firestoreServices ;
4144
45+ @ ConfigProperty (name = "organization.name" )
46+ String organizationName ;
47+
48+ private Set <String > existingMemberLogins = new HashSet <>();
49+ private Set <String > existingGitLabUsernames = new HashSet <>();
50+
51+
4252 @ POST
4353 @ Path ("members/save" )
4454 @ Produces (MediaType .TEXT_PLAIN )
4555 public Response saveMembers () throws DatabaseException {
4656
4757 // Load current state
4858 List <Member > existingMembers = firestoreServices .getAllMembers ();
59+
60+ // Save the logins/usernames of already present members before upserting new ones
61+ existingMemberLogins = existingMembers .stream ()
62+ .filter (m -> m .getGitHubAccount () != null )
63+ .map (m -> m .getGitHubAccount ().getLogin ())
64+ .collect (Collectors .toSet ());
65+ existingGitLabUsernames = existingMembers .stream ()
66+ .filter (m -> m .getGitlabAccount () != null )
67+ .map (m -> m .getGitlabAccount ().getUsername ())
68+ .collect (Collectors .toSet ());
69+
4970 List <GitHubMember > gitHubMembers = gitHubServices .getOrganizationMembersFromConfig ();
5071
5172 // Build a set of current GitHub logins in the organization
@@ -94,7 +115,7 @@ public Response saveForkedProject() {
94115 @ Produces (MediaType .TEXT_PLAIN )
95116 public Response savePersonalProjects () throws DatabaseException {
96117
97- firestoreServices .deleteAllProjects ();
118+ firestoreServices .deleteAllGitHubProjects ();
98119
99120 List <Member > members = firestoreServices .getAllMembers ();
100121
@@ -109,35 +130,57 @@ public Response savePersonalProjects() throws DatabaseException {
109130 return Response .ok ().build ();
110131 }
111132
133+ @ POST
134+ @ Path ("organization-projects/save" )
135+ @ Produces (MediaType .TEXT_PLAIN )
136+ public Response saveOrganizationProjects () throws DatabaseException {
137+ firestoreServices .deleteAllGitHubOrganizationProjects ();
138+ List <GitHubProject > gitHubProjects = gitHubServices .getOrganizationProjects (organizationName );
139+ for (GitHubProject project : gitHubProjects ) {
140+ project .setSource ("GitHub Organization" );
141+ firestoreServices .createProject (project );
142+ }
143+ return Response .ok ().build ();
144+ }
145+
112146 @ POST
113147 @ Path ("stats/save/{year}" )
114148 @ Produces (MediaType .TEXT_PLAIN )
115149 public Response saveStatsForYear (@ PathParam ("year" ) int year ) throws DatabaseException {
116150
117151 int currentYear = LocalDate .now ().getYear ();
118- boolean isCurrentYear = (year == currentYear );
119-
120- if (isCurrentYear ) {
121- firestoreServices .deleteStatsBySourceForYear (year , "GitHub" );
122- firestoreServices .deleteStatsBySourceForYear (year , "GitLab" );
123- }
124152
125153 List <Member > zMembers = firestoreServices .getAllMembers ();
126154
155+ if (existingMemberLogins .isEmpty () && existingGitLabUsernames .isEmpty ()) {
156+ existingMemberLogins = zMembers .stream ()
157+ .filter (m -> m .getGitHubAccount () != null )
158+ .map (m -> m .getGitHubAccount ().getLogin ())
159+ .collect (Collectors .toSet ());
160+ existingGitLabUsernames = zMembers .stream ()
161+ .filter (m -> m .getGitlabAccount () != null )
162+ .map (m -> m .getGitlabAccount ().getUsername ())
163+ .collect (Collectors .toSet ());
164+ }
165+
127166 for (Member member : zMembers ) {
128167 // GitHub
129168 if (member .getGitHubAccount () != null ) {
130- // For past years, skip if stats already exist
131- if (!isCurrentYear && firestoreServices .hasStatsForMemberAndYear (member .getId (), year , "GitHub" )) {
132- System .out .println ("⏭️ Skip GitHub information for " + member .getGitHubAccount ().getLogin ()
133- + " (already exists)" );
169+ // For past years, skip if the person was already present in the organization.
170+ // Sync only for new members to save API quota and preserve existing history.
171+ boolean isPastYear = (year < currentYear );
172+ boolean isExistingMember = existingMemberLogins .contains (member .getGitHubAccount ().getLogin ());
173+ boolean shouldSkip = isPastYear && isExistingMember ;
174+
175+ if (shouldSkip ) {
176+ Log .info ("⏭️ Skip GitHub information for " + member .getGitHubAccount ().getLogin () + " (already exists in organization)" );
134177 } else {
135- System . out . print ("🔎 Check GitHub information for " + member .getGitHubAccount ().getLogin ());
178+ Log . info ("🔎 Check GitHub information for " + member .getGitHubAccount ().getLogin () + " (" + year + ")" );
136179 List <CustomStatsContributionsUserByMonth > stats = gitHubServices
137180 .getContributionsForTheCurrentYear (member .getGitHubAccount ().getLogin (), year );
138181 List <StatsContribution > statsList = StatsMapper .mapGitHubStatisticsToStatsContributions (
139182 member , year , stats );
140- System . out . println ( "... ✅ " );
183+ Log . info ( "✅ GitHub contributions synced for " + member . getGitHubAccount (). getLogin () + " (" + year + ") " );
141184
142185 if (!statsList .isEmpty ()) {
143186 for (StatsContribution stat : statsList ) {
@@ -149,17 +192,21 @@ public Response saveStatsForYear(@PathParam("year") int year) throws DatabaseExc
149192
150193 // GitLab
151194 if (member .getGitlabAccount () != null ) {
152- // For past years, skip if stats already exist
153- if (!isCurrentYear && firestoreServices .hasStatsForMemberAndYear (member .getId (), year , "GitLab" )) {
154- System .out .println ("⏭️ Skip GitLab information for " + member .getGitlabAccount ().getUsername ()
155- + " (already exists)" );
195+ // For past years, skip if the person was already present in the organization.
196+ // Sync only for new members to save API quota and preserve existing history.
197+ boolean isPastYear = (year < currentYear );
198+ boolean isExistingMember = existingGitLabUsernames .contains (member .getGitlabAccount ().getUsername ());
199+ boolean shouldSkip = isPastYear && isExistingMember ;
200+
201+ if (shouldSkip ) {
202+ Log .info ("⏭️ Skip GitLab information for " + member .getGitlabAccount ().getUsername () + " (already exists in organization)" );
156203 } else {
157- System . out . print ("🔎 Check GitLab information for " + member .getGitlabAccount ().getUsername ());
204+ Log . info ("🔎 Check GitLab information for " + member .getGitlabAccount ().getUsername () + " (" + year + ")" );
158205 List <CustomStatsContributionsUserByMonth > stats = gitLabServices
159206 .getContributionsForTheCurrentYear (member .getGitlabAccount ().getUsername (), year );
160207 List <StatsContribution > statsList = StatsMapper .mapGitLabStatisticsToStatsContributions (
161208 member , year , stats );
162- System . out . println ( "... ✅ " );
209+ Log . info ( "✅ GitLab contributions synced for " + member . getGitlabAccount (). getUsername () + " (" + year + ") " );
163210
164211 if (!statsList .isEmpty ()) {
165212 for (StatsContribution stat : statsList ) {
0 commit comments