From 12492f2884b3dff4a272d3be4f239bf180629c4f Mon Sep 17 00:00:00 2001
From: Petar Hristov <hristov@itc.rwth-aachen.de>
Date: Wed, 28 May 2025 10:28:04 +0000
Subject: [PATCH] Fix: ProjectReporting to fetch project quotas individually
 and update API client dependency to version 1.10.0

---
 .../ProjectReportingTests.cs                  | 14 ++++++-----
 src/KpiGenerator/KpiGenerator.csproj          |  2 +-
 src/KpiGenerator/Program.cs                   |  2 +-
 .../Reportings/Project/ProjectReporting.cs    | 25 ++++++++++++++++---
 4 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/src/KpiGenerator.Tests/ProjectReportingTests.cs b/src/KpiGenerator.Tests/ProjectReportingTests.cs
index 861c6fc..84093aa 100644
--- a/src/KpiGenerator.Tests/ProjectReportingTests.cs
+++ b/src/KpiGenerator.Tests/ProjectReportingTests.cs
@@ -26,6 +26,7 @@ public class ProjectReportingTests
     private IOptionsMonitor<ReportingConfiguration> _reportingConfiguration = null!;
 
     private IAdminApi _adminApi = null!;
+    private IProjectQuotaApi _projectQuotaApi = null!;
 
     private ProjectReporting _projectReporting = null!; // System Under Test
 
@@ -70,6 +71,7 @@ public class ProjectReportingTests
         _reportingConfiguration.CurrentValue.Returns(reportingConfig);
 
         _adminApi = Substitute.For<IAdminApi>();
+        _projectQuotaApi = Substitute.For<IProjectQuotaApi>();
     }
 
     #region GenerateReportingAsync Tests
@@ -94,7 +96,7 @@ public class ProjectReportingTests
                 var pagination = new Pagination(currentPage: 1, pageSize: 2, totalCount: 2, totalPages: 1);
                 return Task.FromResult(new ProjectAdminDtoPagedResponse(data: projects, pagination: pagination, statusCode: 200, traceId: "dummy-trace-id"));
             });
-        _projectReporting = new ProjectReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi);
+        _projectReporting = new ProjectReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectQuotaApi);
 
         // Act
         var result = await _projectReporting.GenerateReportingAsync();
@@ -126,7 +128,7 @@ public class ProjectReportingTests
                 var pagination = new Pagination(currentPage: 1, pageSize: 0, totalCount: 0, totalPages: 1);
                 return Task.FromResult(new ProjectAdminDtoPagedResponse(data: [], pagination: pagination, statusCode: 200, traceId: "dummy-trace-id"));
             });
-        _projectReporting = new ProjectReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi);
+        _projectReporting = new ProjectReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectQuotaApi);
 
         // Act
         var result = await _projectReporting.GenerateReportingAsync();
@@ -153,7 +155,7 @@ public class ProjectReportingTests
             };
 
         // We want to ensure that GenerateReportingAsync returns some test objects
-        _projectReporting = Substitute.ForPartsOf<ProjectReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi);
+        _projectReporting = Substitute.ForPartsOf<ProjectReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectQuotaApi);
         _projectReporting
             .Configure()
             .GenerateReportingAsync()
@@ -193,7 +195,7 @@ public class ProjectReportingTests
             };
 
         // Partial mock to override GenerateReportingAsync
-        _projectReporting = Substitute.ForPartsOf<ProjectReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi);
+        _projectReporting = Substitute.ForPartsOf<ProjectReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectQuotaApi);
         _projectReporting
             .Configure()
             .GenerateReportingAsync()
@@ -233,7 +235,7 @@ public class ProjectReportingTests
             };
 
         // Partial mock to override GenerateReportingAsync
-        _projectReporting = Substitute.ForPartsOf<ProjectReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi);
+        _projectReporting = Substitute.ForPartsOf<ProjectReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectQuotaApi);
         _projectReporting
             .Configure()
             .GenerateReportingAsync()
@@ -270,7 +272,7 @@ public class ProjectReportingTests
             };
 
         // Partial mock
-        _projectReporting = Substitute.ForPartsOf<ProjectReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi);
+        _projectReporting = Substitute.ForPartsOf<ProjectReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectQuotaApi);
         _projectReporting
             .Configure()
             .GenerateReportingAsync()
diff --git a/src/KpiGenerator/KpiGenerator.csproj b/src/KpiGenerator/KpiGenerator.csproj
index c304988..bc810e6 100644
--- a/src/KpiGenerator/KpiGenerator.csproj
+++ b/src/KpiGenerator/KpiGenerator.csproj
@@ -21,7 +21,7 @@
 		<PackageReference Include="AutoMapper" Version="12.0.1" />
 		<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
 		<PackageReference Include="CommandLineParser" Version="2.9.1" />
-		<PackageReference Include="Coscine.ApiClient" Version="1.9.9" />
+		<PackageReference Include="Coscine.ApiClient" Version="1.10.0" />
 		<PackageReference Include="dotNetRdf.Core" Version="3.1.1" />
 		<PackageReference Include="GitLabApiClient" Version="1.8.1-beta.5" />
 		<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
diff --git a/src/KpiGenerator/Program.cs b/src/KpiGenerator/Program.cs
index 55e6679..cd1df9d 100644
--- a/src/KpiGenerator/Program.cs
+++ b/src/KpiGenerator/Program.cs
@@ -176,7 +176,7 @@ public class Program
             BasePath = $"{reportingConfiguration.Endpoint.TrimEnd('/')}/coscine",
             ApiKeyPrefix = { { "Authorization", "Bearer" } },
             ApiKey = { { "Authorization", reportingConfiguration.ApiKey } },
-            Timeout = TimeSpan.FromSeconds(300) // 5 minutes
+            Timeout = TimeSpan.FromSeconds(300), // 5 minutes
         };
         services.AddSingleton<IAdminApi>(new AdminApi(apiConfiguration));
         services.AddSingleton<IApplicationProfileApi>(new ApplicationProfileApi(apiConfiguration));
diff --git a/src/KpiGenerator/Reportings/Project/ProjectReporting.cs b/src/KpiGenerator/Reportings/Project/ProjectReporting.cs
index fd98154..da977cb 100644
--- a/src/KpiGenerator/Reportings/Project/ProjectReporting.cs
+++ b/src/KpiGenerator/Reportings/Project/ProjectReporting.cs
@@ -22,6 +22,7 @@ public class ProjectReporting
     private readonly KpiConfiguration _kpiConfiguration;
     private readonly ReportingConfiguration _reportingConfiguration;
     private readonly IAdminApi _adminApi;
+    private readonly IProjectQuotaApi _projectQuotaApi;
 
     public ProjectReportingOptions Options { get; private set; } = null!;
     public string ReportingFileName { get; }
@@ -33,7 +34,8 @@ public class ProjectReporting
         [FromKeyedServices("local")] IStorageService localStorageService,
         IOptionsMonitor<KpiConfiguration> kpiConfiguration,
         IOptionsMonitor<ReportingConfiguration> reportingConfiguration,
-        IAdminApi adminApi
+        IAdminApi adminApi,
+        IProjectQuotaApi projectQuotaApi
     )
     {
         _mapper = mapper;
@@ -45,6 +47,7 @@ public class ProjectReporting
         ReportingFileName = _kpiConfiguration.ProjectKpi.FileName;
 
         _adminApi = adminApi;
+        _projectQuotaApi = projectQuotaApi;
     }
 
     public async Task<bool> RunAsync(ProjectReportingOptions reportingOptions)
@@ -84,8 +87,8 @@ public class ProjectReporting
         var projects = PaginationHelper.GetAllAsync<ProjectAdminDtoPagedResponse, ProjectAdminDto>(
                 (currentPage) =>
                 {
-                _logger.LogDebug("Getting page {page} of projects...", currentPage);
-                    return _adminApi.GetAllProjectsAsync(includeDeleted: false, includeQuotas: true, includePublicationRequests: true, pageNumber: currentPage, pageSize: 50);
+                    _logger.LogDebug("Getting page {page} of projects...", currentPage);
+                    return _adminApi.GetAllProjectsAsync(includeDeleted: false, includeQuotas: false, includePublicationRequests: true, pageNumber: currentPage, pageSize: 50);
                 });
 
         var reportingFiles = new List<ReportingFileObject>();
@@ -95,6 +98,22 @@ public class ProjectReporting
         await foreach (var project in projects)
         {
             _logger.LogDebug("Processing project {projectId}...", project.Id);
+            var quotas = PaginationHelper.GetAllAsync<ProjectQuotaDtoPagedResponse, ProjectQuotaDto>(
+                (currentPage) =>
+                {
+                    _logger.LogDebug("Getting page {page} of quotas for project {projectId}...", currentPage, project.Id);
+                    return _projectQuotaApi.GetProjectQuotasAsync(project.Id.ToString(), pageNumber: currentPage, pageSize: 50);
+                });
+            await foreach (var quota in quotas)
+            {
+                if (quota == null)
+                {
+                    _logger.LogWarning("Quota for project {projectId} is null, skipping...", project.Id);
+                    continue;
+                }
+                // Map the quota to the project
+                project.ProjectQuota.Add(quota);
+            }
             var returnObject = _mapper.Map<ProjectReport>(project);
             returnObjects.Add(returnObject);
         }
-- 
GitLab