diff --git a/src/KpiGenerator.Tests/ProjectReportingTests.cs b/src/KpiGenerator.Tests/ProjectReportingTests.cs index 861c6fc046885a1b48d1d0ce3c2c307b8365b53c..5c9240680e8b0f9f0c106af6c4beaf3b3917343a 100644 --- a/src/KpiGenerator.Tests/ProjectReportingTests.cs +++ b/src/KpiGenerator.Tests/ProjectReportingTests.cs @@ -25,8 +25,8 @@ public class ProjectReportingTests private IOptionsMonitor<KpiConfiguration> _kpiConfiguration = null!; private IOptionsMonitor<ReportingConfiguration> _reportingConfiguration = null!; - private IAdminApi _adminApi = null!; - + private IProjectQuotaApi _projectQuotaApi = null!; + private IProjectCacheService _projectCacheService = null!; private ProjectReporting _projectReporting = null!; // System Under Test [SetUp] @@ -69,7 +69,8 @@ public class ProjectReportingTests _reportingConfiguration = Substitute.For<IOptionsMonitor<ReportingConfiguration>>(); _reportingConfiguration.CurrentValue.Returns(reportingConfig); - _adminApi = Substitute.For<IAdminApi>(); + _projectCacheService = Substitute.For<IProjectCacheService>(); + _projectQuotaApi = Substitute.For<IProjectQuotaApi>(); } #region GenerateReportingAsync Tests @@ -80,21 +81,10 @@ public class ProjectReportingTests // Arrange var projects = TestData.ProjectAdminDtos; - _adminApi - .GetAllProjectsAsync( - includeDeleted: Arg.Any<bool>(), - includeQuotas: Arg.Any<bool>(), - includePublicationRequests: Arg.Any<bool>(), - pageNumber: Arg.Any<int>(), - pageSize: Arg.Any<int>() - ) - .Returns(ci => - { - // Return the test projects data, single page - 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); + _projectCacheService + .GetAllProjectsAsync() + .Returns(ci => Task.FromResult(projects)); + _projectReporting = new ProjectReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _projectCacheService, _projectQuotaApi); // Act var result = await _projectReporting.GenerateReportingAsync(); @@ -118,15 +108,10 @@ public class ProjectReportingTests public async Task GenerateReportingAsync_ReturnsOnlyGeneralFile_WhenNoProjects() { // Arrange - _adminApi + _projectCacheService .GetAllProjectsAsync() - .Returns(ci => - { - // No projects, empty data - 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); + .Returns(ci => Task.FromResult(new List<ProjectAdminDto>())); + _projectReporting = new ProjectReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _projectCacheService, _projectQuotaApi); // Act var result = await _projectReporting.GenerateReportingAsync(); @@ -153,7 +138,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, _projectCacheService, _projectQuotaApi); _projectReporting .Configure() .GenerateReportingAsync() @@ -193,7 +178,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, _projectCacheService, _projectQuotaApi); _projectReporting .Configure() .GenerateReportingAsync() @@ -233,7 +218,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, _projectCacheService, _projectQuotaApi); _projectReporting .Configure() .GenerateReportingAsync() @@ -270,7 +255,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, _projectCacheService, _projectQuotaApi); _projectReporting .Configure() .GenerateReportingAsync() diff --git a/src/KpiGenerator.Tests/ResourceReportingTests.cs b/src/KpiGenerator.Tests/ResourceReportingTests.cs index ebd6030c7a728c925b138f7a6d380d89ffd8022f..652e4c907baa6f0d875934a4150abe2e63d8a485 100644 --- a/src/KpiGenerator.Tests/ResourceReportingTests.cs +++ b/src/KpiGenerator.Tests/ResourceReportingTests.cs @@ -26,7 +26,7 @@ public class ResourceReportingTests private IOptionsMonitor<ReportingConfiguration> _reportingConfiguration = null!; private IAdminApi _adminApi = null!; - + private IProjectCacheService _projectCacheService = null!; private ResourceReporting _resourceReporting = null!; // System Under Test [SetUp] @@ -68,8 +68,9 @@ public class ResourceReportingTests }; _reportingConfiguration = Substitute.For<IOptionsMonitor<ReportingConfiguration>>(); _reportingConfiguration.CurrentValue.Returns(reportingConfig); - + _adminApi = Substitute.For<IAdminApi>(); + _projectCacheService = Substitute.For<IProjectCacheService>(); } #region GenerateReportingAsync Tests @@ -81,18 +82,9 @@ public class ResourceReportingTests var projects = TestData.ProjectAdminDtos; var resources = TestData.ResourceAdminDtos; - _adminApi - .GetAllProjectsAsync( - includeDeleted: Arg.Any<bool>(), - pageNumber: Arg.Any<int>(), - pageSize: Arg.Any<int>() - ) - .Returns(ci => - { - // Return the test projects data, single page - 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")); - }); + _projectCacheService + .GetAllProjectsAsync() + .Returns(ci => Task.FromResult(projects)); _adminApi .GetAllResourcesAsync( includeDeleted: Arg.Any<bool>(), @@ -106,7 +98,7 @@ public class ResourceReportingTests var pagination = new Pagination(currentPage: 1, pageSize: 2, totalCount: 2, totalPages: 1); return Task.FromResult(new ResourceAdminDtoPagedResponse(data: resources, pagination: pagination, statusCode: 200, traceId: "dummy-trace-id")); }); - _resourceReporting = new ResourceReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi); + _resourceReporting = new ResourceReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectCacheService); // Act var result = await _resourceReporting.GenerateReportingAsync(); @@ -130,14 +122,9 @@ public class ResourceReportingTests public async Task GenerateReportingAsync_ReturnsOnlyGeneralFile_WhenNoProjects() { // Arrange - _adminApi + _projectCacheService .GetAllProjectsAsync() - .Returns(ci => - { - // No projects, empty data - 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")); - }); + .Returns(ci => Task.FromResult(new List<ProjectAdminDto>())); _adminApi .GetAllResourcesAsync() .Returns(ci => @@ -146,7 +133,7 @@ public class ResourceReportingTests var pagination = new Pagination(currentPage: 1, pageSize: 0, totalCount: 0, totalPages: 1); return Task.FromResult(new ResourceAdminDtoPagedResponse(data: [], pagination: pagination, statusCode: 200, traceId: "dummy-trace-id")); }); - _resourceReporting = new ResourceReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi); + _resourceReporting = new ResourceReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectCacheService); // Act var result = await _resourceReporting.GenerateReportingAsync(); @@ -173,7 +160,7 @@ public class ResourceReportingTests }; // We want to ensure that GenerateReportingAsync returns some test objects - _resourceReporting = Substitute.ForPartsOf<ResourceReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi); + _resourceReporting = Substitute.ForPartsOf<ResourceReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectCacheService); _resourceReporting .Configure() .GenerateReportingAsync() @@ -213,7 +200,7 @@ public class ResourceReportingTests }; // Partial mock to override GenerateReportingAsync - _resourceReporting = Substitute.ForPartsOf<ResourceReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi); + _resourceReporting = Substitute.ForPartsOf<ResourceReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectCacheService); _resourceReporting .Configure() .GenerateReportingAsync() @@ -253,7 +240,7 @@ public class ResourceReportingTests }; // Partial mock to override GenerateReportingAsync - _resourceReporting = Substitute.ForPartsOf<ResourceReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi); + _resourceReporting = Substitute.ForPartsOf<ResourceReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectCacheService); _resourceReporting .Configure() .GenerateReportingAsync() @@ -290,7 +277,7 @@ public class ResourceReportingTests }; // Partial mock - _resourceReporting = Substitute.ForPartsOf<ResourceReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi); + _resourceReporting = Substitute.ForPartsOf<ResourceReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _projectCacheService); _resourceReporting .Configure() .GenerateReportingAsync() diff --git a/src/KpiGenerator.Tests/UserReportingTests.cs b/src/KpiGenerator.Tests/UserReportingTests.cs index 5386dbd1b25154449f4d568d8308f4e094bb2fef..e17434cb0f22a2c497c4ac3a7428212dfc79f593 100644 --- a/src/KpiGenerator.Tests/UserReportingTests.cs +++ b/src/KpiGenerator.Tests/UserReportingTests.cs @@ -27,7 +27,7 @@ public class UserReportingTests private IAdminApi _adminApi = null!; private IRoleApi _roleApi = null!; - + private IProjectCacheService _projectCacheService = null!; private UserReporting _userReporting = null!; // System Under Test [SetUp] @@ -72,6 +72,7 @@ public class UserReportingTests _adminApi = Substitute.For<IAdminApi>(); _roleApi = Substitute.For<IRoleApi>(); + _projectCacheService = Substitute.For<IProjectCacheService>(); } #region GenerateReportingAsync Tests @@ -84,18 +85,9 @@ public class UserReportingTests var users = TestData.UserDtos; var roles = TestData.RoleDtos; - _adminApi - .GetAllProjectsAsync( - includeDeleted: Arg.Any<bool>(), - pageNumber: Arg.Any<int>(), - pageSize: Arg.Any<int>() - ) - .Returns(ci => - { - // Return the test projects data, single page - 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")); - }); + _projectCacheService + .GetAllProjectsAsync() + .Returns(ci => Task.FromResult(projects)); _adminApi .GetAllUsersAsync( tosAccepted: Arg.Any<bool>(), @@ -119,7 +111,7 @@ public class UserReportingTests var pagination = new Pagination(currentPage: 1, pageSize: 2, totalCount: 2, totalPages: 1); return Task.FromResult(new RoleDtoPagedResponse(data: roles, pagination: pagination, statusCode: 200, traceId: "dummy-trace-id")); }); - _userReporting = new UserReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi); + _userReporting = new UserReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi, _projectCacheService); // Act var result = await _userReporting.GenerateReportingAsync(); @@ -143,14 +135,9 @@ public class UserReportingTests public async Task GenerateReportingAsync_ReturnsOnlyGeneralFile_WhenNoProjects() { // Arrange - _adminApi + _projectCacheService .GetAllProjectsAsync() - .Returns(ci => - { - // No projects, empty data - 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")); - }); + .Returns(ci => Task.FromResult(new List<ProjectAdminDto>())); _adminApi .GetAllUsersAsync() .Returns(ci => @@ -167,7 +154,7 @@ public class UserReportingTests var pagination = new Pagination(currentPage: 1, pageSize: 0, totalCount: 0, totalPages: 1); return Task.FromResult(new RoleDtoPagedResponse(data: [], pagination: pagination, statusCode: 200, traceId: "dummy-trace-id")); }); - _userReporting = new UserReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi); + _userReporting = new UserReporting(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi, _projectCacheService); // Act var result = await _userReporting.GenerateReportingAsync(); @@ -194,7 +181,7 @@ public class UserReportingTests }; // We want to ensure that GenerateReportingAsync returns some test objects - _userReporting = Substitute.ForPartsOf<UserReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi); + _userReporting = Substitute.ForPartsOf<UserReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi, _projectCacheService); _userReporting .Configure() .GenerateReportingAsync() @@ -234,7 +221,7 @@ public class UserReportingTests }; // Partial mock to override GenerateReportingAsync - _userReporting = Substitute.ForPartsOf<UserReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi); + _userReporting = Substitute.ForPartsOf<UserReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi, _projectCacheService); _userReporting .Configure() .GenerateReportingAsync() @@ -274,7 +261,7 @@ public class UserReportingTests }; // Partial mock to override GenerateReportingAsync - _userReporting = Substitute.ForPartsOf<UserReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi); + _userReporting = Substitute.ForPartsOf<UserReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi, _projectCacheService); _userReporting .Configure() .GenerateReportingAsync() @@ -311,7 +298,7 @@ public class UserReportingTests }; // Partial mock - _userReporting = Substitute.ForPartsOf<UserReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi); + _userReporting = Substitute.ForPartsOf<UserReporting>(_mapper, _logger, _gitlabStorageService, _localStorageService, _kpiConfiguration, _reportingConfiguration, _adminApi, _roleApi, _projectCacheService); _userReporting .Configure() .GenerateReportingAsync() diff --git a/src/KpiGenerator/KpiGenerator.csproj b/src/KpiGenerator/KpiGenerator.csproj index c3049884b6b06f479f47aa56b123d9f6d6304911..bc810e6d91d17f9020f35692816848df1a432215 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 55e66793b76afaaeea3961f678a21b01d3e89561..5c1aa636da821e4613ba998f391b3f30d7b5c3e9 100644 --- a/src/KpiGenerator/Program.cs +++ b/src/KpiGenerator/Program.cs @@ -176,10 +176,11 @@ 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)); + services.AddSingleton<IProjectCacheService, ProjectCacheService>(); services.AddSingleton<IProjectApi>(new ProjectApi(apiConfiguration)); services.AddSingleton<IProjectQuotaApi>(new ProjectQuotaApi(apiConfiguration)); services.AddSingleton<IProjectResourceQuotaApi>(new ProjectResourceQuotaApi(apiConfiguration)); diff --git a/src/KpiGenerator/Reportings/Project/ProjectReporting.cs b/src/KpiGenerator/Reportings/Project/ProjectReporting.cs index e8bee5ee1d5235deb95e48cac58a5b1ed03fe0da..08787f782bf484caba645a5e62d35d392cb6fdd9 100644 --- a/src/KpiGenerator/Reportings/Project/ProjectReporting.cs +++ b/src/KpiGenerator/Reportings/Project/ProjectReporting.cs @@ -21,7 +21,8 @@ public class ProjectReporting private readonly IStorageService _localStorageService; private readonly KpiConfiguration _kpiConfiguration; private readonly ReportingConfiguration _reportingConfiguration; - private readonly IAdminApi _adminApi; + private readonly IProjectCacheService _projectCacheService; + 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 + IProjectCacheService projectCacheService, + IProjectQuotaApi projectQuotaApi ) { _mapper = mapper; @@ -44,7 +46,8 @@ public class ProjectReporting _reportingConfiguration = reportingConfiguration.CurrentValue; ReportingFileName = _kpiConfiguration.ProjectKpi.FileName; - _adminApi = adminApi; + _projectCacheService = projectCacheService; + _projectQuotaApi = projectQuotaApi; } public async Task<bool> RunAsync(ProjectReportingOptions reportingOptions) @@ -81,16 +84,36 @@ public class ProjectReporting public virtual async Task<IEnumerable<ReportingFileObject>> GenerateReportingAsync() { _logger.LogDebug("Working on projects asynchronously..."); - var projects = PaginationHelper.GetAllAsync<ProjectAdminDtoPagedResponse, ProjectAdminDto>( - (currentPage) => _adminApi.GetAllProjectsAsync(includeDeleted: false, includeQuotas: true, includePublicationRequests: true, pageNumber: currentPage, pageSize: 50)); + var projects = await _projectCacheService.GetAllProjectsAsync(); + _logger.LogInformation("Found {count} projects.", projects.Count); + + // Filter out projects that are deleted + projects = [.. projects.Where(p => !p.Deleted)]; + _logger.LogInformation("Filtered out deleted projects. Remaining projects: {count}", projects.Count); var reportingFiles = new List<ReportingFileObject>(); var returnObjects = new List<ProjectReport>(); // Additional processing - await foreach (var project in projects) + 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); } diff --git a/src/KpiGenerator/Reportings/Resource/ResourceReporting.cs b/src/KpiGenerator/Reportings/Resource/ResourceReporting.cs index 48fb60b78c12173a504a2c19233f4601be17f7be..e2d4cb552b46682dc3ef31536d84d528ede2d3a5 100644 --- a/src/KpiGenerator/Reportings/Resource/ResourceReporting.cs +++ b/src/KpiGenerator/Reportings/Resource/ResourceReporting.cs @@ -23,6 +23,7 @@ public class ResourceReporting private readonly KpiConfiguration _kpiConfiguration; private readonly ReportingConfiguration _reportingConfiguration; private readonly IAdminApi _adminApi; + private readonly IProjectCacheService _projectCacheService; public ResourceReportingOptions Options { get; private set; } = null!; public string ReportingFileName { get; } @@ -34,7 +35,8 @@ public class ResourceReporting [FromKeyedServices("local")] IStorageService localStorageService, IOptionsMonitor<KpiConfiguration> kpiConfiguration, IOptionsMonitor<ReportingConfiguration> reportingConfiguration, - IAdminApi adminApi + IAdminApi adminApi, + IProjectCacheService projectCacheService ) { _mapper = mapper; @@ -44,16 +46,8 @@ public class ResourceReporting _kpiConfiguration = kpiConfiguration.CurrentValue; _reportingConfiguration = reportingConfiguration.CurrentValue; ReportingFileName = _kpiConfiguration.ResourceKpi.FileName; - - var configuration = new Configuration() - { - BasePath = $"{_reportingConfiguration.Endpoint.TrimEnd('/')}/coscine", - ApiKeyPrefix = { { "Authorization", "Bearer" } }, - ApiKey = { { "Authorization", _reportingConfiguration.ApiKey } }, - Timeout = TimeSpan.FromSeconds(300) // 5 minutes - }; - _adminApi = adminApi; + _projectCacheService = projectCacheService; } public async Task<bool> RunAsync(ResourceReportingOptions reportingOptions) @@ -89,13 +83,16 @@ public class ResourceReporting public virtual async Task<IEnumerable<ReportingFileObject>> GenerateReportingAsync() { _logger.LogDebug("Getting all projects..."); - var projects = await PaginationHelper.GetAllAsync<ProjectAdminDtoPagedResponse, ProjectAdminDto>( - (currentPage) => _adminApi.GetAllProjectsAsync(includeDeleted: true, pageNumber: currentPage, pageSize: 50)).ToListAsync(); - _logger.LogDebug("Got all projects."); + var projects = await _projectCacheService.GetAllProjectsAsync(); + _logger.LogDebug("Got all {count} projects, including deleted ones.", projects.Count); _logger.LogDebug("Working on resources asynchronously..."); var resources = PaginationHelper.GetAllAsync<ResourceAdminDtoPagedResponse, ResourceAdminDto>( - (currentPage) => _adminApi.GetAllResourcesAsync(includeDeleted: false, includeQuotas: true, pageNumber: currentPage, pageSize: 50)); + (currentPage) => + { + _logger.LogDebug("Getting page {page} of resources...", currentPage); + return _adminApi.GetAllResourcesAsync(includeDeleted: false, includeQuotas: true, pageNumber: currentPage, pageSize: 10); + }); var reportingFiles = new List<ReportingFileObject>(); var returnObjects = new List<ResourceReport>(); diff --git a/src/KpiGenerator/Reportings/User/UserReporting.cs b/src/KpiGenerator/Reportings/User/UserReporting.cs index 8db2ad4d1e6c4720e521f501d80a401e2d6bbda6..e7a18367a50360299395628b3e6115e0965e5249 100644 --- a/src/KpiGenerator/Reportings/User/UserReporting.cs +++ b/src/KpiGenerator/Reportings/User/UserReporting.cs @@ -23,6 +23,7 @@ public class UserReporting private readonly ReportingConfiguration _reportingConfiguration; private readonly IAdminApi _adminApi; private readonly IRoleApi _roleApi; + private readonly IProjectCacheService _projectCacheService; public UserReportingOptions Options { get; private set; } = null!; public string ReportingFileName { get; } @@ -35,7 +36,8 @@ public class UserReporting IOptionsMonitor<KpiConfiguration> kpiConfiguration, IOptionsMonitor<ReportingConfiguration> reportingConfiguration, IAdminApi adminApi, - IRoleApi roleApi + IRoleApi roleApi, + IProjectCacheService projectCacheService ) { _mapper = mapper; @@ -48,6 +50,7 @@ public class UserReporting _adminApi = adminApi; _roleApi = roleApi; + _projectCacheService = projectCacheService; } public async Task<bool> RunAsync(UserReportingOptions reportingOptions) @@ -83,9 +86,10 @@ public class UserReporting public virtual async Task<IEnumerable<ReportingFileObject>> GenerateReportingAsync() { _logger.LogDebug("Getting all projects..."); - var projects = await PaginationHelper.GetAllAsync<ProjectAdminDtoPagedResponse, ProjectAdminDto>( - (currentPage) => _adminApi.GetAllProjectsAsync(includeDeleted: false, pageNumber: currentPage, pageSize: 50)).ToListAsync(); - _logger.LogDebug("Got all projects."); + var projects = await _projectCacheService.GetAllProjectsAsync(); + // Filter out projects that are deleted + projects = [.. projects.Where(p => !p.Deleted)]; + _logger.LogInformation("Filtered out deleted projects. Remaining projects: {count}", projects.Count); _logger.LogDebug("Getting all roles..."); var roles = await PaginationHelper.GetAllAsync<RoleDtoPagedResponse, RoleDto>( @@ -94,7 +98,11 @@ public class UserReporting _logger.LogDebug("Working on users asynchronously..."); var users = PaginationHelper.GetAllAsync<UserDtoPagedResponse, UserDto>( - (currentPage) => _adminApi.GetAllUsersAsync(tosAccepted: true, pageNumber: currentPage, pageSize: 50)); + (currentPage) => + { + _logger.LogDebug("Getting page {page} of users...", currentPage); + return _adminApi.GetAllUsersAsync(tosAccepted: true, pageNumber: currentPage, pageSize: 10); + }); var reportingFiles = new List<ReportingFileObject>(); var returnObjects = new List<UserReport>(); diff --git a/src/KpiGenerator/Utils/ProjectCacheService.cs b/src/KpiGenerator/Utils/ProjectCacheService.cs new file mode 100644 index 0000000000000000000000000000000000000000..5416492f7cde8bdac9cf64f4a2fde71156422b4e --- /dev/null +++ b/src/KpiGenerator/Utils/ProjectCacheService.cs @@ -0,0 +1,35 @@ +using Coscine.ApiClient; +using Coscine.ApiClient.Core.Api; +using Coscine.ApiClient.Core.Model; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; + +namespace Coscine.KpiGenerator.Utils; + +public interface IProjectCacheService +{ + Task<List<ProjectAdminDto>> GetAllProjectsAsync(); +} + +public class ProjectCacheService(IAdminApi adminApi, IMemoryCache cache, ILogger<ProjectCacheService> logger) : IProjectCacheService +{ + private const string CacheKey = "AllProjects"; + private readonly IAdminApi _adminApi = adminApi; + private readonly IMemoryCache _cache = cache; + private readonly ILogger<ProjectCacheService> _logger = logger; + + public async Task<List<ProjectAdminDto>> GetAllProjectsAsync() + { + return await _cache.GetOrCreateAsync(CacheKey, async entry => + { + entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(120); + _logger.LogDebug("Fetching all projects from API"); + var list = await PaginationHelper + .GetAllAsync<ProjectAdminDtoPagedResponse, ProjectAdminDto>( + page => _adminApi.GetAllProjectsAsync(includeDeleted: true, includePublicationRequests: true, pageNumber: page, pageSize: 50)) + .ToListAsync(); + _logger.LogDebug("Cached {Count} projects", list.Count); + return list; + }) ?? []; + } +}